  /*
  Frame Lighting — combined stylesheet
  =====================================

  PIPELINE (top to bottom):
  1. --mx / --my        raw mouse position, 0-1, each set by exactly
                         ONE Webflow trigger (no shared-variable
                         fighting between axes).
  2. --b-*              8 geometric brightness fractions (0-1),
                         pure calc() products of intensity x bias.
                         Corner pairs are naturally identical here.
  3. --f-*              final GRAY COLOR for each end, converted
                         from --b-* via hsl(). These are what the
                         overlays actually use.
  4. --overlay-angle /
     --overlay-angle-bottom
                         the gradient direction each overlay paints
                         in, driven by --s-box. Sculpted frames (the
                         default, --s-box: 0) use the "up/down" sweep
                         across the frame's depth, which reads as
                         more dimensional. Shadowbox (--s-box: 1)
                         rotates 90deg into the corner-matched,
                         along-the-side gradient instead.

  No per-face gain constants — with 100 frame variants, hand-tuning
  a constant per face isn't worth it, and a constant multiplier was
  producing a left/right split even when the mouse was dead-center
  (since it wasn't mouse-dependent) and mismatched peak brightness
  between corners. The angle toggle below replaces that entirely.


  STEP 1 — mouse position
  ------------------------
  Set by the two Webflow mousemove interactions — one horizontal, one
  vertical, each targeting ONLY its own variable, output range 0 to 1.

  REVERTED FROM A SCOPED VERSION — read this before trying again.
  These briefly lived on .artwork-padding, with JS/frame-lighting.js doing the
  pointer tracking, to avoid the whole-document style invalidation that a :root
  custom property write causes on every mousemove. The perf reasoning still
  holds, but the change as written was broken:

    Declaring `--mx: 0.5` on .artwork-padding SHADOWS the inherited :root value
    for that whole subtree. So the Webflow interaction kept writing :root and
    the overlays never saw it — and critically, that stayed broken after
    reverting the interactions, because this declaration was still here.

  If you retry the scoped version, the declarations and the writer have to move
  together, atomically:
    1. Webflow interactions disabled AND JS/frame-lighting.js loaded, or
    2. neither — declarations back on :root, as they are now.
  Half of either state produces no lighting at all.
*/

:root {
  --mx: 0.5; /* 0 = left edge, 1 = right edge — set by horizontal trigger */
  --my: 0.5; /* 0 = top edge,  1 = bottom edge — set by vertical trigger */

  /*
    STEP 2 — geometric brightness (0-1)
    ---------------------------------------------------------------
    Each side's overall intensity comes from the axis perpendicular
    to it; each end's bias comes from the axis running along it.
    Corner-pair formulas are identical by construction (e.g.
    top-right and right-top both reduce to mx * (1 - my)) — that's
    what fixes the x/y fighting and gives matching corners for free.
  */
  --b-top-left:     calc((1 - var(--my)) * (1 - var(--mx)));
  --b-top-right:    calc((1 - var(--my)) * var(--mx));
  --b-right-top:    calc(var(--mx) * (1 - var(--my)));
  --b-right-bottom: calc(var(--mx) * var(--my));
  --b-bottom-right: calc(var(--my) * var(--mx));
  --b-bottom-left:  calc(var(--my) * (1 - var(--mx)));
  --b-left-bottom:  calc((1 - var(--mx)) * var(--my));
  --b-left-top:     calc((1 - var(--mx)) * (1 - var(--my)));

  /*
    STEP 3 — convert each 0-1 brightness number into a gray color.
    --lightness-min / --lightness-max set the darkest/brightest
    lightness the effect can reach; tune to taste. Defaults span
    20% (dark) to 80% (bright), centered on 50% at b = 0.5.
  */
  --lightness-min: 20%;
  --lightness-max: 80%;

  --f-top-left:     hsl(0 0% calc(var(--lightness-min) + var(--b-top-left)     * (var(--lightness-max) - var(--lightness-min))));
  --f-top-right:    hsl(0 0% calc(var(--lightness-min) + var(--b-top-right)    * (var(--lightness-max) - var(--lightness-min))));
  --f-right-top:    hsl(0 0% calc(var(--lightness-min) + var(--b-right-top)    * (var(--lightness-max) - var(--lightness-min))));
  --f-right-bottom: hsl(0 0% calc(var(--lightness-min) + var(--b-right-bottom) * (var(--lightness-max) - var(--lightness-min))));
  --f-bottom-right: hsl(0 0% calc(var(--lightness-min) + var(--b-bottom-right) * (var(--lightness-max) - var(--lightness-min))));
  --f-bottom-left:  hsl(0 0% calc(var(--lightness-min) + var(--b-bottom-left)  * (var(--lightness-max) - var(--lightness-min))));
  --f-left-bottom:  hsl(0 0% calc(var(--lightness-min) + var(--b-left-bottom)  * (var(--lightness-max) - var(--lightness-min))));
  --f-left-top:     hsl(0 0% calc(var(--lightness-min) + var(--b-left-top)     * (var(--lightness-max) - var(--lightness-min))));

  /*
    STEP 4 — gradient angle, driven by --s-box.
    top/right/left: 0deg (sculpted default) -> 90deg (shadowbox).
    bottom: 180deg (sculpted default) -> 270deg (shadowbox), offset
    +180deg from the others because of its ::before rotation quirk.
  */
  --overlay-angle: calc(var(--s-box) * 90deg);
  --overlay-angle-bottom: calc(180deg + var(--s-box) * 90deg);
}

