/* =============================================================
   GREEN SKY MANAGEMENT — A to Z
   -------------------------------------------------------------
   Black on charcoal, a deep green-black sky so the name still
   reads, and the mark's gold as the only accent.

   THE RAY IS THE ARCHITECTURE.
   The gold ray is a single element that spans the whole document
   and sits behind everything (z-index 0, under main's z-index 2).
   That is the only way it can genuinely never break at a section
   boundary. The consequence is a hard rule for the rest of this
   file:

       NO SECTION MAY HAVE AN OPAQUE BACKGROUND.

   Sections are transparent; the ground is one fixed layer far
   below. Cards and panels use translucent fills, so the ray
   passes behind them rather than being cut by them. Anything
   that paints solid across the full width would sever the ray,
   which is the one thing this page must not do.
   ============================================================= */

/* -------------------------------------------------------------
   BRAND TYPEFACE
   Nacelle, self-hosted from the brand pack (Logoguides/Font),
   SIL Open Font License — see assets/fonts/OFL.txt. It sets the
   body and UI voice. The huge display headlines stay on a
   condensed face, which is the look the design calls for and
   which Nacelle does not have a condensed cut of.
   ------------------------------------------------------------- */
@font-face {
  font-family: 'Nacelle';
  src: url('../assets/fonts/Nacelle-Regular.otf') format('opentype');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Nacelle';
  src: url('../assets/fonts/Nacelle-SemiBold.otf') format('opentype');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Nacelle';
  src: url('../assets/fonts/Nacelle-Bold.otf') format('opentype');
  font-weight: 700; font-style: normal; font-display: swap;
}

/* -------------------------------------------------------------
   TOKENS
   ------------------------------------------------------------- */
:root {

  /* --- GOLD RAMP -------------------------------------------------
     The brand's own golds, taken from the gradient stops inside
     assets/gsm-mark.svg (which came verbatim from
     Logoguides/Logotype/RGB/GreenSky_Logotype.svg). These are the
     mark's actual stop colours, not an approximation of them:

       #A4702A  0      #E0B655  .2336   #F7F1B4  .5383
       #E1B95A  .7759  #E0B655  .7887   #8D5C21  1

     Every gold on the page resolves through these four stops, and
     gold is always used as a gradient — never a flat yellow. */
  --gold-1: #F7F1B4;   /* pale highlight   */
  --gold-2: #E1B95A;   /* core gold        */
  --gold-3: #A4702A;   /* deep gold        */
  --gold-4: #8D5C21;   /* shadow gold      */

  /* the mark's true aspect (286.55 / 423.18) and the point on its
     centre line where every ray converges (12.65% of its width) —
     the ray leaves the page from exactly that point */
  --mark-h: 40px;
  --mark-aspect: 0.6771;
  --mark-origin: 0.1265;

  /* (There was a --warm token here with no consumers, and a comment
     describing the scope builder as rotating toward red. scope.js
     rewrites --gold-1..4 directly and shifts hue toward lemon on
     narrow scopes — the opposite direction. Both are gone rather than
     left to contradict the code.) */

  --accent:      var(--gold-2);
  /* 52%, not 42%: this is the boundary of every button, so it is a UI
     component boundary and owes 3:1 under WCAG 1.4.11. At 42% it
     composited to 2.70:1; at 52% it reaches 3.5:1. */
  --accent-line: color-mix(in oklab, var(--gold-2) 52%, transparent);

  /* The one gradient every rail, rule and active state uses. */
  --grad-gold: linear-gradient(180deg,
                var(--gold-1) 0%,
                var(--gold-2) 26%,
                var(--gold-3) 64%,
                var(--gold-4) 100%);
  --grad-gold-h: linear-gradient(90deg,
                var(--gold-4) 0%,
                var(--gold-3) 18%,
                var(--gold-2) 50%,
                var(--gold-1) 78%,
                var(--gold-3) 100%);

  /* SMALL gradient-clipped text needs its own ramp.
     --grad-gold-h opens on --gold-4, which is 3.39:1 on this ground —
     fine for display type at 3:1, a fail for anything under 24px. The
     leg readout and the focal port label are both small and both
     clipped, so they use a ramp that never drops below --gold-2
     (10.4:1). Same gold, same tokens, legible at 11px. */
  --grad-gold-text: linear-gradient(90deg,
                var(--gold-2) 0%,
                var(--gold-1) 52%,
                var(--gold-2) 100%);

  /* --- ground --- */
  --ink:        #05070A;
  --charcoal:   #0B0E12;
  --char-2:     #12161B;
  --green-black:#04140E;

  --paper:   #ECEEF0;
  --paper-2: #A7AFB6;
  /* Was #6C757D, which composited to 4.03–4.30:1 across the three
     grounds this page uses — under AA on every one of them. It carries
     every label, hint and legend, including both "nothing is
     transmitted" disclosures, so the honest copy was the least legible
     copy on the page. #7C858D clears 5.0:1 on all three. */
  --paper-3: #7C858D;

  --hair:    rgba(236,238,240,.11);
  --hair-2:  rgba(236,238,240,.06);
  /* --hair is decorative (section rules, dividers) and may stay faint.
     The boundary of an INPUT is a UI component boundary and owes 3:1;
     at .11 it composited to 1.29:1, so interactive controls use this
     instead. Two tokens, because the two jobs have different rules. */
  --hair-strong: rgba(236,238,240,.38);

  /* --- the ray's x position, shared by the mark in the header ---
     The ray must originate from the mark, so both read this one
     value. Content padding is derived from it too, which is what
     keeps the ray clear of text at every width. */
  --ray-x: 64px;
  --gutter: 40px;

  --wrap: 1440px;

  /* The first two are Apple-only and the next two are Windows/Office,
     so the original stack fell all the way through to generic
     sans-serif on Linux and Android — where `font-stretch: condensed`
     does nothing, because the fallback has no condensed axis. The
     headline sizes assume condensed metrics, so that is a layout
     change, not just a different look. Roboto Condensed (Android, most
     Linux) and Liberation/Nimbus Narrow (Linux) close most of it.
     Residual: a Linux box with none of these still gets the generic —
     see the note on --f-display in README. */
  --f-display: 'Avenir Next Condensed', 'HelveticaNeue-CondensedBold',
               'Arial Narrow', 'Roboto Condensed', 'Liberation Sans Narrow',
               'Nimbus Sans Narrow', 'DejaVu Sans Condensed',
               'Haettenschweiler', Impact, sans-serif;
  --f-text: 'Nacelle', -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, Roboto, sans-serif;
  --f-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  --ease: cubic-bezier(.22,.61,.36,1);

  /* FOCUS — one treatment, tokenised so it cannot drift apart again.
     It was --gold-1 as a flat outline on four components and missing
     entirely from the two that matter most for getting around: the
     header links and the chapter buttons.

     An outline rather than a gradient pseudo-element: .btn sets
     overflow:hidden for its fill sweep, which would clip an inset
     ring, and outline is the one property never clipped by the
     element's own overflow. The halo is what makes it read as Green
     Sky rather than as a browser default. */
  --focus-ring: 2px solid var(--gold-1);
  /* derived from the token, never a literal: a hardcoded
     rgb(225,185,90) is --gold-2 written out longhand, which
     contract.test.js correctly fails the build over. Going through
     color-mix also means the halo follows the scope builder's warmth
     shift like every other gold on the page. */
  --focus-halo: 0 0 0 5px color-mix(in srgb, var(--gold-2) 20%, transparent);
  --ease-io: cubic-bezier(.65,.05,.36,1);
}

@media (max-width: 1024px) { :root { --ray-x: 44px; --gutter: 28px; } }
@media (max-width: 640px)  { :root { --ray-x: 22px; --gutter: 18px; --mark-h: 32px; } }

/* -------------------------------------------------------------
   RESET
   ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

/* THE `hidden` ATTRIBUTE MUST WIN.
   `[hidden] { display: none }` lives in the user-agent stylesheet, and
   author-origin declarations outrank user-agent origin no matter how
   weak their specificity. So a single `.form { display: grid }` further
   down this file silently defeated `form.hidden = true` — the review
   form stayed on screen after a successful submit and could be
   submitted again, minting a second reference number for the same
   request. Restating it here, in author origin, makes the attribute
   mean what every author expects it to mean. */
*[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Horizontal clipping belongs on <html>, NOT on <body>.
     `overflow-x: hidden` on body forces its computed overflow-y to
     `auto`, which turns body into the scroll container — window.scrollY
     then stays pinned at 0 and every scroll-driven readout on this page
     freezes. Keeping it here leaves documentElement as the scroller. */
  overflow-x: hidden;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  /* position:relative makes body the containing block for the ray,
     so `top:0;bottom:0` resolves to the full document height. */
  position: relative;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--f-text);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img, svg, canvas { display: block; max-width: 100%; }
button, input, textarea { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }

