/* ============================================================
   v4 — pinned scrollytelling climb.
   Progressive enhancement: default markup is a READABLE STACK
   (works with no JS and under prefers-reduced-motion). scroll.js
   adds `.is-pinned` to enable the sticky, scroll-driven stage where
   the title morphs and the diagram + subtext cross-fade per rung.
   ============================================================ */

/* v4 drives its own progression — drop the v2/v3 section scroll-snap that
   site.css sets on <html>, which otherwise fights the tall pinned scroller.
   In pinned mode we put back a DIFFERENT snap: one mandatory detent per stage
   (see .s-snap below) so each slide is a deliberate stop and a fast flick
   can't skip over one. */
html{scroll-snap-type:none}
/* proximity (not mandatory): the climb's detents still can't be skipped because
   each .s-snap carries scroll-snap-stop:always, but proximity lets the lower
   content sections scroll calmly instead of being force-snapped. */
html.pin{scroll-snap-type:y proximity}
/* lower sections keep site.css's gentle snap-align but drop the forced stop, so
   tall content sections stay freely scrollable. The whole v4 page also shares
   the climb's wider margins so the masthead and sections line up. */
html.pin .section{scroll-snap-stop:normal}
body{--maxw:1320px;--gutter:clamp(24px,5vw,96px)}

/* persistent masthead — the logo sits ABOVE the morphing titles, left-aligned
   with the copy column, and stays put while the stages cross-fade beneath it.
   (Stacked fallback: it's just a normal block at the top of the page.) */
.s-mast{padding:clamp(24px,4vh,44px) var(--gutter) 6px}
.s-mast .brand{font-size:24px}
/* In pinned mode the masthead is an IN-FLOW row at the top of the centred
   column, so the logo + the stage below it move together as one block that
   sits in the vertical middle of the viewport (not pinned to the very top). */
html.pin .scroller .s-mast{
  z-index:7;width:100%;max-width:var(--maxw);margin:0 auto;
  padding:0 var(--gutter);
}
/* keep the wordmark + its signature period together (the period is a flex
   sibling otherwise, so the .5em brand gap would detach it from "Labs") */
.brand-name{display:inline;white-space:nowrap}
.brand-name .dot{margin-left:0}

/* The climb gets its own, more generous margins than the rest of the site: a
   narrower content cap + a wider gutter floor so the big hero never runs to the
   edges on mid-size screens, yet still opens up on wide ones. These cascade to
   the masthead, stages and stepper (all read --maxw/--gutter from here), so
   everything stays aligned. The copy/diagram split also gives the copy column a
   little more room than the site default (diagram 1.06fr instead of 1.18fr) so
   long titles wrap to a clean two lines — e.g. "Judgment becomes" /
   "infrastructure." — rather than breaking to three. */
.scroller{position:relative;--maxw:1320px;--gutter:clamp(24px,5vw,96px);--hero-split:minmax(440px,1fr) minmax(0,1.06fr)}

/* the climb sits on its own faint ground so it reads as one movement */
.s-pin{width:100%}
.s-stages{position:relative;width:100%}

/* ---- a single stage (also the stacked-fallback block) ---- */
.s-stage{
  display:grid;grid-template-columns:var(--hero-split);gap:clamp(28px,3.5vw,64px);
  align-items:center;width:100%;max-width:var(--maxw);margin:0 auto;
  padding:clamp(96px,13vh,150px) calc(var(--gutter) + 30px) clamp(72px,9vh,104px) var(--gutter);
  min-height:100vh;
}
.s-copy{max-width:var(--measure);justify-self:start}
.s-eyebrow{display:flex;align-items:center;gap:10px;font-family:var(--mono);text-transform:uppercase;letter-spacing:.16em;font-size:11px;color:var(--muted);margin:0 0 20px;min-height:14px}
.s-eyebrow .s-idx{color:var(--brand)}
.s-eyebrow .s-proj{color:var(--ink-2)}
/* Sized for a PINNED hero (shares 100vh with the masthead, subtext and
   diagram), so it caps lower and scales more gently than v2's tall scrolling
   hero — ~37px → ~60px instead of running up to 70px. */
