/* ============================================================================
   fde-scroll3d.css — THE DOCUMENT CAMERA (for-employers.html)

   Replaces the `.seam` background animation with a real 3D scroll: the PAGE
   moves through depth, not a decoration behind it.

   WHAT THIS FILE OWNS
     1. a real perspective frustum on each chapter (the camera)
     2. the settled, always-readable default state of every depth layer
     3. neutralising the framework's six independent per-chapter reveals,
        because the camera IS the reveal now
     4. the one CSS-pinned room (opt-in markup; JS writes a number, CSS pins)
     5. the reduced-motion hard gate that switches every one of the above off

   WHAT THIS FILE DOES NOT DO — these are contract, not preference:
     • it declares NO z-index, anywhere. Not one. The Z-INDEX CONTRACT
       (--z-media-max:5 / --z-content:10 / --z-ui:40 / --z-topnav:70 /
       --z-overlay:120, nav.css:25-29) is untouched. `perspective` on a
       .cs-chapter creates a stacking context on an element that ALREADY had
       one (position:relative + z-index:var(--z-content,10),
       chaptered-scroll.css:44-51) — so nothing moves in the paint order and
       nothing can occlude text.
     • it animates `transform` and `opacity` only. No width/height/top/left/
       margin/font-size/filter is touched by any rule here. Zero layout, zero
       paint, compositor only.
     • it never hides content by default. There is no opacity:0 and no
       hiding transform outside of a `html.fde3d` scope, and even inside that
       scope the DECLARED state is `transform:none; opacity:1`. The recessed
       states exist only as GSAP inline styles, i.e. only while JS is live.
     • it edits nothing. `html.fde3d` is added by fde-scroll3d.js only while
       the motion gate matches; `.fde-layer`, `[data-fde-cam]`, `.fde-scene`,
       `.is-fde-pinned`, `.fde-beat` are all applied by that script. With
       JavaScript disabled, not a single selector in this file matches and
       the page is byte-for-byte the page you already have.

   TRANSLATE-Z IS ALWAYS NEGATIVE. Layers only ever recede from the picture
   plane, never advance through it. That is what makes the effect safe under
   any `overflow` value and guarantees no layer can ever clip or cover its
   neighbour.

   LOAD ORDER: after shared/chaptered-scroll.css, and ideally after the page's
   own <style> block. The neutralisers below are written at 0,5,1 / 0,6,1 so
   they beat the framework's 0,4,0 / 0,5,0 reveal rules on specificity, not on
   source order — but last is still safest.
   ========================================================================== */


/* ── 1 · THE CAMERA ─────────────────────────────────────────────────────────
   perspective goes on the CHAPTER, never on `.cs`. One shared vanishing point
   stretched over a ~6,000px scroller gives every chapter below the first a
   different, wrong eyeline — chapter six would be viewed from 5,000px above
   its own centre. Per-chapter is the only placement that yields a consistent
   frustum for every room in the document.

   The layers are DIRECT CHILDREN of this element, so they are all projected
   through this one frustum and therefore share one vanishing point. That
   shared frustum is what makes sibling layers read as one 3D space rather
   than as a stack of independently-tilting panels. (Per-element
   `transformPerspective` would give each layer its own vanishing point at its
   own centre — that is the flat, fake-3D look. Not used here.)

   perspective ≈ 2× the transformed block's rendered height is the editorial
   band: below ~800px it fisheyes a serif, above ~2500px it is effectively
   orthographic and you have paid for nothing.

   perspective-origin sits at 38% rather than 50% so the eye line is a little
   above centre — a chapter entering from below then tilts TOWARD the reader's
   eye instead of rotating about its own middle.

   NOTE for future edits: a non-none `perspective` makes this element the
   containing block for `position:fixed` descendants. Verified safe today —
   the rail, arrows and home link are appended to <body>
   (chaptered-scroll.js:96 / 105 / 113), not into a chapter, and no chapter
   contains a fixed element. If one is ever added inside a chapter, exclude
   that chapter with `data-fde-cam-off`.                                     */
