/* ==========================================================================
   Home film — "The Distance"
   A pinned stage; every element scrubbed by scroll (GSAP). Static-first:
   without JS or under reduced motion the chapters render as stacked blocks.
   ========================================================================== */

.film{position:relative;height:640vh;background:var(--soft)}
.film__stage{position:sticky;top:0;height:100vh;height:100svh;overflow:hidden;background:var(--soft)}
/* the generated field — the ground the camera pulls back through.
   It sits under the photograph, the line, the markers and every beat. */
.film__field{position:absolute;inset:0;z-index:0;width:100%;height:100%;display:block;background:var(--soft)}
.film__photo{position:absolute;inset:0;transform-origin:0% 56%;will-change:transform;z-index:2;background:#dfe6df}
.film__photo img{width:100%;height:100%;object-fit:cover;object-position:52% 46%}
.film__frame{position:absolute;inset:0;border:0 solid rgba(40,40,40,.28);pointer-events:none}
.film__scrim{position:absolute;inset:0;z-index:3;pointer-events:none;background:linear-gradient(90deg,rgba(243,243,243,.84) 0%,rgba(243,243,243,.6) 32%,rgba(243,243,243,0) 60%)}
.film__line{position:absolute;inset:0;width:100%;height:100%;z-index:1;pointer-events:none;overflow:visible}
/* No vector-effect here: the viewBox always matches the stage's CSS box (1:1), so
   non-scaling-stroke changes nothing visually — but it moves dash computation into
   device/host space in some engines (Comet's Chromium 151 at DPR 2, WebKit), where the
   path measures 2L against a dasharray of L and only the first half of the line draws. */
.film__line path{fill:none;stroke:var(--green);stroke-width:1.5;stroke-linecap:round}
.film__line .film__line-ghost{stroke:var(--line);stroke-width:1;stroke-dasharray:2 6}
.film__protein{position:absolute;z-index:1;pointer-events:none;will-change:transform,opacity;opacity:0}
.film__protein img{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);height:100%;width:auto}
.film__protein .film__ring{height:150%;opacity:.42}
.film__protein .film__mol{filter:drop-shadow(0 18px 30px rgba(0,147,69,.18))}
.film__mol-cap{position:absolute;left:50%;top:calc(100% + 14px);transform:translateX(-50%);white-space:nowrap;font-size:var(--fs-label);font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--fg-2)}

/* markers along the line */
.film__markers{position:absolute;inset:0;z-index:2;pointer-events:none}
.mk{position:absolute;left:0;top:0;width:0;height:0;opacity:0;will-change:opacity,transform}
.mk__dot{position:absolute;left:-6px;top:-6px;width:12px;height:12px;border-radius:var(--r-pill);background:var(--green);box-shadow:0 0 0 4px var(--soft)} /* pill, not 50%: same circle, inside the declared radius vocabulary */
.mk--hollow .mk__dot{background:var(--soft);border:1.5px solid var(--fg-3)}
.mk--now .mk__dot::before{content:"";position:absolute;inset:-8px;border-radius:50%;border:1.5px solid var(--green);opacity:.7;animation:mkpulse 2.4s var(--ease-out) infinite}
@keyframes mkpulse{0%{transform:scale(.55);opacity:.8}100%{transform:scale(1.7);opacity:0}}
.mk__label{position:absolute;left:14px;top:-9px;white-space:nowrap;line-height:1.35}
.mk__label b{display:block;font-size:var(--fs-small);font-weight:500;color:var(--ink)}
.mk__label span{display:block;font-size:var(--fs-label);letter-spacing:.06em;text-transform:uppercase;color:var(--fg-2)}
.mk--now .mk__label span{color:var(--green-text)}
.mk--above .mk__label{top:auto;bottom:16px;left:0;transform:translateX(-50%);text-align:center}
.mk--below .mk__label{top:18px;left:0;transform:translateX(-50%);text-align:center}
.mk--right .mk__label{left:16px;top:-9px}
.mk--hollow .mk__label b{color:var(--fg-2)}