.s-title{font-family:var(--display);font-weight:400;font-size:clamp(2.3rem,3.6vw,3.8rem);line-height:1.05;letter-spacing:-.03em;color:var(--ink);margin:0 0 22px;text-wrap:balance}
.s-title .em{font-style:italic;color:var(--brand)}
.s-sub{font-size:clamp(1.04rem,1.05vw,1.18rem);line-height:1.55;color:var(--ink-2);font-weight:300;max-width:46ch;margin:0}
.s-sub + .s-sub{margin-top:.9em}   /* hero carries a second subcopy line (the broader terrain) */
.s-fig{position:relative;min-width:0}
.s-fig .fig{position:relative;width:100%;background:none;border:0;overflow:visible}
.s-fig .fig.r169{aspect-ratio:16/10;max-height:min(74vh,680px);margin-right:clamp(-160px,-10vw,-40px)}
.s-fig iframe{width:100%;height:100%;border:0;display:block;background:transparent}
/* the conceptual turn (stage 4) and the summit (stage 6) center their copy wider */
.s-stage.s-turn .s-sub,.s-stage.s-summit .s-sub{max-width:52ch}

/* ---- progress index (the rungs) ---- */
.s-rail{list-style:none;margin:0;padding:0;display:none}

/* ============================================================
   PINNED MODE — gated by html.pin, set synchronously in <head> so the
   stacked stages never flash on load. Height here (7 stages × 100vh) so
   the tall scroll length exists at first paint; scroll.js re-confirms it.
   ============================================================ */
html.pin .scroller{height:700vh;--slx:7vw}   /* --slx = how far slides travel sideways on each transition */

/* one snap detent per stage. They're invisible 1px markers parked every 100vh
   down the climb; `scroll-snap-stop:always` is the key bit — it forbids the
   scroll from passing a detent without stopping, so no slide gets skipped on a
   momentum flick. The active stage is chosen as the NEAREST detent in scroll.js. */
.s-snaps{display:none}
html.pin .scroller .s-snaps{display:block;position:absolute;inset:0;z-index:0;pointer-events:none}
html.pin .scroller .s-snap{position:absolute;left:0;width:1px;height:1px;scroll-snap-align:start;scroll-snap-stop:always}
/* a final detent at the footer so mandatory snap can release you OUT of the climb */
html.pin .foot{scroll-snap-align:start}

/* centre the masthead + stage block vertically as one unit */
html.pin .scroller .s-pin{position:sticky;top:0;height:100vh;overflow:hidden;display:flex;flex-direction:column;justify-content:center}
/* stack every stage in one grid cell so they overlap for the cross-fade. With
   the diagram lifted onto its own layer (below), the cell sizes to the tallest
   COPY — keeping the masthead + copy block at a constant position per stage so
   nothing jitters as you scroll between stages. */
html.pin .scroller .s-stages{display:grid;height:auto}
/* Asymmetric hand-off: the outgoing stage clears quickly and quietly, the
   incoming one arrives on a longer settle after a short breath — the pause is
   what makes the transition read as deliberate rather than a cross-dissolve. */
html.pin .scroller .s-stage{
  grid-area:1/1;position:static;min-height:0;
  opacity:0;transition:opacity .32s var(--ease-exit);
  pointer-events:none;
  align-content:start;align-items:start;
  padding-top:clamp(18px,3vh,34px);padding-bottom:0;
}
html.pin .scroller .s-stage.is-active{opacity:1;pointer-events:auto;transition:opacity .62s var(--ease-draft) .06s}