html.fde3d .cs-chapter[data-fde-cam]{
  perspective:var(--fde-perspective, 1600px);
  perspective-origin:50% 38%;
  /* the frustum needs an unclipped box. This is the value for-employers.html
     already sets on .cs-chapter (overriding the framework's overflow:hidden);
     it is restated here, scoped to camera chapters only, so the module is not
     silently dependent on a page-level declaration it does not own. */
  overflow:visible;
}


/* ── 2 · THE DEPTH LAYERS — settled default ────────────────────────────────
   `.fde-layer` is applied by JS to the direct children of a camera chapter.
   The declared state is fully settled and fully opaque: if GSAP never runs,
   this is what you see, and it is correct. GSAP's inline transform/opacity
   (inline beats author) is the only thing that ever moves it.               */
html.fde3d .fde-layer{
  transform:none;
  opacity:1;
  /* kills the 1px sub-pixel glyph shimmer WebKit shows on a 3D-projected
     light serif. Costs nothing, no other rule competes for this property. */
  backface-visibility:hidden;
  -webkit-backface-visibility:hidden;
}


/* ── 3 · NEUTRALISE THE FRAMEWORK'S SIX INDEPENDENT REVEALS ────────────────
   chaptered-scroll.css:60-86 fades and lifts every chapter child, then every
   typographic atom inside it, on a CSS transition keyed to `.cs-seen` /
   `.is-active`. That is exactly the "six separate reveals" reading this
   module exists to replace, and its `transition:opacity/transform` would
   double-ease every scrubbed frame into rubber.

   Turned off ONLY while the camera is live (`html.fde3d`, which the script
   adds and removes with the motion gate). Below the gate width, or with JS
   off, or with GSAP missing, the framework's own choreography is untouched.

   Specificity, counted: `html` (1 type) + .fde3d .cs .cs--anim .cs-chapter
   .is-active + :is(.cs-eyebrow…) (6 classes) = 0,6,1, which beats the
   framework's strongest 0,5,0. No `!important` anywhere in this block —
   `transform:none` here MUST stay beatable by GSAP's inline transform.      */
html.fde3d .cs.cs--anim .cs-chapter > *,
html.fde3d .cs.cs--anim .cs-chapter.is-active > *,
html.fde3d .cs.cs--anim .cs-chapter.cs-seen > *,
html.fde3d .cs.cs--anim .cs-chapter :is(.cs-eyebrow,.rig-eyebrow,.num,.mk-head,
  .cs-title,.rig-h2,h1,h2,.cs-lede,.rig-lede,.cs-cta-row,.mk-wrap > *),
html.fde3d .cs.cs--anim .cs-chapter.is-active :is(.cs-eyebrow,.rig-eyebrow,.num,.mk-head,
  .cs-title,.rig-h2,h1,h2,.cs-lede,.rig-lede,.cs-cta-row,.mk-wrap > *),
html.fde3d .cs.cs--anim .cs-chapter.cs-seen :is(.cs-eyebrow,.rig-eyebrow,.num,.mk-head,
  .cs-title,.rig-h2,h1,h2,.cs-lede,.rig-lede,.cs-cta-row,.mk-wrap > *){
  opacity:1;
  transform:none;
  transition:none;
  will-change:auto;
}
/* the CTA micro-interactions (chaptered-scroll.css:109-111) target
   .cs-cta--primary / .cs-cta--ghost, which are CHILDREN of .cs-cta-row and so
   are not matched above. Hover lift, magnetic shadow and focus rings all
   survive intact. Same for .tile:hover / .vcard:hover / .rcpt:hover. */