/* beats */
.beat{position:absolute;z-index:4;opacity:0;visibility:hidden;will-change:opacity,transform;pointer-events:none}
.beat.is-on{pointer-events:auto}
.beat .label{margin-bottom:16px}
.beat h1,.beat h2{color:var(--ink)}
.beat p{color:var(--fg-1)}
.beat .btn-row{display:flex;flex-wrap:wrap;gap:12px;margin-top:30px}
.beat--hero{left:var(--gutter);right:auto;bottom:clamp(64px,10vh,120px);width:min(640px,60vw)}
.beat--hero h1{margin-bottom:22px}
.beat--hero p:not(.label){font-size:var(--fs-lead);font-weight:300;line-height:1.5;max-width:52ch}
.beat--side{left:46vw;top:calc(var(--header-h) + 2vh);width:min(560px,44vw)}
.beat--side h2{font-size:clamp(1.625rem,2.4vw,2.125rem);font-weight:400;line-height:1.16;letter-spacing:-.012em;margin-bottom:12px}
.beat--side p:not(.label){font-size:var(--fs-small);font-size:.9375rem;line-height:1.55;max-width:56ch}
.beat--side .stat{margin-top:20px;flex-direction:row;align-items:baseline;gap:12px}
.beat--side .stat b{font-size:clamp(2rem,3.4vw,2.75rem)}
.beat--side .stat span{max-width:32ch}
.beat--side .link{margin-top:16px}
/* session 11: the eyebrow is a <p>, so the beats' paragraph rules (0,1,1) had been outranking the
   `.label` role (0,1,0) — the hero/finale eyebrows rendered as 20px/300 lead copy and the side-beat
   eyebrows at 15px. Every paragraph rule above and below is `p:not(.label)` now: eyebrows take the
   role and the site-wide tiers (`.label:has(+ .display)` / `:has(+ .h1)` in site.css), and a
   browser without :has() gets the 12px base. Colour still comes from `.beat p` on purpose — --fg-1
   is what every contrast audit has measured over the footage. */
.beat--finale{left:var(--gutter);bottom:clamp(64px,10vh,120px);width:min(640px,60vw)}
.beat--finale h2{margin-bottom:16px}
.beat--finale p:not(.label){font-size:var(--fs-lead);font-weight:300;line-height:1.5;max-width:50ch}
.beat--finale .btn-row{margin-top:26px}

/* chapter readout */
.film__readout::before{content:"";position:absolute;z-index:-1;inset:-38px -74px -38px -96px;pointer-events:none;background:radial-gradient(ellipse closest-side at 50% 50%,rgba(243,243,243,.95) 0%,rgba(243,243,243,.82) 34%,rgba(243,243,243,.45) 62%,rgba(243,243,243,.14) 82%,rgba(243,243,243,0) 100%)}
.film__readout{position:absolute;right:var(--gutter);bottom:34px;z-index:5;display:flex;align-items:center;gap:14px;font-size:var(--fs-label);font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--fg-2)}
.film__readout b{font-weight:500;color:var(--ink);min-width:8.5em}
/* fg-1, not fg-3: the numeral is visible text and fg-3 measured 2.39:1 over the
   readout haze (session-7 audit) — fg-1 keeps it quieter than the ink name at ~9.5:1 */
.film__readout i{font-style:normal;color:var(--fg-1)}
.film__bar{width:120px;height:1px;background:var(--line);position:relative}
.film__bar span{position:absolute;left:0;top:-1px;height:3px;width:0;background:var(--green);border-radius:var(--r-pill)}
.film__cue{position:absolute;left:50%;bottom:34px;transform:translateX(-50%);z-index:5;width:1px;height:44px;background:linear-gradient(to bottom,transparent,var(--fg-2));opacity:.7}
.film__cue::after{content:"";position:absolute;left:-2px;bottom:0;width:5px;height:5px;border-radius:50%;background:var(--fg-2);animation:cue 2.2s var(--ease-inout) infinite}
@keyframes cue{0%{transform:translateY(-36px);opacity:0}30%{opacity:1}100%{transform:translateY(0);opacity:0}}

/* short viewports */
@media (max-height:820px) and (min-width:761px){
  .beat--hero h1{font-size:clamp(2.5rem,5vw,4.25rem)}
  .beat--hero p:not(.label){font-size:var(--fs-body)}
  .beat--hero,.beat--finale{bottom:48px}
  .beat--finale h2{font-size:clamp(2rem,3.6vw,3rem)}
}