/* Deep-link load: keep the whole climb hidden (even the hard-coded is-active
   stage 0) with no transition until scroll.js jumps to the target detent and
   drops html.deep — then only the target stage fades in. Stops the hero flash
   on reload-with-#anchor. */
html.deep .scroller .s-stage{opacity:0!important;transition:none!important}

/* copy rides ABOVE the diagram layer; the block slides in from the side (--dx)
   while its lines rise individually below — lateral travel carried by the
   column, vertical settle carried line by line */
html.pin .scroller .s-copy{position:relative;z-index:2;transform:translateX(calc(var(--dx,0) * var(--slx)));transition:transform .5s var(--ease-exit)}
html.pin .scroller .s-stage.is-active .s-copy{transform:none;transition:transform .8s var(--ease-draft)}

/* typesetting stagger — eyebrow, headline, body, link arrive in reading order,
   each on the same long settle, offset by a beat. Exits collapse the delays and
   return as one quick unit so a fast scroll never feels laggy. */
html.pin .scroller .s-copy :is(.s-eyebrow,.s-title,.s-sub,.s-cta-row){
  transform:translateY(14px);transition:transform .4s var(--ease-exit);
}
html.pin .scroller .s-stage.is-active .s-copy :is(.s-eyebrow,.s-title,.s-sub,.s-cta-row){
  transform:none;transition:transform .8s var(--ease-draft);
}
html.pin .scroller .s-stage.is-active .s-eyebrow{transition-delay:.05s}
html.pin .scroller .s-stage.is-active .s-title{transition-delay:.11s}
html.pin .scroller .s-stage.is-active .s-sub{transition-delay:.18s}
html.pin .scroller .s-stage.is-active .s-sub + .s-sub{transition-delay:.25s}
html.pin .scroller .s-stage.is-active .s-cta-row{transition-delay:.3s}

/* THE SIGNATURE — coordination under ambiguity, enacted: the italic brand word
   of every headline arrives out of focus and resolves a beat after the line
   has settled. The one deliberate flourish; everything else stays quiet. */
html.pin .scroller .s-title .em{
  opacity:.25;filter:blur(7px);
  transition:opacity .3s var(--ease-exit),filter .3s var(--ease-exit);
}
html.pin .scroller .s-stage.is-active .s-title .em{
  opacity:1;filter:blur(0);
  transition:opacity .65s var(--ease-draft) .38s,filter .65s var(--ease-draft) .38s;
}

/* THE DIAGRAM IS ITS OWN LAYER. Lifted out of the grid and anchored to the
   viewport (the stage carries no transform, so it's the sticky pin that
   positions this), it can be far larger and read as an immersive backdrop
   behind the copy. Sized by height + 16:10 aspect so it scales proportionally
   and never distorts; bleeds off the right edge; sits below the copy (z:0) and
   ignores pointer events so links underneath stay clickable. */
/* Right edge aligns to the CONTENT (footer-nav) right edge — the same offset
   the stepper uses — so the diagram starts at the right side of the nav and
   extends left, instead of bleeding out to the viewport margin. Top/bottom
   bound it to a vertical band that clears the masthead above and, crucially,
   the stepper below. Height-driven via 16:9 (matching the diagrams' viewBox)
   so it stays large and undistorted, extending left as a backdrop. */
html.pin .scroller .s-fig{
  position:absolute;z-index:0;pointer-events:none;margin:0;
  /* slides sideways with the copy but at ~0.68× the travel — the backdrop trails
     the text for a gentle parallax, reinforcing the sense of moving across */
  top:50%;transform:translateX(calc(var(--dx,0) * var(--slx) * .68)) translateY(-50%);
  transition:transform .5s var(--ease-exit);
  right:max(var(--gutter),calc((100vw - var(--maxw))/2 + var(--gutter)));
  width:auto;height:auto;
}
/* arriving, the backdrop settles on a longer curve than the copy (.95s vs .8s)
   so it lands last — the trailing layer of the parallax */