::selection { background: var(--gold-3); color: #06070A; }

/* THE GOLD STOPS FOR INLINE SVG GRADIENTS.
   The A→Z arc and the whole network diagram are stroked from
   <linearGradient> defs in index.html. Their stops carry these classes
   rather than literal hexes, so they resolve through --gold-1..4 like
   every other gold and move with the scope builder. Hard-coded stops
   left those two pieces of chrome on the original ramp while the rest
   of the page shifted — two golds on screen at once. */
.gs-1 { stop-color: var(--gold-1); }
.gs-2 { stop-color: var(--gold-2); }
.gs-3 { stop-color: var(--gold-3); }
.gs-4 { stop-color: var(--gold-4); }

/* -------------------------------------------------------------
   THE SEAL — the mark inside a ring of type

   The centre is assets/gsm-mark.svg loaded as a file, sized on its
   own true aspect (286.55 / 423.18) so object-fit has nothing to
   letterbox. It is not rotated, not recoloured, not redrawn: every
   other part of this component is type and two hairline circles
   drawn around it. Scale the whole thing with --seal.
   ------------------------------------------------------------- */
.seal {
  --seal: 200px;
  position: relative;
  width: var(--seal); height: var(--seal);
  display: inline-grid; place-items: center;
  flex: none;
}
.seal__ring {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  overflow: visible;
}
/* Sized against the arc, not by eye: the top arc is a half-circumference
   of pi * 163 = 512 user units, and "Green Sky Management" is 20
   characters, so ~25 units of advance each is the budget. 26px at .30em
   tracking spends ~24 and leaves the ends clear of the vertical. */
.seal__type {
  font-family: var(--f-text); font-weight: 600;
  font-size: 26px; letter-spacing: .30em;
  text-transform: uppercase;
}
.seal__type--sub { font-size: 22px; letter-spacing: .34em; }
/* The mark keeps its own aspect and sits on the seal's centre. Height
   is the constrained axis — the mark is taller than it is wide — and
   0.52 of the diameter leaves the inner hairline clear at every size. */
.seal__mark {
  position: relative;
  height: calc(var(--seal) * .52);
  width: auto;
  display: block;
}

/* the ring rotates only as a whole, and only when motion is welcome —
   the mark inside it never turns, which is the point */
/* The seal used to rotate continuously under an `is-turning` class.
   Nothing has added that class since .seal__prog took over — the ring
   now advances only as far as the film has run, which is information
   rather than decoration. The rule and its keyframes are gone with it. */

/* Skip link — the first focusable element in the document. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 1000;
  padding: 14px 22px;
  background: var(--ink); color: var(--gold-1);
  border: 1px solid var(--gold-2);
  font-family: var(--f-mono); font-size: 11px; letter-spacing: .2em;
  text-transform: uppercase;
}
.skip:focus { left: 12px; top: 12px; }

/* -------------------------------------------------------------
   GROUND — fixed, far below everything
   ------------------------------------------------------------- */
.sky {
  position: fixed; inset: 0; z-index: -3; pointer-events: none;
  background:
    /* the gold origin glow, top-left, where the mark sits */
    radial-gradient(60vw 42vh at var(--ray-x) 0%,
      color-mix(in oklab, var(--gold-3) 16%, transparent) 0%, transparent 70%),
    /* The green-black sky, so the name still reads.
       #051D15, not #06231A: this is the lightest thing the page paints,
       and at the old value --paper-3 landed at 4.43:1 and --gold-4 at
       2.92:1 on it — both under threshold. No text happens to sit there
       today, which is not a property worth depending on. Two shades
       darker and every token is safe wherever it lands. */
    radial-gradient(120vw 90vh at 78% 8%, #051D15 0%, transparent 62%),
    linear-gradient(178deg, var(--green-black) 0%, #061109 22%, var(--charcoal) 58%, var(--ink) 100%);
}

.grain {
  position: fixed; inset: 0; z-index: -2; pointer-events: none;
  opacity: .3; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
}

/* =============================================================
   THE RAY — one element, whole document, never interrupted
   ============================================================= */
.ray {
  position: absolute;
  top: 0; bottom: 0;
  /* the 1px back-shift centres the 2px line exactly on --ray-x,
     which is also the centre of the mark in the header */
  left: calc(var(--ray-x) - 1px);
  width: 2px;
  /* Above the film canvas (z 2) so the ray is actually SEEN to be
     continuous — the point of the ray is that you watch it cross
     every boundary, and it cannot do that from underneath the
     footage. It still never occludes content: every text container
     is padded clear of --ray-x, so there is nothing for it to
     cover. It stays below the header (z 60), so it reads as
     leaving the mark rather than crossing it. */
  z-index: 3;
  pointer-events: none;
}

.ray__line {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 2px;
  background: var(--grad-gold);
  /* the ray is lit, not painted flat */
  box-shadow:
    0 0 14px color-mix(in oklab, var(--gold-2) 45%, transparent),
    0 0 44px color-mix(in oklab, var(--gold-3) 22%, transparent);
  opacity: .92;
}

/* the origin: a bright point directly under the mark */
.ray__origin {
  position: absolute; top: 0; left: 50%;
  width: 12px; height: 12px; margin-left: -6px; margin-top: -4px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--gold-1) 0%, var(--gold-2) 38%, transparent 72%);
  filter: blur(.3px);
}

/* the travelling head — shows where you are on the ray */
.ray__head {
  position: absolute; left: 50%; top: 0;
  width: 7px; height: 7px; margin-left: -3.5px;
  border-radius: 50%;
  background: var(--gold-1);
  box-shadow: 0 0 10px 2px color-mix(in oklab, var(--gold-2) 80%, transparent),
              0 0 30px 6px color-mix(in oklab, var(--gold-3) 40%, transparent);
  will-change: transform;
}

/* stage labels riding the ray */
.ray__label {
  position: absolute;
  left: 14px;
  transform: translateY(-50%);
  font-family: var(--f-mono);
  font-size: 9px;
  letter-spacing: .3em;
  text-transform: uppercase;
  white-space: nowrap;
  color: color-mix(in oklab, var(--gold-2) 72%, var(--paper-3));
  font-weight: 600;
  opacity: 0;
  transition: opacity .5s var(--ease);
}
.ray__label::before {
  content: ''; position: absolute; left: -14px; top: 50%;
  width: 10px; height: 1px; background: var(--accent-line);
}
.ray__label.is-lit { opacity: 1; }
@media (max-width: 640px) {
  .ray__label { font-size: 8px; letter-spacing: .22em; }
}

/* =============================================================
   LAYOUT
   ============================================================= */
main { position: relative; z-index: 2; }

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  /* left padding always clears the ray — this is what keeps the
     ray legible rather than running under body copy */
  padding-left: calc(var(--ray-x) + var(--gutter));
  padding-right: var(--gutter);
}

/* The A→Z indicator is fixed to the right edge (158px of column) and
   is shown from 761px up. Content can only run under it while the
   viewport is near or below --wrap, because past that the centred
   wrap pulls away from the edge on its own. Reserve the column over
   exactly that range rather than padding every layout forever. */
@media (min-width: 761px) and (max-width: 1791px) {
  .wrap { padding-right: 176px; }
}

.band {
  position: relative;
  padding: clamp(96px, 13vh, 190px) 0;
  background: transparent;      /* NEVER opaque — see header note */
}

/* hairline section rules stop short of the ray so they cannot
   read as a crossing that cuts it */
.band + .band::before {
  content: '';
  position: absolute; top: 0;
  left: calc(var(--ray-x) + 26px); right: var(--gutter);
  height: 1px;
  background: linear-gradient(90deg, var(--accent-line), transparent 62%);
}

/* -------------------------------------------------------------
   TYPE
   ------------------------------------------------------------- */
.display {
  font-family: var(--f-display);
  font-weight: 700;
  font-stretch: condensed;
  letter-spacing: -.01em;
  line-height: .86;
  text-transform: uppercase;
  margin: 0;
}

.eyebrow {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: .42em;
  text-transform: uppercase;
  color: var(--paper-3);
  margin: 0 0 22px;
}
.eyebrow::before {
  content: ''; display: inline-block;
  width: 22px; height: 1px; margin-right: 12px; vertical-align: middle;
  background: var(--grad-gold-h);
}

.band__h2 { font-size: clamp(44px, 7.4vw, 128px); }
/* <em> inside a display heading is emphasis in the document outline,
   not a request for italics — this face has no italic cut and the
   browser would synthesise a slant across a gradient-clipped word. */
.band__h2 em { font-style: normal; }
/* No max-width here. `ch` resolves against this element's own
   inherited font (the body face), not the display face used by the
   h2 inside it — a `20ch` cap here crushed every section heading
   into a ~200px column. The h2 sets its own line breaks with <br>,
   and .band__sub carries its own measure. */
.band__head { margin-bottom: clamp(48px, 6vw, 88px); }
.band__sub {
  font-size: clamp(15px, 1.2vw, 18px);
  color: var(--paper-2);
  max-width: 52ch;
  margin: 24px 0 0;
}

.gold-text {
  background: var(--grad-gold-h);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

/* =============================================================
   LOADER
   ============================================================= */
.loader {
  position: fixed; inset: 0; z-index: 999;
  background: var(--ink);
  display: grid; place-items: center;
  transition: opacity .7s var(--ease), visibility .7s;
}
/* pointer-events is not transitioned, so it takes effect the
   instant the class lands. opacity and visibility are — and a
   transition that never completes (background tab, interrupted
   compositor) would otherwise leave a full-viewport overlay at
   z-index 999 swallowing every click on the page. */
.loader.is-done { opacity: 0; visibility: hidden; pointer-events: none; }
/* The guarantee behind the fade. Set ~900ms after is-done, so it lands
   once the transition has had its chance — and lands regardless of
   whether the transition ever actually ran. */
.loader.is-gone { display: none; }

/* NO JS, NO LOADER.
   The `js` class is set by an inline script in <head>. If scripting is
   off, blocked, or the script never runs, nothing will ever add
   `is-done` — and an opaque z-999 overlay would hide the entire site
   behind a progress bar frozen at 0%. The page itself degrades fine
   without JS (see the [data-blur] fallback below), so the honest
   default is for the loader not to exist at all. */
html:not(.js) .loader { display: none; }

.loader__inner { width: min(340px, 74vw); text-align: left; }
.loader__mark {
  font-family: var(--f-display); font-stretch: condensed;
  font-size: 13px; letter-spacing: .58em; color: var(--paper-2);
  margin-bottom: 20px; text-transform: uppercase;
}
.loader__bar { height: 2px; background: var(--hair); overflow: hidden; }
.loader__bar span {
  display: block; height: 100%; width: 0;
  background: var(--grad-gold-h);
  transition: width .3s linear;
}
.loader__pct {
  margin-top: 14px; font-family: var(--f-mono); font-size: 10px;
  letter-spacing: .3em; color: var(--paper-3);
}
.loader__pct em { font-style: normal; margin-left: 14px; opacity: .82; }

/* =============================================================
   HEADER — the mark, and the ray's origin
   ============================================================= */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  display: flex; align-items: center; justify-content: space-between;
  padding: 20px var(--gutter) 20px var(--ray-x);
  transition: background .4s var(--ease), backdrop-filter .4s var(--ease);
}
.nav.is-stuck {
  /* translucent, never opaque: the ray runs under the header too */
  background: linear-gradient(180deg, rgba(5,7,10,.86), rgba(5,7,10,.42) 70%, transparent);
  backdrop-filter: blur(14px);
}

.nav__brand { display: flex; align-items: center; gap: 14px; min-height: 44px; }

/* THE MARK.
   Loaded only from assets/gsm-mark.svg. Never rotated, never
   distorted, never recoloured — no filter, no blend mode and no
   opacity change is applied to this element anywhere in this
   stylesheet.

   The box is set to the mark's true aspect so `contain` has nothing
   to letterbox, then pulled left by its own origin fraction. The
   result is that --ray-x lands on the point where the mark's rays
   converge, so the page's ray leaves the mark exactly where every
   ray in the mark does. */
.mark {
  width: calc(var(--mark-h) * var(--mark-aspect));
  height: var(--mark-h);
  display: block;
  flex: 0 0 auto;
  margin-left: calc(var(--mark-h) * var(--mark-aspect) * var(--mark-origin) * -1);
}
.mark__img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* Shown only if assets/gsm-mark.svg is absent. Deliberately not a
   drawing of the mark — an empty, labelled slot, because nothing
   here is permitted to approximate it. */