/* ── 4 · THE ONE PINNED ROOM ───────────────────────────────────────────────
   Fully opt-in. Nothing here matches until the page adds the markup AND the
   script promotes it (see fde-scroll3d.js §4 for the three attributes).

   CSS does the pinning — `position:sticky` inside a tall track — exactly the
   way apple.com's pin scenes do it. Not ScrollTrigger.pin: that injects a
   pin-spacer, re-measures on every refresh, and mis-measures inside a
   transformed ancestor. Here JS only writes one number per beat.

   A chapter that contains a scene is automatically excluded from the camera
   by the script, because a transformed ancestor traps `position:sticky`
   inside its own box.

   The pin is width-gated in CSS as well as in JS. Two independent gates: if
   either the script's matchMedia teardown or this media query is the one that
   fires, the room still returns to ordinary document flow, in order, readable. */
@media (min-width:60rem){
  html.fde3d .fde-scene.is-fde-pinned{
    height:var(--fde-scene-track, 190vh);
    height:var(--fde-scene-track, 190svh);
  }
  html.fde3d .fde-scene.is-fde-pinned > .fde-scene__stage{
    position:sticky;
    top:var(--fde-scene-top, var(--nav-h, 72px));
    height:calc(100vh - var(--fde-scene-top, var(--nav-h, 72px)));
    height:calc(100svh - var(--fde-scene-top, var(--nav-h, 72px)));
    display:grid;
    align-content:center;
    overflow:clip;
  }
  /* beats stack in one grid cell, in DOM order. No z-index needed and none
     given — later beats paint over earlier ones by document order alone. */
  html.fde3d .fde-scene.is-fde-pinned > .fde-scene__stage > .fde-beat{
    grid-area:1 / 1;
    margin-top:0;
    opacity:var(--fde-t, 1);
    transform:translate3d(0, calc((1 - var(--fde-t, 1)) * 26px), 0);
    backface-visibility:hidden;
    -webkit-backface-visibility:hidden;
  }
}


/* ── 5 · THE ACCESSIBILITY HARD GATE ───────────────────────────────────────
   Every transform, every opacity change, every promoted layer and the pin
   itself, switched off. `!important` is deliberate and is used ONLY here: it
   is the one thing that outranks the inline styles GSAP writes, so this block
   is authoritative even if the script's own reduced-motion teardown (which
   also runs — see fde-scroll3d.js, the gate string includes
   `prefers-reduced-motion: no-preference`) somehow did not.

   Selectors are NOT scoped to `html.fde3d`, so this holds even mid-teardown
   or if the root class is left behind by a failed cleanup.

   Result: perspective off, every layer at its natural position and full
   opacity, the scene back in normal document flow with its beats stacked
   vertically and spaced — i.e. exactly the JS-disabled page.               */
@media (prefers-reduced-motion:reduce){
  .cs-chapter[data-fde-cam]{
    perspective:none !important;
    perspective-origin:50% 50% !important;
  }
  .fde-layer,
  .fde-beat{
    transform:none !important;
    opacity:1 !important;
    will-change:auto !important;
    transition:none !important;
    animation:none !important;
    backface-visibility:visible !important;
    -webkit-backface-visibility:visible !important;
  }
  .fde-scene.is-fde-pinned{
    height:auto !important;
  }
  .fde-scene.is-fde-pinned > .fde-scene__stage{
    position:static !important;
    top:auto !important;
    height:auto !important;
    display:block !important;
    overflow:visible !important;
  }
  .fde-scene.is-fde-pinned > .fde-scene__stage > .fde-beat{
    grid-area:auto !important;
  }
  /* !important is required, not stylistic: at >=60rem BOTH media queries
     match, and the pin rule above (0,4,1) would otherwise beat this (0,3,0)
     and collapse every unpinned beat onto zero spacing. */
  .fde-scene.is-fde-pinned > .fde-scene__stage > .fde-beat + .fde-beat{
    margin-top:var(--sp-5, 3.4rem) !important;
  }
}