html.pin .scroller .s-stage.is-active .s-fig{transition:transform .95s var(--ease-draft)}
/* height kept short enough that, vertically centred, the diagram clears the
   bottom stepper; width follows 16:9 and the right edge sits on the content
   (footer-nav) edge, so it extends LEFT from there rather than off-screen. */
html.pin .scroller .s-fig .fig.r169{
  width:auto;height:min(54vh,500px);max-height:none;aspect-ratio:16/9;margin:0;
}
/* the GenLayer stage runs the jury-theorem figure at 1:1 (20% narrower than the
   earlier 5:4) — taller than the 16:9 slides, the curve over a full-width jury
   panel. Height-driven + right-anchored: right edge on the footer-nav edge,
   clears the stepper at min(70vh,720px). */
html.pin .scroller #ambiguity-needs-judgment .s-fig .fig.r169{
  /* 5:4 (was 1:1) to match the jury figure's cropped viewBox — same width as the
     square version, ~20% less tall (height 640 = 800 × 0.8 → width still 800) */
  aspect-ratio:5/4;height:min(64vh,640px);
}
/* unhardcoded's policy flow fills its 16:9 frame edge-to-edge, so it read wider
   than every other climb diagram — shrink it proportionally (keeps 16:9) to
   bring its ink width down into the cluster with the marks + distribution */
html.pin .scroller #coordination-needs-live-rules .s-fig .fig.r169{
  height:min(48vh,444px);
}

/* progress index — a horizontal stepper along the BOTTOM, kept clear of the
   vertically-centred copy + diagram so it never collides with the text */
html.pin .scroller .s-rail{
  display:flex;z-index:6;
  position:absolute;bottom:clamp(20px,4.2vh,44px);
  left:max(var(--gutter),calc((100vw - var(--maxw))/2 + var(--gutter)));
  right:max(var(--gutter),calc((100vw - var(--maxw))/2 + var(--gutter)));
  border-top:1px solid var(--line);
}
.s-rail li{flex:1 1 0;min-width:0;margin:0;position:relative}
/* the active rung's brand rule is DRAWN left→right along the hairline — a
   plotted line, not a color snap. It lives on the li (the button clips at its
   padding box, which would cut a negative-top pseudo). */
.s-rail li::before{
  content:"";position:absolute;top:-1px;left:0;width:100%;height:2px;
  background:var(--brand);transform:scaleX(0);transform-origin:0 50%;
  transition:transform .4s var(--ease-exit);
}
.s-rail li:has(.is-active)::before{transform:scaleX(1);transition:transform .7s var(--ease-draft) .12s}
.s-rail button{
  width:100%;display:block;text-align:left;cursor:pointer;background:none;
  border:0;border-top:2px solid transparent;margin-top:-1px;padding:11px 8px 0 0;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);opacity:.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:opacity .4s var(--ease-draft),color .4s var(--ease-draft);
}
.s-rail button .rk{display:none}
/* the stepper encodes direction: rungs already climbed read a shade stronger
   than the ones ahead — where you've been vs what remains */
.s-rail li:has(~ li .is-active) button{opacity:.66;color:var(--ink-2)}
/* hover needs the :has() variant too — the traversed rule above otherwise
   outweighs a plain button:hover and climbed rungs would stop responding */
.s-rail button:hover,.s-rail li:has(~ li .is-active) button:hover{opacity:.85}
.s-rail button.is-active{opacity:1;color:var(--ink)}

/* product CTA row inside a stage — the Open buttons are real brand-filled
   pills (same .btn-primary as the summit CTAs) so they read clickable */
.s-cta-row{display:flex;gap:13px;flex-wrap:wrap;margin-top:30px}

/* the old vertical thread + scroll hint are retired in favour of the stepper */
.s-thread{display:none}
.s-hint{display:none}