.mark__missing {
  width: calc(var(--mark-h) * var(--mark-aspect)); height: var(--mark-h);
  margin-left: calc(var(--mark-h) * var(--mark-aspect) * var(--mark-origin) * -1);
  border: 1px dashed var(--accent-line);
  border-radius: 3px;
  display: grid; place-items: center;
  font-family: var(--f-mono); font-size: 7px; line-height: 1.1;
  letter-spacing: .06em; text-align: center;
  color: var(--paper-3);
  background: color-mix(in oklab, var(--gold-2) 5%, transparent);
}

.nav__word { display: flex; flex-direction: column; line-height: 1; }
.nav__word b {
  font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
  font-size: 15px; letter-spacing: .2em; text-transform: uppercase;
}
.nav__word i {
  font-style: normal; font-family: var(--f-mono);
  font-size: 8px; letter-spacing: .34em; color: var(--paper-3);
  margin-top: 4px; text-transform: uppercase;
}

.nav__links { display: flex; align-items: center; gap: 30px; }
.nav__links a {
  font-family: var(--f-mono); font-size: 10px;
  letter-spacing: .24em; text-transform: uppercase; color: var(--paper-2);
  transition: color .3s var(--ease);
}
.nav__links a:hover { color: var(--gold-2); }

/* Keyboard users had no way to see where they were in the header: the
   links carried :hover only, while .btn, .toggle, .field and .foot__nav
   all had proper rings. Same rule as those, so it matches on sight. */
.nav__links a:focus-visible {
  outline: var(--focus-ring); outline-offset: 3px; box-shadow: var(--focus-halo);
}

/* 44px touch targets WITHOUT touching the type size — the links
   measured 48x12, 40x12 and 56x12. Padding grows the target; the equal
   and opposite margin cancels its layout effect, so the 30px flex gap
   still reads as exactly 30px between glyphs and the header is
   pixel-unchanged for a mouse.

   Scoped :not(.nav__cta) on purpose. `.nav__links a` is (0,1,1) and
   `.nav__cta` is (0,1,0), so an unscoped padding here would outrank
   the CTA's own padding and silently reshape the button — the same
   specificity trap that has already caught .film__type and .legs in
   this stylesheet. */
.nav__links a:not(.nav__cta) {
  position: relative;
  padding: 16px 10px;
  margin: -16px -10px;
}

/* CURRENT SECTION. The nav pointed at four sections and never said
   which one you were in. Colour alone would carry it on hue only, so
   the state is an underline as well — and it is drawn on the gold
   gradient, like every other gold on the page. */
.nav__links a:not(.nav__cta)::after {
  content: ''; position: absolute;
  left: 10px; right: 10px; bottom: 12px; height: 1px;
  background: var(--grad-gold-h);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .35s var(--ease);
}
.nav__links a.is-current { color: var(--gold-2); }
.nav__links a:not(.nav__cta).is-current::after { transform: scaleX(1); }

.nav__cta {
  border: 1px solid var(--accent-line);
  padding: 10px 18px;
  position: relative;
  /* the CTA is the one nav item that survives the mobile breakpoint,
     so it is also the one that most needs a real touch target */
  display: inline-flex; align-items: center; min-height: 44px;
}
.nav__cta:hover { color: #06070A !important; }
.nav__cta::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--grad-gold-h); opacity: 0;
  transition: opacity .3s var(--ease);
}
.nav__cta:hover::before { opacity: 1; }
/* the CTA cannot take an underline without reading as a broken button,
   so its current state is carried on the border instead */
.nav__cta.is-current { border-color: var(--gold-2); color: var(--gold-1); }

@media (prefers-reduced-motion: reduce) {
  .nav__links a:not(.nav__cta)::after { transition: none; }
}
/* Must stay in lockstep with the .nav__burger query below: any gap
   between "links off" and "burger on" is a band of viewport widths
   with no navigation at all. 880 was the number until the sequence
   section added a sixth item — at 881px the row still fitted on one
   line, but with 35px between the wordmark and the first link.
   Fitting and being laid out are not the same thing. */
@media (max-width: 940px) { .nav__links a:not(.nav__cta) { display: none; } }

/* =============================================================
   MOBILE MENU
   ============================================================= */
.nav__burger {
  display: none; background: none; border: 0; cursor: pointer;
  width: 44px; height: 44px; align-items: center; justify-content: center;
  margin-left: 14px; padding: 0; flex: none;
}
.nav__burger:focus-visible {
  outline: var(--focus-ring); outline-offset: 2px; box-shadow: var(--focus-halo);
}
.nav__burger-box { display: block; width: 20px; height: 12px; position: relative; }
.nav__burger-box i {
  position: absolute; left: 0; right: 0; height: 1.5px;
  background: var(--paper); transition: transform .34s var(--ease), opacity .2s;
}
.nav__burger-box i:first-child { top: 0; }
.nav__burger-box i:last-child  { bottom: 0; }
/* the bars become the cross — the control says what it will do next */
.nav__burger[aria-expanded="true"] .nav__burger-box i:first-child {
  transform: translateY(5.25px) rotate(45deg);
}
.nav__burger[aria-expanded="true"] .nav__burger-box i:last-child {
  transform: translateY(-5.25px) rotate(-45deg);
}

/* ABOVE .nav, not below it. At z-index 55 the header (60) painted over
   this panel and kept taking its clicks: on a landscape phone the first
   destination landed under the 84px header, so tapping "A to Z" fired the
   header CTA and jumped to the form with the menu still open. A modal
   that the header punches through is not a modal. */
.menu {
  position: fixed; inset: 0; z-index: 70;
  background: color-mix(in srgb, var(--ink) 97%, transparent);
  backdrop-filter: blur(18px);
  display: flex; align-items: center;
  /* Short viewports (landscape phones) could not reach the last
     destination — centred content simply overflowed off both ends. */
  overflow-y: auto; overscroll-behavior: contain;
  padding: 24px var(--gutter) 24px calc(var(--ray-x) + var(--gutter));
  opacity: 0; transition: opacity .34s var(--ease);
}
/* [hidden] is honoured — main.css sets *[hidden]{display:none!important},
   so the panel is out of the tree and out of the tab order when shut. */
.menu.is-open { opacity: 1; }
/* Stands where the burger stands, so the control appears to transform
   rather than to be replaced. Always a cross — it has one job. */
.menu__close {
  position: absolute; top: 20px; right: var(--gutter);
  width: 44px; height: 44px; padding: 0; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer;
}
.menu__close:focus-visible {
  outline: var(--focus-ring); outline-offset: 2px; box-shadow: var(--focus-halo);
}
.menu__close .nav__burger-box i:first-child { transform: translateY(5.25px) rotate(45deg); }
.menu__close .nav__burger-box i:last-child  { transform: translateY(-5.25px) rotate(-45deg); }
.menu__inner { display: flex; flex-direction: column; gap: 6px; width: 100%; }
.menu__inner a {
  display: flex; align-items: baseline; gap: 18px;
  padding: 14px 0; min-height: 44px;
  font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
  font-size: clamp(34px, 11vw, 60px); line-height: 1;
  text-transform: uppercase; letter-spacing: .01em;
  color: var(--paper);
  border-bottom: 1px solid var(--hair);
  transition: color .3s var(--ease);
}
.menu__inner a i {
  font-family: var(--f-mono); font-style: normal;
  font-size: 10px; letter-spacing: .24em; color: var(--paper-3);
  flex: none;
}
.menu__inner a:hover, .menu__inner a:focus-visible { color: var(--gold-2); }
.menu__inner a:focus-visible {
  outline: var(--focus-ring); outline-offset: 4px; box-shadow: var(--focus-halo);
}
/* the current section is marked here too — the same observer drives it */
.menu__inner a.is-current {
  background: var(--grad-gold-text);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.menu__inner a.is-current i { color: var(--gold-2); }

@media (prefers-reduced-motion: reduce) {
  .menu { transition: none; }
  .nav__burger-box i { transition: none; }
}
/* the burger and the menu exist only where the links do not */
/* The burger costs 58px of a 375px header, which pushed both the
   wordmark and the CTA into wrapping onto two lines. Buy the room back
   from the CTA's generous tracking and padding rather than from the
   type size, and stop the wordmark breaking mid-name. */
.nav__word b { white-space: nowrap; }
@media (max-width: 480px) {
  .nav { padding-left: calc(var(--ray-x) + 10px); padding-right: 14px; }
  .nav__cta { padding: 10px 12px; letter-spacing: .14em; white-space: nowrap; }
  .nav__burger { margin-left: 6px; }
  .nav__brand { gap: 10px; }
}

@media (max-width: 940px) { .nav__burger { display: flex; } }
@media (min-width: 881px) { .menu { display: none !important; } }

/* =============================================================
   FILM
   ============================================================= */
.film { position: relative; height: 620vh; }
.film__stage {
  position: sticky; top: 0; height: 100vh; overflow: hidden;
}
.film__canvas { width: 100%; height: 100%; display: block; }

.film__vignette {
  position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(78% 62% at 50% 46%, transparent 34%, rgba(4,6,9,.72) 100%),
    linear-gradient(180deg, rgba(4,6,9,.76) 0%, transparent 26%, transparent 62%, rgba(4,6,9,.92) 100%);
}

.film__type {
  position: absolute; left: calc(var(--ray-x) + var(--gutter));
  right: var(--gutter); bottom: 15vh;
  max-width: 1180px; will-change: transform, opacity;
}
/* Same A→Z clearance as .wrap. It has to live AFTER the .film__type
   rule above — both are single-class selectors, so source order is
   what decides, and declaring it earlier silently loses. */
@media (min-width: 761px) and (max-width: 1791px) {
  .film__type { right: 176px; }
}

/* THE SCRIM.
   The hero copy sat directly on the film, so its legibility was
   whatever frame happened to be behind it. Sampled 276 points per
   position: the average was a comfortable 11-12:1, which is exactly
   why this hid — but where the copy crossed the white device or a
   bright sky the worst case measured 1.00:1. White on white.

   A local gradient rather than a full-frame darkening, so most of the
   picture is left alone — that is the whole reason the film is there.
   Colours come off --ink through color-mix, never literals.

   THE GEOMETRY IS LOAD-BEARING, and the first version got it wrong.
   The gradient reached its transparent stop at 79% of a box that was
   barely wider than the copy, so the last third of a 923px headline
   sat on raw film: re-measured by compositing the frame, the vignette
   and this scrim into an offscreen canvas and sampling under the glyph
   run, the gold ran between 1.00:1 and 2.61:1 at every scroll position
   where the hero is legible. The requirement is 3:1.

   So the tail now lands OUTSIDE the text. The right inset is wide not
   because the picture wants darkening out there but because the box is
   what the percentages are measured against: the copy has to finish
   inside the plateau, and the decay needs somewhere to happen that is
   not on top of a word. Widen the copy or shrink this inset and the
   floor goes with it — re-measure, do not eyeball it. */
/* THE BOX HAD NO VERTICAL FEATHER. The gradient above decays left to
   right and does nothing top to bottom, so the box's top edge — 9vh
   above the copy — ran straight across the film as a hard line, with
   clear picture above it and a 93% scrim below. On a page whose whole
   premise is that nothing interrupts the film, the hero was cut in two
   by its own legibility layer.

   The mask feathers both ends without touching the strength under the
   copy: it is fully opaque from 2vh above the text box to 1vh below it,
   so every glyph sits on exactly the scrim it sat on before. The top
   inset grew from 9vh to 24vh to give the fade room to happen somewhere
   that is not on a word.

   If you move these numbers, keep the opaque band covering the whole
   .film__type box. tools/contrast-probe.js now applies this mask when
   it rebuilds the composite, so a sweep will catch a band that does not. */
.film__type::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -24vh -34vw -11vh -15vw;
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--ink) 93%, transparent) 0%,
    color-mix(in srgb, var(--ink) 88%, transparent) 46%,
    color-mix(in srgb, var(--ink) 68%, transparent) 68%,
    color-mix(in srgb, var(--ink) 22%, transparent) 84%,
    transparent 95%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 22vh, #000 calc(100% - 10vh), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 22vh, #000 calc(100% - 10vh), transparent 100%);
}