/*
  Overlay gradients
  ------------------
  Each overlay's PARENT carries a fixed rotation (top: 0deg, right:
  90deg, bottom: 180deg, left: -90deg) so one base shape can be
  reused on all four sides. The angle below is the LOCAL angle,
  painted before that parent rotation is applied — do not add the
  parent's rotation on top of it here, it's already accounted for.

  At --s-box: 1 the local angle for top/right/left is 90deg, which
  combined with each side's parent rotation reproduces the original
  corner-matched, along-the-side gradient (verified against top: 0,
  right: 90, left: -90). At --s-box: 0 the local angle is 0deg,
  reusing the same two color vars but sweeping them across the
  frame's depth instead — the "up/down" look.

  Bottom uses its own --overlay-angle-bottom (see note in :root)
  because its rotation is applied via ::before rather than directly
  on its parent. If your gradient rule for bottom actually lives on
  the ::before pseudo-element rather than .overlay-bottom itself,
  move this rule there.
*/

.overlay-top {
  background: linear-gradient(var(--overlay-angle), var(--f-top-left), var(--f-top-right));
  mix-blend-mode: soft-light;
}

.overlay-right {
  background: linear-gradient(var(--overlay-angle), var(--f-right-top), var(--f-right-bottom));
  mix-blend-mode: soft-light;
}

.overlay-bottom {
  background: linear-gradient(var(--overlay-angle-bottom), var(--f-bottom-right), var(--f-bottom-left));
  mix-blend-mode: soft-light;
}

.overlay-left {
  background: linear-gradient(var(--overlay-angle), var(--f-left-bottom), var(--f-left-top));
  mix-blend-mode: soft-light;
}

/*
  REMOVED — blend isolation experiment (.frames-parent / .artwork-reflections).
  The premise was that each blended layer's backdrop snapshot was page-sized and
  costing hundreds of MB. Safari's Layers panel disproved it: 134 layers,
  103 MB total, against 1.2 GB resident. Compositing was never where the memory
  was going, so isolating it had nothing to win. Removed rather than left in as
  a no-op with a misleading rationale attached.
*/

/*
  Notes
  ------
  - Scoping to .artwork-padding means each preview lights independently,
    which also makes this correct inside the slider — every slide gets
    its own --mx/--my instead of sharing one page-wide value.
  - --s-box is still set on :root by frame-substrate-var-updates.js and
    inherits down to here. That's fine: it changes on frame selection,
    not on mousemove, so it isn't in the hot path.
  - Only --mx and --my are written at runtime. Every other variable
    here is derived automatically.
  - Future depth-map idea: if you revisit a per-corner depth-map
    approach later, the natural place to fold it in is a small
    multiplier on each --b-* value before it feeds --f-*, rather than
    reviving the old constant-gain layer.
*/