/* ============================================================
   FIRST PAINT — one orchestrated arrival, then stillness. The masthead
   appears, the hero is set line by line, the thesis word resolves out of
   its blur, and the stepper's first rule is drawn. animation-fill-mode is
   BACKWARDS on purpose: each element holds its from-state through its
   delay, then hands control back to the transition system above (forwards
   would pin stage-0's children and break later stage changes). Under a
   deep link html.deep masks the stages, so these run invisibly — only the
   masthead and stepper are seen arriving, which is the right welcome there.
   ============================================================ */
@keyframes s-appear{from{opacity:0}}
@keyframes s-arrive{from{opacity:0;transform:translateY(14px)}}
@keyframes s-resolve{from{opacity:.25;filter:blur(7px)}}
@keyframes s-draw{from{transform:scaleX(0)}}
html.pin .scroller .s-mast{animation:s-appear .7s var(--ease-draft) backwards}
html.pin .scroller .s-stage[data-stage="0"] .s-eyebrow{animation:s-arrive .8s var(--ease-draft) .15s backwards}
html.pin .scroller .s-stage[data-stage="0"] .s-title{animation:s-arrive .8s var(--ease-draft) .25s backwards}
html.pin .scroller .s-stage[data-stage="0"] .s-title .em{animation:s-resolve .7s var(--ease-draft) .75s backwards}
html.pin .scroller .s-stage[data-stage="0"] .s-sub{animation:s-arrive .8s var(--ease-draft) .38s backwards}
html.pin .scroller .s-stage[data-stage="0"] .s-sub + .s-sub{animation-delay:.5s}
html.pin .scroller .s-rail{animation:s-appear .9s var(--ease-draft) .6s backwards}
html.pin .scroller .s-rail li:first-child::before{animation:s-draw .7s var(--ease-draft) 1s backwards}

@media(max-width:900px){
  /* Stacked fallback on small screens — a single readable column. Two paths
     reach here and BOTH must be handled:
       • fresh mobile load: html.pin is never set, so the base two-column
         hero-split (min 440px col) would overflow a phone — collapse it.
       • desktop loaded then resized narrow: html.pin is set (the <head> script
         runs once and never removes it), so we must also undo the pin + the
         grid-stack (display:grid + grid-area:1/1) or every stage piles up.
     The plain `.scroller` selector overrides the base rules; the `html.pin`
     selector has the specificity to override the pinned desktop rules. */
  html.pin .scroller{height:auto !important}
  .scroller .s-pin,html.pin .scroller .s-pin{position:static;height:auto;display:block}
  .scroller .s-mast,html.pin .scroller .s-mast{padding:clamp(32px,8vw,52px) var(--gutter) 0;max-width:none}
  .scroller .s-stages,html.pin .scroller .s-stages{height:auto;display:block}
  .scroller .s-stage,html.pin .scroller .s-stage{position:static;grid-area:auto;opacity:1;transform:none;min-height:0;grid-template-columns:1fr;gap:clamp(24px,5vw,40px);padding:clamp(48px,9vw,80px) var(--gutter)}
  /* put the diagram back IN FLOW (it's a viewport-anchored backdrop on desktop) */
  .scroller .s-copy,html.pin .scroller .s-copy{position:static;z-index:auto;transform:none}
  /* undo the pinned-mode arrival states — stacked stages are all visible at once */
  html.pin .scroller .s-copy :is(.s-eyebrow,.s-title,.s-sub,.s-cta-row){transform:none}
  html.pin .scroller .s-title .em{opacity:1;filter:none}
  .scroller .s-fig,html.pin .scroller .s-fig{position:static;inset:auto;transform:none;width:auto;height:auto;z-index:auto}
  .scroller .s-fig .fig.r169,html.pin .scroller .s-fig .fig.r169{width:100%;height:auto;aspect-ratio:16/10;margin-right:0;max-height:none}
  .scroller .s-rail,html.pin .scroller .s-rail,html.pin .scroller .s-thread,.s-hint{display:none}
}