/* the scroll cue and the skip share a row, so the skip reads as part
   of the same instruction rather than as loose chrome */
/* The 38px belongs to the ROW. It used to sit on .film__scrollcue, one
   item inside an align-items:center row, where it pushed that item down
   by its own margin and the row re-centred the other one against it:
   the two labels that are meant to read as one line sat exactly 19px —
   half the margin — apart. */
.film__cues { margin-top: 38px; display: flex; align-items: center; gap: 26px; flex-wrap: wrap; }
.film__skip {
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .26em;
  text-transform: uppercase; color: var(--paper-3);
  padding: 15px 2px; margin-block: -15px; min-height: 44px;
  display: inline-flex; align-items: center;
  transition: color .3s var(--ease);
}
.film__skip:hover { color: var(--gold-2); }
.film__skip:focus-visible {
  outline: var(--focus-ring); outline-offset: 3px; box-shadow: var(--focus-halo);
}

/* --grad-gold-text, not the inherited --grad-gold-h. Everywhere else
   .gold-text sits on flat --ink, where -h's opening --gold-4 measures
   3.54:1 — a pass with no headroom at all. This is the one place the
   ramp sits on a photograph, so the moment the scrim is anything short
   of opaque that 3.54 is spent and the headline is unreadable. The
   -text ramp never drops below --gold-2, which is 10.8:1 on ink, and
   that margin is what the scrim is then able to preserve. */
/* background-IMAGE, not the `background` shorthand. The shorthand also
   resets background-clip, and because this selector outranks .gold-text
   that reset won the cascade: the ramp stopped clipping to the glyphs
   and painted as a solid gold bar across the whole line box, with the
   headline invisible inside it. */
.film__h1 .gold-text { background-image: var(--grad-gold-text); }
.film__h1 { font-size: clamp(42px, 8.6vw, 168px); }
.film__h1 .line { display: block; }
.film__h1 em { font-style: normal; }
.film__lede {
  margin: 30px 0 0; max-width: 46ch;
  font-size: clamp(15px, 1.25vw, 19px); color: var(--paper-2);
}
.film__scrollcue {
  display: inline-flex; align-items: center; gap: 12px;
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .38em;
  text-transform: uppercase; color: var(--paper-3);
}
.film__scrollcue span {
  width: 30px; height: 1px; background: var(--grad-gold-h);
  animation: cue 2.4s var(--ease-io) infinite;
}
@keyframes cue { 0%,100% { transform: scaleX(.3); transform-origin: left; } 50% { transform: scaleX(1); transform-origin: left; } }

/* Honest state when the rendered sequence is unavailable. */
.film__degraded {
  position: absolute; left: calc(var(--ray-x) + var(--gutter));
  right: var(--gutter); bottom: 30px; max-width: 62ch; margin: 0;
  padding: 14px 18px;
  border: 1px solid var(--accent-line);
  background: rgba(5,7,10,.82);
  font-family: var(--f-mono); font-size: 11px; line-height: 1.6;
  letter-spacing: .04em; color: var(--paper-2);
}
.film__degraded strong { color: var(--gold-1); }

/* ---- BEATS ---------------------------------------------------
   A caption per leg, landing as the leg arrives. They share the hero's
   left edge and baseline so the film has one place where words appear,
   and they stay well clear of the centre of frame, which is where the
   product is in every shot.

   Opacity, visibility and `inert` are set per frame by js/sequence.js.
   The defaults here are the hidden state, so nothing flashes before the
   engine runs and nothing appears at all if it never does. */
.film__beats {
  position: absolute; left: calc(var(--ray-x) + var(--gutter));
  right: var(--gutter); bottom: 15vh; height: 0;
  pointer-events: none;
}
@media (min-width: 761px) and (max-width: 1791px) {
  .film__beats { right: 176px; }
}
/* SIZED TO THE ROOM LEFT OF THE PRODUCT, not to a comfortable measure.
   The product is the protagonist and sits dead centre in every shot; in
   the closest framings its left edge is at about a third of the frame
   width. The first version was a fixed 36rem, which at 1024px ran the
   title straight across the bottom of the product and laid the scrim
   over its lower half and the hands holding it. So the width is a third
   of the viewport less the ray and gutter that already sit to the left,
   capped at 36rem for wide screens where that third is generous.

   Below 761px the frame is portrait and the product fills its width, so
   no width clears it — there the beat clears it vertically instead,
   sitting in the dark band under the product that the vignette already
   provides. */
.beat {
  position: absolute; left: 0; bottom: 0;
  width: min(36rem, calc(31vw - var(--ray-x) - var(--gutter)));
  opacity: 0; visibility: hidden; pointer-events: auto;
  will-change: opacity, transform;
}
/* On a phone the leg readout wraps — six legs do not fit in 375px, so
   "The team" drops to a second row — and at the hero's 15vh the last line
   of a beat ran straight into it. The floor is in pixels because the
   readout's height is set by how many rows it wraps to, not by the
   viewport: 178px clears three rows plus its 30px inset on a 320px phone,
   where 22vh alone would not. */
/* The hero takes the same floor for the same reason. It predates the
   beats but the collision does not: it appeared when the legs went from
   five to six and the readout started wrapping, at which point "Skip the
   film" printed straight over the readout's LEG label. There are ~175px
   free above the headline on a 375x812 phone, so lifting it costs
   nothing. Everything anchored to the bottom of the stage clears the
   readout from one rule. */
@media (max-width: 760px) {
  .film__type { bottom: max(22vh, 178px); }
  /* On a phone the copy runs nearly the full width, so its right-hand
     end reached past the desktop plateau into the decay — and once the
     block was lifted that end sat over the product's white body. The lede
     measured 4.81:1 there against 4.5 needed. A longer plateau puts the
     whole line on the strong part of the scrim. Measured, not guessed:
     see the HANDOFF entry for the before/after. */
  .film__type::before {
    background: linear-gradient(100deg,
      color-mix(in srgb, var(--ink) 93%, transparent) 0%,
      color-mix(in srgb, var(--ink) 90%, transparent) 62%,
      color-mix(in srgb, var(--ink) 74%, transparent) 80%,
      color-mix(in srgb, var(--ink) 30%, transparent) 92%,
      transparent 100%);
  }
  .beat { width: 100%; }
  .film__beats { bottom: max(22vh, 178px); }
  .beat__h { font-size: clamp(26px, 7.4vw, 34px); }
  .beat__p { font-size: 14px; }
}

/* Same construction as the hero scrim, and the same lesson: feathered on
   all four sides, so it never draws an edge across the film. Held to the
   text closely — 9vh above, decaying as soon as the copy ends on the
   right — because everything this layer reaches past the words is
   picture the reader came to see. The plateau has to cover the whole
   block, though: the body copy needs 4.5:1 at its right-hand end too, on
   the brightest frame. tools/contrast-probe.js composites exactly this
   layer and measures that. */
.beat::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -9vh -24vw -10vh -15vw;
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--ink) 92%, transparent) 0%,
    color-mix(in srgb, var(--ink) 88%, transparent) 62%,
    color-mix(in srgb, var(--ink) 50%, transparent) 76%,
    color-mix(in srgb, var(--ink) 14%, transparent) 88%,
    transparent 96%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 7vh, #000 calc(100% - 8vh), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 7vh, #000 calc(100% - 8vh), transparent 100%);
}
.beat__k {
  margin: 0; font-family: var(--f-mono); font-size: 10px;
  letter-spacing: .38em; color: var(--gold-1);
}
.beat__h {
  margin: 14px 0 0;
  font-family: var(--f-display); font-weight: 700; font-stretch: condensed;
  text-transform: uppercase; letter-spacing: .005em; line-height: .94;
  font-size: clamp(30px, 3.9vw, 64px); color: var(--paper);
}
.beat__p {
  margin: 16px 0 0; max-width: 42ch;
  font-size: clamp(15px, 1.15vw, 18px); line-height: 1.55; color: var(--paper-2);
}
/* nowrap: the beat column is sized to the gap left of the product, and on
   a landscape phone that is ~190px — narrow enough that "Request a brand
   audit" broke onto two lines inside the button. The label is allowed to
   run wider than the column; there is room before the product starts. */
.beat__cta { margin-top: 26px; white-space: nowrap; }

/* Short screens get the title and the ask, not the sentence: the same
   trade the hero makes with its lede at this height. */
@media (max-height: 560px) {
  .film__beats { bottom: 8vh; }
  .beat__h { font-size: clamp(24px, 4.4vh, 44px); }
  .beat__p { display: none; }
  .beat__cta { margin-top: 14px; }
}

/* ---- SHORT AND LANDSCAPE VIEWPORTS ---------------------------
   The hero type block is anchored to the bottom of a 100vh stage and
   sized in vw. On a landscape phone (812x375) that put a 70px headline
   straight through the logo and pushed the H1 off the top of the
   viewport, with the fixed chrome landing on top of it. Height, not
   width, is the constraint here, so the query has to be on height. */