/* mobile beats */
@media (max-width:760px){
  .film{height:560vh}
  .film__photo{transform-origin:0% 0%}
  /* Portrait crop and scrim, both measured rather than guessed:
     - object-position 62% cropped the held hands — the whole emotional subject of
       the photograph — clean out of the frame on a 390px viewport. At 84% the
       hands are in frame and the person is still there. Simulated across the
       real asset at the real cover scale before changing it.
     - the old bottom-up scrim reached zero at 72%, and the hero's eyebrow label
       sits at 79% from the bottom, so it landed in the gap: measured 3.54:1
       against #3A3A3D, below AA for 12px text. The ramp now carries to 94%. */
  .film__scrim{background:linear-gradient(to top,rgba(243,243,243,.78) 0%,rgba(243,243,243,.62) 34%,rgba(243,243,243,.42) 58%,rgba(243,243,243,.22) 78%,rgba(243,243,243,0) 94%),linear-gradient(to bottom,rgba(243,243,243,.7) 0%,rgba(243,243,243,0) 18%)}
  .film__photo img{object-position:84% 58%}
  .beat--hero{width:calc(100% - 2*var(--gutter));bottom:88px}
  .beat--hero p:not(.label){font-size:var(--fs-body)}
  .beat--side{left:39vw;top:calc(var(--header-h) + 8px);width:calc(61vw - var(--gutter))}
  .beat--side h2{font-size:1.5rem;letter-spacing:-.01em;margin-bottom:10px}
  .beat--side p:not(.label){font-size:.9375rem;line-height:1.45}
  .beat--side .more{display:none}
  .beat--side .stat{margin-top:12px;flex-direction:column;gap:2px}
  .beat--side .stat b{font-size:1.75rem}
  .beat--finale{width:calc(100% - 2*var(--gutter));bottom:88px}
  .beat--finale p:not(.label){font-size:var(--fs-body)}
  .mk__label b{font-size:.8125rem}
  .mk__label span{font-size:.625rem}
  /* The "now" marker carries the longest label ("Phase 1/Phase 2 · muscle atrophy"); to the right of its dot it ran past the
     viewport edge (measured 427 px on a 390 px phone, session 26). It sits left of the dot and wraps to two lines instead. */
  .film:not(.film--static) .mk--now .mk__label{left:auto;right:30px;text-align:right;white-space:normal;width:max-content;max-width:140px}
  .film__readout{left:var(--gutter);right:auto;bottom:22px}
  .film__readout .film__bar{width:64px}
  .film__cue{display:none}
  .film__mol-cap{display:none}
}

/* ---------- static / reduced-motion rendering ---------- */
.film--static{height:auto}
.film--static .film__stage{position:relative;height:auto;overflow:visible;background:var(--soft);display:flex;flex-direction:column}
.film--static .film__photo{position:relative;inset:auto;height:min(70vh,640px);transform:none!important;order:1;background:none}
.film--static .film__field,.film--static .film__frame,.film--static .film__line,.film--static .film__markers,.film--static .film__protein,.film--static .film__readout,.film--static .film__cue,.film--static .film__scrim{display:none}
/* The stage is a flex column here, and a flex item with auto inline margins does not
   stretch — each chapter became a centred shrink-to-fit box, so the five left edges
   wandered with headline length (281/278/156/289/197px at 1440). Every chapter now
   takes the container's own width and starts where every section below starts. */
.film--static .beat{position:relative;left:auto;right:auto;top:auto;bottom:auto;width:min(var(--container),100% - 2*var(--gutter));max-width:none;opacity:1;visibility:visible;pointer-events:auto;transform:none!important;padding:clamp(48px,7vw,88px) 0 0;margin-inline:auto;align-self:center;box-sizing:border-box}
.film--static .beat--hero{order:0;padding-top:calc(var(--header-h) + clamp(48px,8vw,104px));padding-bottom:clamp(40px,6vw,72px)}
.film--static .beat--hero h1{max-width:16ch}
.film--static .beat--side{order:2}
.film--static .film__static-figure{display:block;order:3;width:min(var(--container),100% - 2*var(--gutter));margin:48px auto 0}
.film--static .beat--finale{order:4;padding-bottom:clamp(56px,8vw,96px)}
.film__static-figure{display:none}
.film__static-figure svg{width:100%;height:auto}
.film__static-figure text{font-family:var(--font)}
/* A 1200-unit SVG scaled to a 350px phone column leaves ~4px labels. Below 760px the
   static render hides the diagram and lays the same five markers out as a vertical
   timeline (the pipeline page's .timeline idiom): real DOM text, readable at any size. */
@media (max-width:760px){
  .film--static .film__static-figure{display:none}
  .film--static .film__markers{display:block;position:relative;inset:auto;order:3;width:min(var(--container),100% - 2*var(--gutter));margin:40px auto 0;padding-left:22px;border-left:1px solid var(--line)}
  .film--static .mk{position:relative;left:auto;top:auto;width:auto;height:auto;opacity:1;transform:none!important;padding:0 0 18px}
  .film--static .mk:last-child{padding-bottom:0}
  .film--static .mk__dot{left:-27px;top:7px;width:9px;height:9px;box-shadow:none}
  .film--static .mk--now .mk__dot{box-shadow:0 0 0 4px var(--tint)}
  .film--static .mk--now .mk__dot::before{display:none}
  .film--static .mk__label{position:static;transform:none;white-space:normal;text-align:left;line-height:1.4}
  .film--static .mk__label b{font-size:var(--fs-small)}
  .film--static .mk__label span{font-size:var(--fs-label)}
}
