/* One type system for the page. The flagship cards were set from the intake
   design reference and read as a different product from the chapters above
   them, so the reference's families now carry the whole landing page:
   Unbounded for display, Manrope for body. Only this page loads this file,
   so the services and products pages keep their own type. Weight follows the
   same reference - nothing large is bold - which is why the headings drop
   from 600 to 300. */
:root{--ff-display:"Unbounded","Bricolage Grotesque",system-ui,sans-serif;--ff-body:"Manrope","Geist",system-ui,sans-serif}
body,h1,h2,h3,h4,p,a,button,span,small,li,input,textarea{font-family:inherit}
body{font-family:var(--ff-body)}
h1,h2,h3,h4{font-family:var(--ff-display);font-weight:300;letter-spacing:-.02em}
.eyebrow{font-family:var(--ff-display);font-weight:500}
.intake-primary{width:min(100%,330px);margin-top:28px;padding:19px 22px;border-radius:18px;background:var(--sky);color:var(--paper);box-shadow:0 16px 40px color-mix(in oklch,var(--sky) 28%,transparent);display:grid;grid-template-columns:1fr auto;gap:4px 20px;align-items:center;font-family:var(--ff-display);font-size:18px;font-weight:600;letter-spacing:-.025em;line-height:1;transition:transform .25s var(--ease-out-quart),background .25s var(--ease-out-quart)}
.theme-runtime-control{display:none!important}.login-link{color:var(--ink);text-decoration:none;transition:border-color .2s ease,color .2s ease,transform .2s ease}.login-link:hover{border-color:var(--sky);color:var(--sky);transform:translateY(-1px)}
.intake-primary small{grid-column:1;font-family:var(--ff-body);font-size:9px;font-weight:500;letter-spacing:.08em;opacity:.82}.intake-primary span{grid-column:2;grid-row:1/span 2;font-size:24px}.intake-primary:hover{background:var(--sky-deep);transform:translateY(-3px)}
:is(#intro.hero-revision,.workflow-scene) .system-visual,:is(#intro.hero-revision,.workflow-scene) .system-module{pointer-events:auto}:is(#intro.hero-revision,.workflow-scene) .system-module{cursor:pointer;text-decoration:none}:is(#intro.hero-revision,.workflow-scene) .system-module .module-face{transition:border-color .2s ease,box-shadow .2s ease,background .2s ease}:is(#intro.hero-revision,.workflow-scene) .system-module:hover .module-face,:is(#intro.hero-revision,.workflow-scene) .system-module:focus-visible .module-face{border-color:var(--sky);background:color-mix(in oklch,var(--sky) 13%,var(--paper));box-shadow:inset 0 0 18px color-mix(in oklch,var(--sky) 20%,transparent),0 0 24px color-mix(in oklch,var(--sky) 28%,transparent)}:is(#intro.hero-revision,.workflow-scene) .system-module:focus-visible{outline:none}:is(#intro.hero-revision,.workflow-scene) .system-module:focus-visible .module-face{outline:2px solid var(--sky);outline-offset:4px}
:is(#intro.hero-revision,.workflow-scene) .module-start{color:var(--sky-deep);font-size:7px;font-weight:700;letter-spacing:.13em}:is(#intro.hero-revision,.workflow-scene) .module-01 .module-face{border-color:var(--sky);background:color-mix(in oklch,var(--sky) 10%,var(--paper));box-shadow:inset 0 0 18px color-mix(in oklch,var(--sky) 15%,transparent),0 0 25px color-mix(in oklch,var(--sky) 21%,transparent)}:is(#intro.hero-revision,.workflow-scene) .module-intake-data{font-size:7px!important;line-height:1.35!important}.workflow-story #consultation{min-width:220px}
/* The bundle ships `:is(#intro.hero-revision,.workflow-scene).workflow-scene .system-visual`
   with perspective:1400px, which projects every module from a different angle
   (divergence grows with distance from the board centre) and pins the raster
   scale. Parallel projection makes all eleven blocks share one angle. */
.workflow-scene.workflow-scene .system-visual{perspective:none!important;will-change:auto!important}
.workflow-scene .system-board,.workflow-scene .system-module,.workflow-scene .module-face{will-change:auto}
.workflow-scene .composition-camera{position:absolute;inset:0;transform-origin:0 0;pointer-events:none}
.workflow-scene .composition-camera .system-visual{position:absolute;left:0;top:0}
.workflow-scene .composition-camera .system-module{pointer-events:auto}
:is(#intro.concept-b,.workflow-scene) .system-module{--thickness:72px}
:is(#intro.concept-b,.workflow-scene) .system-module:before{background:color-mix(in oklch,var(--sky) 11%,var(--paper-2))}
:is(#intro.concept-b,.workflow-scene) .system-module:after{background:color-mix(in oklch,var(--sky) 17%,var(--paper-2))}
:is(#intro.concept-b,.workflow-scene) .module-top{background:color-mix(in oklch,var(--sky) 22%,var(--paper-2))}
@media(max-width:680px){.intake-primary{width:min(100%,300px);margin-top:20px;padding:16px 18px;font-size:16px}}
/* Flat night sky: no gradient. Everything visible in the opener is painted on
   the canvas, so the aurora is the only light in the frame. */
.opening-field{position:relative;min-height:100svh;overflow:hidden;background:transparent;isolation:isolate}
/* The banner's own night sky is now a veil rather than a wall, so the
   travelling field shows through behind the constellation from the first
   frame. Everything painted on the canvas - aurora, ridges, mark - still
   sits on top of it, and the veil still fades out on `opening-passed`. */
.opening-field::before{content:"";position:absolute;z-index:0;inset:0;background:rgba(7,11,17,.5);transition:opacity .65s ease}
.opening-field .opening-constellation{position:absolute;z-index:1;inset:0;width:100%;height:100%;display:block;opacity:.92;transition:opacity .65s ease}
.opening-scroll{position:absolute;z-index:3;left:50%;bottom:max(48px,7svh);display:flex;align-items:center;gap:10px;transform:translateX(-50%);color:#d9e5eb;font-family:var(--ff-body);font-size:10px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;text-decoration:none;opacity:.68;transition:opacity .2s ease}
.opening-scroll:hover,.opening-scroll:focus-visible{opacity:1}.opening-scroll span{font-size:16px}
@media(max-width:680px){.opening-field{min-height:100svh}.opening-scroll{bottom:72px}}
body:not(.story-ready) .workflow-scene,body:not(.story-ready) .chapters{opacity:0!important;visibility:hidden!important;pointer-events:none!important}
body.story-ready:not(.story-text) .workflow-scene{opacity:calc(var(--story-veil,1)*.55);transition:opacity .12s linear}
body:not(.story-text) main>.chapter .chapter-content{opacity:0!important;visibility:hidden!important;pointer-events:none!important}
#intro .chapter-content,.workflow-scene,.chapters{transition:opacity .65s ease}
.opening-passed .opening-field::before,.opening-passed .opening-field .opening-constellation,.opening-passed .opening-scroll,.opening-passed .opening-strapline{opacity:0;pointer-events:none}
#intro{scroll-margin-top:70svh}
@media(max-width:680px){.opening-field .opening-constellation{opacity:.9}}
@media(prefers-reduced-motion:reduce){.opening-field::before,.opening-field .opening-constellation{transition-duration:.01ms}}
/* One light, and it is the reader's. The bundle's own pulse and its charging
   clone loop on a timer and are hidden until the wires they cross have
   assembled, so they contradicted the scroll; the wire stroke itself is already
   drawn by scroll progress, and `.scroll-signal` rides its head. */
:is(#intro.concept-b,.workflow-scene) .system-wires .signal,
:is(#intro.concept-b,.workflow-scene) .system-wires .flow-line{visibility:hidden!important}
:is(#intro.hero-revision,.workflow-scene) .system-wires .scroll-signal{fill:var(--sky);stroke:var(--paper);stroke-width:2;filter:drop-shadow(0 0 5px var(--sky)) drop-shadow(0 0 13px color-mix(in oklch,var(--sky) 55%,transparent))}
:is(#intro.hero-revision,.workflow-scene) .system-wires [data-connected=true] path{filter:drop-shadow(0 0 3px color-mix(in oklch,var(--sky) 40%,transparent))}
/* The end of the map. Fades in exactly as the board and its backdrop leave, so
   the fade at the bottom of the page reads as a handoff instead of a dropout. */
.intake-finale{position:fixed;z-index:4;left:50%;top:50%;width:min(92vw,470px);display:grid;justify-items:center;gap:10px;text-align:center;opacity:0;transform:translate(-50%,calc(-50% + 20px));transition:transform .55s var(--ease-out-quart)}
.intake-finale[data-live=false]{visibility:hidden;pointer-events:none}
.intake-finale[data-live=true]{transform:translate(-50%,-50%)}
.intake-finale .finale-headline{margin:0;color:var(--ink);font-family:var(--ff-display);font-size:clamp(26px,2.4vw,36px);font-weight:600;letter-spacing:-.03em;line-height:1.08;text-wrap:balance}
.intake-finale .finale-steps{margin:0;color:var(--sky);font-family:var(--ff-body);font-size:12px;font-weight:600;letter-spacing:.09em;line-height:1.5}
.intake-finale .finale-go{margin:0;padding:22px 32px;gap:22px;font-size:19px;font-family:var(--ff-display);letter-spacing:-.02em;text-decoration:none;box-shadow:0 20px 55px color-mix(in oklch,var(--sky) 30%,transparent)}
.intake-finale .finale-go span{font-size:24px}
.intake-finale .finale-note{color:var(--ink-soft);font-family:var(--ff-body);font-size:12px}
@media(max-width:680px){.intake-finale{width:min(94vw,360px)}.intake-finale .finale-go{padding:18px 24px;font-size:16px}}
@media(prefers-reduced-motion:reduce){.intake-finale{transition:none}}
/* The chapter rail listed three chapters for five and read "03" at the foot of
   the page. Hidden rather than deleted: the bundle derives its own scroll
   progress from `.chapters a` (ii[1].offsetTop, ii[2].offsetTop), so removing
   the markup throws on every scroll. */
.chapters{display:none}
/* Design-experiment scaffolding: the "01 / INTAKE" label above the hero
   headline and the "HOVER THE TITLE / Preview scatter" hint under it. Hidden
   rather than deleted, for the same reason the chapter rail is: the bundle
   runs `a.querySelector(".preview-scatter").addEventListener(...)` on load
   and animates `.intro-reveal` as one of its entrance targets, so removing
   the markup throws before the hero script finishes wiring itself up. */
#intro .chapter-content>.eyebrow,.scatter-hint{display:none!important}
/* The tagline belongs to the banner, so it is painted on the first frame and
   retires on `.opening-passed` with the same .65s ease as the sky and the
   constellation, instead of arriving late on a scroll reveal.

   Its balance is a three-way clearance, and all three are held here rather
   than by moving anything around it: the header nav above (the block starts
   at 16svh, well below the 100px header), the mark below (intake-cta.js
   places it at 60% of the banner at 74% reach on a desktop, 52%/94% on a
   phone where it is already width-constrained), and its own two lines, which
   get a wider measure and more space between them so the sentence is not
   squeezed under the title. */
.opening-strapline{position:absolute;z-index:3;left:50%;top:14svh;width:min(92vw,980px);transform:translateX(-50%);display:grid;justify-items:center;gap:clamp(22px,3.2svh,38px);text-align:center;transition:opacity .65s ease;animation:opening-strapline-in .9s var(--ease-out-quart) both}
.opening-tagline{margin:0;color:#eaf3f8;font-family:var(--ff-display);font-size:clamp(30px,3.6vw,52px);font-weight:300;letter-spacing:-.025em;line-height:1.06;text-wrap:balance;text-shadow:0 1px 3px rgba(4,9,15,.7)}
.opening-mission{position:relative;width:min(92vw,1040px);min-height:2.65em;margin:0;color:#eaf3f8;font-family:var(--ff-display);font-size:clamp(20px,2.25vw,34px);font-weight:300;letter-spacing:-.025em;line-height:1.3;text-shadow:0 1px 3px rgba(4,9,15,.7)}
.opening-mission-full{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.opening-mission-visual{position:relative;display:grid;min-height:2.65em;align-items:start}
.opening-mission-phrase{grid-area:1/1;display:block;width:100%;opacity:0;transform:translateY(14px);filter:blur(5px);text-wrap:balance;will-change:opacity,transform,filter}
.opening-mission-phrase.is-current{opacity:1;transform:translateY(0);filter:blur(0)}
.opening-mission-phrase.is-entering{animation:opening-mission-enter 1.05s var(--ease-out-quart) forwards}
.opening-mission-phrase.is-leaving{animation:opening-mission-leave 1.05s var(--ease-out-quart) forwards}
@keyframes opening-mission-enter{from{opacity:0;transform:translateY(16px);filter:blur(5px)}to{opacity:1;transform:translateY(0);filter:blur(0)}}
@keyframes opening-mission-leave{from{opacity:1;transform:translateY(0);filter:blur(0)}to{opacity:0;transform:translateY(-16px);filter:blur(5px)}}
@keyframes opening-strapline-in{from{opacity:0;transform:translate(-50%,-14px)}to{opacity:1;transform:translateX(-50%)}}
body.motion-paused .opening-mission-phrase{animation-play-state:paused}
@media(max-width:680px){.opening-strapline{top:12svh;width:90vw;gap:24px}.opening-mission{width:90vw;min-height:5.2em;font-size:clamp(17px,5.2vw,23px)}.opening-mission-visual{min-height:5.2em}}
@media(prefers-reduced-motion:reduce){.opening-strapline{animation:none}.opening-mission{max-width:780px;font-family:var(--ff-display);font-size:clamp(13px,1.5vw,18px);line-height:1.55}.opening-mission-full{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto;white-space:normal}.opening-mission-visual{display:none}}
/* Flagships are wrapped in `.front-sections` so they are
   not `main > .chapter`: the bundle counts that set to pick the live chapter
   and pins every `.chapter-content` inside it to the fixed workflow scene,
   which would have left this section blank. z-index 3 keeps it above that
   scene (z-index 2) for the frames where the two overlap.

   The cards are styled from the intake system's design reference
   (Intake-Funnel/"# AI Onboarding Assessment System"/INTAKE-DESIGN-REFERENCE.md)
   rather than the landing page's own liquid-glass language, so the front of
   the funnel and the assessment a visitor lands in look like one product.
   Its literals are copied here as `--dc-*` and scoped to `.front-sections`,
   so nothing outside this section changes. Two of its rules shape
   everything below: two accents maximum per screen - lime carries state,
   cyan carries labels - and nothing large is ever bold. */
/* `overflow-x:clip` and nothing else: the elements that travel in from the
   right push the page's scrollable width while they are off their mark,
   which showed up as 36px of sideways scroll on a phone. Clipping only the
   horizontal axis leaves the vertical axis visible, so the explanation
   panels can still pop out below their cards. */
.front-sections{
  position:relative;z-index:3;overflow-x:clip;
  --dc-ground:#07100c;
  --dc-ink:#e6efe9;
  --dc-ink-dim:rgba(230,239,233,.75);
  --dc-ink-soft:rgba(230,239,233,.55);
  --dc-hairline:rgba(230,239,233,.1);
  --dc-line:rgba(230,239,233,.12);
  --dc-line-hover:rgba(230,239,233,.4);
  --dc-fill:rgba(230,239,233,.035);
  --dc-accent:oklch(.88 .22 125);
  --dc-cyan:oklch(.85 .12 200);
  --dc-ease:cubic-bezier(.2,.8,.2,1)
}
.front-content{width:min(100%,940px);max-width:none}
/* Scroll-linked entrance and parallax. intake-cta.js publishes two numbers
   per scene - `--enter` (0 -> 1 as the scene rises into the frame) and
   `--drift` (its centre's signed distance from the viewport centre, in
   viewport heights) - and every animated child derives its own state from
   them, so one rAF pass drives the whole composition and nothing measures
   the transform it sets. `--step` places a child in the sequence, `--from-x`
   and `--from-y` decide which edge it travels in from, and `--lift` gives it
   a parallax depth: a bigger lift lags the scroll more. */
/* `--ramp` is how much of a scene's entrance window one child spends
   travelling: at 3.2 each line crossed its whole distance in under a third of
   the window, which on a busy machine is one or two frames - the motion was
   real but unwatchable, and read as the copy simply appearing. Halving the
   ramp stretches each child's travel across most of the window, and the
   slightly tighter stagger keeps the sequence inside it. */
.front-scene{--enter:1;--drift:0;--stagger:.07;--ramp:1.6;--sweep:1}
/* The flagships use a long, wide-spaced sequence: four cards arriving from
   four different edges need most of the scene's
   scroll to read as a sequence rather than a single flourish. */
#flagships{--stagger:.08;--ramp:1.5;min-height:auto;align-items:flex-start;padding-top:clamp(72px,8svh,96px);padding-bottom:clamp(96px,12svh,140px)}
.front-in{
  --r:clamp(0,calc((var(--enter) - var(--step,0)*var(--stagger,.08))*var(--ramp,3.2)),1);
  opacity:var(--r);
  transform:
    translate3d(calc((1 - var(--r))*var(--from-x,0px)*var(--sweep,1)),calc((1 - var(--r))*var(--from-y,30px)*var(--sweep,1) + var(--drift)*var(--lift,0px)),0)
    rotate(calc((1 - var(--r))*var(--from-rot,0deg)))
    scale(calc(1 - (1 - var(--r))*var(--from-scale,0)));
  filter:blur(calc((1 - var(--r))*4px));
  transition:filter .5s ease
}
/* One settled flag per scene retires the blur pass entirely once the scene
   has finished arriving, so a page at rest is not paying for blur(0px). */
.front-scene.is-settled .front-in{filter:none}
.front-eyebrow{
  margin:0 0 26px;color:var(--dc-cyan);
  font-family:"Unbounded",var(--ff-display);font-size:10px;font-weight:500;letter-spacing:.18em;text-transform:uppercase
}
/* The rule draws itself across the scene's own entrance instead of fading in
   with the text, which is what makes the block read as scroll-driven. */
.front-eyebrow .front-rule{
  width:clamp(54px,9vw,140px);height:3px;border-radius:2px;flex:none;
  background:linear-gradient(90deg,color-mix(in oklch,var(--dc-accent) 70%,transparent),transparent);
  transform:scaleX(var(--enter));transform-origin:0 50%;transition:transform .5s var(--dc-ease)
}
.flagship-list{list-style:none;margin:34px 0 0;padding:0;display:grid;gap:18px;grid-template-columns:repeat(3,1fr)}
/* The reference's option button, at card scale: hairline border on a barely
   there fill, quiet until touched. `overflow:visible` and a raised z-index on
   the hovered card let the explanation panel pop out over its neighbours
   rather than pushing the grid around, so the scroll geometry the bundled
   timeline measures never moves while someone reads. */
.flagship{
  position:relative;z-index:1;display:flex;flex-direction:column;align-items:flex-start;gap:11px;
  padding:26px 24px 24px;border:1px solid var(--dc-line);border-radius:11px;
  background:linear-gradient(0deg,var(--dc-fill),var(--dc-fill)),var(--dc-ground);
  transition:background .18s,border-color .18s
}
.flagship-primary{
  grid-column:1/-1;padding:34px 32px 30px;
  border-color:color-mix(in oklch,var(--dc-accent) 30%,transparent);
  background:linear-gradient(180deg,rgba(120,220,140,.05),transparent),var(--dc-ground)
}
/* A single lime sheen that follows the cursor, shown only while a card is
   being read: a state change, not an idle float. */
.flagship-wash{
  position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:0;
  background:radial-gradient(circle 260px at var(--mx,50%) var(--my,0%),rgba(120,220,140,.08),transparent 62%);
  opacity:0;transition:opacity .18s
}
.flagship>*:not(.flagship-wash,.flagship-blurb){position:relative;z-index:1}
.flagship:hover,.flagship:focus-within{z-index:6;border-color:var(--dc-line-hover)}
.flagship[data-open=true]{z-index:6;border-color:color-mix(in oklch,var(--dc-accent) 55%,transparent);background:rgba(120,220,140,.1)}
.flagship:hover .flagship-wash,.flagship:focus-within .flagship-wash,.flagship[data-open=true] .flagship-wash{opacity:1}
.flagship-badge{
  margin:0;padding:5px 11px;border-radius:999px;
  border:1px solid color-mix(in oklch,var(--dc-accent) 40%,transparent);background:rgba(120,220,140,.08);
  color:var(--dc-accent);font-family:"Unbounded",var(--ff-body);font-size:10px;font-weight:500;letter-spacing:.16em;text-transform:uppercase
}
.flagship-name{
  margin:0;color:var(--dc-ink);
  font-family:"Unbounded",var(--ff-display);font-size:clamp(19px,1.5vw,23px);font-weight:300;letter-spacing:-.015em;line-height:1.18;
  transition:color .18s
}
.flagship-primary .flagship-name{font-size:clamp(24px,2.3vw,33px)}
.flagship-line{margin:0;color:var(--dc-ink-soft);font-family:"Manrope",var(--ff-body);font-size:13.5px;font-weight:500;line-height:1.45}
.flagship-primary .flagship-line{font-size:15px;max-width:520px}
.flagship-capabilities{list-style:none;margin:4px 0 2px;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px 22px;width:100%;max-width:920px}
.flagship-capabilities li{position:relative;padding-left:16px;color:var(--dc-ink-dim);font-family:"Manrope",var(--ff-body);font-size:13.5px;font-weight:500;line-height:1.45}
.flagship-capabilities li::before{content:"";position:absolute;left:0;top:.58em;width:5px;height:5px;border-radius:50%;background:var(--dc-accent);box-shadow:0 0 12px color-mix(in oklch,var(--dc-accent) 55%,transparent)}
.flagship-demo{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-top:5px}
.flagship-demo-toggle,.flagship-demo-phone{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:11px 18px;border-radius:999px;font-family:"Manrope",var(--ff-body);font-size:12px;font-weight:650;letter-spacing:.04em}
.flagship-demo-toggle{gap:10px;border:1px solid color-mix(in oklch,var(--dc-accent) 55%,transparent);background:rgba(120,220,140,.08);color:var(--dc-accent);cursor:pointer;transition:background .18s,border-color .18s,color .18s}
.flagship-demo-toggle:hover,.flagship-demo-toggle:focus-visible{background:rgba(120,220,140,.15);border-color:var(--dc-accent);outline:none}
.flagship-demo-phone{border:1px solid rgba(230,239,233,.18);color:var(--dc-ink);text-decoration:none}
.flagship-demo-phone[hidden]{display:none}
.flagship-demo-phone:hover,.flagship-demo-phone:focus-visible{border-color:var(--dc-cyan);color:var(--dc-cyan);outline:none}
.flagship:hover .flagship-name,.flagship:focus-within .flagship-name,.flagship[data-open=true] .flagship-name{color:color-mix(in oklch,var(--dc-accent) 32%,var(--dc-ink))}
/* Hover or keyboard focus reveals the explanation; the <button> stays because
   a touch screen cannot hover, and tapping it pins the panel open
   (`data-open=true`) so it survives the finger lifting. `visibility` carries
   the collapsed copy out of the accessibility tree as well as out of sight,
   so focus is what exposes it to a screen reader. */
.flagship-toggle{
  margin-top:auto;display:inline-flex;align-items:center;gap:9px;min-height:44px;padding:12px 22px;
  border:1px solid rgba(230,239,233,.18);border-radius:999px;background:transparent;color:var(--dc-ink-dim);
  font-family:"Manrope",var(--ff-body);font-size:11px;font-weight:600;letter-spacing:.14em;cursor:pointer;
  transition:background .18s,border-color .18s,color .18s
}
.flagship:hover .flagship-toggle,.flagship:focus-within .flagship-toggle,.flagship[data-open=true] .flagship-toggle{
  border-color:color-mix(in oklch,var(--dc-accent) 55%,transparent);background:rgba(120,220,140,.06);color:var(--dc-accent)
}
.flagship-toggle:focus-visible{outline:2px solid var(--dc-accent);outline-offset:3px}
.flagship-sign{display:block;width:8px;height:8px;flex:none;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(45deg);transition:transform .3s var(--dc-ease)}
.flagship:hover .flagship-sign,.flagship:focus-within .flagship-sign,.flagship[data-open=true] .flagship-sign{transform:rotate(225deg) translate(-1px,-1px)}
.flagship-blurb{
  position:absolute;left:0;right:0;top:calc(100% - 12px);z-index:7;margin:0;padding:20px 22px;
  border:1px solid color-mix(in oklch,var(--dc-accent) 40%,transparent);border-radius:11px;
  background:var(--dc-ground);box-shadow:0 30px 70px rgba(4,9,7,.6);
  color:var(--dc-ink-dim);font-family:"Manrope",var(--ff-body);font-size:13.5px;font-weight:500;line-height:1.6;text-wrap:pretty;
  opacity:0;visibility:hidden;transform:translate3d(0,-10px,0) scale(.97);transform-origin:26px 0;
  transition:opacity .25s ease,transform .3s var(--dc-ease),visibility .25s
}
.flagship:hover .flagship-blurb,.flagship:focus-within .flagship-blurb,.flagship[data-open=true] .flagship-blurb{opacity:1;visibility:visible;transform:none}
@media(max-width:1000px){.flagship-list{grid-template-columns:repeat(2,1fr)}}
/* No hover on a touch screen and no room to float a panel over a single
   column, so below 680px the explanation returns to the flow and the tap
   target is the only way in. A 170-190px sweep is most of a phone screen, so
   the same sequence runs at a fraction of the travel. */
@media(max-width:680px){
  .front-scene{--sweep:.34}
  .flagship-list{grid-template-columns:1fr;gap:14px}
  .flagship,.flagship-primary{padding:22px 20px}
  .flagship-capabilities{grid-template-columns:1fr;gap:7px}
  .front-eyebrow{margin-bottom:20px}
  .flagship-blurb{position:static;opacity:1;visibility:visible;transform:none;padding:0;margin:2px 0 0;border:0;border-radius:0;background:none;box-shadow:none;display:none}
  .flagship[data-open=true] .flagship-blurb{display:block;animation:flagship-blurb-in .3s var(--dc-ease) both}
  .flagship:hover .flagship-blurb,.flagship:focus-within .flagship-blurb{display:none}
  .flagship[data-open=true]:hover .flagship-blurb,.flagship[data-open=true]:focus-within .flagship-blurb{display:block}
}
@keyframes flagship-blurb-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
/* Reduced motion keeps every block visible and still: the entrance is a
   progressive enhancement, never the thing that makes the copy readable. */
@media(prefers-reduced-motion:reduce){
  .front-in{opacity:1;transform:none;filter:none}
  .front-eyebrow .front-rule{transform:none}
  .flagship-blurb{transition:none}
  @media(max-width:680px){.flagship-blurb{animation:none}}
}
/* The travelling star field (warpfield.js, ported from Backgrounds/04-warp-steer)
   sits behind the entire page. It replaces the three drifting ambient layers
   rather than joining them: two star systems in one frame read as noise, and
   the warp's projection already carries far more depth than a scaled layer
   can. The banner keeps its own constellation, which paints over this on its
   own opaque backdrop until the reader scrolls past it. */
.warp-field{position:fixed;z-index:0;inset:0;width:100%;height:100%;display:block;pointer-events:none}
.world{display:none}
/* So the field is visible through the story rather than behind an opaque
   backdrop: the board's scene keeps enough of its own ground to stay
   readable, and the page's base colour becomes the field's. */
html{background:#06040f}
body{background:transparent}
.workflow-scene{background:color-mix(in oklch,var(--paper) 62%,transparent)!important}
/* Superseded: the ambient layers this used to drive are no longer rendered.
   Kept only so a stale cached stylesheet cannot resurrect them mid-flight.

   Travelling through the field. The bundle already drifts the three ambient
   star layers vertically (`--field-scroll`) and with the cursor
   (`--field-x/--field-y`), each multiplied by that layer's own `--depth`.
   Scaling every layer about the centre by the same depth adds the missing
   axis: near stars sweep outward and grow, far stars barely move, which is
   what reads as forward travel rather than a drifting backdrop. */
.world.world{overflow:clip}
.world.world .ambient-layer{
  transform:
    translate3d(calc(var(--field-x)*var(--depth)),calc(var(--field-y)*var(--depth) + var(--field-scroll)*var(--depth)*.55),calc(var(--depth)*20px))
    scale(calc(1 + var(--travel,0)*var(--depth)*.11));
  transition:transform .2s linear
}
/* A little life while the page is still: individual stars vary, so the field
   is never a frozen texture. */
.world.world .ambient-layer i{animation:star-twinkle 9s ease-in-out infinite alternate}
.world.world .ambient-layer i:nth-child(3n){animation-duration:6.5s;animation-delay:-2s}
.world.world .ambient-layer i:nth-child(3n+2){animation-duration:12s;animation-delay:-5s}
@keyframes star-twinkle{from{opacity:.13}to{opacity:.34}}
@media(prefers-reduced-motion:reduce){
  .world.world .ambient-layer{transition:none}
  .world.world .ambient-layer i{animation:none}
}
.motion-paused .world.world .ambient-layer i{animation:none}
.motion-paused .front-in{opacity:1;transform:none;filter:none}
.motion-paused .front-eyebrow .front-rule{transform:none}
/* The board's own build track. The bundled timeline reveals its eleven
   modules across `scrollY / #approach.offsetTop`, a clock that starts at the
   very top of the page - so once the flagships were inserted
   ahead of it, the first stops elapsed while the board was still hidden and
   the reader met a part-built machine. Giving the section above the board
   more scroll of its own pushes those stops down the page, so more
   of the assembly happens in front of the reader. */
/* Compact the board's build track by 12.4% without changing its keyframes. */
.workflow-story main>#intro{min-height:412svh}
.workflow-story main>#dimensions{min-height:394svh}
/* The bundled timeline picks the live chapter from floor(progress*2+.12)
   over `main > .chapter`, a mapping tuned to the geometry it shipped with.
   The front sections moved every offset it measures down the page, so that
   mapping now lands a chapter early and #intro's own hero text would never
   be on screen while #intro is. intake-cta.js re-runs the same formula
   against a scroll position with the inserted height subtracted and
   publishes the answer as `data-story-live`. If that block ever fails no
   attribute is written at all, and the bundle's own behaviour is what
   remains. */
.workflow-story.workflow-enabled main>.chapter[data-story-live=false] .chapter-content{visibility:hidden!important;opacity:0!important;pointer-events:none!important}
/* The bundle disables #intro content with an ID-specific selector; the live
   chapter must explicitly restore hit testing so its links inherit auto. */
.workflow-story.workflow-enabled main>.chapter[data-story-live=true] .chapter-content{visibility:visible;opacity:1;pointer-events:auto!important}

/* ---- Finale dock ---------------------------------------------------------
   Reserved landing space immediately above the site footer. The invitation
   stays `position:fixed` while it is being scrolled toward, then becomes an
   ordinary in-flow block once this slot reaches the centre of the viewport —
   which is where the fixed copy already sits, so the switch moves nothing on
   screen. Before this dock existed the invitation was appended to the body and
   pinned at viewport centre with no exit, so at full scroll it sat on top of
   the footer and on a short window the two shared the same pixels.

   The slot always reserves --finale-h (published by intake-cta.js), so the
   page does not reflow at the moment of docking. Nothing in here may create a
   containing block for fixed positioning: no transform, filter, perspective,
   contain or will-change. */
.finale-dock{
  display:grid;
  place-items:center;
  width:100%;
  min-height:calc(var(--finale-h, 260px) + clamp(6rem, 16vh, 11rem));
  padding:clamp(2.5rem, 6vh, 4.5rem) 1rem;
  pointer-events:none;
}
.finale-dock>*{pointer-events:auto}
.intake-finale[data-docked=true]{
  position:static;
  left:auto;
  top:auto;
  width:min(92vw,470px);
  margin:0 auto;
  transform:none;
  transition:none;
}
.intake-finale[data-docked=true][data-live=false]{visibility:visible;pointer-events:auto}