@media (max-height: 560px) {
  .film__type { bottom: 8vh; }
  .film__h1 { font-size: clamp(26px, 4.6vh, 52px); }
  .film__lede { margin-top: 14px; font-size: 13px; max-width: 52ch; }
  /* .film__cues, not .film__scrollcue — this follows the 38px, which
     moved up to the row so the two labels in it would line up. */
  .film__cues { margin-top: 16px; }
}
@media (max-height: 440px) {
  /* Below this there is genuinely not room for the hero paragraph and
     the fixed readouts at once. The headline and the picture are the
     hero; the supporting copy repeats immediately below the fold.
     The A→Z is NOT dropped — it falls back to the bottom strip (see
     the .az__mini block). The leg readout and chapter rail do go:
     they are per-clip detail, the A→Z is the whole argument. */
  .film__lede, .film__scrollcue { display: none; }
  .film__type { bottom: 8vh; }
  /* .rail was here too. That element was retired when the chapter
     marker replaced it; the selector survived the deletion. */
  .legs { display: none; }
}

/* ---- A→Z arc indicator ---------------------------------------
   Echoes the mark: a letter riding an arc struck from one origin. */
.az {
  position: fixed; z-index: 50;
  right: 26px; top: 50%; transform: translateY(-50%);
  width: 132px; height: 264px;
  opacity: 0; transition: opacity .6s var(--ease);
  pointer-events: none;
}
.az.is-live { opacity: 1; }
.az__svg { width: 100%; height: 100%; overflow: visible; }
.az__track { fill: none; stroke: var(--hair); stroke-width: 1; }
.az__prog  { fill: none; stroke: url(#azGrad); stroke-width: 2; stroke-linecap: round; }
.az__end {
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .2em;
  fill: var(--paper-3);
}
.az__letter {
  font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
  font-size: 40px; fill: var(--gold-1); text-anchor: middle;
  dominant-baseline: central;
}
.az__dot { fill: var(--gold-1); }
.az__cap {
  position: absolute; right: 0; bottom: -6px;
  font-family: var(--f-mono); font-size: 8px; letter-spacing: .3em;
  color: var(--paper-3); text-transform: uppercase; text-align: right;
}
@media (max-width: 1100px) { .az { width: 96px; height: 200px; right: 12px; } .az__letter { font-size: 30px; } }

/* ---- A→Z on narrow screens ------------------------------------
   The arc is hidden below 761px because a fixed 96px column would sit
   on top of a 317px content column. The reading itself is not
   optional, so it becomes a strip across the bottom instead. */
.az__mini { display: none; }

/* Narrow OR short. A landscape phone is 812x375: wide enough to take
   the arc branch, far too short to fit a 200px arc. The height query
   used to simply `display: none` the whole indicator, which put back
   exactly the collateral loss the width fix removed, on the other
   axis. Both cases get the strip instead. */
@media (max-width: 760px), (max-height: 440px) {
  .az {
    display: block;
    top: auto; bottom: 0; left: 0; right: 0;
    width: auto; height: auto; transform: none;
  }
  .az__svg, .az__cap { display: none; }
  .az__mini {
    display: flex; align-items: center; gap: 10px;
    position: relative;
    padding: 7px calc(var(--ray-x) + 10px) 7px calc(var(--ray-x) + 10px);
    font-family: var(--f-mono); font-size: 9px; letter-spacing: .24em;
    color: var(--paper-3);
  }
  /* THE BACKGROUND STOPS SHORT OF THE RAY.
     This strip is fixed, full-width and z-50 — above the ray at z-3 —
     so a full-bleed background dimmed the ray to ~10% across the
     bottom 40px of every narrow viewport. The padding already cleared
     --ray-x; the paint did not. Now nothing is painted in that column
     at all, which is the actual rule. */
  .az__mini::before {
    content: ''; position: absolute;
    inset: 0 0 0 calc(var(--ray-x) + 6px);
    background: linear-gradient(180deg, transparent, rgba(5,7,10,.9) 46%);
    pointer-events: none;
  }
  .az__mini > * { position: relative; }
  .az__mini i { font-style: normal; }
  .az__minitrack {
    flex: 1 1 auto; height: 1px; background: var(--hair);
    position: relative; overflow: hidden;
  }
  .az__minitrack b {
    position: absolute; inset: 0 auto 0 0; width: 0;
    background: var(--grad-gold-h);
  }
  .az__mini em {
    font-style: normal;
    font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
    font-size: 15px; letter-spacing: .1em; color: var(--gold-1);
    min-width: 1.4em; text-align: right;
  }
}

/* ---- leg readout --------------------------------------------- */
.legs {
  position: fixed; z-index: 50;
  /* Both edges pinned. With only `left` set, the readout could not
     wrap however narrow the screen got — flex-wrap never fires on an
     unconstrained line box — so below ~360px "Live", the terminal
     state of the whole A-to-Z argument, was clipped off the right. */
  left: calc(var(--ray-x) + 26px); right: var(--gutter); bottom: 30px;
  /* These are real <button>s now, so opacity alone is not enough: it
     would leave five dead stops in the tab order across every other
     section of the page, each one teleporting the reader into the film
     when activated. visibility takes them out of the tree, and still
     animates because it interpolates discretely over the same
     duration. This is the lesson the old chapter rail already had. */
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .6s var(--ease), visibility .6s;
}
/* Clear the chapter rail's column. Both sit at bottom: 30px, and
   between about 761 and 1100px the wrapped leg readout can run under
   the rail's labels. The rail is pointer-clickable and the legs are
   not, so nothing breaks — it just overprints. */
/* Clear the chapter marker's corner: the seal is 138px wide sitting
   26px off the edge, so 178px keeps the wrapped leg readout from
   running under it. Re-derive this if --seal changes. */
@media (min-width: 761px) { .legs { right: 178px; } }

/* Clear the A→Z strip, which is ~38px tall and pinned to the bottom on
   exactly these viewports. This HAS to live after `.legs` — both are
   single-class selectors, so source order decides, and declaring it up
   in the .az__mini block (which sits earlier in this file) silently
   lost to the base `bottom: 30px`. Same trap as .film__type. */
@media (max-width: 760px), (max-height: 440px) { .legs { bottom: 54px; } }
.legs.is-live { opacity: 1; visibility: visible; pointer-events: auto; }
.legs__k {
  font-family: var(--f-mono); font-size: 8px; letter-spacing: .36em;
  color: var(--paper-3); text-transform: uppercase; display: block; margin-bottom: 8px;
}
/* row-gap 32, not 0. The buttons below buy their 44px touch target with
   `padding: 15px 8px; margin: -15px -8px` — which takes the padding out
   of LAYOUT but not out of the HIT BOX. Wrapped rows therefore sat about
   15px apart while each target was still 44px tall, overlapping by ~29px,
   and elementFromPoint at the centre of "Factory" returned "Live": the
   first stop of the A-to-Z story teleported you to the end. 15 + 15 = 30
   is the exact overlap; 32 leaves 2px of daylight. Re-derive if that
   padding changes. */
.legs__list { display: flex; align-items: center; column-gap: 0; row-gap: 32px; list-style: none; margin: 0; padding: 0; flex-wrap: wrap; }
.legs__list li {
  font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
  font-size: clamp(11px, 1.05vw, 14px); letter-spacing: .16em; text-transform: uppercase;
  /* Full opacity. At .38 an idle leg composited to 1.56:1 — the
     readout that tells you where you are was the least readable thing
     on the page. Colour alone separates the three states now:
     paper-3 ahead, paper-2 behind, gradient gold for the one you are
     actually on. */
  color: var(--paper-3);
  transition: color .45s var(--ease);
  white-space: nowrap;
}
.legs__list li + li::before {
  content: '→'; margin: 0 10px; color: var(--paper-3); opacity: .5;
  font-family: var(--f-text);
}
.legs__list li.is-done { color: var(--paper-2); }
/* The <li> still carries the state classes and the separators; the
   button is a transparent shell that inherits every bit of the type so
   the readout looks identical to the one that was there before. */
.legs__list li button {
  font: inherit; letter-spacing: inherit; text-transform: inherit;
  color: inherit; background: none; border: 0; margin: 0;
  cursor: pointer; white-space: nowrap;
  /* hit area only — the label stays at its clamp(11px,1.05vw,14px) */
  min-height: 44px; padding: 15px 8px; margin: -15px -8px;
  display: inline-flex; align-items: center;
}
.legs__list li button:focus-visible {
  outline: var(--focus-ring); outline-offset: 2px; box-shadow: var(--focus-halo);
}
.legs__list li button:hover { color: var(--gold-2); }

/* The gradient has to be clipped to the element that owns the glyphs.
   Left on the <li>, background-clip:text had nothing to clip to once
   the text moved inside the button, and the active leg rendered
   transparent — invisible. */
.legs__list li.is-active button {
  /* --grad-gold-text, not --grad-gold-h: this is 11–14px type, so it
     owes 4.5:1, and -h opens on --gold-4 at 3.39:1 */
  background: var(--grad-gold-text);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.legs__list li.is-active button:hover { color: transparent; }
@media (max-width: 640px) { .legs__list li { font-size: 9px; letter-spacing: .1em; } .legs__list li + li::before { margin: 0 5px; } }

/* ---- chapter marker ------------------------------------------
   Replaces the old .rail: four 14px buttons in the corner that were
   the only in-film navigation and looked like nothing at all.

   Navigation moved to the leg scrubber, where the eye already goes.
   What is left here is meaning — which service line the picture is
   currently showing — and that is a readout, not a control. So it
   carries no tab stop and is aria-hidden: the legs are the accessible
   path to the same information, in words.
   -------------------------------------------------------------- */
.chapter {
  position: fixed; z-index: 50;
  right: 26px; bottom: 30px;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .6s var(--ease), visibility .6s;
}
.chapter.is-live { opacity: 1; visibility: visible; }

/* Progress is an arc, not a rotation.

   Turning the whole ring with the film did move, but it carried the
   type around with it: at two-thirds through, "Distribution" was
   sitting on a 86-degree tilt, and a marker you are meant to READ had
   become a thing you had to tip your head at. The type now never
   moves. The arc traces the outer ring instead, which costs nothing
   in legibility and adds the one thing the seal could not say before:
   how far through the move you are. */
.seal__prog {
  transform: rotate(-90deg);            /* start the arc at 12 o'clock */
  transform-origin: 50% 50%;
  transition: stroke-dasharray .18s linear;
}
@media (prefers-reduced-motion: reduce) { .seal__prog { transition: none; } }

/* The chapter seal is smaller than the .seal default of 200px. This
   used to be an inline style on the element, which outranks every
   selector in this file — so the step-down below was inert from the
   day it was added and the seal stayed 138px at every width, including
   the ones it was sized down to survive. */
.chapter .seal { --seal: 138px; }

/* Step down, then out. Below the film's comfortable width the seal
   would overprint the wrapped leg scrubber, and the legs carry the
   same information in words. */
@media (max-width: 1100px) { .chapter .seal { --seal: 104px; } }
@media (max-width: 860px), (max-height: 560px) { .chapter { display: none; } }

/* =============================================================
   SECTION REVEAL — directional motion blur
   Blur is dropped to `none` once settled so we are not paying for
   a filter on a full-width section at rest.
   ============================================================= */
/* The blur has to RESOLVE, not switch off.
   An SVG filter reference cannot be interpolated by CSS, so
   `filter: url(#motionBlur)` sits at full strength for the whole
   transition and then pops. A plain blur() is animatable, so the
   section arrives out of a smear and sharpens as it settles —
   which is what reads as motion. The vertical travel supplies the
   direction. `is-settled` then drops the filter entirely so no
   full-width section carries a filter at rest. */
.js [data-blur] > .wrap {
  opacity: 0;
  transform: translateY(38px);
  filter: blur(7px);
  transition: opacity .8s var(--ease),
              transform 1s var(--ease),
              filter .8s var(--ease);
}
.js [data-blur].is-in > .wrap {
  opacity: 1; transform: none; filter: blur(0);
}
.js [data-blur].is-settled > .wrap { filter: none; }
@media (prefers-reduced-motion: reduce) {
  .js [data-blur] > .wrap { opacity: 1; transform: none; filter: none; transition: none; }

  /* A 240-frame scroll-scrubbed film is precisely the effect this
     preference exists to suppress, and the page previously honoured it
     with two rules — smooth scrolling off and the reveal blur off —
     while the scrub itself ran at full rate. Worse, skipping the
     620vh→768vh growth made the film SHORTER, which is more motion per
     pixel scrolled, not less.

     So: no animation anywhere, and sequence.js quantises the film to
     one still per leg instead of scrubbing (see REDUCED there). The
     journey is still told; it just steps instead of moving. */
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .film__scrollcue span { animation: none; transform: scaleX(1); transform-origin: left; }
  .ray__head, .film__type { will-change: auto; }
}
/* no-JS fallback */
html:not(.js) [data-blur] > .wrap { opacity: 1; transform: none; filter: none; }

/* =============================================================
   STATEMENT
   ============================================================= */
.statement { font-size: clamp(40px, 6.6vw, 116px); }
.statement em { font-style: normal; }
.statement__cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 40px; margin-top: 56px; max-width: 1000px;
}
.statement__cols p { margin: 0; color: var(--paper-2); font-size: 16.5px; }

/* =============================================================
   A TO Z — one chain, not four services
   ============================================================= */
.chain { position: relative; }

/* the connective tissue: each link ties back to the ray */
.chain__link {
  position: relative;
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: clamp(20px, 3vw, 54px);
  padding: clamp(30px, 4vw, 52px) 0;
}
.chain__link + .chain__link { border-top: 1px solid var(--hair-2); }

/* the spur that joins each link back to the ray on the left */
.chain__link::before {
  content: '';
  position: absolute; top: 50%; height: 1px;
  left: calc(-1 * (var(--gutter) - 4px)); width: calc(var(--gutter) - 12px);
  background: linear-gradient(90deg, var(--gold-3), transparent);
  opacity: .8;
}

.chain__letter {
  font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
  font-size: clamp(40px, 5.2vw, 82px); line-height: .8;
  background: var(--grad-gold); -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.chain__stage {
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .3em;
  text-transform: uppercase; color: var(--paper-3); margin-top: 12px;
}
.chain__h {
  font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
  font-size: clamp(24px, 2.6vw, 40px); text-transform: uppercase;
  letter-spacing: .01em; margin: 0 0 14px; line-height: 1;
}
.chain__p { margin: 0 0 18px; color: var(--paper-2); max-width: 62ch; }
.chain__items {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 8px 26px;
}
.chain__items li {
  font-size: 13.5px; color: var(--paper-2);
  padding-left: 16px; position: relative;
}
.chain__items li::before {
  content: ''; position: absolute; left: 0; top: .62em;
  width: 6px; height: 1px; background: var(--gold-3);
}
@media (max-width: 720px) {
  .chain__link { grid-template-columns: 1fr; gap: 14px; }
  .chain__link::before { display: none; }
}

.chain__note {
  margin-top: 48px;
  border-left: 1px solid var(--accent-line);
  padding: 18px 0 18px 22px;
  color: var(--paper-2); font-size: 14.5px; max-width: 74ch;
}
.chain__note strong { color: var(--paper); }

/* =============================================================
   AI VISIBILITY
   Two columns that have to be read in order: the question on the
   left, what to look for in the answer on the right. The grading
   column is not decoration — a reader who runs the prompt without
   it gets a fluent paragraph and no way to tell that it is wrong.
   ============================================================= */
.ai {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(30px, 4vw, 68px); align-items: start;
}
/* An `fr` track's automatic minimum is its content, and the brand name
   inside the prompt is arbitrary typed input. Sixty unbroken
   characters of it would widen the track, then the grid, then the
   document — on a page with overflow-x hidden and therefore no
   scrollbar to get back. Exactly the failure the review form's name
   field had; `overflow-wrap` on the prompt itself is the other half. */
.ai > * { min-width: 0; }
@media (max-width: 980px) { .ai { grid-template-columns: 1fr; } }

.ai__k {
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .3em;
  text-transform: uppercase; color: var(--paper-3); margin: 0 0 12px;
}
.ai__h {
  margin: 0 0 26px; max-width: 27ch;
  font-size: clamp(19px, 1.9vw, 25px); font-weight: 600;
  line-height: 1.24; color: var(--paper);
}

.ai__brand { margin-bottom: 22px; max-width: 36ch; }

.ai__prompt {
  position: relative; margin: 0 0 24px;
  padding: clamp(22px, 2.4vw, 30px);
  padding-left: clamp(26px, 2.6vw, 34px);
  border: 1px solid var(--hair);
  background: rgba(255,255,255,.02);
}
.ai__prompt::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--grad-gold);
}
.ai__prompt p {
  margin: 0; font-size: clamp(16px, 1.4vw, 19px); line-height: 1.5;
  color: var(--paper);
  overflow-wrap: anywhere;
}
/* --grad-gold-text, not the inherited --grad-gold-h: this runs at
   16–19px and --grad-gold-h opens on --gold-4 at 3.39:1, which is a
   fail for anything under 24px. Same reason the leg readout uses it. */
.ai__brandout {
  font-style: normal;
  background: var(--grad-gold-text);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

.ai__checks { list-style: none; counter-reset: aicheck; margin: 0; padding: 0; }
.ai__checks li {
  counter-increment: aicheck;
  display: grid; grid-template-columns: 34px 1fr; gap: 0 12px;
  padding: 20px 0; border-top: 1px solid var(--hair-2);
}
.ai__checks li:first-child { border-top: 0; padding-top: 0; }
.ai__checks li::before {
  content: counter(aicheck, decimal-leading-zero);
  grid-row: 1 / span 2;
  font-family: var(--f-mono); font-size: 10px; letter-spacing: .18em;
  line-height: 21px;
  background: var(--grad-gold-text);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.ai__checks h4 {
  margin: 0 0 6px; font-size: 15.5px; font-weight: 600;
  line-height: 1.3; color: var(--paper);
}
.ai__checks p {
  margin: 0; font-size: 14px; line-height: 1.55;
  color: var(--paper-2); max-width: 46ch;
}

.ai__foot {
  margin-top: clamp(38px, 4.5vw, 62px);
  padding-top: clamp(30px, 3.4vw, 44px);
  border-top: 1px solid var(--hair);
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(30px, 4vw, 68px);
}
@media (max-width: 980px) { .ai__foot { grid-template-columns: 1fr; } }
.ai__verdict, .ai__vs {
  margin: 0; font-size: 14.5px; line-height: 1.62; max-width: 62ch;
}
.ai__verdict { color: var(--paper-2); }
.ai__verdict strong { color: var(--paper); }
.ai__vs { color: var(--paper-3); }
.ai__vs strong { color: var(--paper-2); }

/* =============================================================
   HOW WE WORK

   Three columns per row: the number, the step, and what skipping it
   costs. The third column is not decoration — without it this is a
   process diagram, which every competitor also has.

   The list is split in two around the free/paid gate, so the second
   one carries start="5" for assistive tech and a matching
   counter-reset for the rendered numerals. Both are needed and they
   are set independently: `start` does not move a CSS counter, and a
   counter does not reach the accessibility tree.
   ============================================================= */
.seq { list-style: none; margin: 0; padding: 0; counter-reset: seq; }
.seq[start="5"] { counter-reset: seq 4; }

.seq li {
  counter-increment: seq;
  display: grid;
  grid-template-columns: 52px minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 0 clamp(24px, 3vw, 54px);
  align-items: start;
  padding: clamp(22px, 2.6vw, 32px) 0;
  border-top: 1px solid var(--hair-2);
}
.seq li:first-child { border-top: 0; padding-top: 0; }
.seq li::before {
  content: counter(seq, decimal-leading-zero);
  font-family: var(--f-mono); font-size: 11px; letter-spacing: .18em;
  line-height: 1.9;
  /* small type — --grad-gold-h opens at 3.39:1 and owes 4.5 here */
  background: var(--grad-gold-text);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.seq__h {
  margin: 0 0 8px; font-size: clamp(18px, 1.7vw, 22px);
  font-weight: 600; line-height: 1.25; color: var(--paper);
}
.seq__p {
  margin: 0; font-size: 14.5px; line-height: 1.6;
  color: var(--paper-2); max-width: 48ch;
}
/* The cost reads as an aside typographically and as the point
   editorially, so it keeps --paper-2 rather than dimming to
   --paper-3: the rule and the label carry the distinction, and
   dimming the one sentence a skeptic actually stops on would be
   styling against the argument. */
.seq__cost {
  margin: 0; padding-left: clamp(16px, 1.6vw, 22px);
  border-left: 1px solid var(--hair);
  font-size: 14px; line-height: 1.55; color: var(--paper-2);
  max-width: 40ch;
}
.seq__cost b {
  display: block; margin-bottom: 6px; font-weight: 400;
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .3em;
  text-transform: uppercase; color: var(--paper-3);
}

@media (max-width: 860px) {
  .seq li { grid-template-columns: 34px minmax(0, 1fr); gap: 0 14px; }
  /* Explicit, because auto-placement drops it into column one under
     the numeral and it loses its indent. */
  .seq__cost { grid-column: 2; margin-top: 15px; padding-left: 14px; }
}

.seq__gate {
  position: relative;
  margin: clamp(12px, 1.6vw, 20px) 0;
  padding: clamp(20px, 2.2vw, 28px);
  padding-left: clamp(24px, 2.4vw, 32px);
  border: 1px solid var(--hair);
  background: rgba(255, 255, 255, .02);
  display: grid;
  grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
  gap: 10px clamp(24px, 3vw, 54px);
  align-items: start;
}
.seq__gate::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0;
  width: 2px; background: var(--grad-gold);
}
.seq__gatek {
  margin: 0; line-height: 1.9;
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .3em;
  text-transform: uppercase;
  background: var(--grad-gold-text);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.seq__gatep {
  margin: 0; font-size: 14.5px; line-height: 1.62;
  color: var(--paper-2); max-width: 62ch;
}
@media (max-width: 860px) { .seq__gate { grid-template-columns: 1fr; } }

.seq__note {
  margin-top: clamp(32px, 3.6vw, 48px);
  border-left: 1px solid var(--accent-line);
  padding: 18px 0 18px 22px;
  color: var(--paper-2); font-size: 14.5px; line-height: 1.62; max-width: 74ch;
}
.seq__note strong { color: var(--paper); }

/* =============================================================
   SCOPE BUILDER
   ============================================================= */
.scope { display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(30px, 4vw, 68px); align-items: start; }
@media (max-width: 980px) { .scope { grid-template-columns: 1fr; } }

.toggles { list-style: none; margin: 0 0 26px; padding: 0; }
.toggles li + li { margin-top: 10px; }

.toggle {
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: 18px;
  padding: 20px 22px;
  border: 1px solid var(--hair);
  background: rgba(255,255,255,.014);
  cursor: pointer;
  transition: border-color .35s var(--ease), background .35s var(--ease);
}
.toggle:hover { border-color: var(--accent-line); }
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }

.toggle__box {
  width: 42px; height: 22px; border-radius: 22px;
  border: 1px solid var(--hair-strong); position: relative;
  transition: border-color .3s var(--ease), background .3s var(--ease);
  flex: 0 0 auto;
}
.toggle__box i {
  position: absolute; top: 50%; left: 3px; transform: translateY(-50%);
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--paper-3);
  transition: transform .34s var(--ease), background .34s var(--ease);
}
.toggle input:checked ~ .toggle__box { background: color-mix(in oklab, var(--gold-2) 16%, transparent); border-color: var(--accent-line); }
.toggle input:checked ~ .toggle__box i { transform: translateY(-50%) translateX(19px); background: var(--grad-gold); }
.toggle input:focus-visible ~ .toggle__box { outline: var(--focus-ring); outline-offset: 3px; box-shadow: var(--focus-halo); }

.toggle__text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.toggle__text strong {
  font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
  font-size: 17px; text-transform: uppercase; letter-spacing: .04em;
}
.toggle__text em {
  font-style: normal; font-size: 12.5px; color: var(--paper-3);
}
.toggle__state {
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .2em;
  color: var(--paper-3); text-transform: uppercase;
}
.toggle input:checked ~ .toggle__state { color: var(--gold-2); }

.scope__actions { display: flex; gap: 12px; flex-wrap: wrap; }

.summary {
  border: 1px solid var(--hair);
  background: rgba(255,255,255,.02);
  padding: clamp(24px, 3vw, 38px);
}
/* Stacked, not a two-column baseline row: "Full account, end to end"
   is the longest of the four resolutions and needs the panel's full
   measure rather than whatever is left beside its label. */
.summary__top { display: block; }
.summary__k {
  display: block; margin-bottom: 10px;
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .3em;
  color: var(--paper-3); text-transform: uppercase;
}
.summary__resolve {
  display: block;
  font-family: var(--f-display); font-stretch: condensed; font-weight: 700;
  font-size: clamp(26px, 2.5vw, 40px); text-transform: uppercase; line-height: .96;
  /* the text ramp, not -h: this string has to stay readable in the
     desaturated "No scope selected" state too */
  background: var(--grad-gold-text);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.summary__count {
  margin: 22px 0; padding-bottom: 22px; border-bottom: 1px solid var(--hair-2);
  font-family: var(--f-display); font-stretch: condensed; font-size: 46px; line-height: 1;
}
.summary__count em {
  font-style: normal; font-family: var(--f-mono); font-size: 10px;
  letter-spacing: .24em; color: var(--paper-3); margin-left: 12px; text-transform: uppercase;
}
.summary__list { list-style: none; margin: 0 0 24px; padding: 0; }
.summary__list li {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 0; font-size: 14px; color: var(--paper-2);
  border-bottom: 1px solid var(--hair-2);
}
.summary__list li:last-child { border-bottom: 0; }
.summary__list .dot {
  width: 5px; height: 5px; border-radius: 50%; background: var(--grad-gold); flex: 0 0 auto;
}
/* Off state is carried by colour and by the word "Off" that scope.js
   writes into each row — not by opacity. At .5 an off row composited to
   1.90:1, and opacity alone told a screen reader nothing at all. */
.summary__list li.is-off { color: var(--paper-3); }
.summary__list li.is-off .dot { background: var(--paper-3); }
.summary__list li em {
  font-style: normal; margin-left: auto;
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--gold-2);
}
.summary__list li.is-off em { color: var(--paper-3); }

.summary__engagement {
  font-size: 13.5px; color: var(--paper-2); margin: 0;
  border-top: 1px solid var(--hair-2); padding-top: 20px;
}
.summary__badge {
  display: inline-block; margin-right: 10px; padding: 3px 9px;
  border: 1px solid var(--accent-line);
  font-family: var(--f-mono); font-size: 8px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--gold-2);
  vertical-align: middle;
}

/* =============================================================
   NETWORK — generic nodes on radiating geometry
   ============================================================= */
.net { position: relative; }
.net__stage { width: 100%; height: auto; overflow: visible; }
.net__ray { stroke: url(#netGrad); stroke-width: 1; fill: none; opacity: .5; }
.net__arc { stroke: url(#netGrad); stroke-width: 1.5; fill: none; opacity: .7; }
.net__node { fill: var(--charcoal); stroke: var(--gold-3); stroke-width: 1.2; }
.net__node--on { fill: var(--gold-2); }
.net__origin { fill: url(#netGrad); }
/* the label layer sits on the SVG's own coordinate space: the svg
   keeps its aspect ratio, so percentage offsets track the geometry */
.net__frame { position: relative; }
.net__labels { position: absolute; inset: 0; pointer-events: none; }
.net__tag {
  position: absolute;
  transform: translate(-100%, -50%);
  white-space: nowrap;
  pointer-events: auto;
  font-family: var(--f-mono);
  /* sized against the room the fan actually leaves: 13 labels down a
     diagram whose height is 45% of its width, and a label column that
     ends 16 viewBox units left of the outermost node */
  font-size: clamp(9px, .85vw, 11px);
  letter-spacing: .1em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--paper-2);
  display: flex; align-items: baseline; gap: 8px;
}
.net__tag b { font-weight: 600; }
.net__tag i {
  font-style: normal; opacity: .78; font-size: .86em; letter-spacing: .1em;
}

/* San Pedro Bay — the home complex, on the centre ray */
.net__tag--focal {
  font-size: clamp(11px, 1.05vw, 14px);
  letter-spacing: .07em;
}
.net__tag--focal b {
  font-weight: 700;
  background: var(--grad-gold-text);   /* small type — see the token */
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.net__tag--focal i { color: var(--gold-2); opacity: .85; }
.net__ray--focal { stroke-width: 2; opacity: 1; }
.net__node--focal { stroke: var(--gold-1); stroke-width: 1.6; }
circle.net__node--on.net__node--focal { fill: var(--gold-1); }
.net__tag--origin {
  transform: translate(-50%, 0);
  color: var(--gold-2);
  border: 0; background: none; padding: 0;
  letter-spacing: .28em;
}
/* --- narrow screens: spine instead of fan ---------------------
   The fan is hidden rather than shrunk. Below ~761px the diagram is
   about 317px wide, and 13 labels in the resulting ~143px of height
   land at ~6px type — present but unreadable, which is worse than
   an honest change of layout. */
.net__list { display: none; }

@media (max-width: 760px) {
  .net__frame { display: none; }

  .net__list {
    display: block; list-style: none; margin: 0; padding: 0 0 0 30px;
    position: relative;
  }
  /* The spine — one origin, running through every destination.
     Deliberately thinner and dimmer than the document ray running a
     few pixels to its left: only one line on this page is THE ray,
     and a second one at equal weight would argue with it. */
  .net__list::before {
    content: ''; position: absolute; left: 8px; top: 6px; bottom: 6px;
    width: 1px; background: var(--grad-gold); opacity: .5;
  }
  .net__row {
    position: relative; display: flex; align-items: baseline; gap: 10px;
    padding: 11px 0;
    font-family: var(--f-mono); font-size: 11px; letter-spacing: .13em;
    text-transform: uppercase; color: var(--paper-2);
  }
  .net__row + .net__row { border-top: 1px solid var(--hair-2); }
  .net__rowdot {
    position: absolute; left: -25px; top: 50%; transform: translateY(-50%);
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--charcoal); border: 1px solid var(--gold-3);
  }
  .net__row b { font-weight: 600; }
  .net__row i { font-style: normal; opacity: .78; font-size: .86em; }

  .net__row--focal { padding: 15px 0; font-size: 13px; letter-spacing: .09em; }
  .net__row--focal .net__rowdot {
    width: 13px; height: 13px; left: -28px;
    background: var(--gold-1); border-color: var(--gold-1);
    box-shadow: 0 0 12px 2px color-mix(in oklab, var(--gold-2) 70%, transparent);
  }
  .net__row--focal b {
    font-weight: 700;
    background: var(--grad-gold-text);
    -webkit-background-clip: text; background-clip: text; color: transparent;
  }
  .net__row--focal i { color: var(--gold-2); opacity: .9; }
}
.net__legend {
  margin-top: 34px; display: flex; gap: 28px; flex-wrap: wrap; align-items: center;
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--paper-3);
}
.net__legend-home { color: var(--gold-2); }
.net__legend-home::before {
  content: ''; display: inline-block; vertical-align: middle;
  width: 7px; height: 7px; border-radius: 50%; margin-right: 9px;
  background: var(--gold-1);
  box-shadow: 0 0 8px 1px color-mix(in oklab, var(--gold-2) 70%, transparent);
}

/* .ph / .ph--logo / .ph-tag are gone with the last placeholder — the
   inventory is empty, so the styles for marking one are dead weight. */

/* =============================================================
   BUTTONS
   ============================================================= */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 15px 30px; cursor: pointer; border: 1px solid var(--accent-line);
  background: transparent; position: relative; overflow: hidden;
  font-family: var(--f-mono); font-size: 10px; letter-spacing: .26em;
  text-transform: uppercase; color: var(--paper);
  transition: color .32s var(--ease);
}
.btn::before {
  content: ''; position: absolute; inset: 0;
  background: var(--grad-gold-h);
  transform: scaleX(0); transform-origin: left;
  transition: transform .44s var(--ease);
}
.btn > * , .btn { z-index: 0; }
.btn span { position: relative; z-index: 1; }
.btn:hover::before { transform: scaleX(1); }
.btn:hover { color: #06070A; }
.btn--solid { color: #06070A; }
.btn--solid::before { transform: scaleX(1); }
.btn--solid:hover::before { transform: scaleX(1); filter: brightness(1.12); }
.btn:focus-visible { outline: var(--focus-ring); outline-offset: 3px; box-shadow: var(--focus-halo); }

/* the scope panel's forward CTA — full width of the summary card so it
   reads as the panel's conclusion rather than a stray control */
.summary__cta {
  display: flex; width: 100%; margin-top: 26px; text-decoration: none;
}

/* =============================================================
   FORM
   ============================================================= */
.review { display: grid; grid-template-columns: .85fr 1.15fr; gap: clamp(32px, 5vw, 84px); align-items: start; }
/* An `fr` track has an automatic minimum of its content, so one long
   unbroken string inside it widens the track, then the grid, then the
   document — and with overflow-x hidden on <html> there is no scrollbar
   to get back. A 400-character name did exactly that: 5,222px of
   document, scrolled sideways by scrollIntoView, with the gold ray
   ending up off the left edge and unreachable. */
.review > * { min-width: 0; }
@media (max-width: 980px) { .review { grid-template-columns: 1fr; } }
.review__meta { font-size: 13px; color: var(--paper-3); margin-top: 26px; }

/* Borrowed from .seq__note rather than boxed: this is an aside to the
   pitch, not a pricing table, and giving it a panel would make the page
   look like it publishes rates. */
.review__price {
  margin: 26px 0 0; border-left: 1px solid var(--accent-line);
  padding: 4px 0 4px 20px;
  font-size: 14px; line-height: 1.6; color: var(--paper-2); max-width: 52ch;
}
.review__price b {
  display: block; margin-bottom: 7px; font-weight: 400;
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .3em;
  text-transform: uppercase; color: var(--paper-3);
}
/* The one commitment on the page with a deadline attached to it, so it
   gets paper weight rather than the --paper-3 of the meta line under
   it. The rule carries the gold; the sentence itself stays legible. */
/* Hung, not inline. As an inline-block the rule sat in the text flow,
   so the moment the sentence wrapped — which it does at every width
   below the desktop two-column split — line two returned to the left
   margin and the rule stopped reading as a marker and started reading
   as a dash the sentence began with. */
.review__reply {
  position: relative; margin: 22px 0 0; padding-left: 29px;
  font-size: 14.5px; line-height: 1.55; color: var(--paper);
}
.review__reply::before {
  content: ''; position: absolute; left: 0; top: .7em;
  width: 18px; height: 1px; background: var(--grad-gold);
}

.form { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
@media (max-width: 620px) { .form { grid-template-columns: 1fr; } }
.field { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.field--full { grid-column: 1 / -1; }
.field label {
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .24em;
  text-transform: uppercase; color: var(--paper-3);
}
.field .opt { text-transform: none; letter-spacing: .06em; opacity: .7; margin-left: 6px; }
.field input, .field textarea {
  background: rgba(255,255,255,.03);
  /* --hair-strong, not --hair: a control boundary owes 3:1 */
  border: 1px solid var(--hair-strong);
  padding: 14px 16px; color: var(--paper);
  transition: border-color .3s var(--ease), background .3s var(--ease);
  border-radius: 0; width: 100%;
}
/* :focus-visible, not :focus — removing the ring for pointer users too
   was gratuitous, and the replacement was a 1px border-colour change. */
.field input:focus-visible, .field textarea:focus-visible {
  outline: var(--focus-ring); outline-offset: 2px; box-shadow: var(--focus-halo);
  border-color: var(--gold-2); background: color-mix(in oklab, var(--gold-2) 5%, transparent);
}
.field input:focus, .field textarea:focus {
  border-color: var(--gold-2); background: color-mix(in oklab, var(--gold-2) 5%, transparent);
}
.field input[readonly] { color: var(--gold-2); cursor: default; }
.field textarea { resize: vertical; }
.field__err {
  margin: 0; font-size: 11.5px; color: #FF8B7A; min-height: 1em;
  font-family: var(--f-mono); letter-spacing: .04em;
}
.field__hint { margin: 0; font-size: 11.5px; color: var(--paper-3); }
/* "Change the scope" sits inline in a sentence, so it cannot take a
   44px block without breaking the line box — vertical padding on an
   inline element grows the hit area without affecting layout, which is
   the right trade here. */
.field__hint a {
  color: var(--gold-2); padding: 16px 3px; margin: -16px -3px;
}
.field__hint a:focus-visible {
  outline: var(--focus-ring); outline-offset: 2px; box-shadow: var(--focus-halo);
}
/* Back to top is a standalone control and can take the full block. */
.foot__meta a {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: 14px 6px; margin: -14px -6px;
}
.foot__meta a:focus-visible {
  outline: var(--focus-ring); outline-offset: 2px; box-shadow: var(--focus-halo);
}
.field.is-bad input, .field.is-bad textarea { border-color: #FF8B7A; }

.check { display: flex; align-items: flex-start; gap: 12px; cursor: pointer; font-size: 14px; color: var(--paper-2); }
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check__box {
  width: 18px; height: 18px; border: 1px solid var(--hair-strong);
  flex: 0 0 auto; margin-top: 2px; position: relative;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.check input:checked ~ .check__box { background: var(--grad-gold); border-color: var(--gold-2); }
.check input:checked ~ .check__box::after {
  content: ''; position: absolute; left: 5px; top: 1px;
  width: 5px; height: 10px; border: solid #06070A;
  border-width: 0 2px 2px 0; transform: rotate(42deg);
}
.check input:focus-visible ~ .check__box { outline: var(--focus-ring); outline-offset: 3px; box-shadow: var(--focus-halo); }

.form__foot { grid-column: 1 / -1; display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
/* The disclosure that this build sends nothing sits directly beside a
   full-contrast gold CTA. It gets body weight, not fine print. */
.form__note { margin: 0; font-size: 13.5px; color: var(--paper-2); max-width: 44ch; }
/* The bot trap. Off-screen rather than display:none — some bots skip
   fields that are not rendered. */
.form__trap { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
#submitBtn[aria-busy="true"] { opacity: .7; cursor: progress; }
.form__note strong { color: var(--gold-1); }

.confirm {
  border: 1px solid var(--accent-line);
  padding: clamp(26px, 3.4vw, 44px);
  background: color-mix(in oklab, var(--gold-2) 4%, transparent);
  /* Everything echoed back here is user-supplied, so none of it may be
     allowed to set the width of anything. */
  min-width: 0; overflow-wrap: anywhere; word-break: break-word;
}
/* The gold check disc is gone with the success framing — a tick is the
   single strongest "it happened" signal a form can emit, and nothing
   happened. */
.confirm__h { font-family: var(--f-display); font-stretch: condensed; font-size: 34px; text-transform: uppercase; margin: 0 0 12px; }
.confirm__p { color: var(--paper-2); margin: 0 0 26px; }
.confirm__p strong { color: var(--paper); }
.confirm__meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px; margin: 0 0 26px; }
.confirm__meta dt { font-family: var(--f-mono); font-size: 8.5px; letter-spacing: .24em; text-transform: uppercase; color: var(--paper-3); margin-bottom: 7px; }
.confirm__meta dd { margin: 0; font-family: var(--f-mono); font-size: 14px; color: var(--gold-2); word-break: break-word; }
/* body weight, not fine print — this is the true part */
.confirm__note { font-size: 13.5px; color: var(--paper-2); margin: 0 0 24px; }

/* =============================================================
   FOOTER — translucent, so the ray reaches the very bottom
   ============================================================= */
.foot {
  position: relative; z-index: 2;
  border-top: 1px solid var(--hair-2);
  padding: 64px 0 54px;
  background: transparent;
}
.foot__grid { display: grid; grid-template-columns: auto 1fr auto; gap: 44px; align-items: start; }
@media (max-width: 900px) { .foot__grid { grid-template-columns: 1fr; } }
.foot__brand { display: flex; align-items: center; gap: 13px; }
.foot__word b {
  display: block; font-family: var(--f-display); font-stretch: condensed;
  font-size: 14px; letter-spacing: .2em; text-transform: uppercase;
}
.foot__word i {
  font-style: normal; font-family: var(--f-mono); font-size: 8px;
  letter-spacing: .3em; color: var(--paper-3); text-transform: uppercase;
}
.foot__note p { margin: 0; font-size: 12px; color: var(--paper-3); max-width: 76ch; }
/* Footer nav. The header drops its section links below 940px, which
   left a ~19-screen document with no in-page navigation on a phone. */
.foot__nav {
  display: flex; gap: 22px; flex-wrap: wrap; margin: 0 0 16px; padding: 0;
  list-style: none;
  font-family: var(--f-mono); font-size: 10px; letter-spacing: .2em;
  text-transform: uppercase;
}
/* Same padding-and-cancel trick as the header: these measured 112x12,
   and on a page where the footer WAS the only navigation under 940px
   they were the hardest things on it to hit. The 22px gap is preserved
   because the negative margin gives back exactly what the padding took. */
.foot__nav a {
  color: var(--paper-2);
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 16px 6px; margin: -16px -6px;
}
.foot__nav a:hover, .foot__nav a:focus-visible { color: var(--gold-2); }
.foot__nav a:focus-visible {
  outline: var(--focus-ring); outline-offset: 2px; box-shadow: var(--focus-halo);
}
.foot__meta {
  display: flex; flex-direction: column; gap: 10px; align-items: flex-end;
  font-family: var(--f-mono); font-size: 9px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--paper-3);
}
@media (max-width: 900px) { .foot__meta { align-items: flex-start; } }

/* utility */
.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
