/* ============================================================
   Fresh4cast · marketing site prototype · design system
   Spec: Claude_Fresh4cast_Website_Rebuild_Build_Spec.md §3
   Premium pass: layered light on ink, soft elevation on paper,
   refined controls. Class contract unchanged.
   ============================================================ */

/* ---------- 1 · Tokens ---------- */
:root {
  /* ---- signal green · the only hue that means "act" or "happening now" ----
     Every green in the codebase resolves to a token here, so the allowlist
     in DESIGN.md stays grep-enforceable:
       grep -rnE 'sig-green' site/ --include=*.css --include=*.js --include=*.html
     A new green literal anywhere silently breaks that guarantee.
     #45CB30 and the -deep/-text steps are logo-sampled (spec §3.1). */
  --sig-green:          #45CB30;   /* the signal */
  --sig-green-rgb:      69 203 48;
  --sig-green-deep:     #368E22;   /* AA on light: 3.87:1 paper · focus ring, large text */
  --sig-green-text:     #2C731B;   /* AA on light: 5.47:1 paper · body-size text */
  --sig-green-lift:     #7BD75F;   /* the signal, lifted for ink grounds · 9.65:1 on ink */
  --sig-green-lift-rgb: 123 215 95;
  --sig-green-pulse:    #B9F3A6;   /* travelling pulse · live only */
  --sig-green-ink:      #08240A;   /* dark text on bright live-signal faces */
  --sig-green-face-a:   #4FD93A;   /* bright signal face · top stop */
  --sig-green-face-b:   #3DBB2B;   /* bright signal face · bottom stop */

  /* The CTA is a green outline that fills with green on hover (Michele, 25 Oct
     2026: the flat logo-green face of the day before was the loudest thing on the
     first screen, brighter than the butterfly). On ink: a lifted green rim, white
     type, a green arrow, a deep green tint on hover. On paper: a deep green rim
     and type (AA), a pale tint on hover. Machined, never a "PPT button": no
     gradient, no gloss, no glow. */
  --cta-rim:          var(--sig-green-deep);                    /* on paper · 3.87:1 edge */
  --cta-ink:          var(--sig-green-text);                    /* on paper · 5.47:1 type */
  --cta-fill-h:       rgb(var(--sig-green-rgb) / 0.12);
  --cta-fill-a:       rgb(var(--sig-green-rgb) / 0.2);
  --cta-rim-ink:      rgb(var(--sig-green-lift-rgb) / 0.85);    /* on ink */
  --cta-fill-ink-h:   rgb(var(--sig-green-rgb) / 0.16);
  --cta-fill-ink-a:   rgb(var(--sig-green-rgb) / 0.24);

  --f4-blue:       #1D78E4;
  --f4-blue-rgb:   29 120 228;
  /* blue · the second accent DESIGN.md always named but never spent.
     It carries navigation and reference (links, "explore" affordances)
     so green is left to carry decision alone. Two hues, two jobs:
     blue = where you can go, green = what to do / what is live. */
  --f4-blue-deep:  #1663C0;   /* link text on light · 5.41:1 paper · 4.89:1 mist */
  --f4-blue-lift:  #7FB8F2;   /* link text on ink · 8.26:1 · the node-field supply blue */
  --f4-blue-lift-rgb: 127 184 242;
  --f4-ink:        #0E1B2E;
  --f4-ink-rgb:    14 27 46;
  --f4-ink-800:    #16233A;
  --f4-paper:      #F4F6F8;
  --f4-paper-rgb:  244 246 248;
  --f4-mist:       #DFE6EF;
  --f4-slate:      #54646F;
  --f4-slate-rgb:  84 100 111;
  --f4-line:       #D8DFE7;
  --f4-line-dark:  rgba(255, 255, 255, 0.12);

  /* ---- ink · an opaque navy chroma ladder ----
     Detomaso: deep navy structure, layered blue surfaces. Every raised
     surface is an opaque step, never a white veil over the ground. Alpha
     lifts desaturate as they stack and drag the hue toward grey, which is
     why hierarchy dissolves by the third layer; these hold their chroma.
     Each step adds lightness AND blue chroma, the way a polished flank
     catches more sky than the dial beside it. OKLCH: L .189 -> .346 in
     even steps (dL .032-.045), C .031 -> .062, hue held at 255-263. */
  --ink-900:  #0A1421;              /* deepest · behind the ground */
  --ink-900-rgb: 10 20 33;
  --ink-800:  var(--f4-ink);        /* var(--f4-ink) · the ink ground */
  --ink-700:  var(--f4-ink-800);    /* var(--ink-700) · raised: cards, panels */
  --ink-600:  #1E2E49;              /* raised further · nested, hover */
  --ink-500:  #28395A;              /* highest · popovers, active */

  /* ---- cool-white information ladder ----
     Opaque, not alpha: the same rgba() reads as three different greys over
     three ink steps, which is precisely how a hierarchy stops being one.
     All three clear AA (>=4.5:1) on every ink step above. */
  --ink-text-1:      #E6EBF2;   /* primary   · 14.43:1 on ink-800 */
  --ink-text-1-rgb:  230 235 242;
  --ink-text-2:      #AFBDD0;   /* secondary ·  9.06:1 on ink-800 */
  --ink-text-2-rgb:  175 189 208;
  --ink-text-3:      #94A5BC;   /* tertiary  ·  6.89:1 on ink-800 · 4.59:1 worst case */
  --ink-text-3-rgb:  148 165 188;   /* for rules derived from the ladder, never for text */

  /* semantic UI-state colours · mini-demos only, never brand chrome */
  --f4-signal:     #21AEB8;
  --f4-signal-rgb: 33 174 184;
  --f4-warn:       #F2A93B;
  --f4-warn-rgb:   242 169 59;
  --f4-crit:       #DD5B55;
  --f4-crit-rgb:   221 91 85;

  /* Readable text forms of the three states, one per ground. These existed as
     eight literals with no names, which is how .k-crit and .state-crit ended up
     rendering two different reds inside the same demo. Light values clear AA on
     paper and mist; ink values clear AA on every step of the ink ladder. */
  --warn-text:    #8A5407;   /* 7.4:1 on paper */
  --crit-text:    #A32F29;   /* 7.7:1 on paper */
  --signal-text:  #146C74;
  --warn-ink:     #F7C173;
  --crit-ink:     #F08A84;
  --signal-ink:   #7FD9DF;
  --f4-blue-pale: #A8CFF5;   /* small type on blue pills · lighter than --f4-blue-lift by design */

  --font-display:  "Playfair Display", Georgia, serif;
  --font-body:     "Hanken Grotesk", "Segoe UI", system-ui, sans-serif;
  --font-mono:     "Geist Mono", "IBM Plex Mono", "Consolas", monospace;

  /* ---- document type ----
     Seventeen steps, each already a high-frequency size in the file. The pairs
     that were 0.6px apart doing the same job (0.9 vs 0.9375, 0.7 vs 0.6875,
     0.72 vs 0.71875) are collapsed; nothing else moves.
     Instrument type stays in px: inside .rt-*, .sp-*, .mv-*, .f4dial and .nf-*
     a font-size is engraving in viewBox space, sized against the geometry
     around it, and pulling it onto a document ladder would break that. */
  --fs-4xs:        0.5625rem;    /*  9px */
  --fs-3xs:        0.625rem;     /* 10px */
  --fs-2xs:        0.65625rem;   /* 10.5px · mono micro-caption */
  --fs-xs:         0.6875rem;    /* 11px */
  --fs-kicker:     0.71875rem;   /* 11.5px */
  --fs-sm:         0.75rem;      /* 12px */
  --fs-cap-s:      0.78125rem;   /* 12.5px */
  --fs-cap:        0.8125rem;    /* 13px */
  --fs-base:       0.875rem;     /* 14px */
  --fs-md:         0.9375rem;    /* 15px */
  --fs-lg:         1rem;         /* 16px */
  --fs-xl:         1.0625rem;    /* 17px */
  --fs-2xl:        1.125rem;     /* 18px */
  --fs-3xl:        1.25rem;      /* 20px */
  --fs-display-xs: 1.3125rem;    /* 21px */
  --fs-h3:         1.375rem;     /* 22px */
  --fs-display-s:  1.625rem;     /* 26px */
  --fs-panel-title: 1.5rem;    /* a panel heading, not a section h2 */
  --fs-kpi:        1.375rem;     /* the one KPI number size · was 1.375 and 1.4375 */

  /* line-height · four roles, not sixteen one-offs */
  --lh-body:   1.6;
  --lh-body-l: 1.55;
  --lh-ui:     1.5;
  --lh-tight:  1.45;

  /* aliases · the ~90 existing call sites inherit the opaque ladder untouched */
  --text-on-ink:        var(--ink-text-1);
  --text-on-ink-dim:    var(--ink-text-2);

  /* One geometry · four steps and two reserved shapes, nothing between.
     Panels, controls, small cells, fine detail; plus 50% for true circles
     (data nodes, indicators) and 999px for pills. Every stray 9/10/11/14px
     one-off collapses onto this so components read as one system. */
  --radius-card:   16px;   /* panels: cards, mega, demo frames, mini-map */
  --radius-btn:    12px;   /* controls: buttons, inputs */
  --radius-sm:     8px;    /* small cells: chips, mega items, icon cells */
  --radius-xs:     4px;    /* fine detail: ticks, small marks */
  --radius-circle: 50%;    /* reserved · true circles: data nodes, indicators */
  --radius-pill:   999px;  /* reserved · pills, and the round cap on 1-2px bars */

  --container:     1200px;
  --gutter:        24px;
  --header-h:      72px;   /* the sticky bar · also read by site.js */

  /* ---- spacing · one scale, named in pixels ----
     2px steps to 20, 4px to 40, 8px to 96. There were 61 distinct rem values
     doing this job with a 1px grid latent underneath and 16 values sitting off
     it, which is the fingerprint of tuning rather than a system. Every step
     below was already a high-frequency value in the file.
     Layout boxes only. Inside the instrument namespaces (.rt-*, .sp-*, .mv-*,
     .nf-*, .f4dial) a px is a drawing coordinate in viewBox space, not rhythm,
     and those are deliberately left alone. */
  --space-2:  0.125rem;   --space-24: 1.5rem;
  --space-4:  0.25rem;    --space-28: 1.75rem;
  --space-6:  0.375rem;   --space-32: 2rem;
  --space-8:  0.5rem;     --space-36: 2.25rem;
  --space-10: 0.625rem;   --space-40: 2.5rem;
  --space-12: 0.75rem;    --space-48: 3rem;
  --space-14: 0.875rem;   --space-56: 3.5rem;
  --space-16: 1rem;       --space-64: 4rem;
  --space-18: 1.125rem;   --space-72: 4.5rem;
  --space-20: 1.25rem;    --space-80: 5rem;
                          --space-88: 5.5rem;
                          --space-96: 6rem;

  /* section rhythm · five competing clamps collapsed to three */
  --rhythm-lg: clamp(5rem, 10vh, 8.5rem);
  --rhythm-md: clamp(3.5rem, 7vh, 5.5rem);
  --rhythm-sm: clamp(3rem, 6vh, 4.5rem);

  /* One curve. Durations are a four-step ladder so "quick" and "settled"
     are decisions rather than whatever felt right in the moment. */
  --ease-out:      cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast:      140ms;  /* colour/background swaps on small controls */
  --dur-base:      200ms;  /* the default · hover, borders, transforms */
  --dur-slow:      300ms;  /* larger surfaces, panels */
  --dur-entrance:  450ms;  /* scroll entrances (DESIGN.md) */
  --stagger:       60ms;   /* scroll entrance stagger (DESIGN.md) */

  /* ---- light surfaces · finish, not float ----
     White Birch builds depth from how light meets a finish, not from a
     drop shadow: a polished top edge catches light, the body stays matte,
     a hairline is the case edge. The old elevation floated cards on a big
     soft ambient blur (the SaaS tell, -32px spreads). These sit ON the
     surface: a 1px specular top edge (the polish), then a tight contact
     shadow close to the plane. The specular only reads because --surface
     sits a hair below white; on a #fff card it was invisible. */
  /* Five cool steps between white and --f4-mist. There were eleven near-whites
     doing this job, several of them 2/255 apart on adjacent components, which is
     drift rather than hierarchy. */
  --surface:    #FBFCFE;   /* raised light panel · just below white so the specular edge shows */
  --surface-1:  #F7FAFD;   /* gradient top stop on raised panels */
  --surface-2:  #F1F5FA;   /* recessed well · toggle tracks, tab strips, insets */
  --surface-3:  #EBF0F7;   /* deeper well · the mist gradient's own top stop */
  --surface-4:  #E7EDF5;   /* deepest · one step above --f4-mist */

  /* The polished top edge, at four strengths instead of fifteen hand-typed alphas. */
  --specular:       inset 0 1px 0 rgba(255, 255, 255, 0.9);    /* light panels */
  --specular-ink:   inset 0 1px 0 rgba(255, 255, 255, 0.07);   /* ink panels · the default */
  --specular-ink-2: inset 0 1px 0 rgba(255, 255, 255, 0.14);   /* ink panels · raised */
  --specular-lit:   inset 0 1px 0 rgba(255, 255, 255, 0.24);   /* lit faces · CTA, spotlight */

  --shadow-sm: var(--specular), 0 1px 1px rgb(var(--f4-ink-rgb) / 0.05), 0 3px 6px -2px rgb(var(--f4-ink-rgb) / 0.07);
  --shadow-md: var(--specular), 0 2px 4px -1px rgb(var(--f4-ink-rgb) / 0.06), 0 10px 20px -8px rgb(var(--f4-ink-rgb) / 0.12);
  --shadow-lg: var(--specular), 0 6px 12px -4px rgb(var(--f4-ink-rgb) / 0.07), 0 22px 44px -16px rgb(var(--f4-ink-rgb) / 0.17);

  /* the same three steps for panels sitting on ink · these were nine hand-typed
     ambients, one of which was the exact -32px spread the note above disowns */
  --shadow-ink-sm: var(--specular-ink), 0 8px 20px -16px rgb(var(--ink-900-rgb) / 0.55);
  --shadow-ink-md: var(--specular-ink), 0 16px 40px -24px rgb(var(--ink-900-rgb) / 0.55);
  --shadow-ink-lg: var(--specular-ink), 0 20px 48px -32px rgb(var(--ink-900-rgb) / 0.6);

  /* dark-surface recipe */
  --ink-card-grad: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.018));
  --ink-card-line: rgba(255, 255, 255, 0.09);

  /* fine noise for dark sections */
  --noise: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="180" height="180"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="2" stitchTiles="stitch"/><feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.035 0"/></filter><rect width="180" height="180" filter="url(%23n)"/></svg>');

  /* ---- glow · a verb, not a finish ----
     A bloom means "this is live": it is moving, or you are touching it.
     Everything at rest renders flat, so emitted light reads as motion
     rather than decoration. Four glowing stat numbers are not four live
     things, they are a fact with a halo.
     Nulled under prefers-reduced-motion below: a halo that implies motion
     which never arrives is a lie told to the one user who opted out. */
  --glow-live:      0 0 12px rgb(var(--sig-green-rgb) / 0.55);
  --glow-live-ink:  0 0 12px rgb(var(--sig-green-lift-rgb) / 0.5);
  --glow-warn-ink:  0 0 16px rgb(var(--f4-warn-rgb) / 0.5);   /* the ripple's amber strike */
  --glow-ref-ink:   0 0 12px rgb(var(--f4-blue-rgb) / 0.45);  /* touch on a reference/import mark */

  /* hero safe zone · a left-edge fade so hero geometry keeps clear of the copy
     column; only faint ambient (~14%) bleeds behind the headline, ramping to
     full strength by 47% width where the focal mass begins. */
  --hero-safe: linear-gradient(to right, rgba(0,0,0,0.10) 0, rgba(0,0,0,0.10) 22%, #000 54%);

  /* z-scale */
  --z-drop:    40;
  --z-sticky:  50;
  --z-nav:     60;
  --z-scrim:   65;   /* the mobile nav scrim · above the bar, below the sheet */
  --z-overlay: 70;
  --z-skip:    100;  /* the skip link, which must clear everything */
}

/* ---------- 2 · Reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Glow claims "this is live". With motion off, nothing is: the claim
   would be false, so it is withdrawn. `0 0 0 0 transparent` rather than
   `none` because these tokens sit inside comma-separated shadow lists,
   where `none` would invalidate the whole declaration. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --glow-live:     0 0 0 0 transparent;
    --glow-live-ink: 0 0 0 0 transparent;
    --glow-warn-ink: 0 0 0 0 transparent;
    --glow-ref-ink:  0 0 0 0 transparent;
  }
}

body {
  font-family: var(--font-body);
  font-size: var(--fs-lg);
  line-height: var(--lh-body);
  color: var(--f4-ink);
  background: var(--f4-paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
a { color: inherit; }
/* Prose links carry the navigation hue. Scoped deliberately rather than set on a
   global `a`: over ink, --f4-blue-deep fails contrast, so the ink ground re-keys to
   the lifted blue and chrome/nav links keep their own treatment. */
.card p a, .sub a, .hint a, .consent-row a, .muted a, address a { color: var(--f4-blue-deep); }
.bg-ink .card p a, .bg-ink .sub a, .bg-ink .hint a, .bg-ink .consent-row a,
.bg-ink .muted a, .bg-ink address a, .site-footer address a { color: var(--f4-blue-lift); }

/* WCAG 2.2 SC 1.4.11 needs 3:1 for a focus indicator. --sig-green is 1.99:1 on
   paper and 1.91:1 on mist: it never passed. --sig-green-deep clears every
   ground the ring can land on (3.87:1 paper · 3.72:1 mist · 4.16:1 ink). */
:focus-visible {
  outline: 2px solid var(--sig-green-deep);
  outline-offset: 3px;
  border-radius: var(--radius-xs);
}
.bg-ink :focus-visible, .site-footer :focus-visible { outline-color: var(--sig-green-lift); }

::selection { background: rgb(var(--f4-blue-rgb) / 0.22); }

/* quiet, themed scrollbar */
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #C3C9D1; border-radius: var(--radius-sm); border: 3px solid var(--f4-paper); }
::-webkit-scrollbar-thumb:hover { background: #A8AFB9; }

h1, h2, h3, h4 { text-wrap: balance; }
p { text-wrap: pretty; }

/* ---------- 3 · Type roles ---------- */
.display-xl {
  font-family: var(--font-display);
  font-size: clamp(2.75rem, 4.4vw, 4rem);
  font-weight: 520;
  font-variation-settings: "opsz" 144;
  line-height: 1.03;
  letter-spacing: -0.022em;
}
.h1, h1 {
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 4vw, 3.5rem);
  font-weight: 500;
  font-variation-settings: "opsz" 100;
  line-height: 1.06;
  letter-spacing: -0.016em;
}
.h2, h2 {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  font-weight: 500;
  font-variation-settings: "opsz" 72;
  line-height: 1.12;
  letter-spacing: -0.012em;
}
.h3, h3 {
  font-family: var(--font-body);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.008em;
}
h4 { font-family: var(--font-body); font-size: var(--fs-xl); font-weight: 600; }

.body-l { font-size: var(--fs-2xl); line-height: var(--lh-body-l); }
.caption { font-family: var(--font-mono); font-size: var(--fs-cap); line-height: var(--lh-ui); }

.kicker {
  display: inline-flex;
  align-items: center;
  gap: var(--space-10);
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--f4-slate);
}
/* The node-dot is a registration mark, not decoration: hollow, drawn in
   the label's own ink, so it reads as a graduation on an instrument
   rather than a green bullet. It fills with signal only where something
   is genuinely live (.is-live, set by the scroll engine on the section
   currently playing). 82 section kickers, one hue quieter. */
.kicker::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid currentColor;
  opacity: 0.6;
  flex: none;
}
.bg-ink .kicker { color: var(--ink-text-2); }
.kicker.is-live::before {
  background: var(--sig-green);
  border-color: var(--sig-green);
  opacity: 1;
}
.bg-ink .kicker.is-live::before { background: var(--sig-green-lift); border-color: var(--sig-green-lift); }

.stat-num {
  font-family: var(--font-mono);
  font-size: clamp(2.5rem, 5vw, 4rem);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.muted { color: var(--f4-slate); }
.bg-ink .muted, .bg-ink p { color: var(--text-on-ink-dim); }
.bg-ink, .bg-ink h1, .bg-ink h2, .bg-ink h3 { color: #fff; }
.bg-ink { color: var(--text-on-ink); }

.measure { max-width: 68ch; }

/* ---------- 4 · Layout ---------- */
.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--rhythm-lg); }
.section-tight { padding-block: var(--rhythm-sm); }

.bg-paper { background: var(--f4-paper); }
.bg-mist  { background: linear-gradient(180deg, var(--surface-3) 0%, var(--f4-mist) 100%); }
/* adjacent light sections need a machined boundary, not a guess: mist
   sections carry their own register hairlines top and bottom */
section.bg-mist { border-top: 1px solid var(--f4-line); border-bottom: 1px solid var(--f4-line); }

/* The ink ground is a navy field lit from two corners by blue alone.
   A green radial used to wash the top-right at 10%: the largest single
   green surface on the site, and the reason green could not read as a
   signal — the ground it had to contrast against was already green.
   Depth here comes from the ladder and the noise, never from a wash. */
.bg-ink {
  background-color: var(--ink-800);
  background-image:
    var(--noise),
    radial-gradient(1100px 620px at 82% -12%, rgb(var(--f4-blue-rgb) / 0.10), transparent 62%),
    radial-gradient(900px 560px at -8% 108%, rgb(var(--f4-blue-rgb) / 0.07), transparent 60%),
    linear-gradient(180deg, #0C1828 0%, var(--ink-800) 45%, #0F1D31 100%);
}

.section-head { max-width: 62ch; margin-bottom: clamp(2.5rem, 5vh, 4rem); }
.section-head .kicker { margin-bottom: var(--space-20); }
.section-head .sub { margin-top: var(--space-18); font-size: var(--fs-2xl); color: var(--f4-slate); }
.bg-ink .section-head .sub { color: var(--text-on-ink-dim); }

.grid { display: grid; gap: var(--gutter); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-split { grid-template-columns: 7fr 5fr; align-items: center; gap: clamp(2rem, 5vw, 4.5rem); }

@media (max-width: 1023px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 767px) {
  .grid-2, .grid-3, .grid-4, .grid-split { grid-template-columns: 1fr; }
}
/* Sees layer · give the Control Tower instrument the larger share */
@media (min-width: 768px) {
  .grid-split.ct-split { grid-template-columns: 5fr 7fr; }
}
/* Plan hero · the consensus gate needs more than the default 5fr, and it stacks
   a breakpoint earlier than the rest: at 768-1023 a 5fr column is ~270px, which
   would shrink the instrument's 11px mono labels to ~7px. */
@media (min-width: 1024px) {
  .grid-split.plan-split { grid-template-columns: 6fr 6fr; }
}
@media (max-width: 1023px) {
  .grid-split.plan-split { grid-template-columns: 1fr; }
}

/* faint node texture for select sections · drifts almost imperceptibly */
.node-texture { position: relative; overflow: hidden; }
.node-texture::before {
  content: "";
  position: absolute; inset: -80px;
  background-image: radial-gradient(circle 1.5px at 1.5px 1.5px, currentColor 1.5px, transparent 0);
  background-size: 44px 44px;
  opacity: 0.05;
  pointer-events: none;
  animation: ntDrift 70s linear infinite alternate;
}
@keyframes ntDrift { to { transform: translate3d(52px, 36px, 0); } }

/* ---------- 5 · Buttons & links ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-14) var(--space-28);
  border-radius: var(--radius-btn);
  font-weight: 600;
  font-size: var(--fs-md);
  line-height: 1.2;
  text-decoration: none;
  border: 1.5px solid transparent;
  /* one curve and one duration · the lift, the fill and the bloom arrive together.
     The shadow used to run 250ms against the transform's 200ms, which reads as the
     glow trailing the button on a large hero CTA. */
  transition: transform var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out);
}
.btn:active { transform: translateY(1px) scale(0.995); }

/* The primary is the one green button on a screen: a green outline that fills
   with green as you reach for it. It holds still under the pointer: the tint
   arrives and the arrow nudges, and nothing else moves (no lift, no glow, no
   magnetic pull · Michele, 24 and 25 Oct 2026). */
.btn-primary {
  --cta-arrow: var(--cta-rim);
  background: transparent;
  color: var(--cta-ink);
  border-color: var(--cta-rim);
}
.btn-primary:hover, .btn-primary:focus-visible { background: var(--cta-fill-h); }
.btn-primary:active { background: var(--cta-fill-a); }
/* on ink · a lifted rim and white type. The open phone menu turns the header to
   paper, so the header's button keeps the paper face there. */
.bg-ink .btn-primary, .cta-band .btn-primary, body:not(.nav-open) .site-header.is-dark .btn-primary {
  --cta-arrow: var(--sig-green-lift);
  color: var(--ink-text-1);
  border-color: var(--cta-rim-ink);
}
.bg-ink .btn-primary:hover, .cta-band .btn-primary:hover, body:not(.nav-open) .site-header.is-dark .btn-primary:hover,
.bg-ink .btn-primary:focus-visible, .cta-band .btn-primary:focus-visible {
  background: var(--cta-fill-ink-h);
  border-color: var(--sig-green-lift);
  color: rgb(255 255 255);
}
.bg-ink .btn-primary:active, .cta-band .btn-primary:active, body:not(.nav-open) .site-header.is-dark .btn-primary:active { background: var(--cta-fill-ink-a); }
/* the arrow is drawn, not typed, so a screen reader never reads "right arrow" */
.btn-primary:not(.btn-sm)::after {
  content: "";
  flex: none;
  width: 16px; height: 16px;
  margin-right: calc(var(--space-6) * -1);
  background: var(--cta-arrow);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h10.5M9 4l4 4-4 4'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h10.5M9 4l4 4-4 4'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform var(--dur-base) var(--ease-out);
}
.btn-primary:not(.btn-sm) { gap: var(--space-10); }
.btn-primary:hover::after, .btn-primary:focus-visible::after { transform: translateX(3px); }
@media (prefers-reduced-motion: reduce) {
  .btn-primary:hover::after, .btn-primary:focus-visible::after { transform: none; }
}

.btn-outline { border-color: rgb(var(--f4-ink-rgb) / 0.35); color: var(--f4-ink); background: rgba(255, 255, 255, 0.4); }
.btn-outline:hover { border-color: var(--f4-ink); background: var(--surface); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.bg-ink .btn-outline, .on-dark.btn-outline {
  border-color: rgba(255, 255, 255, 0.35); color: #fff;
  background: rgba(255, 255, 255, 0.04);
}
.bg-ink .btn-outline:hover, .on-dark.btn-outline:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: rgba(255, 255, 255, 0.75);
  box-shadow: 0 12px 32px -16px rgba(0, 0, 0, 0.5);
}

.btn-sm { padding: var(--space-10) var(--space-18); font-size: var(--fs-base); }

.link-quiet {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  font-weight: 600;
  font-size: var(--fs-md);
  color: var(--f4-blue-deep);
  text-decoration: none;
  position: relative;
}
.link-quiet::after {
  content: "";
  position: absolute;
  left: 0; bottom: -3px;
  width: 100%; height: 1.5px;
  background: var(--f4-blue-deep);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 260ms var(--ease-out);
}
.link-quiet:hover::after { transform: scaleX(1); }
.link-quiet .arr { transition: transform 260ms var(--ease-out); }
.link-quiet:hover .arr { transform: translateX(4px); }
.bg-ink .link-quiet { color: var(--f4-blue-lift); }
.bg-ink .link-quiet::after { background: var(--f4-blue-lift); }

/* ---------- 6 · Header / nav ---------- */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: var(--z-nav);
  transition: background 260ms var(--ease-out), box-shadow 260ms var(--ease-out), border-color 260ms var(--ease-out);
  border-bottom: 1px solid transparent;
}
.header-inner {
  display: flex;
  align-items: center;
  gap: var(--space-32);
  height: var(--header-h);
  position: relative; /* the mega panel centres on the bar, not its button */
}

/* solid state (default on light pages, on-scroll everywhere) */
/* An opaque bar, not frosted glass: a precise edge on the page, not a
   blurred pane floating over it. The hairline and a 1px contact do the
   separation the 32px float used to. */
.site-header.is-solid {
  background: var(--f4-paper);
  border-bottom-color: rgb(var(--f4-ink-rgb) / 0.08);
  box-shadow: 0 1px 0 rgb(var(--f4-ink-rgb) / 0.05), 0 6px 16px -14px rgb(var(--f4-ink-rgb) / 0.4);
}

/* transparent-over-ink state */
.site-header.is-dark { color: #fff; }
.site-header.is-dark .nav-link { color: rgba(255, 255, 255, 0.88); }
.site-header.is-dark .login-link { color: rgba(255, 255, 255, 0.78); }

/* Keep the same green/white action treatment in both header states. */
.site-header .btn-primary { transition: background 260ms var(--ease-out), color 260ms var(--ease-out), border-color 260ms var(--ease-out), box-shadow 260ms var(--ease-out); }
/* One green button per screen. While a page's own hero primary is in view
   (site.js sets .cta-quiet), the header's twin steps back to an outline, and
   turns green again once the hero's has scrolled away. */
.site-header.is-dark.cta-quiet .header-actions .btn-primary {
  background: transparent;
  border-color: rgb(255 255 255 / 0.3);
  color: var(--ink-text-1);
  box-shadow: none;
}
.site-header.is-dark.cta-quiet .header-actions .btn-primary:hover {
  background: rgb(255 255 255 / 0.08);
  border-color: rgb(255 255 255 / 0.6);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-10);
  text-decoration: none;
  flex: none;
}
.brand-logo { display: block; height: 30px; width: auto; }
.site-footer .brand-logo { height: 34px; }
/* hold legibility for the blue wordmark over ink */
.site-header.is-dark .brand-logo, .site-footer .brand-logo {
  filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.35)) drop-shadow(0 1px 3px rgba(0, 0, 0, 0.45));
}

.main-nav { flex: 1; }
.main-nav > ul {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  list-style: none;
  margin: 0; padding: 0;
}
.nav-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-8) var(--space-14);
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--f4-ink);
  text-decoration: none;
  border-radius: var(--radius-sm);
  transition: background 180ms var(--ease-out), color 180ms var(--ease-out);
}
.nav-link:hover { background: rgb(var(--f4-ink-rgb) / 0.06); }
.site-header.is-dark .nav-link:hover { background: rgba(255, 255, 255, 0.1); }
.nav-link .chev { width: 9px; height: 9px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg) translateY(-2px); opacity: .55; transition: transform 200ms var(--ease-out); }
.nav-item:hover .chev { transform: rotate(45deg) translateY(1px); }
.nav-item.open .chev { transform: rotate(-135deg) translateY(1px); opacity: 1; }

.header-actions { display: flex; align-items: center; gap: var(--space-18); flex: none; }
.login-link { font-size: var(--fs-md); font-weight: 500; color: var(--f4-slate); text-decoration: none; transition: color 160ms var(--ease-out); }
.login-link:hover { color: var(--f4-ink); }
.site-header.is-dark .login-link:hover { color: #fff; }

/* dropdown / mega menu */
.nav-item { position: relative; }
.drop-panel {
  position: absolute;
  top: calc(100% + 12px);
  left: 50%;
  transform: translateX(-50%) translateY(8px) scale(0.99);
  background: var(--surface);
  color: var(--f4-ink);
  border: 1px solid var(--f4-line);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-lg);
  padding: var(--space-28);
  opacity: 0;
  visibility: hidden;
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out), visibility 0s 220ms var(--ease-out);
  z-index: var(--z-drop);
}
.nav-item.open > .drop-panel {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0) scale(1);
  transition-delay: 0s;
}
/* keyboard path · hover-open now lives in JS (with intent delay + aria sync) */
@media (min-width: 1024px) {
  .nav-item:focus-within > .drop-panel {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0) scale(1);
    transition-delay: 0s;
  }
}

.mega { width: min(1160px, calc(100vw - 48px)); }
/* centre the wide panel on the header bar so it can never clip a viewport edge */
@media (min-width: 1024px) {
  .nav-item.has-panel { position: static; }
}
/* head-row + five columns (SEES · ADVISES · ACTS ×2 · REMEMBERS · EXPLORE BY
   PROBLEM) + foot-row. This grid used to live in a runtime <style> patch in
   site.js because the stylesheet still declared the old five-track rail grid;
   folded back here so markup and CSS agree in one place. */
.mega-cols {
  display: grid;
  grid-template-columns: 1fr 1fr 2fr 1fr 1.05fr;
  grid-template-rows: auto auto;
  align-items: start;            /* columns hug the top · no stretch to the tallest */
  gap: var(--space-14) var(--space-24);
}
.mega-head { grid-column: 1 / -1; border-bottom: 1px solid var(--f4-line); padding-bottom: var(--space-6); }
.mega-foot {
  grid-column: 1 / -1;
  border-top: 1px solid var(--f4-line);
  padding-top: var(--space-6);
  display: flex; flex-wrap: wrap; align-items: flex-start;
  gap: var(--space-2) var(--space-40);
}
.mega-foot a { color: var(--f4-slate); }
/* the foundation under the four layers · a product, so it reads in ink and
   carries its sub-line; Technology beside it stays the quiet utility link */
.mega-foot a.mega-base { color: var(--f4-ink); }
.mega-col-label {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--f4-slate);
  padding-bottom: var(--space-10);
  margin-bottom: var(--space-10);
  border-bottom: 1px solid var(--f4-line);
}
.mega a {
  display: flex;
  align-items: flex-start;
  gap: var(--space-10);
  padding: var(--space-6) var(--space-10);
  margin-left: -0.5625rem;
  font-size: var(--fs-md);
  font-weight: 500;
  text-decoration: none;
  border-radius: var(--radius-sm);
  transition: background 140ms var(--ease-out), color 140ms var(--ease-out), transform 200ms var(--ease-out);
}
.mega a:hover { background: var(--f4-mist); color: var(--sig-green-text); transform: translateX(2px); }
.mega a .mega-sub { display: block; font-size: var(--fs-sm); font-weight: 400; color: var(--f4-slate); }
.mega .mega-txt { min-width: 0; }

/* module icons · the same 1.75px line language as the rest of the site */
.mega-ic {
  flex: none;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  background: rgb(var(--f4-ink-rgb) / 0.05);
  color: var(--f4-slate);
  margin-top: 1px;
  transition: background 140ms var(--ease-out), color 140ms var(--ease-out);
}
.mega-ic svg { width: 16px; height: 16px; transition: transform 200ms var(--ease-out); }
.mega a:hover .mega-ic { background: rgb(var(--sig-green-rgb) / 0.14); color: var(--sig-green-text); }
.mega a:hover .mega-ic svg { transform: scale(1.12); }

/* current page inside the panel · kicker-style node dot */
.mega a[aria-current="page"] { background: var(--f4-mist); color: var(--sig-green-text); }
.mega a[aria-current="page"] .mega-txt { position: relative; padding-left: var(--space-14); }
.mega a[aria-current="page"] .mega-txt::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--sig-green);
}

.mega .acts-grid { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--space-8); }

/* ONE panel, always — and it is the LIGHT one (client call). The panel
   used to flip light/dark with the header state, which read as two
   different menus. The base .drop-panel above is that single identity:
   opaque --surface, machined border, finish shadow. It is not the old
   foreign object — that was a translucent blurred slab; this one is a
   solid printed panel that drops over the hero like a dial card. No
   is-dark scoping exists anymore, so it cannot vary again. */

.mega-all { color: var(--sig-green-text); font-weight: 600; margin-top: var(--space-4); }

/* The panel arrives as one object.
   It used to stagger its columns 0/40/80/120/160/200ms on top of the panel's own
   220ms open, so the Remembers column landed roughly 0.4s after the pointer stopped
   and the menu was visibly still assembling when you were already reading it. The
   60ms stagger in DESIGN.md governs scroll entrances, where content is arriving as
   you travel to it; a menu you opened deliberately should simply be there. */
@media (min-width: 1024px) {
  .mega-cols > div {
    opacity: 0;
    transform: translateY(7px);
    transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
  }
  .nav-item.open .mega-cols > div,
  .nav-item:focus-within .mega-cols > div {
    opacity: 1;
    transform: none;
  }
}

/* mobile nav */
.nav-scrim {
  display: none;
  position: fixed;
  inset: var(--header-h) 0 0 0;
  padding: 0;
  border: none;
  background: rgb(var(--f4-ink-rgb) / 0.45);
  opacity: 0;
  visibility: hidden;
  transition: opacity 260ms var(--ease-out), visibility 0s 260ms var(--ease-out);
  z-index: var(--z-scrim);
  cursor: pointer;
}
.nav-toggle { display: none; width: 44px; height: 44px; position: relative; border-radius: var(--radius-sm); }
.nav-toggle span {
  position: absolute; left: 11px; right: 11px; height: 2px;
  background: currentColor; border-radius: var(--radius-pill);
  transition: transform 260ms var(--ease-out), opacity 180ms var(--ease-out);
}
.nav-toggle span:nth-child(1) { top: 15px; }
.nav-toggle span:nth-child(2) { top: 21px; }
.nav-toggle span:nth-child(3) { top: 27px; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

@media (max-width: 1023px) {
  /* backdrop-filter would make the header a containing block for the
     fixed sheet/scrim below · plain paper on mobile instead */
  .site-header.is-solid {
    background: rgb(var(--f4-paper-rgb) / 0.96);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .main-nav {
    display: none;
    position: fixed;
    inset: var(--header-h) 0 0 auto;
    width: min(440px, 100vw);
    background: var(--f4-paper);
    color: var(--f4-ink);
    overflow-y: auto;
    padding: var(--space-24) var(--gutter) var(--space-64);
    transform: translateX(100%);
    visibility: hidden;
    pointer-events: none;
    transition: transform 320ms var(--ease-out);
    z-index: var(--z-overlay);
    box-shadow: -24px 0 60px rgb(var(--f4-ink-rgb) / 0.25);
  }
  body.nav-open .main-nav {
    display: block;
    transform: translateX(0);
    visibility: visible;
    pointer-events: auto;
  }
  body.nav-open { overflow: hidden; }
  /* Load-bearing: at scroll 0 every route's header is .is-dark (transparent over the
     ink hero), so opening the sheet has to key the bar to paper itself. It now lands
     on the same cool paper as .is-solid, where it used to jump to a warm off-white. */
  body.nav-open .site-header { background: var(--f4-paper); color: var(--f4-ink); border-bottom-color: var(--f4-line); }
  .nav-scrim { display: block; }
  body.nav-open .nav-scrim { opacity: 1; visibility: visible; transition-delay: 0s; }

  .main-nav > ul { flex-direction: column; align-items: stretch; gap: 0; }
  .nav-item { border-bottom: 1px solid var(--f4-line); }
  .nav-link { width: 100%; justify-content: space-between; padding: var(--space-16) var(--space-4); font-size: var(--fs-xl); color: var(--f4-ink); }
  .site-header.is-dark .nav-link { color: var(--f4-ink); }

  /* items step in behind the sheet */
  .main-nav > ul > li {
    opacity: 0;
    transform: translateX(14px);
    transition: opacity 240ms var(--ease-out), transform 300ms var(--ease-out);
  }
  body.nav-open .main-nav > ul > li { opacity: 1; transform: none; }
  body.nav-open .main-nav > ul > li:nth-child(1) { transition-delay: 50ms; }
  body.nav-open .main-nav > ul > li:nth-child(2) { transition-delay: 88ms; }
  body.nav-open .main-nav > ul > li:nth-child(3) { transition-delay: 126ms; }
  body.nav-open .main-nav > ul > li:nth-child(4) { transition-delay: 164ms; }
  body.nav-open .main-nav > ul > li:nth-child(5) { transition-delay: 202ms; }
  body.nav-open .main-nav > ul > li:nth-child(6) { transition-delay: 240ms; }

  /* accordion · rows unfold instead of snapping */
  .drop-panel {
    position: static;
    transform: none;
    box-shadow: none;
    border: none;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    padding: 0;
    width: 100%;
    display: grid;
    grid-template-rows: 0fr;
    opacity: 1;
    visibility: hidden;
    transition: grid-template-rows 320ms var(--ease-out), visibility 0s 320ms var(--ease-out);
  }
  .nav-item.open > .drop-panel {
    grid-template-rows: 1fr;
    transform: none;
    visibility: visible;
    transition-delay: 0s;
  }
  .drop-panel > .mega-cols { overflow: hidden; min-height: 0; padding: 0 var(--space-4); }
  .nav-item.open > .drop-panel > .mega-cols { padding-bottom: var(--space-16); }
  .mega-cols { grid-template-columns: 1fr; grid-template-rows: none; gap: var(--space-16); }
  .nav-toggle { display: block; }

  /* The bar always fits its menu. Every part used to keep its full size, so at
     390px the actions ran 24px past the screen and at 360px the menu was off it
     entirely. A tighter row and a compact button; below 375px the menu alone. */
  .header-inner { gap: var(--space-12); }
  .header-actions { margin-left: auto; gap: var(--space-6); }
  .header-actions .btn-sm { padding: var(--space-8) var(--space-12); font-size: var(--fs-cap); }
  /* the target stays 44px; its lines sit flush with the gutter */
  .nav-toggle { margin-right: -10px; }
  /* while the hero's own primary is on screen, the logo and the menu only */
  .site-header.cta-quiet .header-actions .btn-primary { display: none; }
  /* once the page moves the bar takes ink, so nothing runs under the logo */
  body:not(.nav-open) .site-header.is-dark.is-scrolled {
    background: rgb(var(--ink-900-rgb) / 0.96);
    border-bottom-color: rgb(255 255 255 / 0.08);
  }
}
@media (max-width: 374px) {
  .site-header .header-actions .btn-primary { display: none; }
}

/* skip link */
.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--sig-green); color: var(--f4-ink);
  padding: var(--space-10) var(--space-16); font-weight: 600; z-index: var(--z-skip);
  border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }

/* ---------- 7 · Footer ---------- */
.site-footer {
  background-color: var(--f4-ink);
  background-image:
    var(--noise),
    radial-gradient(900px 420px at 90% 0%, rgb(var(--sig-green-rgb) / 0.07), transparent 60%),
    linear-gradient(180deg, #0D1A2D, #0B1626);
  color: var(--text-on-ink-dim);
  padding: var(--rhythm-md) 0 var(--space-40);
  font-size: var(--fs-md);
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr 1.3fr;
  gap: var(--space-40);
  padding-bottom: var(--space-48);
  border-bottom: 1px solid rgba(255, 255, 255, 0.09);
}
@media (max-width: 1023px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px)  { .footer-grid { grid-template-columns: 1fr; gap: var(--space-32); } }

.footer-brand p { margin-top: var(--space-14); max-width: 30ch; line-height: var(--lh-body-l); }

.footer-col h4 {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  margin-bottom: var(--space-16);
}
.footer-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-10); }
.footer-col a { text-decoration: none; color: var(--text-on-ink-dim); transition: color 150ms var(--ease-out); }
.footer-col a:hover { color: #fff; }

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-16) var(--space-32);
  justify-content: space-between;
  padding-top: var(--space-28);
  font-size: var(--fs-cap);
  color: var(--ink-text-3);
}
.footer-bottom a { color: inherit; text-decoration: none; }
.footer-bottom a:hover { color: #fff; }
.footer-legal-links { display: flex; flex-wrap: wrap; gap: var(--space-20); }

/* ---------- 8 · Cards & content components ---------- */
.card {
  position: relative;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.06);
  border-radius: var(--radius-card);
  /* one padding for the raised-light-panel role · the same .card class used to
     render at 30px here and 26px inside .next-rail */
  padding: var(--space-28);
  box-shadow: var(--shadow-sm);
  transition: transform 240ms var(--ease-out), box-shadow 260ms var(--ease-out), border-color 240ms var(--ease-out);
}
/* a green signal line draws across the top on hover */
.card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--sig-green);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 320ms var(--ease-out);
}
/* Hover is an affordance, not decoration. Roughly 63 of the 78 .card instances on
   the site are static <div>s: they were all lifting, drawing a green rule and
   scaling their icon on hover, offering a click that goes nowhere — and spending
   green on a state that is not a decision. Only cards that are links respond. */
a.card:hover::before, a.card:focus-visible::before { transform: scaleX(1); }
.bg-ink .card::before { background: var(--sig-green-lift); }
a.card:hover, a.card:focus-visible {
  transform: translateY(-3px);
  border-color: rgb(var(--sig-green-rgb) / 0.28);
  box-shadow: var(--shadow-md);
}
.card h3 { font-size: var(--fs-2xl); margin-bottom: var(--space-8); }
.card p { font-size: var(--fs-md); color: var(--f4-slate); }
.card .card-icon { margin-bottom: var(--space-20); color: var(--f4-slate); }
.card .card-icon svg, .card .icon-tile svg { transition: transform 220ms var(--ease-out); }
a.card:hover .card-icon svg, a.card:hover .icon-tile svg { transform: scale(1.1); }

.bg-ink .card, .card.on-ink {
  background: var(--ink-card-grad);
  border-color: var(--ink-card-line);
  box-shadow: var(--shadow-ink-lg);
}
.bg-ink a.card:hover, .bg-ink a.card:focus-visible {
  border-color: rgb(var(--sig-green-lift-rgb) / 0.35);
  box-shadow: var(--specular-ink),
              0 0 0 1px rgb(var(--sig-green-lift-rgb) / 0.12),
              0 24px 56px -28px rgb(var(--sig-green-rgb) / 0.28);
}
.bg-ink .card h3 { color: #fff; }
.bg-ink .card p { color: var(--text-on-ink-dim); }
.bg-mist .card { background: var(--surface); border-color: rgb(var(--f4-ink-rgb) / 0.05); }

a.card { display: block; text-decoration: none; color: inherit; }

/* module card */
.module-card { position: relative; }
.module-card .mod-verb {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--f4-slate);
}
.bg-ink .module-card .mod-verb { color: var(--ink-text-2); }
.module-card h3 { margin-top: var(--space-4); }
.module-card .link-quiet { margin-top: var(--space-16); font-size: var(--fs-base); }
.module-card.spotlight { border-color: rgb(var(--sig-green-rgb) / 0.45); }
.bg-ink .module-card.spotlight {
  border-color: rgb(var(--sig-green-lift-rgb) / 0.4);
  background:
    radial-gradient(420px 200px at 100% 0%, rgb(var(--sig-green-rgb) / 0.12), transparent 65%),
    var(--ink-card-grad);
  box-shadow: var(--specular-lit), var(--shadow-md);
}

/* stat block · the top rule draws itself in with the reveal */
.stat { padding-top: var(--space-18); position: relative; }
.stat::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: rgb(var(--f4-ink-rgb) / 0.1);
  transform-origin: left;
}
.bg-ink .stat::before { background: rgba(255, 255, 255, 0.14); }
.reveal-group .stat::before { transform: scaleX(0); transition: transform 700ms var(--ease-out); }
.reveal-group.in .stat::before { transform: scaleX(1); }
.reveal-group.in .stat:nth-child(2)::before { transition-delay: 90ms; }
.reveal-group.in .stat:nth-child(3)::before { transition-delay: 180ms; }
.reveal-group.in .stat:nth-child(4)::before { transition-delay: 270ms; }
/* KPIs are the brand's most important marks and read in flat signal
   green (client call, overriding the earlier cool-white pass). The
   discipline that stays: no glow at rest — the halo, not the hue, was
   what cheapened the four numbers. */
.stat .stat-num { display: block; color: var(--f4-ink); }
.bg-ink .stat .stat-num { color: var(--sig-green-lift); }
.stat .stat-cap {
  display: block;
  margin-top: var(--space-12);
  font-size: var(--fs-base);
  line-height: var(--lh-ui);
  color: var(--f4-slate);
  max-width: 26ch;
}
.bg-ink .stat .stat-cap { color: var(--text-on-ink-dim); }
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3rem var(--gutter); }
@media (max-width: 1023px) { .stat-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px)  { .stat-grid { grid-template-columns: 1fr; } }

/* stat hierarchy · shared starts and description heights keep every metric
   aligned even when the supporting copy wraps differently */
.stat-hero-grid { display: grid; grid-template-columns: 1.7fr 1fr 1fr 1fr; gap: 3rem var(--gutter); align-items: stretch; }
.stat-hero-grid .stat { display: grid; grid-template-rows: auto minmax(4.5em, auto); align-content: start; }
.stat-hero-grid .stat-num { line-height: 1; }
.stat-hero-grid .stat-cap { min-height: 4.5em; }
.stat.featured .stat-cap { font-size: var(--fs-base); max-width: 30ch; }
.stat-secondary {
  margin-top: var(--space-48);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-16) var(--space-48);
  padding-top: var(--space-24);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.stat-secondary .stat-sm { font-family: var(--font-mono); font-size: var(--fs-base); color: var(--text-on-ink-dim); }
.stat-secondary .stat-sm b { font-weight: 500; font-size: var(--fs-3xl); color: var(--f4-ink); margin-right:var(--space-8); }
.bg-ink .stat-secondary .stat-sm b { color: var(--sig-green-lift); }
@media (max-width: 1023px) { .stat-hero-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 480px)  {
  .stat-hero-grid { grid-template-columns: 1fr; }
  .stat-hero-grid .stat { grid-template-rows: auto auto; }
  .stat-hero-grid .stat-cap { min-height: 0; }
}

/* proof chip */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-6) var(--space-16);
  border-radius: var(--radius-pill);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.1);
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--f4-ink);
  white-space: nowrap;
  box-shadow: 0 1px 2px rgb(var(--f4-ink-rgb) / 0.05);
}
.bg-ink .chip { background: var(--ink-card-grad); border-color: var(--ink-card-line); color: var(--text-on-ink); box-shadow: none; }
.chip-row { display: flex; flex-wrap: wrap; gap: var(--space-10); }

/* selected-deployment tag */
.dep-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--f4-slate);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.12);
  border-radius: var(--radius-pill);
  padding: var(--space-4) var(--space-12);
  background: rgba(255, 255, 255, 0.6);
}
.bg-ink .dep-tag { color: var(--ink-text-2); border-color: var(--f4-line-dark); background: transparent; }

/* pull strip */
.pull-strip {
  background: linear-gradient(180deg, var(--surface-2) 0%, var(--surface-4) 100%);
  border-top: 1px solid var(--f4-line);
  border-bottom: 1px solid var(--f4-line);
  padding: var(--rhythm-md) 0;
  position: relative;
  overflow: hidden;
}
.pull-strip::after {
  content: "";
  position: absolute;
  right: -60px; top: 50%;
  width: 340px; height: 340px;
  transform: translateY(-50%);
  background-image: radial-gradient(circle 2px at 2px 2px, rgb(var(--f4-blue-rgb) / 0.10) 2px, transparent 0);
  background-size: 34px 34px;
  opacity: 0.1;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(closest-side, #000, transparent);
  mask-image: radial-gradient(closest-side, #000, transparent);
  animation: pullSpin 140s linear infinite;
}
@keyframes pullSpin { to { transform: translateY(-50%) rotate(360deg); } }
.pull-strip p {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.8vw, 2.25rem);
  font-weight: 480;
  line-height: 1.28;
  letter-spacing: -0.012em;
  max-width: 34ch;
}
/* CTA band · the surface breathes and a few signals drift */
.cta-band {
  position: relative;
  overflow: hidden;
  border-top: 1px solid rgba(255, 255, 255, 0.08); /* seam against stacked dark sections */
  background-color: var(--f4-ink);
  background-image:
    var(--noise),
    radial-gradient(600px 400px at 100% 120%, rgb(var(--f4-blue-rgb) / 0.1), transparent 60%),
    linear-gradient(180deg, #0C1828, var(--f4-ink));
  text-align: center;
}
.cta-band::before {
  content: "";
  position: absolute;
  left: 50%; top: -160px;
  width: 780px; height: 480px;
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgb(var(--f4-blue-rgb) / 0.12), transparent 72%);
  animation: ctaBreathe 9s ease-in-out infinite alternate;
  pointer-events: none;
}
@keyframes ctaBreathe {
  from { opacity: 0.5; transform: translateX(-50%) scale(0.92); }
  to   { opacity: 1;   transform: translateX(-50%) scale(1.06); }
}
.cta-band::after {
  content: "";
  position: absolute;
  inset: -60px;
  background-image:
    radial-gradient(circle 2px at 12% 30%, rgb(var(--sig-green-lift-rgb) / 0.5) 2px, transparent 0),
    radial-gradient(circle 1.5px at 28% 74%, rgb(var(--sig-green-lift-rgb) / 0.35) 1.5px, transparent 0),
    radial-gradient(circle 2px at 55% 16%, rgb(var(--f4-blue-rgb) / 0.4) 2px, transparent 0),
    radial-gradient(circle 1.5px at 76% 66%, rgb(var(--sig-green-lift-rgb) / 0.4) 1.5px, transparent 0),
    radial-gradient(circle 2px at 90% 32%, rgb(var(--sig-green-lift-rgb) / 0.3) 2px, transparent 0);
  background-repeat: no-repeat;
  animation: ntDrift 46s ease-in-out infinite alternate;
  pointer-events: none;
}
.cta-band .inner { max-width: 46rem; margin-inline: auto; position: relative; z-index: 1; }
.cta-band h2 { color: #fff; }
.cta-band p { margin-top: var(--space-18); color: var(--text-on-ink-dim); font-size: var(--fs-xl); }
.cta-band .cta-actions { margin-top: var(--space-36); display: flex; gap: var(--space-18); justify-content: center; flex-wrap: wrap; align-items: center; }
.cta-band .alt-mail { font-size: var(--fs-md); color: var(--text-on-ink-dim); }
.cta-band .alt-mail a { color: var(--f4-blue-lift); }
.cta-band .triad {
  margin-top: var(--space-40);
  font-family: var(--font-mono);
  font-size: var(--fs-cap-s);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sig-green-lift);
}

/* trust strip · thin credibility band directly under the hero
   (the logo carousel itself lives in section 14) */
.logo-strip { padding: var(--space-36) 0; border-bottom: 1px solid var(--f4-line); }

/* story card */
.story-card { display: flex; flex-direction: column; gap: var(--space-16); }
.story-card .story-logo {
  font-family: var(--font-display);
  font-weight: 540;
  font-size: var(--fs-3xl);
  color: var(--f4-ink);
}
.story-card dl { margin: 0; display: grid; gap: var(--space-16); }
.story-card dt {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sig-green-text);
  margin-bottom: var(--space-4);
}
.story-card dd { margin: 0; font-size: var(--fs-md); color: var(--f4-slate); }
.story-card .story-quote {
  margin: 0;
  border-top: 1px solid var(--f4-line);
  padding-top: var(--space-18);
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 460;
  font-style: italic;
  line-height: var(--lh-body-l);
  color: #23334A;
}
.story-card .story-attrib {
  font-family: var(--font-body);
  font-style: normal;
  font-size: var(--fs-cap);
  color: var(--f4-slate);
  margin-top: var(--space-8);
  display: block;
}
.story-card .story-foot { display: flex; gap: var(--space-10); align-items: center; flex-wrap: wrap; margin-top: auto; }
/* Home · Advises (24 Oct review) · Saga gets an instrument, a dark slab to
   the Control Tower's finish on the light section: reads, structures,
   reports. The story engine plays it while in view (the step on the beat
   carries the green rim); reduced motion shows it complete. */
.sgx { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: clamp(2rem, 4vw, 4rem); align-items: center; }
.sgx .section-head { margin-bottom: 0; }
.sgx-facts { display: grid; gap: var(--space-18); margin-top: var(--space-32); }
.sgx-facts strong { font-size: var(--fs-md); }
.sgx-slab {
  margin: 0; padding: var(--space-20) var(--space-20) var(--space-24);
  border-radius: 18px;
  background: linear-gradient(180deg, var(--ink-700), var(--ink-800));
  box-shadow: 0 24px 60px rgb(var(--f4-ink-rgb) / 0.28), inset 0 1px 0 rgb(255 255 255 / 0.06);
  color: var(--ink-text-1);
}
.sgx-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-16); font-family: var(--font-mono); font-size: var(--fs-4xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-text-3); }
.sgx-live { color: var(--sig-green-lift); }
.sgx-live::before { content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 7px; border-radius: 50%; background: var(--sig-green); vertical-align: 1px; }
.sgx-step { position: relative; padding: var(--space-16) var(--space-14) var(--space-14) var(--space-16); border: 1px solid rgb(255 255 255 / 0.09); border-radius: 12px; background: rgb(255 255 255 / 0.03); transition: border-color 400ms var(--ease-out); }
.sgx-step.is-lit { border-color: rgb(var(--sig-green-lift-rgb) / 0.5); }
.sgx-step + .sgx-step { margin-top: var(--space-24); }
.sgx-step + .sgx-step::before { content: ""; position: absolute; left: 50%; top: calc(-1 * var(--space-24)); width: 1px; height: var(--space-24); background: rgb(var(--sig-green-lift-rgb) / 0.5); }
.sgx-k { position: absolute; top: -9px; left: 14px; padding: 2px 8px; border-radius: var(--radius-pill); border: 1px solid rgb(var(--sig-green-lift-rgb) / 0.35); background: var(--ink-800); font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--sig-green-lift); }
.sgx-mail { display: grid; grid-template-columns: 32px minmax(0, 1fr) auto; gap: var(--space-10); align-items: center; margin-top: var(--space-6); font-size: var(--fs-sm); color: var(--ink-text-1); }
.sgx-av { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%; background: rgb(var(--f4-blue-lift-rgb) / 0.2); color: var(--f4-blue-pale); font-family: var(--font-mono); font-size: 11px; font-weight: 600; font-style: normal; }
.sgx-dim { color: var(--ink-text-3); font-family: var(--font-mono); font-size: 11px; }
.sgx-att { display: flex; align-items: center; gap: var(--space-8); margin-top: var(--space-10); padding: 7px 10px; border-radius: 8px; background: rgb(255 255 255 / 0.05); font-family: var(--font-mono); font-size: 12px; color: var(--ink-text-2); }
.sgx-xls { padding: 2px 5px; border-radius: 4px; background: var(--sig-green-text); color: rgb(255 255 255); font-size: 9.5px; font-weight: 600; }
.sgx-ok { margin-left: auto; white-space: nowrap; color: var(--sig-green-lift); }
.sgx-tab { width: 100%; margin-top: var(--space-6); border-collapse: collapse; font-family: var(--font-mono); font-size: 12px; color: var(--ink-text-1); }
.sgx-tab th { padding: 4px 6px; border-bottom: 1px solid rgb(255 255 255 / 0.12); text-align: left; font-weight: 500; color: var(--ink-text-3); }
.sgx-tab th.is-hit { color: var(--f4-blue-pale); }
.sgx-tab td { padding: 5px 6px; border-bottom: 1px solid rgb(255 255 255 / 0.05); }
.sgx-tab td.is-hit { box-shadow: inset 0 0 0 1px rgb(var(--f4-blue-lift-rgb) / 0.35); background: rgb(var(--f4-blue-lift-rgb) / 0.06); }
.sgx-note { margin: var(--space-8) 0 0; font-family: var(--font-mono); font-size: 11px; color: var(--sig-green-lift); }
.sgx-rep { display: grid; grid-template-columns: minmax(0, 1fr) 150px; gap: var(--space-14); align-items: center; margin-top: var(--space-6); }
.sgx-rep b { font-size: var(--fs-md); color: var(--ink-text-1); }
.sgx-rep p { margin: var(--space-4) 0 var(--space-8); font-size: var(--fs-sm); color: var(--ink-text-2); }
.sgx-langs { font-family: var(--font-mono); font-size: 11px; color: var(--ink-text-3); }
.sgx-langs i { display: inline-block; margin-right: 4px; padding: 1px 6px; border-radius: var(--radius-pill); border: 1px solid rgb(var(--f4-blue-lift-rgb) / 0.45); font-style: normal; color: var(--f4-blue-pale); }
.sgx-rep svg { display: block; width: 150px; height: auto; }
.sgx-bar { fill: rgb(var(--f4-blue-lift-rgb) / 0.55); }
.sgx-bar.is-short { fill: var(--f4-warn); }
.sgx-line { stroke: rgb(255 255 255 / 0.45); stroke-dasharray: 3 3; }
@media (max-width: 899px) { .sgx { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 520px) {
  .sgx-mail { grid-template-columns: 32px minmax(0, 1fr); }
  .sgx-mail > .sgx-dim { display: none; }
  .sgx-att { flex-wrap: wrap; }
  .sgx-att > .sgx-dim { display: none; }
  .sgx-rep { grid-template-columns: minmax(0, 1fr); }
  .sgx-tab { font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) { .sgx-step { transition: none; } }
/* Home · Remembers (24 Oct review, the simple cut) · one question answered
   from Memory as a line: decided, planned, what happened. On reveal the
   line runs from the decision to the outcome and the outcome node fills;
   under reduced motion it rests complete. */
.mm2 { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(2rem, 4vw, 4rem); align-items: center; }
.mm2 .section-head { margin-bottom: 0; }
.mm2-card { margin: 0; padding: var(--space-28) var(--space-28) var(--space-24); background: var(--surface); border: 1px solid rgb(var(--f4-ink-rgb) / 0.08); border-radius: var(--radius-card); box-shadow: var(--shadow-md); }
.mm2-q { display: flex; align-items: center; gap: var(--space-12); margin: 0; padding-bottom: var(--space-18); border-bottom: 1px solid var(--f4-line); font-family: var(--font-display); font-size: var(--fs-xl); line-height: 1.3; color: var(--f4-ink); }
.mm2-q svg { width: 20px; height: 20px; flex: none; fill: none; stroke: var(--f4-slate); stroke-width: 2; stroke-linecap: round; }
.mm2-line { list-style: none; margin: var(--space-28) 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-18); position: relative; }
/* the rail runs node to node and stops at the outcome */
.mm2-line::before { content: ""; position: absolute; top: 6px; left: 7px; width: calc((100% - 2 * var(--space-18)) * 2 / 3 + 2 * var(--space-18)); height: 2px; background: rgb(var(--f4-ink-rgb) / 0.14); }
.mm2-line::after { content: ""; position: absolute; top: 6px; left: 7px; width: calc((100% - 2 * var(--space-18)) * 2 / 3 + 2 * var(--space-18)); height: 2px; background: var(--f4-ink); transform-origin: 0 50%; }
.mm2-line li { position: relative; padding-top: var(--space-28); }
.mm2-line li::before { content: ""; position: absolute; top: 0; left: 0; z-index: 1; width: 14px; height: 14px; border-radius: 50%; background: var(--surface); border: 2px solid var(--f4-ink); }
.mm2-line li.is-out::before { background: var(--sig-green); border-color: var(--sig-green); }
.mm2-when { display: block; font-family: var(--font-mono); font-size: var(--fs-4xs); letter-spacing: 0.06em; color: var(--f4-slate); }
.mm2-line b { display: block; margin-top: var(--space-6); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--f4-slate); }
.mm2-line p { margin: var(--space-4) 0 0; font-size: var(--fs-md); line-height: var(--lh-ui); color: var(--f4-ink); }
.mm2-line li.is-out p { color: var(--sig-green-text); font-weight: 600; }
.mm2-foot { margin: var(--space-24) 0 0; font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--f4-slate); }
.reveal.in .mm2-line::after { animation: mm2Run 1.4s var(--ease-out) 0.4s backwards; }
.reveal.in .mm2-line li.is-out::before { animation: mm2Fill 0.5s var(--ease-out) 1.6s backwards; }
@keyframes mm2Run { from { transform: scaleX(0); } }
@keyframes mm2Fill { from { background: var(--surface); border-color: var(--f4-ink); } }
@media (max-width: 899px) { .mm2 { grid-template-columns: minmax(0, 1fr); } }
/* stacked, each step draws its own link down to the next node, so the
   rail stops at the outcome whatever the rows' heights */
@media (max-width: 599px) {
  .mm2-line { grid-template-columns: minmax(0, 1fr); gap: var(--space-20); }
  .mm2-line::before, .mm2-line::after { display: none; }
  .mm2-line li { padding: 0 0 0 var(--space-28); }
  .mm2-line li:not(:last-child)::after { content: ""; position: absolute; left: 6px; top: 14px; bottom: calc(-1 * var(--space-20)); width: 2px; background: var(--f4-ink); }
}
@media (prefers-reduced-motion: reduce) { .reveal.in .mm2-line::after, .reveal.in .mm2-line li.is-out::before { animation: none; } }
/* Results · customer stories (24 Oct review) · who and the one fact that
   matters first, the problem, change and impact on a connected run of
   labelled rows, the customer's words in full as a pull quote. Logos sit
   on a paper plate because BerryWorld's knockout is baked to --f4-paper.
   The run is the site's registration-node idiom: hollow nodes on a
   hairline that stops dead at the last one, the impact node filled. */
.rs { display: grid; gap: var(--gutter); margin-top: var(--space-32); }
.rs-feat {
  display: grid;
  grid-template-columns: 200px minmax(0, 1.2fr) minmax(0, 1fr);
  gap: var(--space-28) clamp(1.5rem, 3vw, 2.75rem);
  align-items: start;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  background: var(--surface);
  border: 1px solid rgb(var(--sig-green-rgb) / 0.45);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-md);
}
.rs-who { display: grid; gap: var(--space-14); justify-items: start; }
.rs-logo {
  --rs-h: 2.4rem;
  display: inline-flex; align-items: center; justify-content: center;
  height: 4.5rem; padding: 0 var(--space-18);
  border-radius: var(--radius-btn);
  background: var(--f4-paper);
}
.rs-logo img { display: block; width: auto; height: var(--rs-h); }
.rs-logo.is-llv { height: 6.25rem; --rs-h: 4.6rem; }
.rs-logo.is-angus { --rs-h: 3.05rem; }
.rs-logo.is-bw { --rs-h: 3.25rem; }
.rs-logo.is-driscolls { --rs-h: 2.1rem; }
.rs-logo.is-spreafico { --rs-h: 1.65rem; }
.rs-logo.is-jingold { --rs-h: 2.3rem; }
.rs-logo.is-tangmere { --rs-h: 1.9rem; }
.rs-flow { margin: 0; display: grid; gap: var(--space-14); }
.rs-flow > div { position: relative; display: grid; grid-template-columns: 5.25rem minmax(0, 1fr); gap: var(--space-10); align-items: baseline; padding-left: 20px; }
.rs-flow > div::before {
  content: ""; position: absolute; left: 0; top: 0.4em;
  width: 9px; height: 9px; border-radius: 50%;
  border: 1.5px solid var(--sig-green-deep); background: var(--surface);
}
.rs-flow > div:not(:last-child)::after {
  content: ""; position: absolute; left: 4px; width: 1px;
  top: calc(0.4em + 9px); bottom: calc(-1 * (var(--space-14) + 0.4em));
  background: rgb(var(--sig-green-rgb) / 0.45);
}
.rs-card .rs-flow > div:last-child::before { background: var(--sig-green-deep); }
.rs-flow dt { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.14em; text-transform: uppercase; color: var(--sig-green-text); }
.rs-flow dd { margin: 0; font-size: var(--fs-md); line-height: var(--lh-body-l); color: var(--f4-slate); }
.rs-impact { display: grid; justify-items: start; padding-left: clamp(1rem, 2vw, 1.75rem); border-left: 1px solid var(--f4-line); }
.rs-k { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.14em; text-transform: uppercase; color: var(--sig-green-text); }
.rs-big { margin-top: var(--space-8); font-family: var(--font-display); font-weight: 500; font-size: clamp(3.25rem, 5vw, 4.5rem); line-height: 1; letter-spacing: -0.02em; color: var(--sig-green-text); }
.rs-big-cap { margin-top: var(--space-8); font-size: var(--fs-md); color: var(--f4-ink); }
.rs-more { list-style: none; margin: var(--space-16) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-6) var(--space-18); font-size: var(--fs-sm); color: var(--f4-slate); }
.rs-more b { font-family: var(--font-mono); font-weight: 500; color: var(--f4-ink); }
.rs-quote {
  position: relative; margin: 0;
  padding: var(--space-18) 0 0 2.5rem;
  border-top: 1px solid var(--f4-line);
  font-family: var(--font-display); font-style: italic; font-weight: 460;
  font-size: var(--fs-lg); line-height: var(--lh-body-l); color: var(--f4-ink);
}
.rs-quote::before {
  content: "\201C"; position: absolute; left: 0; top: var(--space-10);
  font-size: 3.4rem; line-height: 1; font-style: normal; color: var(--sig-green-deep);
}
.rs-quote cite { display: block; margin-top: var(--space-10); font-family: var(--font-body); font-style: normal; font-size: var(--fs-cap); color: var(--f4-slate); }
.rs-feat .rs-quote { grid-column: 1 / -1; font-size: var(--fs-xl); }
.rs-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gutter); }
.rs-card {
  display: flex; flex-direction: column; gap: var(--space-18);
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.07);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
}
.rs-card .rs-logo { align-self: flex-start; }
.rs-head { margin: 0; font-family: var(--font-display); font-weight: 500; font-size: var(--fs-2xl); line-height: 1.2; color: var(--f4-ink); }
@media (max-width: 999px) {
  .rs-feat { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .rs-who { grid-column: 1 / -1; }
}
@media (max-width: 699px) {
  .rs-feat, .rs-grid { grid-template-columns: minmax(0, 1fr); }
  .rs-impact { padding-left: 0; padding-top: var(--space-16); border-left: 0; border-top: 1px solid var(--f4-line); }
  .rs-flow > div { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
}

/* layer band (platform page + S2 row) */
.layer-band {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: var(--space-32);
  padding: var(--space-40) 0;
  border-top: 1px solid rgb(var(--sig-green-rgb) / 0.22);
  align-items: start;
}
.bg-ink .layer-band { border-top-color: var(--f4-line-dark); }
.layer-band:last-child { border-bottom: 1px solid rgb(var(--sig-green-rgb) / 0.22); }
.layer-band .lb-verb {
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sig-green-text);
  display: flex; align-items: center; gap: var(--space-10);
}
.layer-band .lb-verb svg { color: var(--sig-green-deep); }
.layer-band .lb-name { font-family: var(--font-display); font-size: var(--fs-display-s); font-weight: 500; margin-top: var(--space-8); letter-spacing: -0.01em; }
.layer-band .lb-body p { color: var(--f4-slate); max-width: 62ch; }
.layer-band ul { margin: var(--space-14) 0 0; padding-left: var(--space-18); color: var(--f4-slate); font-size: var(--fs-md); display: grid; gap: var(--space-8); }
@media (max-width: 767px) { .layer-band { grid-template-columns: 1fr; gap: var(--space-14); } }

/* the signal lights each layer as you scroll past (site.js adds .lit) */
.layer-band { position: relative; }
.layer-band::before {
  content: "";
  position: absolute;
  top: -1px; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--sig-green-deep), rgb(var(--sig-green-rgb) / 0.35) 52%, rgb(var(--sig-green-rgb) / 0.08));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 900ms var(--ease-out);
}
.layer-band.lit::before { transform: scaleX(1); }
.layer-band::after {
  content: "";
  position: absolute;
  top: -1px; left: 0; right: 0;
  height: 1px;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(90deg, transparent, var(--sig-green-pulse), transparent);
  background-size: clamp(72px, 10vw, 132px) 1px;
  background-repeat: no-repeat;
  background-position: -132px 0;
  filter: drop-shadow(0 0 3px rgb(var(--sig-green-rgb) / 0.38));
}
.layer-band.lit::after { animation: layerBandFlow 1600ms var(--ease-out) 260ms both; }
@keyframes layerBandFlow {
  0% { opacity: 0; background-position: -132px 0; }
  18% { opacity: 0.72; }
  82% { opacity: 0.55; }
  100% { opacity: 0; background-position: calc(100% + 132px) 0; }
}
.layer-band .lb-verb { transition: color 400ms var(--ease-out); }
.layer-band .lb-verb svg { transition: filter 400ms var(--ease-out); }
.layer-band.lit .lb-verb { color: var(--sig-green-text); }
.layer-band.lit .lb-verb svg { filter: drop-shadow(0 0 6px rgb(var(--sig-green-rgb) / 0.55)); }
.bg-ink .layer-band.lit .lb-verb { color: var(--sig-green-lift); }

/* ============================================================
   Operating-model span map (who it's for)
   The four models are not four stacked bands: they are four
   spans over one shared chain axis, so "where do I sit?" is
   answered by geometry instead of by four paragraphs. Filled =
   the stage you run (supply reads as ink fill, per the
   node-graph colours) · hollow = the stage you coordinate but
   do not own. Green is spent twice only: the model verb (a
   layer verb, allowlisted) and the touch state, where lighting
   your own span is the whole point of the graphic.
   ============================================================ */
.opmap {
  --om-c1: 292px;
  --om-c3: 168px;
  --om-gap: 28px;
  --om-pad: 1.125rem;
  margin-top: var(--space-36);
}
.om-axis,
.om-row {
  display: grid;
  grid-template-columns: var(--om-c1) minmax(0, 1fr) var(--om-c3);
  gap: var(--om-gap);
  align-items: center;
}
.om-axis { align-items: end; padding-bottom: var(--space-8); }
.om-axis-title,
.om-axis-end,
.om-stages span {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--f4-slate);
}
/* the chain does not stop at "sell" · the terminal marker hangs off the
   track's own right rule rather than heading the links column */
.om-axis-end {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  margin-left: calc(var(--om-gap) * -1 + 10px);
}
/* the header is the chain itself: five gates on one hairline, the stage
   names sitting in the spans between them, and every gate dropping a rule
   through the four models below */
.om-scale { display: grid; gap: var(--space-6); }
.om-gates { position: relative; height: 9px; }
.om-gates::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 1px;
  background: var(--f4-line);
}
.om-gates i {
  position: absolute;
  top: 50%; left: var(--x);
  width: 9px; height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  border: 1.5px solid rgb(var(--f4-slate-rgb) / 0.5);
  background: var(--f4-paper);
}
.om-gates i:nth-child(1) { --x: 0%; }
.om-gates i:nth-child(2) { --x: 33.3333%; }
.om-gates i:nth-child(3) { --x: 66.6667%; }
.om-gates i:nth-child(4) { --x: 100%; }
.om-stages { display: grid; grid-template-columns: repeat(3, 1fr); }
.om-stages span { text-align: center; }

.om-rows { list-style: none; margin: 0; padding: 0; }
.om-row {
  position: relative;
  padding-block: var(--om-pad);
  border-top: 1px solid var(--f4-line);
}
.om-rows > .om-row:last-child { border-bottom: 1px solid var(--f4-line); }
/* the reading highlight sits on a bleed layer so the hairlines stay
   registered to the container while the tint breathes past them */
.om-row::before {
  content: "";
  position: absolute;
  inset: 1px -1rem;
  border-radius: var(--radius-sm);
  background: var(--surface);
  opacity: 0;
  transition: opacity 300ms var(--ease-out);
  pointer-events: none;
}
.om-row:hover::before,
.om-row:focus-within::before { opacity: 1; }
.om-row > * { position: relative; }

.om-id { min-width: 0; }
.om-verb {
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sig-green-text);
}
.om-name {
  font-family: var(--font-display);
  font-size: var(--fs-display-xs);
  font-weight: 500;
  line-height: 1.16;
  letter-spacing: -0.012em;
  margin-top: var(--space-6);
}
.om-line {
  margin-top: var(--space-8);
  max-width: 44ch;
  font-size: var(--fs-cap);
  line-height: var(--lh-tight);
  color: var(--f4-slate);
}

.om-track {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: center;
  height: 38px;
}
/* stage rules · bridged across the row padding so the four rows read as
   one ruled field rather than four unrelated bars */
.om-track::before {
  content: "";
  position: absolute;
  inset: calc(var(--om-pad) * -1) 0;
  background-image: linear-gradient(90deg, var(--f4-line) 1px, transparent 1px);
  background-size: 33.3333% 100%;
  border-right: 1px solid var(--f4-line);
  pointer-events: none;
}
/* the top row's rules climb back to the gates, fading in, so the scale and
   the spans read as one drawing rather than a header above a table */
.om-rows > li:first-child .om-track::before {
  top: calc((var(--om-pad) + 1.375rem) * -1);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 42%);
          mask-image: linear-gradient(180deg, transparent, #000 42%);
}
.om-seg {
  position: relative;
  height: 12px;
  margin-inline: var(--space-4);
  border-radius: var(--radius-xs);
  border: 1px solid rgb(var(--f4-slate-rgb) / 0.42);
  background: rgb(var(--f4-slate-rgb) / 0.05);
  transition: background-color 320ms var(--ease-out), border-color 320ms var(--ease-out);
}
.om-seg.is-own {
  border-color: transparent;
  background: var(--f4-ink);
  box-shadow: var(--specular-ink-2);
}
.om-row:hover .om-seg,
.om-row:focus-within .om-seg { border-color: rgb(var(--sig-green-rgb) / 0.5); }
.om-row:hover .om-seg.is-own,
.om-row:focus-within .om-seg.is-own {
  border-color: transparent;
  background: var(--sig-green-deep);
}

.om-go { display: grid; gap: var(--space-6); justify-items: start; }
.om-go .link-quiet { font-size: var(--fs-cap); }

.om-key {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8) var(--space-24);
  margin-top: var(--space-18);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--f4-slate);
}
.om-key > span { display: inline-flex; align-items: center; gap: var(--space-8); }
.om-swatch {
  width: 22px; height: 10px; flex: none;
  border-radius: var(--radius-xs);
  border: 1px solid rgb(var(--f4-slate-rgb) / 0.42);
  background: rgb(var(--f4-slate-rgb) / 0.05);
}
.om-swatch.is-own { border-color: transparent; background: var(--f4-ink); }
.om-key .om-key-note {
  margin-left: auto;
  font-family: var(--font-body);
  font-size: var(--fs-cap);
  letter-spacing: 0;
  text-transform: none;
}

/* each span draws out along the chain · row stagger, then stage stagger */
.opmap.in .om-seg {
  animation: omSpan 620ms var(--ease-out) backwards;
  animation-delay: calc(var(--om-rd, 0ms) + var(--om-sd, 0ms));
}
@keyframes omSpan { from { transform: scaleX(0); } }
.om-seg { transform-origin: left center; }
.om-rows > li:nth-child(1) { --om-rd: 60ms; }
.om-rows > li:nth-child(2) { --om-rd: 150ms; }
.om-rows > li:nth-child(3) { --om-rd: 240ms; }
.om-rows > li:nth-child(4) { --om-rd: 330ms; }
.om-track > .om-seg:nth-child(2) { --om-sd: 80ms; }
.om-track > .om-seg:nth-child(3) { --om-sd: 160ms; }

@media (max-width: 1023px) {
  /* stacked, the four tracks sit hundreds of pixels below the axis, so the
     key travels with them: the chain header pins under the fixed nav and
     bleeds to the viewport edges so rows pass cleanly underneath */
  .om-axis {
    position: sticky;
    top: var(--header-h);
    z-index: 2;
    grid-template-columns: 1fr auto;
    gap: var(--space-8);
    padding-block: var(--space-10) var(--space-8);
    margin-bottom: var(--space-4);
  }
  .om-axis::before {
    content: "";
    position: absolute;
    inset: 0 calc(var(--gutter) * -1);
    background: var(--f4-paper);
    border-bottom: 1px solid var(--f4-line);
    z-index: -1;
  }
  .om-axis-title { grid-row: 1; grid-column: 1; }
  .om-axis-end { grid-row: 1; grid-column: 2; margin-left: 0; }
  .om-scale { grid-row: 2; grid-column: 1 / -1; }
  .om-row { grid-template-columns: 1fr; gap: var(--space-14); align-items: start; }
  .om-line { max-width: 62ch; }
  .om-track { height: 30px; }
  .om-track::before,
  .om-rows > li:first-child .om-track::before {
    inset: -0.375rem 0;
    -webkit-mask-image: none;
            mask-image: none;
  }
  .om-go { display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-24); }
  .om-key .om-key-note { margin-left: 0; }
}
@media (max-width: 480px) {
  .om-stages span { font-size: var(--fs-4xs); letter-spacing: 0.1em; }
  .om-seg { margin-inline: var(--space-4); }
}

@media (prefers-reduced-motion: reduce) {
  .opmap.in .om-seg { animation: none; }
  .om-row::before, .om-seg { transition: none; }
}

/* icon chip */
/* No tile. The pastel rounded square around every heading glyph was the
   "large rounded-corner icons above every heading" tell, and it spent
   green on 66 static marks. The glyph now sits in the flow as a precise
   cool line-mark: the heading carries the hierarchy, the icon supports it.
   The box footprint is kept only so flex rows stay aligned. */
.icon-tile {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  background: none;
  border: none;
  box-shadow: none;
  color: var(--f4-slate);
  flex: none;
}
.icon-tile svg { width: 22px; height: 22px; }
.bg-ink .icon-tile { color: var(--ink-text-2); }

/* signal chips (S3) */
.signal-list { display: grid; gap: var(--space-18); margin-top: var(--space-28); }
.signal-item { display: flex; gap: var(--space-16); align-items: flex-start; }
.signal-item strong { display: block; font-size: var(--fs-lg); }
.signal-item span { font-size: var(--fs-md); color: var(--f4-slate); }

/* callout */
.callout {
  margin-top: var(--space-32);
  padding: var(--space-24) var(--space-28);
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.06);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-display);
  font-size: var(--fs-2xl);
  font-weight: 480;
  line-height: var(--lh-tight);
  position: relative;
  overflow: hidden;
}
.callout::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--f4-blue-deep), rgb(var(--f4-blue-rgb) / 0.2));
}
.bg-mist .callout { background: var(--surface); }
.bg-ink .callout { background: var(--ink-card-grad); border-color: var(--ink-card-line); color: #fff; box-shadow: var(--specular-ink); }

/* ============================================================
   Control Tower · dark instrument dashboard (home · Sees layer)
   A live product screen embedded on the light Sees section: the
   instrument world rendered as a real device on the printed page.
   Self-contained dark styling — it never relies on a .bg-ink ancestor.
   ============================================================ */
.ctower {
  --ct-line:      rgba(255, 255, 255, 0.09);
  --ct-line-soft: rgba(255, 255, 255, 0.055);
  --ct-cell:      linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.012));
  position: relative;
  border-radius: var(--radius-card);
  border: 1px solid var(--ct-line);
  color: var(--ink-text-1);
  overflow: hidden;
  background:
    radial-gradient(130% 92% at 84% -12%, rgba(31, 46, 73, 0.7), transparent 58%),
    linear-gradient(180deg, #15263F 0%, var(--f4-ink) 50%, #0B1626 100%);
  box-shadow:
    var(--specular-ink),
    0 42px 84px -38px rgba(5, 11, 21, 0.74),
    0 10px 26px -18px rgba(5, 11, 21, 0.6);
}
/* faint instrument graticule behind the readouts */
.ctower::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(127, 184, 242, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(127, 184, 242, 0.05) 1px, transparent 1px);
  background-size: 34px 34px;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 20%, #000 90%, transparent);
          mask-image: linear-gradient(180deg, transparent, #000 20%, #000 90%, transparent);
  pointer-events: none;
}

/* top bar */
.ct-bar {
  position: relative;
  display: flex; align-items: center; gap: var(--space-12);
  padding: var(--space-12) var(--space-18);
  border-bottom: 1px solid var(--ct-line);
  background: rgba(9, 17, 30, 0.55);
  font-family: var(--font-mono);
}
.ct-mark {
  display: inline-flex; align-items: center; gap: var(--space-8);
  font-size: var(--fs-cap); font-weight: 500; color: #fff; letter-spacing: 0.005em;
}
.ct-mark::before {   /* hollow registration mark · the kicker's dot language */
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  border: 1.5px solid var(--sig-green-lift);
}
.ct-live {
  display: inline-flex; align-items: center; gap: var(--space-8);
  font-size: var(--fs-2xs); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--sig-green-lift);
}
.ct-live i {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--sig-green-lift); box-shadow: var(--glow-live-ink);
  animation: ctPulse 2.4s ease-in-out infinite;
}
.ct-clock { margin-left: auto; font-size: var(--fs-xs); letter-spacing: 0.06em; color: var(--ink-text-3); }
@keyframes ctPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.32; } }

.ct-body { position: relative; padding: var(--space-16); display: grid; gap: var(--space-12); }
/* the instrument lays itself out by its own width, not the page's: it sits
   in a 7/12 column on desktop, alone on a phone, and in between on tablets */
.ctower { container-type: inline-size; }

/* KPI row · each readout carries its own mark: a ring for accuracy against
   its target, growth bars for demand against last year, a gauge for cover
   against its floor */
.ct-kpis { display: grid; grid-template-columns: 1fr; gap: var(--space-10); }
@container (min-width: 470px) { .ct-kpis { grid-template-columns: repeat(3, 1fr); } }
.ct-kpi {
  border: 1px solid var(--ct-line-soft); border-radius: var(--radius-sm);
  padding: var(--space-12) var(--space-14); background: var(--ct-cell); min-width: 0;
}
.ct-kpi .k-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-8); }
.ct-kpi .k-label {
  font-family: var(--font-mono); font-size: var(--fs-3xs); letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--ink-text-3); line-height: 1.25;
}
.ct-kpi .k-val {
  font-family: var(--font-mono); font-size: var(--fs-h3); font-weight: 500; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: var(--ink-text-1); margin-top: var(--space-6);
}
.ct-kpi .k-val small { font-size: 0.5em; letter-spacing: 0; color: var(--ink-text-2); margin-left: 2px; }
.ct-kpi .k-delta {
  display: inline-flex; align-items: center; gap: var(--space-6);
  font-family: var(--font-mono); font-size: var(--fs-3xs); margin-top: var(--space-6); line-height: 1.3;
}
.ct-kpi .k-delta::before { font-size: var(--fs-xs); line-height: 1; }
.k-up   { color: var(--sig-green-lift); }
.k-up::before   { content: "\25B2"; }   /* ▲ */
.k-risk { color: var(--f4-warn); }
.k-risk::before { content: "\25B3"; }    /* △ — risk uses hollow + label, never colour alone */
.ct-kmark { flex: none; overflow: visible; }
.ct-kmark .km-track { fill: none; stroke: rgb(var(--ink-text-3-rgb) / 0.2); }
.ct-kmark .km-ring { fill: none; stroke: var(--sig-green-lift); stroke-linecap: round; }
.ct-kmark .km-target { stroke: var(--ink-text-1); stroke-width: 1.5; stroke-linecap: round; }
.ct-kmark .km-bar { fill: var(--sig-green-lift); }
.ct-kmark .km-gtrack { fill: rgb(var(--ink-text-3-rgb) / 0.22); }
.ct-kmark .km-gfill { fill: var(--f4-warn); }
.ct-kmark .km-gfill.is-ok { fill: var(--sig-green-lift); }
.ct-kmark .km-floor { stroke: var(--ink-text-1); stroke-width: 1.5; stroke-linecap: round; }

/* the four signals · sales wide, the three that explain it underneath */
.ct-sig {
  min-width: 0;
  padding: var(--space-12) var(--space-14) var(--space-10);
  border: 1px solid var(--ct-line-soft); border-radius: var(--radius-sm);
  background: rgba(9, 17, 30, 0.28);
}
/* tag and value share the first row, the title runs under them, so the
   three small panels line up head for head at any width */
.ct-ph { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--space-6) var(--space-8); margin-bottom: var(--space-8); }
.ct-ph .ct-title { grid-column: 1 / -1; }
.ct-sigtag {
  padding: 1px var(--space-6);
  border: 1px solid var(--ct-line); border-radius: var(--radius-pill);
  font-family: var(--font-mono); font-size: var(--fs-4xs); letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-text-3);
}
.ct-title { font-size: var(--fs-cap); font-weight: 600; color: var(--ink-text-1); letter-spacing: -0.005em; }
.ct-unit, .ct-val { justify-self: end; font-family: var(--font-mono); font-size: var(--fs-3xs); color: var(--ink-text-3); white-space: nowrap; }
.ct-val b { font-weight: 500; color: var(--ink-text-1); }
.ct-val b.is-risk { color: var(--f4-warn); }
.ct-val b.k-up::before, .ct-val b.k-risk::before { font-size: 0.8em; margin-right: 3px; }
.ct-svg { min-height: 104px; }
.ct-svg svg { display: block; overflow: visible; }
.ct-minis { display: grid; grid-template-columns: 1fr; gap: var(--space-10); }
@container (min-width: 560px) { .ct-minis { grid-template-columns: repeat(3, 1fr); } }

/* chart marks */
.ct-gl { stroke: rgb(var(--ink-text-3-rgb) / 0.13); stroke-width: 1; }
.ct-axisline { stroke: var(--ct-line); stroke-width: 1; }
.ct-yl, .ct-xl { font-family: var(--font-mono); font-size: 9px; fill: var(--ink-text-3); letter-spacing: 0.04em; }
.ct-xl.is-now { fill: var(--sig-green-lift); }
.ct-band { fill: rgb(var(--f4-warn-rgb) / 0.08); stroke: rgb(var(--f4-warn-rgb) / 0.3); stroke-width: 1; }
.ct-band-l { font-family: var(--font-mono); font-size: 8.5px; fill: var(--f4-warn); letter-spacing: 0.08em; }
.ct-col.is-act { fill: var(--ink-text-2); fill-opacity: 0.55; }
.ct-col.is-fc { stroke: rgb(var(--ink-text-3-rgb) / 0.6); stroke-width: 1; }
.ct-hatch-line { stroke: rgb(var(--ink-text-3-rgb) / 0.55); stroke-width: 1.4; }
.ct-col.is-up { fill: var(--sig-green-lift); }
.ct-ly { fill: none; stroke: var(--f4-blue-lift); stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; }
.ct-ly-dot { fill: var(--f4-ink); stroke: var(--f4-blue-lift); stroke-width: 1.5; }
.ct-now { stroke: var(--sig-green-lift); stroke-width: 1.25; stroke-dasharray: 2 3; }
.ct-now-l { font-family: var(--font-mono); font-size: 8.5px; fill: var(--sig-green-lift); letter-spacing: 0.1em; }
.ct-peak-l { font-family: var(--font-mono); font-size: 10px; font-weight: 500; fill: var(--sig-green-lift); }
.ct-legend {
  display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-14); margin-top: var(--space-6);
  font-family: var(--font-mono); font-size: var(--fs-4xs); letter-spacing: 0.04em; color: var(--ink-text-3);
}
.ct-legend span { display: inline-flex; align-items: center; gap: var(--space-6); }
.ct-legend i { width: 10px; height: 8px; border-radius: 2px; flex: none; }
.ct-legend .lg-act i { background: var(--ink-text-2); opacity: 0.55; }
.ct-legend .lg-fc i {
  border: 1px solid rgb(var(--ink-text-3-rgb) / 0.7);
  background: repeating-linear-gradient(45deg, rgb(var(--ink-text-3-rgb) / 0.6) 0 1.4px, transparent 1.4px 3.6px);
}
.ct-legend .lg-up i { background: var(--sig-green-lift); }
.ct-legend .lg-ly i { height: 2px; border-radius: 1px; background: var(--f4-blue-lift); }
/* weather · rain on the reference blue, heat on the cool white, the day past the line in amber */
.ct-wbar { fill: var(--f4-blue-lift); fill-opacity: 0.7; }
.ct-wbar.is-heat { fill: var(--ink-text-2); fill-opacity: 0.55; }
.ct-wbar.is-risk { fill: var(--f4-warn); fill-opacity: 1; }
.ct-thr { stroke: var(--f4-warn); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0.85; }
.ct-thr-l { font-family: var(--font-mono); font-size: 8px; fill: var(--f4-warn); letter-spacing: 0.03em; }
.ct-vl { font-family: var(--font-mono); font-size: 9px; font-weight: 500; fill: var(--ink-text-1); }
/* supply · gate encodings, colour always doubled by shape + the legend */
.ra-axis { stroke: var(--ct-line); stroke-width: 1; }
.ra-tick { stroke: rgb(var(--ink-text-3-rgb) / 0.28); stroke-width: 1; }
.ra-tick.is-now { stroke: var(--sig-green-lift); }
.ra-day.is-now { fill: var(--sig-green-lift); }
.ra-origin { font-family: var(--font-mono); font-size: 9.5px; font-weight: 500; fill: var(--ink-text-1); }
.ra-load { font-family: var(--font-mono); font-size: 8.5px; fill: var(--ink-text-3); }
.ra-stem { stroke-width: 1.5; }
.is-confirmed .ra-dot { fill: var(--sig-green-lift); }
.is-confirmed .ra-stem { stroke: var(--sig-green-lift); }
.is-risk .ra-dot { fill: var(--f4-warn); }
.is-risk .ra-stem { stroke: var(--f4-warn); }
.is-planned .ra-dot { fill: var(--f4-ink); stroke: var(--ink-text-3); stroke-width: 1.5; }
.is-planned .ra-stem { stroke: var(--ink-text-3); stroke-dasharray: 2 2.5; }
.ct-gates {
  display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-10); margin-top: var(--space-4);
  font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-3);
}
.ct-gates span { display: inline-flex; align-items: center; gap: var(--space-4); }
.ct-gates i { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.ct-gates .g-confirmed i { background: var(--sig-green-lift); }
.ct-gates .g-risk i { background: var(--f4-warn); }
.ct-gates .g-planned i { border: 1.5px solid var(--ink-text-3); }
.ct-gates .g-thr i { width: 12px; height: 0; border-radius: 0; border-top: 1px dashed var(--f4-warn); }
.ct-gates .g-share i { width: 10px; height: 7px; border-radius: 2px; background: rgb(var(--f4-blue-lift-rgb) / 0.25); border-top: 1.5px solid var(--ink-text-1); }
/* market · share as a line over its own area, the latest week called out */
.ct-sh-area { fill: rgb(var(--f4-blue-lift-rgb) / 0.1); }
.ct-sh-line { fill: none; stroke: var(--ink-text-1); stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; }
.ct-sh-dot { fill: var(--ink-text-1); }

/* priority synthesis strip */
.ct-foot {
  position: relative;
  display: flex; align-items: center; gap: var(--space-10);
  padding: var(--space-14) var(--space-18);
  border-top: 1px solid var(--ct-line);
  background: rgba(9, 17, 30, 0.55);
  font-size: var(--fs-cap-s); color: var(--ink-text-2); line-height: var(--lh-tight);
}
.ct-flag {
  flex: none;
  display: inline-flex; align-items: center; gap: var(--space-6);
  padding: var(--space-4) var(--space-10); border-radius: var(--radius-pill);
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--f4-warn); background: rgb(var(--f4-warn-rgb) / 0.15);
}
.ct-flag::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.ct-foot b { color: var(--ink-text-1); font-weight: 600; }

/* motion · columns grow from the axis, the reference lines draw in, the
   ring sweeps, the lots drop onto the rail. Every mark rests at its final
   shape; ct-wait holds them hidden until the instrument is first on screen */
.ct-col, .ct-wbar, .ra-lot { transform-box: fill-box; transform-origin: 50% 100%; }
@media (prefers-reduced-motion: no-preference) {
  .ctower.ct-wait .ct-col, .ctower.ct-wait .ct-wbar { transform: scaleY(0); }
  .ctower.ct-wait .ct-ly, .ctower.ct-wait .ct-sh-line, .ctower.ct-wait .km-ring { stroke-dashoffset: 100; }
  .ctower.ct-wait .ra-lot, .ctower.ct-wait .ct-peak-l, .ctower.ct-wait .ct-ly-dot { opacity: 0; }
  .ctower.is-in:not(.is-settled) .ct-col { animation: ctGrow 650ms var(--ease-out) backwards; animation-delay: calc(160ms + var(--i, 0) * 45ms); }
  .ctower.is-in:not(.is-settled) .ct-wbar { animation: ctGrow 520ms var(--ease-out) backwards; animation-delay: calc(560ms + var(--i, 0) * 40ms); }
  .ctower.is-in:not(.is-settled) .ct-ly,
  .ctower.is-in:not(.is-settled) .ct-sh-line,
  .ctower.is-in:not(.is-settled) .km-ring { animation: ctDraw 1100ms var(--ease-out) backwards 280ms; }
  .ctower.is-in:not(.is-settled) .ct-ly-dot { animation: ctFade 400ms var(--ease-out) backwards 1000ms; }
  .ctower.is-in:not(.is-settled) .ct-peak-l { animation: ctFade 400ms var(--ease-out) backwards 1150ms; }
  .ctower.is-in:not(.is-settled) .ra-lot { animation: ctPop 420ms var(--ease-out) backwards; animation-delay: calc(760ms + var(--i, 0) * 120ms); }
}
@keyframes ctGrow { from { transform: scaleY(0); } }
@keyframes ctDraw { from { stroke-dashoffset: 100; } }
@keyframes ctFade { from { opacity: 0; } }
@keyframes ctPop { from { opacity: 0; transform: translateY(-8px); } }
@media (prefers-reduced-motion: reduce) {
  .ct-live i { animation: none; }
}

/* before / after (yesterday → today) */
.before-after { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gutter); }
@media (max-width: 767px) { .before-after { grid-template-columns: 1fr; } }
.ba-col {
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.07);
  border-radius: var(--radius-card);
  padding: var(--space-32);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.ba-col.ba-today {
  background: linear-gradient(180deg, var(--surface-2), var(--surface-3));
  border-color: rgb(var(--sig-green-rgb) / 0.3);
  box-shadow: 0 1px 2px rgb(var(--f4-ink-rgb) / 0.04), 0 18px 40px -20px rgb(var(--ink-900-rgb) / 0.19);
}
.ba-col .ba-tag {
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--f4-slate); display: block; margin-bottom: var(--space-16);
}
.ba-col.ba-today .ba-tag { color: var(--sig-green-text); }
.ba-col ul { margin: 0; padding-left: var(--space-18); display: grid; gap: var(--space-10); font-size: var(--fs-md); color: var(--f4-slate); }
.ba-col.ba-today ul { color: var(--f4-ink); }

/* yesterday → today · the arrow lands once both columns are on screen */
.before-after { position: relative; --ba-rot: 0deg; }
.before-after::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 38px; height: 38px;
  border-radius: 50%;
  background:
    url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%2308240A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>') center / 18px 18px no-repeat,
    linear-gradient(180deg, var(--sig-green-face-a) 0%, var(--sig-green-face-b) 100%);
  box-shadow: 0 4px 14px -4px rgb(var(--ink-900-rgb) / 0.37), var(--specular-lit);
  transform: translate(-50%, -50%) rotate(var(--ba-rot));
  z-index: 1;
  pointer-events: none;
}
@media (max-width: 767px) { .before-after { --ba-rot: 90deg; } }
.reveal .before-after::after, .before-after.reveal::after, .reveal-group .before-after::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(var(--ba-rot)) scale(0.4);
  transition: opacity 300ms var(--ease-out) 350ms, transform 480ms var(--ease-out) 350ms;
}
.reveal.in .before-after::after, .before-after.reveal.in::after, .reveal-group.in .before-after::after {
  opacity: 1;
  transform: translate(-50%, -50%) rotate(var(--ba-rot)) scale(1);
}
/* today's list earns its state line by line */
.reveal .ba-today li, .reveal-group .ba-today li {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 400ms var(--ease-out), transform 400ms var(--ease-out);
}
.reveal.in .ba-today li, .reveal-group.in .ba-today li { opacity: 1; transform: none; }
.reveal.in .ba-today li:nth-child(1), .reveal-group.in .ba-today li:nth-child(1) { transition-delay: 430ms; }
.reveal.in .ba-today li:nth-child(2), .reveal-group.in .ba-today li:nth-child(2) { transition-delay: 500ms; }
.reveal.in .ba-today li:nth-child(3), .reveal-group.in .ba-today li:nth-child(3) { transition-delay: 570ms; }
.reveal.in .ba-today li:nth-child(4), .reveal-group.in .ba-today li:nth-child(4) { transition-delay: 640ms; }
.reveal.in .ba-today li:nth-child(5), .reveal-group.in .ba-today li:nth-child(5) { transition-delay: 710ms; }
/* yesterday → today, upgraded (24 Oct review) · yesterday is a pile of the
   sheets it ran on, each with its file tab and its pain struck through;
   today is one instrument card, a small drawn proof beside every line. The
   arrow sits in the gap between the two, wherever the columns fall. */
.before-after { grid-template-columns: minmax(0, 1fr) minmax(0, 1.12fr); column-gap: 76px; align-items: center; }
.before-after::after { left: calc((100% - 76px) * 0.4717 + 38px); }
.ba-col:not(.ba-today) { padding: 0; border: 0; background: none; box-shadow: none; }
.ba-col:not(.ba-today) ul { list-style: none; padding: 0; gap: 0; }
.ba-col:not(.ba-today) li {
  position: relative;
  padding: var(--space-12) var(--space-16) var(--space-14);
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.1);
  border-radius: 6px;
  box-shadow: 0 6px 18px rgb(var(--f4-ink-rgb) / 0.08);
  transform: rotate(var(--ba-r, -2deg));
  margin-left: var(--ba-x, 0);
  width: 88%;
}
.ba-col:not(.ba-today) li + li { margin-top: -4px; }
.ba-col:not(.ba-today) li:nth-child(1) { --ba-r: -2.4deg; --ba-x: 0; }
.ba-col:not(.ba-today) li:nth-child(2) { --ba-r: 1.6deg; --ba-x: 9%; }
.ba-col:not(.ba-today) li:nth-child(3) { --ba-r: -1.1deg; --ba-x: 3%; }
.ba-col:not(.ba-today) li:nth-child(4) { --ba-r: 2deg; --ba-x: 10%; }
.ba-col:not(.ba-today) li::before {
  content: attr(data-file);
  display: table;
  margin-bottom: var(--space-8);
  padding: 2px 7px;
  border-radius: var(--radius-xs);
  background: rgb(var(--f4-ink-rgb) / 0.06);
  font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--f4-slate);
}
.ba-col:not(.ba-today) li::after {
  content: ""; display: block; height: 14px; margin-top: var(--space-10);
  background-image: linear-gradient(rgb(var(--f4-ink-rgb) / 0.1) 1px, transparent 1px), linear-gradient(90deg, rgb(var(--f4-ink-rgb) / 0.1) 1px, transparent 1px);
  background-size: 100% 7px, 26px 100%;
}
.ba-col:not(.ba-today) li > span { text-decoration: line-through; text-decoration-color: rgb(var(--f4-crit-rgb) / 0.55); text-decoration-thickness: 1.5px; }
.ba-col.ba-today { padding: var(--space-8) var(--space-28); background: var(--surface); border-color: rgb(var(--sig-green-rgb) / 0.5); }
.ba-col.ba-today .ba-tag { margin: var(--space-16) 0 0; }
.ba-col.ba-today ul { list-style: none; padding: 0; gap: 0; }
.ba-col.ba-today li { display: grid; grid-template-columns: 24px minmax(0, 1fr) 120px; gap: var(--space-14); align-items: center; padding: var(--space-16) 0; }
.ba-col.ba-today li + li { border-top: 1px solid var(--f4-line); }
.ba-col.ba-today li::before {
  content: ""; width: 24px; height: 24px; border-radius: 50%;
  background: rgb(var(--sig-green-rgb) / 0.16) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%232C731B" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="m7 12.5 3.2 3.2L17 8.6"/></svg>') center / 15px 15px no-repeat;
}
.ba-proof svg { display: block; width: 120px; height: auto; overflow: visible; }
.bap-k { font-family: var(--font-mono); font-size: 8.5px; fill: var(--f4-slate); }
.bap-k.is-warn { fill: var(--warn-text); }
.bap-k.is-green { fill: var(--sig-green-text); }
.bap-v { font-family: var(--font-mono); font-size: 9.5px; font-weight: 600; fill: var(--sig-green-text); }
.bap-track { fill: rgb(var(--f4-ink-rgb) / 0.12); }
.bap-fill { fill: var(--sig-green); }
.bap-n { fill: var(--f4-blue); }
.bap-n.is-s { fill: rgb(var(--f4-blue-rgb) / 0.45); }
.bap-line { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.35); stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
.bap-line.is-s { stroke: rgb(var(--f4-ink-rgb) / 0.2); }
.bap-wk { fill: rgb(var(--f4-blue-rgb) / 0.22); }
.bap-wk.is-short { fill: var(--f4-warn); }
.bap-margin { fill: var(--sig-green); }
.bap-chip { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.2); }
.bap-ok { fill: rgb(var(--sig-green-rgb) / 0.16); }
.bap-tick { fill: none; stroke: var(--sig-green-text); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.bap-axis { stroke: rgb(var(--f4-ink-rgb) / 0.25); }
.bap-bandr { fill: rgb(var(--sig-green-rgb) / 0.14); }
.bap-target { stroke: var(--sig-green-deep); stroke-dasharray: 2 2; }
.bap-pin { fill: var(--sig-green); stroke: var(--surface); stroke-width: 1.5; }
.bap-path { fill: none; stroke: var(--sig-green-deep); stroke-width: 2; stroke-linecap: round; }
.bap-doc { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.35); stroke-width: 1.3; stroke-linejoin: round; }
.bap-scr { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.35); stroke-width: 1.3; }
.bap-tile { fill: rgb(var(--f4-blue-rgb) / 0.3); }
.bap-spark { fill: none; stroke: var(--f4-blue); stroke-width: 1.8; stroke-linejoin: round; }
.bap-alert { fill: var(--f4-warn); stroke: var(--surface); stroke-width: 1.5; }
@media (max-width: 767px) {
  .before-after { grid-template-columns: minmax(0, 1fr); row-gap: 64px; }
  /* stacked, the gap is no longer at half height · the arrow moves into it */
  .before-after::after { left: 50%; top: auto; bottom: 0; display: none; }
  .ba-col.ba-today { position: relative; }
  .ba-col.ba-today::before {
    content: ""; position: absolute; left: 50%; top: -51px; width: 38px; height: 38px; border-radius: 50%;
    transform: translateX(-50%) rotate(90deg);
    background:
      url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%2308240A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>') center / 18px 18px no-repeat,
      linear-gradient(180deg, var(--sig-green-face-a) 0%, var(--sig-green-face-b) 100%);
    box-shadow: 0 4px 14px -4px rgb(var(--ink-900-rgb) / 0.37), var(--specular-lit);
  }
  .ba-col:not(.ba-today) li { width: 92%; }
  .ba-col.ba-today { padding: var(--space-4) var(--space-18); }
  .ba-col.ba-today li { grid-template-columns: 24px minmax(0, 1fr); }
  .ba-proof { grid-column: 2; }
}

/* weekly cycle timeline (sop) — a true sequence, numbering earned */
.cycle { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gutter); }
@media (max-width: 767px) { .cycle { grid-template-columns: 1fr; } }
.cycle-step {
  position: relative;
  padding: var(--space-32);
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.06);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
}
.cycle-step .cy-day {
  font-family: var(--font-mono); font-size: var(--fs-kicker); letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--sig-green-text);
}
.cycle-step h3 { font-size: var(--fs-xl); margin-top: var(--space-8); }
.cycle-step p { font-size: var(--fs-md); color: var(--f4-slate); margin-top: var(--space-8); }
/* S&OP · the two loops, drawn (24 Oct review) · the weekly ring with its
   three beats and the daily loop meshing on Wednesday to Friday, both
   hand-offs inside the ring, the two loops explained beside it. In view
   ([data-mini]) a marker walks the week while the daily marker turns five
   times; under reduced motion both rest at the top of their rings. */
.lpx { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: clamp(2rem, 4vw, 4rem); align-items: center; }
.lpx .section-head { margin-bottom: 0; }
.lpx-legend { display: grid; gap: var(--space-24); margin-top: var(--space-32); }
.lpx-item { padding-left: var(--space-20); border-left: 3px solid var(--f4-blue-deep); }
.lpx-item.is-day { border-left-color: var(--sig-green-deep); }
.lpx-item h3 { font-size: var(--fs-lg); }
.lpx-item p { margin-top: var(--space-6); font-size: var(--fs-md); line-height: var(--lh-body-l); color: var(--f4-slate); }
.lpx-foot { margin-top: var(--space-4); font-family: var(--font-mono); font-size: var(--fs-kicker); color: var(--f4-slate); }
.lpx-stage { overflow-x: auto; }
.lpx-stage svg { display: block; width: 100%; min-width: 520px; height: auto; overflow: visible; }
.lpx-track { fill: none; stroke: rgb(var(--f4-blue-rgb) / 0.1); stroke-width: 18; }
.lpx-beat { fill: none; stroke: rgb(var(--f4-blue-rgb) / 0.72); stroke-width: 18; stroke-linecap: round; }
.lpx-beat.is-meet { stroke: var(--f4-blue-deep); }
.lpx-wknd { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.09); stroke-width: 18; stroke-linecap: round; }
.lpx-lead { stroke: rgb(var(--f4-ink-rgb) / 0.3); stroke-width: 1; }
.lpx-day { font-size: 14px; font-weight: 600; fill: var(--f4-ink); }
.lpx-what { font-family: var(--font-mono); font-size: 11px; fill: var(--f4-slate); }
.lpx-what.is-quiet { fill: rgb(var(--f4-slate-rgb) / 0.75); }
.lpx-core { font-family: var(--font-display); font-size: 40px; fill: var(--f4-ink); }
.lpx-core.is-day { font-size: 22px; fill: var(--sig-green-text); }
.lpx-core-s { font-family: var(--font-mono); font-size: 11px; fill: var(--f4-slate); }
.lpx-core-s.is-day { font-size: 10.5px; fill: var(--sig-green-text); }
.lpx-day-bg { fill: var(--f4-mist); }
.lpx-day-ring { fill: var(--surface); stroke: var(--sig-green-deep); stroke-opacity: 0.78; stroke-width: 10; }
.lpx-notch { stroke: var(--surface); stroke-width: 2; }
.lpx-spin { fill: none; stroke: var(--sig-green-deep); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.lpx-hand { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.lpx-back { fill: none; stroke: var(--sig-green-deep); stroke-width: 1.6; stroke-dasharray: 4 5; stroke-linecap: round; }
.lpx-back-h { fill: none; stroke: var(--sig-green-deep); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.lpx-note { font-family: var(--font-mono); font-size: 11px; font-weight: 500; fill: var(--f4-blue-deep); }
.lpx-note.is-back { fill: var(--sig-green-text); }
.lpx-run { transform-box: view-box; }
.lpx-run.is-week circle { fill: var(--surface); stroke: var(--f4-blue-deep); stroke-width: 3; }
.lpx-run.is-day circle { fill: var(--surface); stroke: var(--sig-green-deep); stroke-width: 2.5; }
.lpx.is-on .lpx-run.is-week { animation: lpxTurn 25s linear infinite; }
.lpx.is-on .lpx-run.is-day { animation: lpxTurn 5s linear infinite; }
@keyframes lpxTurn { to { transform: rotate(360deg); } }
@media (max-width: 899px) { .lpx { grid-template-columns: minmax(0, 1fr); } }
@media (prefers-reduced-motion: reduce) { .lpx.is-on .lpx-run { animation: none; } }
/* the weekly cycle on its timeline (24 Oct review) · a playhead walks the
   week, each beat drops what it produces, and its card lights in step */
.cy-tl { margin: var(--space-24) 0 var(--space-16); overflow-x: auto; }
.cy-tl svg { display: block; width: 100%; min-width: 720px; height: auto; overflow: visible; }
.cyt-band { fill: rgb(var(--f4-ink-rgb) / 0.035); }
.cyt-band.is-meet { fill: rgb(var(--sig-green-rgb) / 0.08); }
.cyt-beat { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; fill: var(--f4-slate); }
.cyt-beat.is-quiet { fill: rgb(var(--f4-slate-rgb) / 0.6); }
.cyt-tick { stroke: rgb(var(--f4-ink-rgb) / 0.08); }
.cyt-day { font-family: var(--font-mono); font-size: 11px; fill: var(--f4-slate); }
.cyt-pill rect { fill: rgb(var(--sig-green-rgb) / 0.12); stroke: var(--sig-green-deep); stroke-width: 1; }
.cyt-pill text { font-family: var(--font-mono); font-size: 10px; fill: var(--sig-green-text); }
.cyt-pill.is-data rect { fill: rgb(var(--f4-blue-rgb) / 0.1); stroke: var(--f4-blue-deep); }
.cyt-pill.is-data text { fill: var(--f4-blue-deep); }
.cyt-dec circle { fill: var(--surface); stroke: var(--sig-green-deep); stroke-width: 1.5; }
.cyt-dec path { fill: none; stroke: var(--sig-green-deep); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.cyt-track { fill: rgb(var(--f4-ink-rgb) / 0.08); }
.cyt-bar { fill: var(--sig-green); }
.cyt-note { font-family: var(--font-mono); font-size: 10px; font-weight: 500; fill: var(--sig-green-text); }
.cyt-note.is-loop { font-weight: 400; fill: var(--f4-blue-deep); }
.cyt-loop { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1.5; stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset 1.6s var(--ease-out), opacity 400ms var(--ease-out); }
.cyt-loop.is-on { stroke-dashoffset: 0; }
.cyt-loop-tip { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.cyt-head line { stroke: var(--sig-green-deep); stroke-width: 1.5; }
.cyt-head circle { fill: var(--sig-green); }
/* the story engine · marks wait hidden for their moment, fills run on --p */
[data-story] [data-at] { opacity: 0; transition: opacity 400ms var(--ease-out); }
[data-story] .cyt-loop[data-at] { transition: stroke-dashoffset 1.6s var(--ease-out), opacity 400ms var(--ease-out); }
[data-story] [data-at].is-on { opacity: 1; }
[data-story] [data-st-bar] { transform-box: fill-box; transform-origin: 0 50%; transform: scaleX(var(--p, 0)); }
[data-story].is-static [data-st-head] { display: none; }
.cycle-step { transition: border-color 400ms var(--ease-out), box-shadow 400ms var(--ease-out); }
.cycle-step.is-lit { border-color: rgb(var(--sig-green-rgb) / 0.55); box-shadow: 0 0 0 1px rgb(var(--sig-green-rgb) / 0.2), var(--shadow-md); }
@media (prefers-reduced-motion: reduce) {
  [data-story] [data-at], [data-story] .cyt-loop[data-at], .cycle-step { transition: none; }
}
/* Control without friction as a storyline (24 Oct review) · one price, the
   avocado 4-pack from the waterfall demo, walked through its five stations:
   built from the bottom up, seen by role, moved inside its band or routed to
   approval, promoted into S&OP, and checked against the realised sale */
.prs-story { margin-top: var(--space-24); }
.prs-tl { overflow-x: auto; margin-bottom: var(--space-16); }
.prs-tl svg { display: block; width: 100%; min-width: 900px; height: auto; }
.prs-panel { fill: rgb(var(--f4-ink-rgb) / 0.035); }
.prs-seg.c0 { fill: rgb(var(--f4-blue-rgb) / 0.75); }
.prs-seg.c1 { fill: rgb(var(--f4-blue-rgb) / 0.55); }
.prs-seg.c2 { fill: rgb(var(--f4-blue-rgb) / 0.4); }
.prs-seg.c3 { fill: rgb(var(--f4-blue-rgb) / 0.28); }
.prs-seg.is-margin { fill: var(--sig-green); }
.prs-lead { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.25); stroke-width: 1; }
.prs-lab, .prs-val, .prs-role, .prs-note, .prs-tick-t, .prs-pin-t, .prs-req-t, .prs-band-t, .prs-unit, .prs-tag-t, .prs-tag-v, .prs-sop, .prs-lift-t, .prs-chip-t, .prs-warn-t, .stl-stop text { font-family: var(--font-mono); }
.prs-lab { font-size: 10px; fill: var(--f4-slate); }
.prs-val { font-size: 10px; fill: var(--f4-ink); }
.prs-lab.is-margin, .prs-val.is-margin, .prs-note .is-margin { fill: var(--sig-green-text); font-weight: 500; }
.prs-price { font-family: var(--font-mono); font-size: 17px; font-weight: 500; fill: var(--f4-ink); }
.prs-unit { font-size: 10px; fill: var(--f4-slate); }
.prs-role { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; fill: var(--f4-slate); }
.prs-note { font-size: 10px; fill: var(--f4-slate); }
.prs-note .is-ink { fill: var(--f4-ink); font-weight: 500; }
.prs-note .is-warn { fill: var(--warn-text); font-weight: 500; }
.prs-note.is-ok { fill: var(--sig-green-text); font-weight: 500; }
.prs-hidden { fill: rgb(var(--f4-ink-rgb) / 0.06); }
.prs-hatch { stroke: rgb(var(--f4-ink-rgb) / 0.14); stroke-width: 1.4; }
.prs-chip { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.4); }
.prs-chip-t { font-size: 10px; font-weight: 500; fill: var(--f4-ink); }
.prs-band { fill: rgb(var(--sig-green-rgb) / 0.12); }
.prs-band-t { font-size: 9.5px; fill: var(--sig-green-text); }
.prs-axis { stroke: rgb(var(--f4-ink-rgb) / 0.3); stroke-width: 1; }
.prs-tick { stroke: rgb(var(--f4-ink-rgb) / 0.3); }
.prs-tick-t { font-size: 9px; fill: var(--f4-slate); }
.prs-target { stroke: var(--sig-green-deep); stroke-width: 1.25; stroke-dasharray: 3 3; }
.prs-pin { stroke-width: 1.5; }
.prs-pin.is-ok { stroke: var(--sig-green-deep); }
.prs-pin.is-out { stroke: var(--warn-text); }
.prs-pin-dot.is-ok { fill: var(--sig-green); }
.prs-pin-dot.is-out { fill: var(--f4-warn); }
.prs-pin-t { font-size: 10px; font-weight: 500; }
.prs-pin-t.is-ok { fill: var(--sig-green-text); }
.prs-pin-t.is-out { fill: var(--warn-text); }
.prs-route { fill: none; stroke: var(--warn-text); stroke-width: 1.25; stroke-dasharray: 2 3; }
.prs-req { fill: rgb(var(--f4-warn-rgb) / 0.14); stroke: var(--warn-text); stroke-width: 1; }
.prs-req-t { font-size: 9px; fill: var(--warn-text); }
.prs-ok { fill: var(--sig-green); }
.prs-ok-t { fill: none; stroke: var(--surface); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.prs-tag { fill: var(--surface); stroke: var(--f4-blue-deep); stroke-width: 1.25; stroke-linejoin: round; }
.prs-tag-hole { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1; }
.prs-tag-t { font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase; fill: var(--f4-slate); }
.prs-tag-v { font-size: 10px; font-weight: 500; fill: var(--f4-blue-deep); }
.prs-arrow { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.45); stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }
.prs-sop { font-size: 11px; font-weight: 600; fill: var(--f4-ink); }
.prs-vol { fill: rgb(var(--f4-ink-rgb) / 0.16); }
.prs-lift { fill: var(--f4-blue); }
.prs-lift-t { font-size: 10px; font-weight: 500; fill: var(--f4-blue-deep); }
.prs-list { fill: rgb(var(--f4-ink-rgb) / 0.2); }
.prs-real { fill: var(--f4-blue); }
.prs-gap { fill: rgb(var(--f4-warn-rgb) / 0.18); stroke: var(--warn-text); stroke-width: 1; stroke-dasharray: 2 2; }
.prs-warn { fill: rgb(var(--f4-warn-rgb) / 0.16); stroke: var(--warn-text); stroke-width: 1; }
.prs-warn-t { font-size: 10px; font-weight: 500; fill: var(--warn-text); }
.stl-thread { stroke: rgb(var(--f4-ink-rgb) / 0.12); stroke-width: 2; }
.stl-stop circle { fill: var(--surface); stroke: var(--sig-green-deep); stroke-width: 1.5; }
.stl-stop text { font-size: 10px; font-weight: 600; fill: var(--sig-green-text); }
.stl-head circle { fill: var(--sig-green); }
/* the vertical fill: a cost stack builds from the floor up */
[data-story] [data-st-bar="y"] { transform-origin: 50% 100%; transform: scaleY(var(--p, 0)); }
/* the storyline's shared grammar (Pricing and Plan): a thread under the
   stations with a numbered stop for each, the playhead that walks it, and
   the steps beneath, one under each stop, lit while their beat plays */
.stl-steps { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); column-gap: 2.2727%; row-gap: var(--space-16); }
.stl-step { padding: var(--space-20); background: var(--surface); border: 1px solid rgb(var(--f4-ink-rgb) / 0.06); border-radius: var(--radius-card); box-shadow: var(--shadow-sm); transition: border-color 400ms var(--ease-out), box-shadow 400ms var(--ease-out); }
.stl-step .cy-day { font-family: var(--font-mono); font-size: var(--fs-kicker); letter-spacing: 0.14em; text-transform: uppercase; color: var(--sig-green-text); }
.stl-step h3 { font-size: var(--fs-lg); margin-top: var(--space-8); }
.stl-step p { font-size: var(--fs-sm); color: var(--f4-slate); margin-top: var(--space-8); }
.stl-step.is-lit { border-color: rgb(var(--sig-green-rgb) / 0.55); box-shadow: 0 0 0 1px rgb(var(--sig-green-rgb) / 0.2), var(--shadow-md); }
@media (max-width: 1099px) { .stl-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--gutter); } }
@media (max-width: 599px) { .stl-steps { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) { .stl-step { transition: none; } }
/* One plan the whole team can see, change and sign off, as a storyline
   (24 Oct review) · the plan drills down, shifts a week in one move, opens
   a supply gap, is edited by three teams and signed off as a new version */
.pls-tl { overflow-x: auto; margin: var(--space-24) 0 var(--space-16); }
.pls-tl svg { display: block; width: 100%; min-width: 900px; height: auto; }
.pls-panel { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.07); }
.pls-wk, .pls-tot, .pls-flag, .pls-rd, .pls-badge-t, .pls-vtag-t { font-family: var(--font-mono); }
.pls-wk { font-size: 10px; fill: var(--f4-slate); }
.pls-row { font-size: 12px; fill: var(--f4-ink); }
.pls-row.is-top { font-weight: 600; }
.pls-row.is-sup { fill: var(--f4-slate); }
.pls-tot { font-size: 10px; fill: var(--f4-slate); }
.pls-tree { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.2); stroke-width: 1; }
.pls-base { fill: var(--surface); }
.pls-cell { fill: rgb(var(--f4-blue-rgb) / var(--o)); }
.pls-moved { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1.25; }
.pls-sweep { fill: rgb(var(--f4-blue-rgb) / 0.1); }
.pls-sup { fill: rgb(var(--sig-green-rgb) / 0.22); }
.pls-sup.is-short { fill: rgb(var(--f4-warn-rgb) / 0.4); stroke: var(--warn-text); stroke-width: 1; }
.pls-sup.is-fixed { fill: rgb(var(--sig-green-rgb) / 0.34); stroke: var(--sig-green-deep); stroke-width: 1; }
.pls-flag { font-size: 9px; font-weight: 500; }
.pls-flag.is-short { fill: var(--warn-text); }
.pls-flag.is-fixed { fill: var(--sig-green-text); }
.pls-av circle { stroke: var(--surface); stroke-width: 2; }
.pls-av text { font-size: 10px; font-weight: 600; fill: var(--surface); }
.pls-av.is-com circle, .pls-chip-dot.is-com { fill: var(--f4-blue); }
.pls-av.is-sup circle, .pls-chip-dot.is-sup { fill: var(--sig-green-deep); }
.pls-av.is-fin circle, .pls-chip-dot.is-fin { fill: var(--f4-signal); }
.pls-point { fill: none; stroke-width: 1.25; }
.pls-point.is-com { stroke: var(--f4-blue); }
.pls-point.is-sup { stroke: var(--sig-green-deep); }
.pls-point.is-fin { stroke: var(--f4-signal); }
.pls-badge { fill: var(--surface); stroke: var(--f4-blue); }
.pls-badge-t { font-size: 9px; font-weight: 500; fill: var(--f4-blue-deep); }
.pls-badge.is-fin { stroke: var(--f4-signal); }
.pls-badge-t.is-fin { fill: var(--signal-text); }
.pls-tot.is-short { fill: var(--warn-text); font-weight: 500; }
.pls-ic { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
.pls-ic .pls-ic-c { fill: rgb(var(--f4-blue-rgb) / 0.1); stroke: none; }
.pls-ic .pls-ic-f { fill: var(--f4-blue-deep); stroke: none; }
.pls-ic.is-ok { stroke: var(--sig-green-text); }
.pls-ic.is-ok .pls-ic-c { fill: rgb(var(--sig-green-rgb) / 0.16); }
.pls-rt { font-size: 12px; font-weight: 600; fill: var(--f4-ink); }
.pls-rd { font-size: 10px; fill: var(--f4-slate); }
.pls-rd.is-ok { fill: var(--sig-green-text); font-weight: 500; }
.pls-chip { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.16); }
.pls-chip-t { font-size: 11px; fill: var(--f4-ink); }
.pls-commit { fill: none; stroke: var(--sig-green-deep); stroke-width: 1.5; }
.pls-vtag { fill: var(--sig-green-deep); }
.pls-vtag-t { font-size: 9.5px; font-weight: 500; fill: var(--surface); }
.stl-steps.is-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1099px) { .stl-steps.is-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 599px) { .stl-steps.is-4 { grid-template-columns: 1fr; } }

/* generic reveal */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity 550ms var(--ease-out), transform 550ms var(--ease-out); }
.reveal.in { opacity: 1; transform: none; }
.reveal-group > * { opacity: 0; transform: translateY(14px); transition: opacity 550ms var(--ease-out), transform 550ms var(--ease-out); }
.reveal-group.in > * { opacity: 1; transform: none; }
.reveal-group.in > *:nth-child(2) { transition-delay: 70ms; }
.reveal-group.in > *:nth-child(3) { transition-delay: 140ms; }
.reveal-group.in > *:nth-child(4) { transition-delay: 210ms; }
.reveal-group.in > *:nth-child(5) { transition-delay: 280ms; }
.reveal-group.in > *:nth-child(6) { transition-delay: 350ms; }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal-group > * { opacity: 1 !important; transform: none !important; transition: none !important; }
  .btn, .card, .link-quiet::after, .link-quiet .arr { transition: none !important; }
}

/* ============================================================
   9 · Sequence A · hero "the four layers assemble"
   ============================================================ */
/* the pin holds one headline, so the track is only as tall as the four beats
   need · 260vh kept the reader on an unchanging screen and pushed the client
   logo wall (the fastest credibility signal on the page) far down the scroll. */
.seqA-track { height: 150vh; position: relative; }
.seqA-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background-color: var(--f4-ink);
  background-image:
    var(--noise),
    radial-gradient(1200px 700px at 78% 10%, rgb(var(--sig-green-rgb) / 0.13), transparent 58%),
    radial-gradient(900px 600px at 8% 100%, rgb(var(--f4-blue-rgb) / 0.12), transparent 60%),
    linear-gradient(160deg, #0B1626 0%, var(--f4-ink) 55%, #11213A 100%);
  display: flex;
  align-items: center;
}
/* copy and cards sit above the ambient field · chips/streaks pass behind,
   pointer events fall through to the field except on real controls */
.seqA-pin > .container {
  position: relative;
  z-index: 1;
  pointer-events: none;
}
.seqA-pin > .container a,
.seqA-pin > .container button { pointer-events: auto; }
.hero-grid {
  display: grid;
  grid-template-columns: 6fr 5fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
  width: 100%;
  /* the copy group sits a touch above centre · the kicker fills the space it
     used to leave empty, while a safe area below the header is preserved */
  padding-top: var(--space-24);
}
/* continuous scroll feedback · a slight camera pull-back as the pin progresses.
   The copy no longer drifts with the pointer: its buttons hold still under the
   cursor, and the depth lives in the scene behind it (Michele, 24 Oct 2026). */
.seqA-pin .hero-copy {
  transform: translateY(calc(var(--p, 0) * -16px))
             scale(calc(1 - var(--p, 0) * 0.025));
  transform-origin: left center;
}
.hero-copy .kicker { margin-bottom: var(--space-28); }
.hero-copy h1 { color: #fff; }
.hero-copy .hero-sub {
  margin-top: var(--space-28);
  font-size: var(--fs-2xl);
  line-height: var(--lh-body);
  color: var(--text-on-ink-dim);
  max-width: 46ch;
}
/* one green button and a clear second choice · the secondary is a link, so the
   eye lands on the primary first. Blue, because it is where you can go. */
.hero-ctas { margin-top: var(--space-40); display: flex; align-items: center; gap: var(--space-16) var(--space-28); flex-wrap: wrap; }
.hero-ctas .hero-link { padding: var(--space-8) 0; font-size: var(--fs-lg); }
.hero-ctas .hero-link::after { bottom: 4px; }
@media (max-width: 767px) {
  /* a phone · the primary runs the full width, the link sits under it */
  .hero-ctas { flex-direction: column; align-items: stretch; }
  .hero-ctas .btn-primary { justify-content: center; }
  .hero-ctas .hero-link { align-self: flex-start; }
}

/* the narrative HUD · the decision loop the sub-copy describes, made visible
   and shared by every lens: See earlier → Decide faster → Protect value →
   Remember why. Stages light as the live story narrates; the message line
   carries the current beat. */
.hero-hud {
  margin-top: var(--space-36);
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  max-width: 34rem;
  animation: heroIn 850ms var(--ease-out) 540ms backwards;
}
/* one row at reading size · hairlines between the steps, and the step that is
   playing lit as a pill (it read as an 11px footnote with arrows) */
.hud-rail { display: flex; align-items: center; gap: 0; flex-wrap: nowrap; }
/* Each stage is a real control: it seeks the story to its own act, and the rail
   holds the clock while a pointer or keyboard focus rests on it. min-height is
   the WCAG 2.2 target size — an 8px dot beside a --fs-3xs label is nowhere near
   24px on its own, and qa.mjs runs axe with the wcag22aa tag. */
.hud-stage {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  min-height: 24px;
  padding: 3px 6px;
  border: 0;
  background: none;
  border-radius: var(--radius-pill);
  font: inherit;
  cursor: pointer;
  -webkit-appearance: none;
          appearance: none;
  transition: background 320ms var(--ease-out);
}
/* the first dot still sits on the copy's left edge */
.hud-stage:first-child { margin-left: -6px; }
.hud-stage:hover { background: rgb(255 255 255 / 0.06); }
.hud-stage:hover .hud-lab { color: var(--ink-text-1); }
.hud-stage:hover .hud-dot { border-color: rgb(var(--sig-green-lift-rgb) / 0.6); }
.hud-stage:focus-visible { outline: 2px solid var(--sig-green-lift); outline-offset: 3px; }
/* The held state used to dim the message line to 0.55, which dropped it to
   3.8:1 — below AA, in the exact state a reader is in while reading it. The
   affordance moved onto the rail's own dots instead, where contrast is not the
   carrier of meaning. */
.hero-hud.hud-held .hud-dot { border-color: rgb(var(--sig-green-lift-rgb) / 0.55); }
.hud-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.28);
  background: transparent;
  transition: background 320ms var(--ease-out), border-color 320ms var(--ease-out), box-shadow 320ms var(--ease-out);
}
.hud-lab {
  font-family: var(--font-mono);
  font-weight: 500; font-style: normal;
  font-size: var(--fs-sm); letter-spacing: 0.06em; text-transform: uppercase;
  white-space: nowrap;
  color: var(--ink-text-3);
  transition: color 320ms var(--ease-out);
}
/* a narrower copy column keeps the one row at 11px */
@media (max-width: 1279px) { .hud-lab { font-size: var(--fs-xs); } }
.hud-arrow { flex: none; width: 10px; height: 1px; background: rgb(255 255 255 / 0.2); }
/* a completed stage settles to a quiet green; the active stage is live */
.hud-stage.done .hud-dot { background: rgb(var(--sig-green-lift-rgb) / 0.45); border-color: rgb(var(--sig-green-lift-rgb) / 0.45); }
.hud-stage.done .hud-lab { color: var(--ink-text-2); }
.hud-stage.on { background: rgb(var(--sig-green-rgb) / 0.12); }
.hud-stage.on .hud-dot { background: var(--sig-green-lift); border-color: var(--sig-green-lift); box-shadow: var(--glow-live-ink); }
.hud-stage.on .hud-lab { color: var(--sig-green-lift); }
.hud-msg {
  min-height: 1.1em;
  font-family: var(--font-mono); font-weight: 500;
  font-size: var(--fs-xs); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--sig-green-lift);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 300ms var(--ease-out), transform 300ms var(--ease-out);
}
.hud-msg.show { opacity: 1; transform: none; }

.hero-visual { position: relative; height: min(66vh, 560px); }

/* ambient node field (JS-generated) · spans the whole pin, lags the scroll */
.node-field {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  transform: translate3d(0, calc(var(--p, 0) * 52px), 0);
  /* The instrument is composed against the copy, and the copy lives in a
     1200px container. The field itself is the viewport, so above ~1500px the
     two coordinate systems diverge and the drawing spreads into a margin the
     reader's eye has already left: at 2560 the leftmost node sat 503px outside
     the container and the "actuals · settled" caption 349px outside it. This
     pad is the difference, and .nf-tilt (which carries every drawn mark) is
     inset by it. The world plane, the bloom and the bokeh are NOT — they are
     atmosphere and are meant to bleed to the edges. */
  --nf-pad: max(0px, calc((100% - var(--container)) / 2));
}
/* readability scrim · deepens the ink behind the copy column. Keyed off the
   pad rather than a percentage: at 25% it tracked the viewport, so it drifted
   off the copy exactly as the viewport got wide enough for that to matter. */
.node-field::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(740px 580px at calc(var(--nf-pad, 0px) + 300px) 46%, rgba(9, 18, 32, 0.62), transparent 68%);
  pointer-events: none;
}
.seqA-pin > .container { position: relative; z-index: 1; }

/* ============================================================
   The now-line field · a four-week supply chain, alive.
   Everything on the map lives inside .nf-tilt (the plane that
   leans toward the cursor); node drift and parallax are computed
   per-frame by the engine in sequences.js, lanes re-drawn from
   the same offsets so geometry never disagrees.
   ============================================================ */

/* the physical world · actuals side only: past = real, future = the model.
   Heavily treated so the copy and the live field keep primacy; masked out
   before the now-line so the forecast half stays pure signal */
/* the parallax lives on the parent (compositor-only transform); the heavy
   treated bitmap lives on a static ::before so its blurred texture rasters
   ONCE at full quality and is only cheaply translated — otherwise the browser
   re-rasters the filter every frame and drops to a grainy low-res backing
   under animation load */
.nf-world {
  position: absolute;
  top: 0; bottom: 0;
  left: 0; width: 52%;
  opacity: calc(0.38 * (1 - var(--cv, 0) * 1.4));
  transform: translate3d(calc(var(--mx, 0) * 0.12px), calc(var(--my, 0) * 0.09px - var(--p, 0) * 10px), 0);
  will-change: transform;
  pointer-events: none;
}
.nf-world::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url("../img/actuals-world.jpg") left center / cover no-repeat;
  /* out of focus on purpose · the past is real but settled; blur also melts
     the backdrop's own baked-in icon nodes so only texture survives */
  filter: saturate(0.5) brightness(0.5) contrast(1.05) blur(2px);
  transition: filter 900ms var(--ease-out);
  -webkit-mask-image: linear-gradient(90deg, #000 40%, transparent 96%);
  mask-image: linear-gradient(90deg, #000 40%, transparent 96%);
}
/* On the Live chain the photograph is not decoration, it is the settled half:
   it ends AT the now-line and travels with it, so the picture of the real world
   is literally the part of the week that has already happened.

   Scoped to the field lens on purpose. The other three lenses share this
   ::before (they override its filter and mask below) and none of them has a
   now-line, so an unscoped rule reading --nfxf would fall back to 0 and clip
   their world to nothing. The three sub-page instrument heroes mount .nf-world
   through the same path and are covered by the same scope. */
/* The ramp is long — 420px, and it starts fading 520px out — because a short
   one put a visible vertical seam down the hero where the photograph stopped.
   The picture should run out of the frame, not end at an edge; the now-line is
   the only vertical the eye should find here. */
[data-hero-variant="field"] .nf-world { width: 74%; }
[data-hero-variant="field"] .nf-world::before {
  -webkit-mask-image: linear-gradient(90deg, #000 0,
      #000 max(0px, calc(var(--nfxf, 0) * 1px - 520px)), transparent calc(var(--nfxf, 0) * 1px - 100px));
          mask-image: linear-gradient(90deg, #000 0,
      #000 max(0px, calc(var(--nfxf, 0) * 1px - 520px)), transparent calc(var(--nfxf, 0) * 1px - 100px));
}
/* the physical world reacts to weather · it cools while hail plays */
.node-field.weathered .nf-world::before {
  filter: saturate(0.38) brightness(0.4) contrast(1.05) blur(2.5px) hue-rotate(-14deg);
}

/* ---- the world plane across the other lenses ----
   Shared so no lens reads as weightless vector-on-void, but tuned down: only
   the field earns the full strength, where the texture IS the settled actuals
   zone. Elsewhere it is a material ground, so it must never compete with the
   instrument on top of it — quieter, softer, and dissolving earlier. */
[data-hero-variant="routing"] .nf-world { width: 46%; opacity: calc(0.30 * (1 - var(--cv, 0) * 1.4)); }
[data-hero-variant="butterfly"] .nf-world { width: 46%; opacity: calc(0.28 * (1 - var(--cv, 0) * 1.4)); }
[data-hero-variant="movement"] .nf-world { width: 44%; opacity: calc(0.24 * (1 - var(--cv, 0) * 1.4)); }
/* space is a void · only a whisper of terrain, or the conceit breaks (at this
   strength, blurred, it reads as nebula rather than as a photograph) */
[data-hero-variant="space"] .nf-world { width: 42%; opacity: calc(0.18 * (1 - var(--cv, 0) * 1.4)); }
[data-hero-variant="routing"] .nf-world::before,
[data-hero-variant="butterfly"] .nf-world::before,
[data-hero-variant="movement"] .nf-world::before,
[data-hero-variant="space"] .nf-world::before {
  filter: saturate(0.42) brightness(0.44) contrast(1.02) blur(3px);
  -webkit-mask-image: linear-gradient(90deg, #000 26%, transparent 88%);
          mask-image: linear-gradient(90deg, #000 26%, transparent 88%);
}

/* The freeze-frame fallback (.nf-still) was REMOVED on client call
   (Aug 2026): it kept lagging generations behind the live butterfly and
   read as a worse product. Where the live scene cannot run (below 1024px,
   reduced motion) the hero is copy-only on the dark ground · no stand-in. */

/* the map plane · leans ≤ ~1.6° toward the cursor, flattens as --cv rises.
   Inset by --nf-pad so the instrument shares the copy's coordinate system:
   every drawn mark hangs off this plane, so one inset holds the whole chain
   inside the container at any width. */
.nf-tilt {
  position: absolute;
  inset: 0;
  transform: perspective(1200px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
}
/* Scoped to the Live chain, and that scope is load-bearing. All four lenses
   build a .nf-tilt, but only this one anchors its marks as percentages of that
   box. The space lens sizes its chip overlay in JS from the FIELD's rect to
   match an svg that covers the same box — inset the tilt for that lens and the
   overlay keeps the old width while the scene inside it narrows, so every cause
   chip drifts off its station. */
/* Asymmetric on purpose. The LEFT edge registers to the container so the chain
   shares the copy's coordinate system and never drifts under the headline. The
   RIGHT edge does not: holding it to the container squeezed four weeks of
   horizon into half a screen and the whole chain read vertical, stacked rather
   than spanning. Out here there is nothing to protect, so the forecast gets the
   width and the lanes get their diagonal back. */
[data-hero-variant="field"] .nf-tilt {
  inset: 0 min(var(--nf-pad, 0px), 56px) 0 var(--nf-pad, 0px);
}

/* week grid · the far plane: columns, week labels, zone captions, tier labels */
.nf-grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transform: translate3d(calc(var(--mx, 0) * 0.25px), calc(var(--my, 0) * 0.18px - var(--p, 0) * 20px), 0);
  opacity: calc(1 - var(--cv, 0) * 1.4);
}
.nf-grid i {
  position: absolute;
  top: 6%; bottom: 6%;
  width: 1px;
  background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, 0.1) 14%, rgba(255, 255, 255, 0.1) 86%, transparent);
  transition: background 500ms var(--ease-out), box-shadow 500ms var(--ease-out);
  animation: nfBootFade 500ms var(--ease-out) backwards;
}
/* the uncertainty fan · deeper weeks are visibly less certain */
.nf-grid i:nth-of-type(1) { animation-delay: 650ms; }
.nf-grid i:nth-of-type(2) { opacity: 0.8; animation-delay: 770ms; }
.nf-grid i:nth-of-type(3) { opacity: 0.62; animation-delay: 890ms; }
.nf-grid i:nth-of-type(4) { opacity: 0.45; animation-delay: 1010ms; }
.nf-grid b { animation: nfBootFade 500ms var(--ease-out) backwards; }
.nf-grid b:nth-of-type(1) { animation-delay: 710ms; }
.nf-grid b:nth-of-type(2) { animation-delay: 830ms; }
.nf-grid b:nth-of-type(3) { animation-delay: 950ms; }
.nf-grid b:nth-of-type(4) { animation-delay: 1070ms; }
/* The boot stagger is set inline by the engine, not by :nth-of-type. Both
   .nf-cap and .nf-tier are spans, so the old nth-of-type(1)/(2) rules matched
   the two zone captions and selected no tier at all — tiers 1 and 2 booted at
   0ms and tiers 3 and 4 wore the delays meant for 1 and 2. Any further span
   added to .nf-grid would have shifted it again. */
.nf-tier { animation: nfBootFade 450ms var(--ease-out) backwards; }
.nf-cap { animation: nfBootFade 500ms var(--ease-out) 1550ms backwards; }
@keyframes nfBootFade { from { opacity: 0; } }
.nf-grid i.commit {
  background: linear-gradient(to bottom, transparent, rgb(var(--sig-green-lift-rgb) / 0.45) 14%, rgb(var(--sig-green-lift-rgb) / 0.45) 86%, transparent);
}
.nf-grid b, .nf-cap, .nf-tier {
  position: absolute;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-3xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
}
.nf-grid b {
  top: 8.5%;
  transform: translateX(-50%);
  color: var(--ink-text-2);
}
/* Above the control deck, not behind it. At 92.5% these captions cleared the
   deck only because they sat out at the viewport edges; once the instrument was
   registered to the 1200px container they moved inboard, straight under the
   deck's pill at every desktop width. */
.nf-cap { top: 88%; color: var(--ink-text-2); }
.nf-cap.past { color: var(--ink-text-2); }
/* The tier captions sit in the gutter between the copy and the chain, which is
   also the band the now-line now travels through — it starts at 49% and ends at
   65.5%, so for most of the story it is somewhere inside these four strings.
   There is no width where they can clear it: below ~1200px the copy column ends
   past 49%, so any position left of the line is under the headline instead.
   They therefore read as captions ON a ruler, which is what an instrument does,
   and the scrim is what keeps that legible where the line passes. Same idiom as
   .nf-delta, which has the same job over the lanes. */
.nf-tier {
  left: 51.5%;
  transform: translateY(-50%);
  letter-spacing: 0.12em;
  color: var(--ink-text-2);
  text-shadow: 0 0 7px rgba(9, 18, 32, 0.98), 0 0 3px rgba(9, 18, 32, 0.95), 0 1px 2px rgba(9, 18, 32, 0.9);
}

/* the now-line · crisp core glued to the grid plane; it slides right as the
   four platform layers settle into view */
/* --nfx is the line's x IN THE TILT PLANE, in px, published per frame by the
   engine; --nfxf is the same point measured in the unpadded field, for the two
   elements that deliberately live outside the tilt. The position used to be a
   49% literal repeated in four rules, which is why the line could never move.
   Both default to 0 so a lens that never sets them is simply not affected. */
.nf-nowline {
  position: absolute;
  left: 0;
  top: 5%; bottom: 5%;
  width: 2px;
  border-radius: var(--radius-pill);
  background: linear-gradient(to bottom, transparent, var(--sig-green) 12%, var(--sig-green) 88%, transparent);
  opacity: calc(0.85 * (1 - var(--cv, 0) * 1.18));
  transform: translate3d(calc(var(--nfx, 0) * 1px + var(--mx, 0) * 0.25px + var(--cv, 0) * 34vw), calc(var(--my, 0) * 0.18px), 0);
  transform-origin: top;
  animation: nfBootLine 800ms var(--ease-out) 350ms backwards;
  pointer-events: none;
}
/* glow discipline · the halo is a pseudo-element and only its opacity breathes */
.nf-nowline::after {
  content: "";
  position: absolute;
  inset: -2px -4px;
  border-radius: inherit;
  box-shadow: var(--glow-live-ink);
  opacity: 0.5;
  animation: nfBreathe 4s ease-in-out infinite;
}
@keyframes nfBreathe {
  0%, 100% { opacity: 0.3; }
  50%      { opacity: 0.9; }
}
@keyframes nfBootLine { from { transform: scaleY(0); } }
.nf-nowtag {
  position: absolute;
  left: 12px;
  top: 8.5%;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sig-green-lift);
  white-space: nowrap;
  opacity: calc(1 - var(--cv, 0) * 1.18);
  transform: translate3d(calc(var(--nfx, 0) * 1px + var(--mx, 0) * 0.25px + var(--cv, 0) * 34vw), calc(var(--my, 0) * 0.18px), 0);
  animation: nfBootFade 400ms var(--ease-out) 1050ms backwards;
  pointer-events: none;
}
/* split-depth trick · the line's soft bloom floats on the nearest plane */
.nf-nowbloom {
  position: absolute;
  left: 0;
  top: 0; bottom: 0;
  width: 60px;
  opacity: calc(1 - var(--cv, 0) * 1.3);
  /* --nfxf, not --nfx: this one is appended to the field rather than the tilt
     (the comment above explains why), so it needs the point measured in the
     unpadded box or it would sit one pad-width left of its own line. */
  transform: translate3d(calc(var(--nfxf, 0) * 1px + var(--mx, 0) * 2.1px + var(--cv, 0) * 34vw), calc(var(--my, 0) * 1.6px), 0);
  will-change: transform;
  pointer-events: none;
}
/* blurred bloom on a static child · rasters once, parent just translates it */
.nf-nowbloom::before {
  content: "";
  position: absolute;
  inset: 0;
  /* softer and wider than it was (0.15 over 60px, blur 9): at that strength the
     bloom had a readable right edge and the pair read as a shaded vertical
     band beside the line rather than as light coming off it */
  background: linear-gradient(90deg, rgb(var(--sig-green-rgb) / 0.085), transparent 68%);
  filter: blur(16px);
}

/* the settlement wake · the width of ground NOW has crossed this loop.
   It spans the four tier bands only (16/38/60/82%), staying clear of the week
   labels above and the zone captions below. Cool-white at 5% because it lands
   under the headline: the donor's wedge on the movement dial can afford weight
   because nothing is reading over it, and this one cannot. */
.nf-wake {
  position: absolute;
  left: 0;
  top: 11%; bottom: 12%;
  width: 1px;
  transform: translateX(calc(var(--nfx, 0) * 1px + var(--cv, 0) * 34vw)) scaleX(var(--nfwake, 0));
  transform-origin: right center;
  background: linear-gradient(90deg, transparent, rgb(var(--ink-text-3-rgb) / 0.05) 35%, rgb(var(--ink-text-3-rgb) / 0.07));
  opacity: calc(1 - var(--cv, 0) * 1.4);
  /* feathered top and bottom · square ends made it read as a panel laid over
     the field rather than as ground the line has already crossed */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent);
          mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent);
  pointer-events: none;
}
/* the week the NOW tag is already naming · the ruler yields to the cursor */
.nf-grid b.stood-down { opacity: 0; }

/* the predictable peak · information, not risk and not a decision, so teal and
   never anything else. It rides the axis furniture at the top of the W+3
   column, above the week labels and clear of every node, and hangs to the LEFT
   of its column so a long string cannot be clipped by the pin's overflow. */
.nf-peak {
  position: absolute;
  /* rides the W+3 column · remapX(82) when the now-line moved 49% → 42%, and it
     has to keep landing ON that column or the marker stops annotating a week */
  left: 80.4%;
  /* In the open band between the packhouse and depot tiers. It cannot ride the
     week-label row (that row sits at 8.5%, just clear of the fixed nav, and its
     own W+3 label is already there), and at 26% it ran into the soft-fruit chip
     at 68%,26%. Its dot lands on the column itself, so the marker reads as an
     annotation of that week from any height. */
  top: 42%;
  transform: translateX(-100%);
  padding-right: 9px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-3xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  /* --signal-ink, not --f4-signal · the system keeps the raw signal hue for
     fills and reserves the lifted step for teal TEXT on an ink ground, which is
     what this is (see .cg-over, the only other teal text in the build) */
  color: var(--signal-ink);
  /* a legibility scrim, not emitted light · the same idiom .nf-delta uses */
  text-shadow: 0 1px 6px rgba(9, 18, 32, 0.95), 0 0 2px rgba(9, 18, 32, 0.9);
  animation: nfBootFade 500ms var(--ease-out) 1450ms backwards;
}
/* the dot is a fill, so it keeps the raw signal hue */
.nf-peak::after {
  content: "";
  position: absolute;
  right: 0; top: 50%;
  width: 5px; height: 5px;
  margin-top: -2.5px;
  border-radius: 50%;
  background: var(--f4-signal);
}

/* forecast commit sweep · leaves the now-line on the story clock's cue */
.nf-sweep {
  position: absolute;
  left: 0;
  top: 5%; bottom: 5%;
  width: 90px;
  translate: calc(var(--nfx, 0) * 1px + var(--cv, 0) * 34vw) 0;
  background: linear-gradient(90deg, rgb(var(--sig-green-rgb) / 0.15), rgb(var(--sig-green-rgb) / 0.04) 60%, transparent);
  opacity: 0;
  pointer-events: none;
}
.nf-sweep.go { animation: nfSweep 2.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
@keyframes nfSweep {
  from { transform: translateX(0); opacity: 0; }
  10%  { opacity: 1; }
  to   { transform: translateX(44vw); opacity: 0; }
}

/* chain nodes · squares are facilities, circles are fields and shelves;
   settled actuals are filled and dim, projections are hollow rings.
   State enters fast and decays slowly (the commit residue, the amber drain);
   they boot in past-to-future via a per-node inline delay from the engine. */
.nf-node {
  position: absolute;
  pointer-events: none;
  /* opacity is in the list because settlement swaps .fut for .past as NOW
     crosses a mark, and the two carry different opacity expressions · without
     it the projection would not fade into an actual, it would jump */
  transition: box-shadow 400ms var(--ease-out), background 1200ms var(--ease-out), border-color 1200ms var(--ease-out), opacity 900ms var(--ease-out);
  animation: nfBootNode 600ms var(--ease-out) backwards;
}
.nf-node.commit, .nf-node.hit-amber { transition-duration: 400ms, 250ms, 250ms, 900ms; }
.f-chip, .nf-speck { animation: nfBootNode 600ms var(--ease-out) backwards; }
@keyframes nfBootNode { from { opacity: 0; transform: translate3d(0, 7px, 0) scale(0.55); } }
.nf-g { width: 6px; height: 6px; margin: -3px 0 0 -3px; border-radius: 50%; color: rgba(255, 255, 255, 0.6); }
.nf-p { width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: var(--radius-xs); color: rgba(255, 255, 255, 0.6); }
.nf-d { width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: var(--radius-xs); color: var(--f4-blue-lift); }
.nf-r { width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 50%; color: var(--sig-green); }
.nf-node.past {
  background: var(--ink-700);
  border: 1px solid rgba(255, 255, 255, 0.28);
  opacity: calc(0.38 * (1 - var(--cv, 0) * 1.6));
}
.nf-r.past { background: var(--sig-green); border-color: transparent; }
.nf-node.fut {
  background: rgb(var(--f4-ink-rgb) / 0.55);
  border: 1.5px solid currentColor;
  opacity: calc(var(--fan, 1) * (0.92 - var(--cv, 0) * 0.6));
}
/* .fut is a structural class, not a state, so anything it emits burns for the
   life of the page · the flat ring stays (it reads as a projected depot), the
   14px halo goes */
.nf-d.fut { box-shadow: 0 0 0 4px rgb(var(--f4-blue-rgb) / 0.12); }
.nf-node.flare {
  border-color: var(--sig-green-pulse);
  box-shadow: var(--glow-live-ink);
}
/* commit beat · the sweep momentarily solidifies the near week */
.nf-node.commit { background: rgb(var(--sig-green-rgb) / 0.45); border-color: var(--sig-green); }
/* A settled mark can still be caught up in the drama — the scenarios target
   nodes by name, and NOW may already have crossed them. In the settled register
   (0.38) an amber strike or a green commit was barely visible, so a node the
   story is actively talking about looked inert. Any live state lifts it back to
   the forecast register for as long as that state is on. */
.nf-node.past.commit, .nf-node.past.hit-amber, .nf-node.past.flare, .nf-node.past.solved {
  opacity: calc(0.92 - var(--cv, 0) * 0.6);
}
/* ripple states · amber is the only issue colour, and it always gets caught
   (.f-chip.blue.hit-amber keeps the strike visible on blue chips: .f-chip.blue
   re-declares the same properties later in the file at equal specificity) */
.nf-node.hit-amber, .f-chip.hit-amber, .f-chip.blue.hit-amber {
  border-color: var(--f4-warn);
  color: var(--warn-ink);
  background: rgb(var(--f4-warn-rgb) / 0.24);
  box-shadow: var(--glow-warn-ink);
}

/* ghost echoes · this node next week, and the week after (fold home on scroll) */
.nf-ghost {
  position: absolute;
  top: 50%; left: 50%;
  width: 7px; height: 7px;
  border: 1px solid currentColor;
  border-radius: inherit;
  opacity: 0.32;
  transform: translate(-50%, -50%)
             translateX(calc(var(--nfgx, 150) * max(0, 1 - var(--cv, 0) * 3.2) * 1px));
  pointer-events: none;
}
.nf-ghost.g2 {
  opacity: 0.16;
  transform: translate(-50%, -50%)
             translateX(calc(var(--nfgx, 150) * max(0, 1 - var(--cv, 0) * 3.2) * 2px));
}
/* the projection reacts before the front arrives · see earlier, literally */
.nf-node.warnblink .nf-ghost { animation: nfWarn 900ms linear; }
@keyframes nfWarn {
  0%, 100% { border-color: currentColor; }
  15%, 45%, 75% { border-color: var(--f4-warn); opacity: 0.95; }
  30%, 60%, 90% { opacity: 0.2; }
}
/* the forecast updates because the platform acted */
.nf-node.ghostblink .nf-ghost { animation: nfGhostUpdate 600ms ease-out; }
@keyframes nfGhostUpdate {
  0% { border-color: var(--sig-green-pulse); opacity: 0.95; }
  100% { border-color: currentColor; }
}

/* crop-row field marks · the chain starts in an actual field */
.nf-fieldmark {
  position: absolute;
  right: calc(100% + 5px);
  bottom: calc(100% - 2px);
  width: 13px; height: 11px;
  background: repeating-linear-gradient(115deg, currentColor 0 1px, transparent 1px 4px);
  opacity: 0.5;
  transition: opacity 300ms var(--ease-out), filter 300ms var(--ease-out);
  pointer-events: none;
}
/* hail hits the field first · a white strobe, then the amber story */
.nf-node.hail .nf-fieldmark {
  color: var(--surface-1);
  opacity: 1;
  filter: drop-shadow(0 0 7px rgb(var(--f4-warn-rgb) / 0.8));
  animation: nfHail 380ms steps(2, jump-none) 3;
}
@keyframes nfHail {
  0%   { color: #FFFFFF; opacity: 1; }
  100% { color: var(--f4-warn); opacity: 0.55; }
}

/* cascade micro-deltas · each struck point names its own consequence */
.nf-delta {
  position: absolute;
  left: calc(100% + 8px);
  top: 50%;
  font-family: var(--font-mono);
  font-style: normal;
  font-weight: 500;
  font-size: var(--fs-4xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--warn-ink);
  text-shadow: 0 1px 6px rgba(9, 18, 32, 0.95), 0 0 2px rgba(9, 18, 32, 0.9);
  opacity: 0;
  transform: translateY(-50%) translateX(-4px);
  transition: opacity 280ms var(--ease-out), transform 280ms var(--ease-out);
  pointer-events: none;
}
.nf-delta.show { opacity: 1; transform: translateY(-50%) translateX(0); }
/* the recovery · the platform's decision shows up in the numbers */
.nf-delta { transition: opacity 280ms var(--ease-out), transform 280ms var(--ease-out), color 350ms var(--ease-out); }
.nf-delta.ok { color: var(--sig-green-lift); }

/* atmosphere · a few remnant specks on the horizon side */
.nf-speck {
  position: absolute;
  width: 3px; height: 3px;
  border-radius: 50%;
  background: rgba(180, 220, 190, 0.5);
  opacity: calc(0.22 * (1 - var(--cv, 0) * 1.5));
}

/* issue ignition ring · expands twice from the struck node */
.nf-ring {
  position: absolute;
  inset: -4px;
  border: 1.5px solid var(--f4-warn);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}
.nf-ring.go { animation: nfRing 800ms ease-out 2; }
@keyframes nfRing {
  from { transform: scale(0.5); opacity: 0.9; }
  to   { transform: scale(3.2); opacity: 0; }
}

/* the catch · a green reticle snaps shut around the ripple front */
.nf-reticle {
  position: absolute;
  inset: -8px;
  border: 1.5px solid var(--sig-green);
  border-radius: 50%;
  box-shadow: var(--glow-live-ink);
  opacity: 0;
  transform: scale(1.9);
  transition: opacity 250ms var(--ease-out), transform 500ms var(--ease-out);
  pointer-events: none;
}
.nf-reticle.go { opacity: 1; transform: scale(1); }
/* the solved tick · every catch ends with a literal check (scale-pop entry) */
.nf-reticle::after {
  content: "\2713";
  position: absolute;
  top: -14px; right: -11px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--sig-green-lift);
  text-shadow: var(--glow-live-ink);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 280ms var(--ease-out) 220ms, transform 280ms var(--ease-out) 220ms;
}
.nf-node.solved .nf-reticle::after { opacity: 1; transform: scale(1); }

/* roving control-tower alert · teal = signal, per the product's own state colours */
.nf-alert {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translate(-50%, 4px);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-3xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--signal-ink);
  background: rgba(9, 18, 32, 0.85);
  border: 1px solid rgb(var(--f4-signal-rgb) / 0.45);
  border-radius: var(--radius-pill);
  padding: 0.2rem 0.625rem;
  opacity: 0;
  transition: opacity 250ms var(--ease-out), transform 250ms var(--ease-out);
  pointer-events: none;
}
.nf-alert::before {
  content: "";
  display: inline-block;
  width: 5px; height: 5px;
  margin-right: 7px;
  border-radius: 50%;
  background: var(--f4-signal);
  /* flat, matching its structural twin .nf-move::before · this was the hottest
     hand-rolled halo in the namespace and it sat on a mark that never moves */
  vertical-align: 1px;
}
.nf-alert.show { opacity: 1; transform: translate(-50%, 0); }

/* planning move · the modules speak in green: a decision, not an alarm */
.nf-move {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translate(-50%, 4px);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-3xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--sig-green-lift);
  background: rgba(9, 18, 32, 0.85);
  border: 1px solid rgb(var(--sig-green-lift-rgb) / 0.45);
  border-radius: var(--radius-pill);
  padding: 0.2rem 0.625rem;
  opacity: 0;
  transition: opacity 250ms var(--ease-out), transform 250ms var(--ease-out);
  pointer-events: none;
}
.nf-move::before {
  content: "";
  display: inline-block;
  width: 5px; height: 5px;
  margin-right: 7px;
  border-radius: 50%;
  background: var(--sig-green);
  vertical-align: 1px;
}
.nf-move.show { opacity: 1; transform: translate(-50%, 0); }

/* the hero control deck · one grouped, labelled bar carrying the four lenses
   and the three disruption signals. Centred in the container, opaque ink (no
   glassmorphism on chrome), fades out as the layer stack assembles. */
.hero-deck {
  position: absolute;
  left: 50%;
  bottom: 30px;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 16px;
  max-width: min(1200px, calc(100% - 48px));
  padding: 8px 10px 8px 16px;
  border-radius: var(--radius-pill);
  background: rgba(9, 18, 32, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: var(--specular-ink), 0 10px 30px -12px rgba(0, 0, 0, 0.6);
  opacity: calc(1 - var(--cv, 0) * 2.5);
  animation: nfBootFade 500ms var(--ease-out) 1900ms backwards;
}
.deck-group { display: flex; align-items: center; gap: 10px; }
.deck-label {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-3xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-text-3);
  white-space: nowrap;
}
.deck-btns { display: flex; align-items: center; gap: 6px; }
.deck-div { width: 1px; align-self: stretch; margin: 4px 2px; background: rgba(255, 255, 255, 0.12); }
.deck-btn {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  color: var(--ink-text-2);
  min-height: 32px;
  padding: 0.35rem 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.02);
  cursor: pointer;
  white-space: nowrap;
  transition: color 180ms var(--ease-out), border-color 180ms var(--ease-out), background 180ms var(--ease-out);
}
.deck-btn:hover, .deck-btn:focus-visible {
  color: #fff;
  border-color: rgb(var(--sig-green-lift-rgb) / 0.55);
  background: rgb(var(--sig-green-rgb) / 0.1);
}
.deck-btn:focus-visible { outline: 2px solid var(--sig-green-lift); outline-offset: 3px; }
/* the active lens · the one persistent state in the deck */
.deck-tab.is-on {
  color: #fff;
  border-color: rgb(var(--sig-green-lift-rgb) / 0.7);
  background: rgb(var(--sig-green-rgb) / 0.16);
}
.deck-tab.is-on::before {
  content: "\25C6\00A0";
  color: var(--sig-green-lift);
}
/* the signals read as actions · a small play caret */
.deck-run::before { content: "\25B8\00A0"; color: var(--sig-green-lift); }
/* below the full-experience width the group labels step aside so the deck
   stays a single row · the divider, active state and carets still group it */
@media (max-width: 1279px) {
  .hero-deck { gap: 12px; padding-left: 12px; }
  .deck-label { display: none; }
  .deck-btns { gap: 5px; }
  .deck-btn { padding: 0.35rem 0.6rem; letter-spacing: 0.02em; }
}

/* cause chip · the issue named at its node, amber, factual */
.nf-cause {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translate(-50%, 4px);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--warn-ink);
  background: rgba(9, 18, 32, 0.85);
  border: 1px solid rgb(var(--f4-warn-rgb) / 0.45);
  border-radius: var(--radius-pill);
  padding: 0.2rem 0.625rem;
  opacity: 0;
  transition: opacity 250ms var(--ease-out), transform 250ms var(--ease-out);
  pointer-events: none;
}
.nf-cause.show { opacity: 1; transform: translate(-50%, 0); }
/* the ship chip hugs the right edge · its cause pill right-aligns to stay on screen */
.f-chip .nf-cause { left: auto; right: -6px; transform: translate(0, 4px); }
.f-chip .nf-cause.show { transform: translate(0, 0); }
/* grower-lane origins sit under the week ruler · their cause pill flips below
   the node so the week axis stays clean */
.nf-g .nf-cause { bottom: auto; top: calc(100% + 10px); }

/* floating signal chips · glass badges pulled into the bands */
.f-chip {
  position: absolute;
  width: 52px; height: 52px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--sig-green-lift);
  background: linear-gradient(180deg, rgb(var(--sig-green-lift-rgb) / 0.16), rgb(var(--sig-green-lift-rgb) / 0.04));
  border: 1px solid rgb(var(--sig-green-lift-rgb) / 0.38);
  /* Specular edge and contact shadow only. The 28px coloured halo that used to
     sit between them is gone: ten chips carrying one each were the bulk of the
     hero's resting glow, and "a bloom is a verb, not a finish" cannot be true
     of the page while a dozen marks glow at rest. The halo comes back on touch,
     below, where it means something. */
  box-shadow: var(--specular-ink-2),
              0 14px 30px -14px rgba(0, 0, 0, 0.6);
  opacity: calc(1 - 0.88 * var(--cv, 0));
  transition: box-shadow 260ms var(--ease-out);
}
.f-chip:hover, .f-chip:focus-visible {
  box-shadow: var(--specular-ink-2), var(--glow-live-ink),
              0 14px 30px -14px rgba(0, 0, 0, 0.6);
}
/* a chip that is currently in trouble keeps its amber under the cursor · touch
   must not be able to repaint a risk as a healthy mark */
.f-chip.hit-amber:hover, .f-chip.hit-amber:focus-visible,
.f-chip.blue.hit-amber:hover, .f-chip.blue.hit-amber:focus-visible {
  box-shadow: var(--specular-ink-2), var(--glow-warn-ink),
              0 14px 30px -14px rgba(0, 0, 0, 0.6);
}
/* NB source order: this block re-declares .f-chip's shadow at equal specificity
   and must stay AFTER it, which is also what keeps the amber strike visible on
   blue chips (see the .nf-node.hit-amber note above). Edit in place; do not
   move it. Same discipline as the green chip: flat at rest. */
.f-chip.blue {
  color: var(--f4-blue-lift);
  background: linear-gradient(180deg, rgb(var(--f4-blue-rgb) / 0.18), rgb(var(--f4-blue-rgb) / 0.05));
  border-color: rgb(var(--f4-blue-rgb) / 0.4);
  box-shadow: var(--specular-ink-2),
              0 14px 30px -14px rgba(0, 0, 0, 0.6);
}
.f-chip.blue:hover, .f-chip.blue:focus-visible {
  box-shadow: var(--specular-ink-2), var(--glow-ref-ink),
              0 14px 30px -14px rgba(0, 0, 0, 0.6);
}

/* chips reward the cursor: brighten + reveal their mono label */
.f-chip { pointer-events: auto; cursor: default; }
.f-chip svg { transition: transform 260ms var(--ease-out); }
.f-chip:hover svg { transform: scale(1.2); }
.f-chip:hover { border-color: currentColor; }
.f-chip::before {
  content: attr(data-label);
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translate(-50%, 4px);
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(226, 234, 242, 0.9);
  background: rgba(9, 18, 32, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-pill);
  padding: var(--space-4) var(--space-10);
  opacity: 0;
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
}
.f-chip:hover::before { opacity: 1; transform: translate(-50%, 0); }

/* Atmospheric depth on the nearest plane, not glowing orbs. The brief
   bans decorative circles and excessive glow: these were 400px green
   blooms. Now a faint cool haze, barely there, that only registers as the
   pointer parallaxes it, the way depth-of-field softens a far field. */
.bokeh {
  position: absolute;
  width: 440px; height: 440px;
  opacity: calc(0.5 * (1 - 0.7 * var(--cv, 0)));
  pointer-events: none;
  transform: translate3d(calc(var(--mx, 0) * var(--z, 1.5) * 1px),
                         calc((var(--my, 0) * var(--z, 1.5) - var(--p, 0) * 80) * 1px), 0);
  will-change: transform;
}
/* the 56px blur — the biggest banding/raster cost — lives on a static child so
   the parallax never re-rasters it */
.bokeh::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(var(--f4-blue-rgb) / 0.10), transparent 70%);
  filter: blur(56px);
}
.bokeh.blue { width: 360px; height: 360px; }
.bokeh.blue::before { background: radial-gradient(circle, rgb(var(--f4-blue-rgb) / 0.08), transparent 70%); }

/* four-layer stack · settles upward as the dots converge */
.layer-stack {
  position: absolute;
  inset: 6% 4%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-14);
  /* the cards are links, so they hold still under the pointer (no parallax) */
  transform: translateY(calc((1 - var(--cv, 1)) * 30px));
}
.layer-row {
  position: relative;
  z-index: 1;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--radius-card);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.065), rgba(255, 255, 255, 0.02));
  box-shadow: var(--specular-ink), 0 16px 40px -24px rgba(0, 0, 0, 0.55);
  padding: var(--space-16) var(--space-24);
  display: flex;
  align-items: center;
  gap: var(--space-16);
  min-height: 66px;
  opacity: 0;
  transform: translateY(14px) scale(0.98);
  transition: opacity 600ms var(--ease-out), transform 600ms var(--ease-out),
              border-color 500ms var(--ease-out), box-shadow 500ms var(--ease-out), background 500ms var(--ease-out);
}
/* The home hero assembles these links on scroll. Before the first visible beat
   they are also absent from hit-testing; sequences.js mirrors the state with
   aria-hidden and tabindex=-1 for keyboard and assistive-technology users. */
.seqA-pin:not([data-beat]) .layer-row,
.seqA-pin[data-beat="0"] .layer-row {
  visibility: hidden;
  pointer-events: none;
}
.seqA-pin[data-beat="1"] .layer-row,
.seqA-pin[data-beat="2"] .layer-row,
.seqA-pin[data-beat="3"] .layer-row {
  visibility: visible;
  pointer-events: auto;
}
.layer-row:focus-visible {
  outline: 2px solid var(--sig-green-lift);
  outline-offset: 3px;
}
.layer-row .lr-jump {
  flex: none;
  color: var(--sig-green-lift);
  font-family: var(--font-mono);
  transition: transform 200ms var(--ease-out);
}
.layer-row:hover .lr-jump,
.layer-row:focus-visible .lr-jump { transform: translateY(3px); }
.layer-row .lr-verb {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-text-2);
  min-width: 96px;
  transition: color 400ms var(--ease-out);
}
.layer-row .lr-name { font-weight: 600; color: #fff; font-size: var(--fs-md); letter-spacing: -0.005em; }
.layer-row .lr-cap {
  margin-left: auto;
  font-size: var(--fs-cap);
  color: var(--ink-text-3);
  opacity: 0;
  transition: opacity 500ms 150ms var(--ease-out);
  text-align: right;
}
.layer-row.lit {
  border-color: rgb(var(--sig-green-lift-rgb) / 0.55);
  background: linear-gradient(180deg, rgb(var(--sig-green-lift-rgb) / 0.1), rgb(var(--sig-green-lift-rgb) / 0.03));
  box-shadow: var(--specular-ink-2),
              0 0 0 1px rgb(var(--sig-green-lift-rgb) / 0.22),
              0 12px 44px -14px rgb(var(--sig-green-rgb) / 0.45);
}
.layer-row.lit .lr-verb { color: var(--sig-green-lift); }
.layer-row.lit .lr-cap { opacity: 1; }

/* module dots inside ACTS row */
.lr-mods { display: flex; gap: var(--space-8); margin-left: auto; }
/* the platform hero's layer links: the arrow sits at the row's end, and the
   band a row jumps to clears the fixed header (week 44) */
.layer-stack > a.layer-row .lr-jump { margin-left: auto; }
.layer-stack > a.layer-row .lr-mods, .layer-stack > a.layer-row .lr-cap { margin-left: 0; }
.layer-stack > a.layer-row:hover { border-color: rgb(var(--sig-green-lift-rgb) / 0.45); }
.layer-band[id] { scroll-margin-top: 96px; }
.lr-mods i {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--sig-green);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 400ms var(--ease-out), transform 400ms var(--ease-out);
}
.layer-row.lit .lr-mods i { opacity: 1; transform: scale(1); }
.layer-row.lit .lr-mods i:nth-child(2) { transition-delay: 60ms; }
.layer-row.lit .lr-mods i:nth-child(3) { transition-delay: 120ms; }
.layer-row.lit .lr-mods i:nth-child(4) { transition-delay: 180ms; }
.layer-row.lit .lr-mods i:nth-child(5) { transition-delay: 240ms; }
.layer-row.lit .lr-mods i:nth-child(6) { transition-delay: 300ms; }

/* beat-driven band appearance */
[data-beat="1"] .layer-row, [data-beat="2"] .layer-row, [data-beat="3"] .layer-row {
  opacity: 1; transform: none;
}
[data-beat="1"] .layer-row:nth-child(2) { transition-delay: 80ms; }
[data-beat="1"] .layer-row:nth-child(3) { transition-delay: 160ms; }
[data-beat="1"] .layer-row:nth-child(4) { transition-delay: 240ms; }

/* ---- the home hero's four layers, refined (24 Oct 2026) ----
   One rail and four hairline cards, each with its layer's icon, its line on two
   short lines, and a small glyph that says what the layer does. Green goes on
   the verbs and the rail only, so it means something again: a lit card no
   longer glows. The platform hero's stack keeps the older rows. */
.seqA .layer-stack { gap: var(--space-10); padding-left: 26px; }
.seqA .layer-row,
.seqA .layer-row.lit {
  gap: var(--space-14);
  min-height: 0;
  padding: var(--space-14) var(--space-16);
  border-color: rgb(255 255 255 / 0.1);
  background: linear-gradient(180deg, rgb(255 255 255 / 0.045), rgb(255 255 255 / 0.015));
  box-shadow: var(--specular-ink), 0 18px 40px -28px rgb(0 0 0 / 0.7);
}
.seqA .layer-row:hover { border-color: rgb(var(--sig-green-lift-rgb) / 0.45); }
/* the rail · a node per layer, and a hairline down to the next one */
.seqA .layer-row::before {
  content: "";
  position: absolute; left: -22px; top: 50%;
  width: 7px; height: 7px; margin-top: -3.5px;
  border-radius: 50%;
  background: var(--ink-800);
  border: 1.5px solid rgb(var(--sig-green-lift-rgb) / 0.55);
  transition: background 320ms var(--ease-out), border-color 320ms var(--ease-out);
}
.seqA .layer-row:not(:last-child)::after {
  content: "";
  position: absolute; left: -19px; top: calc(50% + 5px);
  width: 1px; height: calc(100% + var(--space-10) - 10px);
  background: rgb(var(--sig-green-lift-rgb) / 0.28);
}
.seqA .layer-row.lit::before, .seqA .layer-row:hover::before { background: var(--sig-green-lift); border-color: var(--sig-green-lift); }
.lr-ic {
  position: relative;   /* a corner mark can sit on the tile */
  flex: none;
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: var(--radius-btn);
  background: rgb(255 255 255 / 0.05);
  border: 1px solid rgb(255 255 255 / 0.1);
  color: var(--ink-text-1);
}
.lr-ic svg { width: 19px; height: 19px; }
.lr-txt { flex: 1; min-width: 0; display: grid; gap: 2px; }
.seqA .layer-row .lr-verb { min-width: 0; font-size: var(--fs-3xs); letter-spacing: 0.16em; line-height: 1.2; }
.seqA .layer-row .lr-name { font-size: var(--fs-lg); line-height: 1.25; white-space: nowrap; }
.seqA .layer-row .lr-cap { margin-left: 0; text-align: left; line-height: 1.35; }
.seqA .layer-row .lr-jump { color: var(--ink-text-3); }
.seqA .layer-row:hover .lr-jump, .seqA .layer-row:focus-visible .lr-jump { color: var(--sig-green-lift); }
/* the glyph · it plays once as its layer lights */
.lr-glyph { flex: none; width: 112px; height: 34px; display: flex; align-items: center; justify-content: flex-end; color: var(--ink-text-2); }
.lg { overflow: visible; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.lg-line { stroke-width: 1.6; opacity: 0.7; stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset 700ms var(--ease-out) 150ms; }
.lg-tip { stroke: var(--f4-warn); stroke-width: 1.6; opacity: 0; transition: opacity 240ms var(--ease-out) 760ms; }
.lg-blip { fill: var(--f4-warn); stroke: none; opacity: 0; transform-box: fill-box; transform-origin: center; transform: scale(0.3); transition: opacity 240ms var(--ease-out) 800ms, transform 420ms var(--ease-out) 800ms; }
.lg-ring { stroke: var(--f4-warn); stroke-width: 1; opacity: 0; transform-box: fill-box; transform-origin: center; }
.lit .lg-line { stroke-dashoffset: 0; }
.lit .lg-tip, .lit .lg-blip { opacity: 1; }
.lit .lg-blip { transform: none; }
.lit .lg-ring { animation: lgPing 1100ms var(--ease-out) 900ms both; }
@keyframes lgPing { from { opacity: 0.7; transform: scale(0.5); } to { opacity: 0.35; transform: scale(1); } }
.lg-bubble { stroke-width: 1.4; opacity: 0.7; }
.lg-dot { fill: currentColor; stroke: none; opacity: 0; transition: opacity 260ms var(--ease-out); }
.lit .lg-dot:nth-of-type(1) { opacity: 1; transition-delay: 250ms; }
.lit .lg-dot:nth-of-type(2) { opacity: 0.7; transition-delay: 450ms; }
.lit .lg-dot:nth-of-type(3) { opacity: 0.4; transition-delay: 650ms; }
/* a reply forming · the dots type while the card is pointed at */
.seqA .layer-row:hover .lg-dot { animation: lgType 1.2s ease-in-out infinite; }
.seqA .layer-row:hover .lg-dot:nth-of-type(2) { animation-delay: 160ms; }
.seqA .layer-row:hover .lg-dot:nth-of-type(3) { animation-delay: 320ms; }
@keyframes lgType { 0%, 100% { opacity: 0.35; } 40% { opacity: 1; } }
.lg-axis { stroke-width: 1; opacity: 0.35; }
.lg-ticks { stroke-width: 2; opacity: 0.55; }
.lg-stem { stroke: var(--sig-green-lift); stroke-width: 1.4; opacity: 0; transition: opacity 260ms var(--ease-out) 620ms; }
.lg-pick { fill: var(--sig-green-lift); stroke: none; opacity: 0; transform: translateY(-9px); transition: opacity 300ms var(--ease-out) 300ms, transform 520ms var(--ease-out) 300ms; }
.lit .lg-stem, .lit .lg-pick { opacity: 1; }
.lit .lg-pick { transform: none; }
/* Acts · the six modules' own icons from the menu, landing one by one */
.seqA .lr-mods { gap: 5px; margin-left: 0; }
.seqA .lr-mods i { display: grid; place-items: center; width: 16px; height: 16px; border-radius: 0; background: none; color: var(--ink-text-2); }
.seqA .lr-mods i svg { width: 15px; height: 15px; }

/* hero scroll hint · superseded by the control deck at the hero's foot */
.scroll-hint {
  position: absolute;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-text-3);
  display: none; /* the deck now owns the hero's foot */
  flex-direction: column; align-items: center; gap: var(--space-8);
  transition: opacity 400ms var(--ease-out);
}
.scroll-hint::after {
  content: "";
  width: 1.5px; height: 26px;
  background: linear-gradient(to bottom, rgb(var(--ink-text-3-rgb) / .8), transparent);
  animation: hintPulse 1.8s ease-in-out infinite;
}
[data-beat="2"] .scroll-hint, [data-beat="3"] .scroll-hint { opacity: 0; }
@keyframes hintPulse { 0%,100% { opacity: .3; } 50% { opacity: 1; } }

/* mini-map (desktop, home only) */
/* layer minimap · the platform spine, a floating instrument on the left */
.layer-minimap {
  position: fixed;
  left: 20px;
  top: 50%;
  z-index: var(--z-sticky);
  display: flex;
  flex-direction: column;
  gap: var(--space-14);
  padding: var(--space-20) var(--space-20) var(--space-20) var(--space-18);
  border-radius: var(--radius-card);
  border: 1px solid var(--f4-line);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(-50%) translateX(-12px);
  pointer-events: none;
  transition: opacity 450ms var(--ease-out), transform 450ms var(--ease-out),
              background 300ms var(--ease-out), border-color 300ms var(--ease-out), box-shadow 300ms var(--ease-out);
}
.layer-minimap.show { opacity: 1; transform: translateY(-50%); pointer-events: auto; }
.layer-minimap.on-dark {
  border-color: var(--f4-line-dark);
  background: var(--ink-700);
  box-shadow: var(--shadow-ink-lg);
}
/* each row is a station: [dot on the thread] · [icon] · [label] */
.layer-minimap a {
  position: relative;
  display: grid;
  grid-template-columns: 16px 20px auto;
  align-items: center;
  column-gap: var(--space-8);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--f4-slate);
  transition: color 250ms var(--ease-out), opacity 350ms var(--ease-out), transform 350ms var(--ease-out);
}
/* the station · a node sitting on the thread, breaking it cleanly */
.layer-minimap a::before {
  content: "";
  grid-column: 1;
  justify-self: center;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--f4-paper);
  border: 1.5px solid rgba(91, 107, 123, 0.55);
  box-shadow: 0 0 0 3.5px rgb(var(--f4-paper-rgb) / 0.92);
  z-index: 1;
  transition: background 250ms var(--ease-out), border-color 250ms var(--ease-out), transform 250ms var(--ease-out), box-shadow 250ms var(--ease-out);
}
/* the four layer icons · the same set the platform page uses */
.mm-ic {
  grid-column: 2;
  justify-self: center;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px;
  color: var(--f4-slate);
  transition: color 250ms var(--ease-out), transform 250ms var(--ease-out), filter 250ms var(--ease-out);
}
.mm-ic svg { width: 17px; height: 17px; }
/* At rest the minimap is a compact spine of dots and icons, narrow enough
   to sit in the gutter beside a 1200px container without touching the
   headings; the labels expand on hover or keyboard focus. This is what
   lets it stay an opaque instrument (no glass) instead of a translucent
   pane clipping text, which the frost used to hide. */
.layer-minimap a .mm-label {
  grid-column: 3;
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: max-width 320ms var(--ease-out), opacity 240ms var(--ease-out);
}
.layer-minimap:hover a .mm-label,
.layer-minimap:focus-within a .mm-label { max-width: 130px; opacity: 0.66; }
.layer-minimap:hover a:hover .mm-label { opacity: 1; }
.layer-minimap a:hover .mm-ic { transform: scale(1.1); color: var(--f4-ink); }
.layer-minimap a:hover::before { border-color: var(--sig-green); }

/* below 1600px the gutter is too tight for the labels to expand without
   crossing into the 1200px container, so the spine stays icons-only there;
   the label expansion is allowed only from 1600px up (24px+ gutter clearance). */
@media (max-width: 1399px) {
  .layer-minimap:hover a .mm-label,
  .layer-minimap:focus-within a .mm-label { max-width: 0; opacity: 0; }
}

/* active · you are here */
.layer-minimap a.active { color: var(--sig-green-text); }
.layer-minimap a.active .mm-label { opacity: 1; font-weight: 600; }
.layer-minimap a.active .mm-ic {
  color: var(--sig-green-deep);
  transform: scale(1.12);
  filter: drop-shadow(0 0 5px rgb(var(--sig-green-rgb) / 0.5));
}
.layer-minimap a.active::before {
  background: var(--sig-green);
  border-color: var(--sig-green);
  transform: scale(1.18);
  box-shadow: 0 0 0 3.5px rgb(var(--f4-paper-rgb) / 0.92), var(--glow-live-ink);
}

/* dark surfaces */
.layer-minimap.on-dark a { color: var(--ink-text-2); }
.layer-minimap.on-dark a.active { color: var(--sig-green-lift); }
.layer-minimap.on-dark .mm-ic { color: var(--ink-text-2); }
.layer-minimap.on-dark a.active .mm-ic { color: var(--sig-green-lift); }
.layer-minimap.on-dark a::before { background: var(--f4-ink); border-color: rgb(var(--ink-text-3-rgb) / 0.55); box-shadow: 0 0 0 3.5px rgb(var(--f4-ink-rgb) / 0.72); }
.layer-minimap.on-dark a.active::before { background: var(--sig-green-lift); border-color: var(--sig-green-lift); box-shadow: 0 0 0 3.5px rgb(var(--f4-ink-rgb) / 0.72), var(--glow-live-ink); }
/* arrival · the spine draws in and the layers land in sequence */
.layer-minimap a { opacity: 0; transform: translateX(-6px); }
.layer-minimap.show a { opacity: 1; transform: none; }
.layer-minimap.show a:nth-of-type(1) { transition-delay: 0ms, 110ms, 110ms; }
.layer-minimap.show a:nth-of-type(2) { transition-delay: 0ms, 155ms, 155ms; }
.layer-minimap.show a:nth-of-type(3) { transition-delay: 0ms, 200ms, 200ms; }
.layer-minimap.show a:nth-of-type(4) { transition-delay: 0ms, 245ms, 245ms; }
.layer-minimap.show a:nth-of-type(5) { transition-delay: 0ms, 290ms, 290ms; }
.layer-minimap.show a:nth-of-type(6) { transition-delay: 0ms, 335ms, 335ms; }
.layer-minimap.show a:nth-of-type(7) { transition-delay: 0ms, 380ms, 380ms; }
.layer-minimap.show a:nth-of-type(8) { transition-delay: 0ms, 425ms, 425ms; }
/* Collapsed (icons only) the minimap clears a 1200px container from about
   1400px up; below that the gutter is too tight even for the spine, so it
   steps aside. It is a scroll-position aid, so the page is complete
   without it on narrower screens. */
/* content-measured, not a ladder step: the rail needs gutter outside the 1200px
   container (1200 + 2x100), so below this it steps aside entirely. */
@media (max-width: 1399px) { .layer-minimap { display: none; } }

/* reduced motion on a desktop keeps the side-by-side hero: copy left, the
   still right with the four layer links in a 2 x 2 under it. No pin, no engine. */
@media (prefers-reduced-motion: reduce) and (min-width: 1024px) {
  .seqA-track { height: auto; }
  .seqA-pin { position: relative; height: auto; min-height: 0; padding: calc(var(--header-h) + var(--space-40)) 0 var(--space-64); }
  .node-field, .bokeh, .f-chip, .hero-deck, .scroll-hint { display: none; }
  .seqA-pin .hero-copy { transform: none; }
  .hero-visual { height: auto; margin-top: 0; }
  .bf-static { display: block; width: 100%; max-width: 620px; margin: 0 auto; }
  .layer-stack { position: static; transform: none; display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-12); margin-top: var(--space-20); }
  .layer-row { opacity: 1; transform: none; min-height: 52px; padding: var(--space-12) var(--space-16); }
  .layer-row .lr-cap { display: none; }
  .layer-row .lr-name { white-space: nowrap; }
  .layer-row.lit-static {
    border-color: rgb(var(--sig-green-lift-rgb) / 0.55);
    background: linear-gradient(180deg, rgb(var(--sig-green-lift-rgb) / 0.1), rgb(var(--sig-green-lift-rgb) / 0.03));
  }
  .layer-row.lit-static .lr-verb { color: var(--sig-green-lift); }
  .lr-mods i { opacity: 1; transform: none; }
}
/* Sequence A responsive fallback */
@media (max-width: 1023px) {
  .seqA-track { height: auto; }
  .seqA-pin { position: relative; height: auto; min-height: 0; padding: 7.5rem 0 var(--space-64); }
  .hero-grid { grid-template-columns: 1fr; }
  .hero-visual { height: auto; margin-top: var(--space-32); }
  .node-field { display: none; }
  .bokeh, .f-chip, .hero-deck { display: none; }
  .seqA-pin .hero-copy, .layer-stack { transform: none; }
  .layer-stack { position: static; }
  .layer-row { opacity: 1; transform: none; }
  .layer-row .lr-cap { opacity: 1; }
  .layer-row.lit-static {
    border-color: rgb(var(--sig-green-lift-rgb) / 0.55);
    background: linear-gradient(180deg, rgb(var(--sig-green-lift-rgb) / 0.1), rgb(var(--sig-green-lift-rgb) / 0.03));
    box-shadow: var(--specular-ink-2),
                0 0 0 1px rgb(var(--sig-green-lift-rgb) / 0.22),
                0 12px 44px -14px rgb(var(--sig-green-rgb) / 0.45);
  }
  .layer-row.lit-static .lr-verb { color: var(--sig-green-lift); }
  .lr-mods i { opacity: 1; transform: none; }
  .scroll-hint { display: none; }
}
@media (max-width: 767px) {
  /* a phone reader needs the sentence, not four bare nouns · the caption drops
     onto its own line and the decorative jump arrow steps aside for it (the
     whole row is already the link) */
  .layer-row { flex-wrap: wrap; }
  .layer-row .lr-jump { display: none; }
  .layer-row .lr-cap { flex-basis: 100%; margin-left: 0; text-align: left; }
}
/* the refined four layers in the static layouts. On a phone each card is one
   compact row (icon, verb, name, line) and the glyphs step aside. Under reduced
   motion on a desktop the cards sit 2 x 2 under the still, where a rail would
   run through nothing, so the rail and the glyphs both step aside. */
@media (max-width: 767px) {
  .seqA .layer-stack { padding-left: 18px; }
  .seqA .layer-row { flex-wrap: nowrap; }
  .seqA .layer-row::before { left: -18px; }
  .seqA .layer-row:not(:last-child)::after { left: -15px; }
  .seqA .lr-glyph { display: none; }
}
@media (prefers-reduced-motion: reduce) and (min-width: 1024px) {
  .seqA .layer-stack { padding-left: 0; }
  .seqA .layer-row::before, .seqA .layer-row::after, .seqA .lr-glyph { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .lg *, .seqA .lr-mods i { transition: none !important; animation: none !important; }
  .lit .lg-ring { opacity: 0.35; }
}

/* phones · the butterfly shares the first screen with the headline */
@media (max-width: 767px) {
  .seqA-pin { padding-top: calc(var(--header-h) + var(--space-24)); }
  .hero-copy .kicker { margin-bottom: var(--space-16); }
  .hero-copy .display-xl { font-size: clamp(2.125rem, 10vw, 2.75rem); }
  .hero-copy .hero-sub { margin-top: var(--space-16); font-size: var(--fs-xl); max-width: 34ch; }
  .hero-ctas { margin-top: var(--space-24); gap: var(--space-10); }
  .hero-visual { margin-top: var(--space-16); }
  .bf-static { margin-bottom: var(--space-16); }
}

/* ===================== HERO VARIANT · THE BUTTERFLY · BEGIN =============== */
/* Articulated crystalline hero, with projected planning signals and a static
   artwork fallback. Overscan keeps the moving wing tips within the canvas. */
/* the field below · crop rows drawn by hero-ground.js behind the whole scene,
   arriving after the butterfly, like light coming up over a field */
.bf-ground {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  animation: bfGroundIn 1800ms var(--ease-out) 700ms backwards;
}
@keyframes bfGroundIn { from { opacity: 0; } to { opacity: 1; } }
/* the land beyond the field (F4) · three ridges, the farm, the lane and the
   village, painted by hero-ground.js at the screen's density; it keeps the
   horizon through the scroll and arrives with the field */
.bf-land {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
  animation: bfGroundIn 1800ms var(--ease-out) 700ms backwards;
}
@media (prefers-reduced-motion: reduce) { .bf-ground, .bf-land { animation: none; } }
/* the lorry on the lane beyond the field · its own small sprite, placed and
   faded by hero-ground.js on the story's clock, above the field and behind
   the butterfly */
.bf-lorry {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
  opacity: 0;
  will-change: transform, opacity;
}
.bf-stage {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: max(0, calc(1 - var(--cv, 0) * 1.6));
  transform: scale(calc(1 - var(--cv, 0) * 0.04));
}
.bf-frame {
  position: absolute;
  top: 50%;
  right: max(24px, calc((100vw - 1440px) / 2 + 24px));
  width: min(720px, 51vw, calc((100svh - 240px) * 1.2));
  aspect-ratio: 1374 / 1145;
  transform: translateY(-50%);
  perspective: 1100px;
  animation: heroIn 1100ms var(--ease-out) 480ms backwards;
}
.bf-crystal-plane { position: absolute; inset: 0; transform-style: preserve-3d; }
.bf-canvas { position: absolute; inset: -12%; width: 124%; height: 124%; opacity: 0; transition: opacity 400ms var(--ease-out); }
/* routes, marks and words fade ahead of the wings as the hero scrolls away */
.bf-annot { position: absolute; inset: 0; opacity: calc(max(0, 1 - var(--cv, 0) * 3) * var(--bf-open, 1)); }
.bf-crystal.is-realtime .bf-canvas { opacity: 1; }
.bf-crystal.is-realtime .bf-crystal-art { opacity: 0; }
.bf-live-label {
  display: none; position: absolute;
  font-family: var(--font-mono); font-size: 11px;
  text-transform: uppercase; letter-spacing: 0.08em;
  line-height: 1.6; white-space: nowrap;
  color: var(--ink-text-1);
  text-shadow: 0 1px 2px var(--ink-900), 0 0 5px var(--ink-900), 0 0 10px var(--ink-900);
  transform: translate(12px, -45%);
}
.bf-crystal.is-realtime .bf-live-label { display: grid; }
.bf-live-label b { font-weight: 600; }
.bf-live-label small { font-size: 9px; color: var(--ink-text-1); letter-spacing: 0.035em; }
.bf-live-label.demand { transform: translate(calc(-100% - 12px), -45%); text-align: right; }
.bf-live-label.centre { transform: translate(-50%, 10px); font-size: 9px; }
.bf-live-label.zone { transform: translate(-50%, -50%); }
.bf-live-label.spine {
  transform: translate(-50%, -50%);
  padding: 2px 5px;
  line-height: 1.3;
  letter-spacing: 0.055em;
  background: radial-gradient(ellipse, var(--ink-900) 25%, transparent 72%);
}
.bf-live-label.spine b { font-weight: 500; }
.bf-route-bed, .bf-packets { display: none; }
.bf-crystal.is-realtime .bf-route-bed, .bf-crystal.is-realtime .bf-packets { display: block; }
.bf-route-bed { fill: none; stroke: var(--ink-900); stroke-width: 3.8; opacity: 0.58; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.bf-crystal.is-realtime .bf-crystal-pip { display: none; }
.bf-packet { fill: var(--sig-green-pulse); }
.bf-packet.demand { fill: var(--f4-blue-lift); }
.bf-packet[data-state="risk"] { fill: var(--warn-ink); }
.bf-packet[data-state="solved"] { fill: var(--sig-green-pulse); }
.bf-packet-head { fill: var(--ink-text-1); stroke: var(--ink-900); stroke-width: 0.8; }
.bf-packet[data-state="risk"] .bf-packet-head { fill: var(--warn-ink); }
.bf-packet[data-state="solved"] .bf-packet-head { fill: var(--sig-green-pulse); }
.bf-crystal.is-realtime .bf-crystal-mark { opacity: 0.95; width: 9px; height: 9px; border-width: 1.5px; color: var(--ink-text-1); }
.bf-crystal.is-realtime .bf-crystal-mark.risk { opacity: 1; color: var(--warn-ink); }
.bf-crystal.is-realtime .bf-crystal-mark.seen { opacity: 1; color: var(--signal-ink); }
.bf-crystal.is-realtime .bf-crystal-mark.solved { opacity: 1; color: var(--sig-green-pulse); }
.bf-crystal.is-realtime .bf-crystal-route.ambient { opacity: 0.82; stroke: var(--ink-text-1); stroke-width: 1.45; }
.bf-crystal.is-realtime .bf-crystal-route.structural { opacity: 0.62; stroke: var(--ink-text-1); stroke-width: 1.1; }
.bf-crystal.is-realtime .bf-crystal-route.risk { opacity: 1; stroke: var(--f4-warn); stroke-width: 2.4; }
.bf-crystal.is-realtime .bf-crystal-route.solved { opacity: 0.9; stroke: var(--sig-green-pulse); stroke-width: 2.4; }
/* ---- signals that read at hero scale ---- */
/* the station's words take the state colour with its mark */
.bf-live-label.risk b, .bf-live-label.risk small { color: var(--warn-ink); }
.bf-live-label.seen b { color: var(--signal-ink); }
.bf-live-label.solved b, .bf-live-label.solved small { color: var(--sig-green-pulse); }
/* transient pills · the signal named at the antenna club, the delta at the
   struck station, the gain at the station the decision reaches */
.bf-live-label.sense, .bf-live-label.delta {
  opacity: 0; pointer-events: none;
  padding: 2px 8px; border-radius: var(--radius-pill);
  font-size: 9px; letter-spacing: 0.06em; line-height: 1.5; text-shadow: none;
  background: rgb(var(--ink-900-rgb) / 0.88);
  border: 1px solid rgb(var(--ink-text-3-rgb) / 0.35);
  transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out);
}
.bf-live-label.sense b, .bf-live-label.delta b { font-weight: 500; }
.bf-live-label.sense { transform: translate(-50%, calc(-100% - 16px)); }
.bf-live-label.sense.show { opacity: 1; transform: translate(-50%, calc(-100% - 11px)); }
.bf-live-label.sense.seen { border-color: color-mix(in srgb, var(--signal-ink) 55%, transparent); }
.bf-live-label.sense.seen b { color: var(--signal-ink); }
.bf-live-label.delta.supply { transform: translate(calc(-100% - 12px), -50%); text-align: right; }
.bf-live-label.delta.demand { transform: translate(12px, -50%); }
.bf-live-label.delta.centre { transform: translate(-50%, 16px); }
.bf-live-label.delta.show { opacity: 1; }
.bf-live-label.delta.risk { border-color: rgb(var(--f4-warn-rgb) / 0.55); }
.bf-live-label.delta.risk b { color: var(--warn-ink); }
.bf-live-label.delta.solved { border-color: rgb(var(--sig-green-lift-rgb) / 0.55); }
.bf-live-label.delta.solved b { color: var(--sig-green-pulse); }
/* the struck station · a halo on its mark, and its delta as a card at reading
   size with the signal that caused it underneath */
.bf-crystal.is-realtime .bf-crystal-mark.struck {
  width: 18px; height: 18px; border-width: 2px;
  box-shadow: 0 0 0 7px rgb(var(--f4-warn-rgb) / 0.16), 0 0 22px 4px rgb(var(--f4-warn-rgb) / 0.3);
}
.bf-live-label.delta small:empty { display: none; }
.bf-live-label.delta.card {
  gap: 2px; padding: 7px 11px; border-radius: 10px;
  font-size: var(--fs-cap); letter-spacing: 0.02em; text-transform: none; line-height: 1.3;
  background: rgb(var(--ink-900-rgb) / 0.94);
  box-shadow: 0 10px 26px -10px rgb(0 0 0 / 0.7);
}
.bf-live-label.delta.card b { font-weight: 600; }
.bf-live-label.delta.card small { font-size: var(--fs-2xs); color: var(--ink-text-2); letter-spacing: 0.04em; }
/* outboard on the demand wing; on the supply wing outboard is the headline, so
   the card rides above its station */
.bf-live-label.delta.card.supply { transform: translate(-50%, calc(-100% - 20px)); text-align: center; }
.bf-live-label.delta.card.demand { transform: translate(20px, -50%); }
/* perception · the antenna club blooms and radars when a signal lands, and the
   antenna itself carries the pulse down to the head */
.bf-crystal.is-realtime .bf-crystal-mark[data-station^="ant_"].seen {
  width: 13px; height: 13px; border-width: 2px; color: var(--signal-ink);
  background: radial-gradient(circle, #fff 0 2px, color-mix(in srgb, var(--signal-ink) 60%, transparent) 2.5px 4px, transparent 4.5px);
  box-shadow: 0 0 16px 3px color-mix(in srgb, var(--signal-ink) 55%, transparent);
}
.bf-crystal-mark[data-station^="ant_"].seen::before {
  content: ""; position: absolute; inset: -6px;
  border: 1px solid currentColor; border-radius: inherit;
  animation: bfRadar 1.6s ease-out infinite;
}
.bf-crystal-mark[data-station^="ant_"].seen::after { inset: -6px; animation: bfRadar 1.6s ease-out 0.55s infinite; }
@keyframes bfRadar { from { opacity: 0.9; transform: scale(0.55); } to { opacity: 0; transform: scale(3.4); } }
.bf-crystal-route.seen { opacity: 0.95; stroke: var(--signal-ink); stroke-dasharray: 2 4; animation: bfSignalFlow 1.4s linear infinite; }
.bf-crystal.is-realtime .bf-crystal-route.seen { opacity: 1; stroke: var(--signal-ink); stroke-width: 1.8; stroke-dasharray: none; animation: none; }
.bf-packet[data-state="seen"] { fill: var(--signal-ink); }
.bf-packet[data-state="seen"] .bf-packet-head { fill: #fff; stroke: var(--signal-ink); }
/* a wide soft stroke beneath every route blooms in the state colour */
.bf-route-glow { fill: none; stroke-width: 7; opacity: 0; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; transition: opacity var(--dur-base); }
.bf-route-glow.risk { stroke: var(--f4-warn); opacity: 0.32; }
.bf-route-glow.solved { stroke: var(--sig-green-pulse); opacity: 0.3; }
.bf-route-glow.seen { stroke: var(--signal-ink); opacity: 0.3; }
/* the answer station sparkles once as it resolves */
.bf-crystal-mark.solved::before {
  content: ""; position: absolute; inset: -10px;
  background:
    linear-gradient(currentColor, currentColor) center / 1.5px 100% no-repeat,
    linear-gradient(currentColor, currentColor) center / 100% 1.5px no-repeat;
  animation: bfSparkle 900ms var(--ease-out) 1 both;
}
@keyframes bfSparkle { from { opacity: 1; transform: scale(0.2) rotate(0deg); } to { opacity: 0; transform: scale(1.7) rotate(45deg); } }
.bf-crystal-art { margin: 0; position: absolute; inset: 0; }
.bf-crystal-art picture, .bf-crystal-art img,
.bf-static picture, .bf-static img { display: block; width: 100%; height: auto; }
.bf-crystal-art img, .bf-static img {
  -webkit-mask-image: linear-gradient(to right, transparent, black 3%, black 97%, transparent),
    linear-gradient(to bottom, transparent, black 3%, black 96%, transparent);
  mask-image: linear-gradient(to right, transparent, black 3%, black 97%, transparent),
    linear-gradient(to bottom, transparent, black 3%, black 96%, transparent);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
.bf-crystal-routes { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.bf-crystal-route, .bf-crystal-pip {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.bf-crystal-route { opacity: 0; stroke-width: 2; transition: opacity var(--dur-base); }
.bf-crystal-route.risk { opacity: 1; stroke: var(--f4-warn); stroke-dasharray: 4 2; animation: bfSignalFlow 2s linear infinite; }
.bf-crystal-route.solved { opacity: 0.9; stroke: var(--sig-green-pulse); stroke-dasharray: 2 5; animation: bfSignalFlow 2.4s linear infinite; }
.bf-crystal-pip {
  stroke-width: 2;
  stroke-dasharray: 0.45 99.55;
  stroke: var(--ink-text-1);
  opacity: 0.7;
  animation: bfSignalFlow 7s linear infinite;
}
.bf-crystal-pip.supply { stroke: var(--sig-green-pulse); }
.bf-crystal-pip.demand { stroke: var(--f4-blue-lift); }
@keyframes bfSignalFlow { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
.bf-crystal-mark {
  position: absolute;
  width: 14px; height: 14px;
  border: 2px solid currentColor;
  border-radius: var(--radius-circle);
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity var(--dur-base), color var(--dur-base);
}
.bf-crystal-mark.risk { opacity: 1; color: var(--f4-warn); box-shadow: var(--glow-warn-ink); }
.bf-crystal-mark.seen { opacity: 1; color: var(--signal-ink); }
.bf-crystal-mark.solved { opacity: 1; color: var(--sig-green-pulse); }
.bf-crystal-mark.risk::after, .bf-crystal-mark.seen::after, .bf-crystal-mark.solved::after {
  content: "";
  position: absolute; inset: -4px;
  border: 1px solid currentColor;
  border-radius: inherit;
  animation: bfSignalRing 1.8s ease-out infinite;
}
@keyframes bfSignalRing { from { opacity: 0.8; transform: scale(0.8); } to { opacity: 0; transform: scale(1.7); } }
/* ---- the story card · signal tabs + the act in play, under the wings ---- */
/* It sits under the frame with the frame's own right/width rules (frame height
   is width × 1145/1374), beside the inert field so its buttons stay real. */
.bf-story {
  position: absolute; z-index: 3;
  right: max(24px, calc((100vw - 1440px) / 2 + 24px));
  width: min(720px, 51vw, calc((100svh - 240px) * 1.2));
  top: calc(50% + min(720px, 51vw, calc((100svh - 240px) * 1.2)) * 0.4167 - 14px);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px 12px;
  opacity: max(0, calc(1 - var(--cv, 0) * 1.6));
  animation: nfBootFade 500ms var(--ease-out) 1900ms backwards;
  pointer-events: none;
}
.bf-story-tabs, .bf-crystal-caption { pointer-events: auto; }
.bf-story-tabs { display: flex; align-items: center; gap: 8px; }
/* the pause · one press holds the beat a visitor is reading */
.deck-pause {
  flex: none; display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: 50%;
  color: var(--ink-text-1); cursor: pointer;
  background: rgba(9, 18, 32, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: var(--specular-ink);
  transition: background 180ms var(--ease-out), border-color 180ms var(--ease-out), color 180ms var(--ease-out);
}
.deck-pause svg { width: 12px; height: 12px; fill: currentColor; }
.deck-pause .i-play, .deck-pause.is-paused .i-pause { display: none; }
.deck-pause.is-paused .i-play { display: inline; }
.deck-pause:hover, .deck-pause:focus-visible { border-color: rgb(var(--sig-green-lift-rgb) / 0.55); color: rgb(255 255 255); }
.deck-pause:focus-visible { outline: 2px solid var(--sig-green-lift); outline-offset: 3px; }
.deck-pause.is-paused { background: var(--sig-green); border-color: transparent; color: var(--sig-green-ink); }
/* the act in play wears its chip, and the act's clock runs along it */
.bf-story .deck-run { position: relative; }
.bf-story .deck-run.is-running { color: rgb(255 255 255); border-color: rgb(var(--sig-green-lift-rgb) / 0.7); background: rgb(var(--sig-green-rgb) / 0.12); }
.bf-story .deck-run.is-running::after {
  content: ""; position: absolute; left: 12px; right: 12px; bottom: 3px; height: 2px; border-radius: 1px;
  background: var(--sig-green-lift); transform: scaleX(var(--p, 0)); transform-origin: left;
}
.bf-story.has-run .bf-card-progress { opacity: 0; }
/* from the full-experience width the bar runs 300px wider than the frame · the
   copy column's controls sit higher, so that room is free and the line, now at
   reading size beside the pause, never clips */
@media (min-width: 1280px) and (min-height: 761px) { .bf-story { width: max(1000px, calc(min(720px, 51vw, calc((100svh - 240px) * 1.2)) + 300px)); } }
/* below it the bar takes two rows: the signals alone on the first, where the
   copy column's rail ends, and the pause beside the line on the second. A short
   screen takes them too: there the copy column (CTAs, the AI line, the rail)
   reaches the bar's height, so the bar keeps to the frame's width */
@media (max-width: 1279px), (max-height: 760px) {
  .bf-story { display: grid; grid-template-columns: auto minmax(0, 1fr); justify-items: end; }
  .bf-story-tabs { display: contents; }
  .bf-story .hero-deck { grid-row: 1; grid-column: 1 / -1; }
  .bf-story .deck-pause { grid-row: 2; grid-column: 1; }
  .bf-story .bf-crystal-caption { grid-row: 2; grid-column: 2; width: 100%; }
}
.bf-story .hero-deck { position: static; transform: none; max-width: none; animation: none; opacity: 1; padding: 5px 6px; gap: 8px; }
.bf-story .deck-label { display: none; }
.bf-story .deck-btn { padding: 0.3rem 0.6rem; letter-spacing: 0.03em; }
.bf-crystal-caption {
  position: relative;
  flex: 1 1 200px; min-width: 0; min-height: 36px;
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px 0 16px;
  font-family: var(--font-mono); font-size: var(--fs-xs); line-height: var(--lh-ui);
  color: var(--ink-text-2);
  background: rgba(9, 18, 32, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--radius-pill);
  box-shadow: var(--specular-ink), 0 10px 30px -12px rgba(0, 0, 0, 0.6);
  overflow: hidden;
  opacity: 0; transform: translateY(4px);
  transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out);
}
.bf-crystal-caption.show { opacity: 1; transform: none; }
/* a coloured rule at the left tells the state at a glance */
.bf-crystal-caption::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--ink-text-3); opacity: 0.5; transition: background 260ms var(--ease-out);
}
.bf-crystal-caption[data-state="sensing"]::before, .bf-crystal-caption[data-state="planning"]::before,
.bf-crystal-caption[data-state="seen"]::before { background: var(--signal-ink); opacity: 1; }
.bf-crystal-caption[data-state="risk"]::before { background: var(--f4-warn); opacity: 1; }
.bf-crystal-caption[data-state="decided"]::before, .bf-crystal-caption[data-state="resolved"]::before { background: var(--sig-green-lift); opacity: 1; }
/* seen → decided → protected · the act's three beats */
.bf-card-phase { display: inline-flex; flex: none; gap: 6px; }
.bf-card-phase i {
  width: 6px; height: 6px; border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.28);
  transition: background 320ms var(--ease-out), border-color 320ms var(--ease-out), box-shadow 320ms var(--ease-out);
}
.bf-crystal-caption[data-phase="1"] .bf-card-phase i:nth-child(1),
.bf-crystal-caption[data-phase="2"] .bf-card-phase i:nth-child(-n+2) { background: rgb(var(--sig-green-lift-rgb) / 0.45); border-color: rgb(var(--sig-green-lift-rgb) / 0.45); }
.bf-crystal-caption[data-phase="0"] .bf-card-phase i:nth-child(1),
.bf-crystal-caption[data-phase="1"] .bf-card-phase i:nth-child(2),
.bf-crystal-caption[data-phase="2"] .bf-card-phase i:nth-child(3) { background: var(--sig-green-lift); border-color: var(--sig-green-lift); box-shadow: var(--glow-live-ink); }
.bf-crystal-caption[data-state="risk"][data-phase="0"] .bf-card-phase i:nth-child(1) { background: var(--f4-warn); border-color: var(--f4-warn); box-shadow: var(--glow-warn-ink); }
.bf-crystal-caption[data-state="sensing"] .bf-card-phase i:nth-child(1) { background: var(--signal-ink); border-color: var(--signal-ink); box-shadow: none; }
/* the butterfly says its beats in the bar, so the copy column's narration line steps aside */
.seqA-pin[data-hero-variant="butterfly"] .hud-msg { display: none; }
/* the step named · seen, deciding, decided, protected */
.bf-card-step {
  flex: none; font-size: var(--fs-2xs); font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-text-3);
}
.bf-card-step:empty { display: none; }
.bf-crystal-caption.is-paused .bf-card-step { display: inline; padding: 3px 7px; border-radius: 6px; background: rgba(255, 255, 255, 0.08); color: var(--ink-text-1); }
.bf-crystal-caption.is-paused .bf-card-step::before { content: "paused · "; }
.bf-crystal-caption.is-paused .bf-card-step:empty::before { content: "paused"; }
.bf-crystal-caption[data-state="sensing"] .bf-card-step, .bf-crystal-caption[data-state="planning"] .bf-card-step { color: var(--signal-ink); }
.bf-crystal-caption[data-state="risk"] .bf-card-step { color: var(--warn-ink); }
.bf-crystal-caption[data-state="decided"] .bf-card-step,
.bf-crystal-caption[data-state="resolved"] .bf-card-step { color: var(--sig-green-pulse); }
/* the one line · the current beat, at reading size: its head in the state
   colour, the rest plain */
.bf-crystal-outcome {
  flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-family: var(--font-body); font-size: var(--fs-md); font-weight: 400; letter-spacing: 0;
  color: var(--ink-text-1);
}
.bf-crystal-outcome b { font-weight: 600; }
.bf-crystal-outcome.in { animation: bfLineIn 320ms var(--ease-out) both; }
@keyframes bfLineIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
.bf-crystal-caption[data-state="intro"] .bf-crystal-outcome b { color: var(--ink-text-2); font-weight: 400; }
.bf-crystal-caption[data-state="sensing"] .bf-crystal-outcome b, .bf-crystal-caption[data-state="planning"] .bf-crystal-outcome b { color: var(--signal-ink); }
.bf-crystal-caption[data-state="risk"] .bf-crystal-outcome b { color: var(--warn-ink); }
.bf-crystal-caption[data-state="decided"] .bf-crystal-outcome b,
.bf-crystal-caption[data-state="resolved"] .bf-crystal-outcome b { color: var(--sig-green-pulse); }
/* the act's own clock along the bottom edge */
.bf-card-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: rgba(255, 255, 255, 0.06); }
.bf-card-progress b { display: block; height: 100%; width: calc(var(--p, 0) * 100%); background: rgb(var(--sig-green-lift-rgb) / 0.7); }
/* the plumb line from the station in play down to the card */
.bf-lead { fill: none; stroke: var(--ink-text-2); stroke-width: 1; stroke-dasharray: 2 3; opacity: 0; vector-effect: non-scaling-stroke; transition: opacity 260ms var(--ease-out); }
.bf-lead.show { opacity: 0.55; }
.bf-lead.risk { stroke: var(--f4-warn); }
.bf-lead.solved { stroke: var(--sig-green-pulse); }
.bf-lead.seen { stroke: var(--signal-ink); }
.bf-static { display: none; margin: 0; position: relative; container-type: inline-size; overflow: hidden; }
.bf-crystal-art { container-type: inline-size; }
.bf-still-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.bf-still-layer { position: absolute; inset: 0; pointer-events: none; }
.bf-still-stream { fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-dasharray: 0.1 9; opacity: 0.55; vector-effect: non-scaling-stroke; }
.bf-still-stream.supply { stroke: var(--sig-green-lift); }
.bf-still-stream.demand { stroke: var(--f4-blue-lift); }
.bf-still-lens, .bf-still-antenna, .bf-still-axis, .bf-still-fairing { fill: none; stroke: #DCEBF7; stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.bf-still-lens { fill: rgb(var(--ink-900-rgb) / 0.35); }
.bf-still-axis { stroke: rgb(220 235 247 / 0.7); stroke-width: 1; }
.bf-still-fairing.supply { stroke: var(--sig-green-lift); opacity: 0.8; }
.bf-still-fairing.demand { stroke: var(--f4-blue-lift); opacity: 0.8; }
.bf-still-glow { fill: rgb(220 235 247 / 0.16); }
.bf-still-light { fill: #fff; }
.bf-still-label {
  position: absolute; display: grid; pointer-events: none;
  font-family: var(--font-mono); font-size: clamp(7.5px, 2.4cqw, 11px);
  text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.5; white-space: nowrap;
  color: var(--ink-text-1);
  text-shadow: 0 1px 2px var(--ink-900), 0 0 5px var(--ink-900), 0 0 10px var(--ink-900);
  transform: translate(10px, -45%);
}
.bf-still-label b { font-weight: 600; }
.bf-still-label small { font-size: 0.82em; color: var(--ink-text-2); letter-spacing: 0.035em; }
.bf-still-label.demand { transform: translate(calc(-100% - 10px), -45%); text-align: right; }
.bf-still-label.centre { transform: translate(-50%, 8px); }
.bf-still-label.spine { transform: translate(-50%, -50%); padding: 2px 5px; line-height: 1.3; background: radial-gradient(ellipse, var(--ink-900) 25%, transparent 72%); }
.bf-still-label.spine b { font-weight: 500; }
.bf-still-label.zone { transform: translate(-50%, -50%); font-size: clamp(7px, 2.1cqw, 9.5px); }
.bf-still-label.risk b, .bf-still-label.risk small { color: var(--warn-ink); }
.bf-still-label.seen b { color: var(--signal-ink); }
.bf-still-label.solved b, .bf-still-label.solved small { color: var(--sig-green-pulse); }
.bf-static .bf-crystal-mark { opacity: 0.9; width: clamp(6px, 1.7cqw, 9px); height: clamp(6px, 1.7cqw, 9px); border-width: 1.5px; color: var(--ink-text-1); }
.bf-static .bf-crystal-mark.risk { color: var(--f4-warn); }
.bf-static .bf-crystal-mark.seen { color: var(--signal-ink); }
.bf-static .bf-crystal-mark.solved { color: var(--sig-green-pulse); }
.bf-static .bf-crystal-route.risk, .bf-static .bf-crystal-route.solved, .bf-static .bf-crystal-route.seen { stroke-width: 2; }
/* the still's story · one control (the pause, then the three signals), the
   line, and on a phone a two-card legend for the words that left the picture */
.bf-still-story { display: none; margin: var(--space-12) auto var(--space-24); width: 100%; max-width: 760px; }
.bf-still-ctl { display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 6px; }
.bf-still-ctl .deck-pause { width: auto; height: auto; min-height: 44px; border-radius: 12px; }
.bf-still-chips { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.bf-still-chip { min-height: 44px; border-radius: 12px; white-space: normal; line-height: 1.25; text-align: center; padding: 6px 8px; }
.bf-still-chip.is-running { color: rgb(255 255 255); border-color: rgb(var(--sig-green-lift-rgb) / 0.7); background: rgb(var(--sig-green-rgb) / 0.16); }
.bf-still-story .bf-crystal-caption { margin: 8px 0 0; width: 100%; }
/* the story's one label on the picture · it follows the beat from station to station */
.bf-still-card {
  position: absolute; z-index: 2; display: grid; gap: 1px;
  padding: 6px 10px; border-radius: 9px;
  font-family: var(--font-mono); white-space: nowrap; pointer-events: none;
  background: rgb(var(--ink-900-rgb) / 0.94);
  border: 1px solid rgb(var(--ink-text-3-rgb) / 0.35);
  box-shadow: 0 8px 20px -8px rgb(0 0 0 / 0.7);
  opacity: 0; transition: opacity 260ms var(--ease-out);
}
.bf-still-card.show { opacity: 1; }
.bf-still-card b { font-size: var(--fs-cap); font-weight: 600; color: var(--ink-text-1); }
.bf-still-card small { font-size: var(--fs-2xs); letter-spacing: 0.04em; color: var(--ink-text-2); }
.bf-still-card small:empty { display: none; }
.bf-still-card.seen { border-color: color-mix(in srgb, var(--signal-ink) 55%, transparent); }
.bf-still-card.seen b { color: var(--signal-ink); }
.bf-still-card.risk { border-color: rgb(var(--f4-warn-rgb) / 0.6); }
.bf-still-card.risk b { color: var(--warn-ink); }
.bf-still-card.solved { border-color: rgb(var(--sig-green-lift-rgb) / 0.55); }
.bf-still-card.solved b { color: var(--sig-green-pulse); }
.bf-static .bf-crystal-mark.struck {
  width: clamp(12px, 4.4cqw, 18px); height: clamp(12px, 4.4cqw, 18px); border-width: 2px;
  box-shadow: 0 0 0 6px rgb(var(--f4-warn-rgb) / 0.16), 0 0 18px 3px rgb(var(--f4-warn-rgb) / 0.3);
}
.bf-still-legend { display: none; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px; }
.bf-still-legend p {
  margin: 0; padding: 10px 12px; border-radius: 12px;
  font-family: var(--font-body); font-size: var(--fs-sm); line-height: 1.45; color: var(--ink-text-2);
  background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08);
}
.bf-still-legend b { display: block; margin-bottom: 2px; font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
.bf-still-legend .supply b { color: var(--sig-green-lift); }
.bf-still-legend .demand b { color: var(--f4-blue-pale); }
@media (max-width: 479px) {
  .bf-static .bf-still-label:not(.zone) { display: none; }
  .bf-still-legend { display: grid; }
  .bf-still-chip .bf-chip-sep { display: none; }
  .bf-still-chip span { display: block; }
  .bf-still-story .bf-crystal-caption { flex-wrap: wrap; row-gap: 4px; padding: 10px 14px 11px 16px; border-radius: 14px; }
  .bf-still-story .bf-crystal-outcome { flex-basis: 100%; font-size: var(--fs-lg); }
}
@media (max-width: 1023px), (prefers-reduced-motion: reduce) { .bf-still-story { display: block; } }
@media (max-width: 1023px), (prefers-reduced-motion: reduce) {
  .bf-static { display: block; width: 100%; max-width: 760px; margin: 0 auto var(--space-32); }
}
@media (prefers-reduced-motion: reduce) {
  .bf-crystal-pip, .bf-crystal-route, .bf-crystal-mark::after { animation: none !important; }
}
/* ===================== HERO VARIANT · THE BUTTERFLY · END ================= */


/* ===================== HERO VARIANT · DECISION ROUTING · BEGIN ============ */
/* Decision Routing (.rt-*) · an isometric operations board seen like a builder
   game: extruded solids with two lit faces, iso road ribbons, a green NOW
   light-wall, signal beacons, produce crates, and a recorded outcome. Buildings
   sit in the cool-white/ink ladder; green stays on the decision, the revised
   route, the plan token, the NOW line and Memory; amber on the disruption;
   blue on the import. Meaningful geometry stays inside the hero safe zone. */
.rt-stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  perspective: 1900px;
  /* dissolve on scroll-commit via opacity + a whisper of scale only. No
     blur: a defocus here read as "out of focus" behind the layer-stack, and
     an always-on filter (blur(0px) at rest) needlessly rasterized the crisp
     isometric board. Fade + shrink alone give a clean hand-off. */
  opacity: calc(1 - var(--cv, 0) * 1.6);
  transform: scale(calc(1 - var(--cv, 0) * 0.035));
  -webkit-mask-image: var(--hero-safe);
          mask-image: var(--hero-safe);
}
.rt-plane {
  position: absolute;
  inset: 0;
  transform-origin: 70% 52%;
  transform-style: preserve-3d;
  will-change: transform;
}
.rt-map {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.rt-arrowhead { fill: context-stroke; }

/* ---- the ground plate ---- */
.rt-plot {
  fill: rgba(20, 32, 54, 0.42);
  stroke: rgba(var(--ink-text-3-rgb) / 0.16);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  animation: rtBootFade 700ms var(--ease-out) both;
}
.rt-grid, .rt-contour {
  fill: none;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
}
.rt-grid { stroke: rgba(var(--ink-text-3-rgb) / 0.07); stroke-width: 1; }
.rt-contour { stroke: rgba(var(--ink-text-3-rgb) / 0.06); stroke-width: 1; }
.rt-lattice { animation: rtBootFade 900ms var(--ease-out) 120ms both; }

/* ---- roads · iso ribbons ---- */
.rt-road-bed, .rt-road-line {
  fill: none;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.rt-road { animation: rtRouteIn 820ms var(--ease-out) backwards; }
.rt-road:nth-of-type(2) { animation-delay: 70ms; }
.rt-road:nth-of-type(3) { animation-delay: 140ms; }
.rt-road:nth-of-type(4) { animation-delay: 210ms; }
.rt-road:nth-of-type(5) { animation-delay: 280ms; }
.rt-road:nth-of-type(6) { animation-delay: 350ms; }
.rt-road:nth-of-type(n+7) { animation-delay: 420ms; }
.rt-road-bed { stroke: rgba(var(--ink-text-3-rgb) / 0.10); stroke-width: 15; }
.rt-road-line { stroke: rgba(var(--ink-text-3-rgb) / 0.42); stroke-width: 1.1; }
.rt-road-demand .rt-road-bed { stroke: rgba(var(--ink-text-3-rgb) / 0.07); }
.rt-road-import .rt-road-bed { stroke: rgba(var(--f4-blue-rgb) / 0.13); }
.rt-road-import .rt-road-line { stroke: rgba(var(--f4-blue-rgb) / 0.7); }
@keyframes rtRouteIn { from { opacity: 0; transform: translateY(14px); } }
@keyframes rtBootFade { from { opacity: 0; } }

/* ---- extruded solids · shared face grammar ---- */
.rt-shadow { fill: rgba(0, 0, 0, 0.30); }
.rt-face-t, .rt-face-l, .rt-face-r {
  vector-effect: non-scaling-stroke;
  stroke-width: 1;
  stroke-linejoin: round;
  transition: fill 260ms var(--ease-out), stroke 260ms var(--ease-out);
}
.rt-face-t { fill: #2A3D60; stroke: rgba(255, 255, 255, 0.17); }
.rt-face-l { fill: #172740; stroke: rgba(255, 255, 255, 0.06); }
.rt-face-r { fill: #0D1A2D; stroke: rgba(255, 255, 255, 0.05); }

.rt-location {
  animation: rtBuildIn 620ms var(--ease-out) backwards;
  transform-box: fill-box;
  transform-origin: 50% 100%;
}
.rt-builds > g:nth-child(1)  { animation-delay: 140ms; }
.rt-builds > g:nth-child(2)  { animation-delay: 195ms; }
.rt-builds > g:nth-child(3)  { animation-delay: 250ms; }
.rt-builds > g:nth-child(4)  { animation-delay: 305ms; }
.rt-builds > g:nth-child(5)  { animation-delay: 360ms; }
.rt-builds > g:nth-child(6)  { animation-delay: 415ms; }
.rt-builds > g:nth-child(7)  { animation-delay: 470ms; }
.rt-builds > g:nth-child(8)  { animation-delay: 525ms; }
.rt-builds > g:nth-child(9)  { animation-delay: 580ms; }
.rt-builds > g:nth-child(10) { animation-delay: 635ms; }
.rt-builds > g:nth-child(11) { animation-delay: 690ms; }
@keyframes rtBuildIn { from { opacity: 0; transform: translateY(18px) scale(0.965); } }

/* the disrupted origin flushes amber while its scenario runs */
.rt-location.is-hit .rt-face-t { fill: rgba(var(--f4-warn-rgb) / 0.24); stroke: rgba(var(--f4-warn-rgb) / 0.6); }
.rt-location.is-hit .rt-face-l { fill: rgba(var(--f4-warn-rgb) / 0.13); }
.rt-location.is-hit .rt-face-r { fill: rgba(var(--f4-warn-rgb) / 0.08); }

/* ---- hover · the building lifts and takes a green edge (green = touch,
   per the allowlist); its label lights green. Only the solids opt back into
   pointer events (the board container is pointer-events:none); roads/tokens
   stay transparent, so a building still highlights where a route crosses it,
   and pointermove still bubbles to the hero pin for the parallax. ---- */
.rt-location, .rt-memory { pointer-events: auto; cursor: pointer; transition: transform 200ms var(--ease-out), filter 200ms var(--ease-out); }
.rt-location:hover, .rt-memory:hover { transform: translateY(-5px); filter: drop-shadow(var(--glow-live-ink)); }
.rt-location:hover .rt-face-t { fill: #33496B; stroke: rgba(var(--sig-green-lift-rgb) / 0.9); }
.rt-location:hover .rt-face-l { fill: #1f3556; }
.rt-location:hover .rt-face-r { fill: #12243d; }
.rt-location:hover .rt-location-label,
.rt-memory:hover .rt-memory-label { fill: var(--sig-green-lift); }
.rt-memory:hover .rt-mem-face.rt-face-t { stroke: rgba(var(--sig-green-lift-rgb) / 0.9); }

/* ---- the farm (grower) · a tilled field, two poly-tunnels, a small barn ---- */
.rt-field.rt-face-t { fill: #24344f; }
.rt-field.rt-face-l { fill: var(--ink-700); }
.rt-field.rt-face-r { fill: #0d1a2d; }
.rt-furrow { stroke: rgba(var(--ink-text-3-rgb) / 0.34); stroke-width: 1.1; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-tunnel { fill: rgba(var(--ink-text-2-rgb, 175 189 208) / 0.13); stroke: none; }
.rt-tunnel-ridge { fill: none; stroke: rgba(var(--ink-text-2-rgb, 175 189 208) / 0.62); stroke-width: 1.3; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-tunnel-hoop { stroke: rgba(var(--ink-text-2-rgb, 175 189 208) / 0.4); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rt-location.is-hit .rt-tunnel { fill: rgba(var(--f4-warn-rgb) / 0.14); }
.rt-location.is-hit .rt-tunnel-ridge { stroke: rgba(var(--f4-warn-rgb) / 0.6); }
.rt-location.is-hit .rt-furrow { stroke: rgba(var(--f4-warn-rgb) / 0.42); }

/* ---- toppers ---- */
.rt-glass {
  fill: rgba(var(--ink-text-3-rgb) / 0.16);
  stroke: rgba(var(--ink-text-1-rgb, 230 235 242) / 0.36);
  stroke-width: 1; vector-effect: non-scaling-stroke;
}
.rt-glass-b { fill: rgba(var(--ink-text-3-rgb) / 0.08); }
.rt-ridge { stroke: rgba(var(--ink-text-2-rgb, 175 189 208) / 0.6); stroke-width: 1.2; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-crop { stroke: rgba(var(--ink-text-3-rgb) / 0.5); stroke-width: 1.4; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-roof { fill: #223350; stroke: rgba(255, 255, 255, 0.1); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rt-roof-b { fill: #172740; }
.rt-door { fill: rgb(var(--ink-900-rgb) / 0.72); stroke: rgba(var(--ink-text-3-rgb) / 0.3); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rt-rib { stroke: rgba(var(--ink-text-2-rgb, 175 189 208) / 0.28); stroke-width: 1.2; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-awning { fill: rgba(var(--ink-text-3-rgb) / 0.24); stroke: rgba(var(--ink-text-2-rgb, 175 189 208) / 0.42); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rt-bar { stroke: rgba(var(--ink-text-2-rgb, 175 189 208) / 0.78); stroke-width: 2.4; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-bar-dot { fill: var(--ink-text-2); }
.rt-gantry { fill: none; stroke: rgba(var(--f4-blue-rgb) / 0.72); stroke-width: 2; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-gantry-line { stroke: rgba(var(--f4-blue-rgb) / 0.4); stroke-width: 1.3; }

/* per-type face tints */
.rt-location-port .rt-face-t { fill: #21374F; }
.rt-container.rt-face-t { fill: rgba(var(--f4-blue-rgb) / 0.34); stroke: rgba(var(--f4-blue-rgb) / 0.55); }
.rt-container.rt-face-l { fill: rgba(var(--f4-blue-rgb) / 0.2); stroke: rgba(var(--f4-blue-rgb) / 0.4); }
.rt-container.rt-face-r { fill: rgba(var(--f4-blue-rgb) / 0.12); stroke: rgba(var(--f4-blue-rgb) / 0.3); }
.rt-location-coldstore .rt-face-t { fill: #2E4468; }

/* ---- location labels ---- */
.rt-location-label {
  fill: rgba(var(--ink-text-3-rgb) / 0.9);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 9.5px;
  letter-spacing: 0.9px;
}
.rt-location-port .rt-location-label { fill: rgba(var(--f4-blue-rgb) / 0.92); }
.rt-location-demand .rt-location-label { fill: rgba(var(--ink-text-3-rgb) / 0.68); }

/* ---- produce fruit · moving load tokens + idle stock ---- */
.rt-prop { opacity: 0.72; }
.rt-fruit-shadow { fill: rgba(0, 0, 0, 0.3); }
.rt-fruit-body { stroke: rgba(255, 255, 255, 0.42); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rt-fruit-spec { fill: none; stroke: rgba(255, 255, 255, 0.5); stroke-width: 1.2; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-fruit-stem { stroke: rgba(var(--ink-text-3-rgb) / 0.85); stroke-width: 1.4; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rt-fruit-leaf { stroke: none; }
.rt-fb-warn { fill: var(--f4-warn); filter: drop-shadow(0 0 6px rgba(var(--f4-warn-rgb) / 0.4)); }
.rt-fl-warn { fill: rgba(var(--f4-warn-rgb) / 0.55); }
.rt-fb-live { fill: var(--sig-green-lift); filter: drop-shadow(var(--glow-live-ink)); }
.rt-fl-live { fill: var(--sig-green-deep); }
.rt-fb-idle { fill: #33496b; }
.rt-fl-idle { fill: rgba(var(--ink-text-3-rgb) / 0.5); }

/* ---- overline + week ---- */
.rt-overline, .rt-week, .rt-location-label, .rt-origin-label,
.rt-sensor-label, .rt-junction-label, .rt-result-label, .rt-memory-label, .rt-now-text, .rt-pylon-wk {
  font-family: var(--font-mono);
  font-weight: 500;
}
.rt-overline { fill: var(--ink-text-3); font-size: 10px; letter-spacing: 2.4px; }
.rt-week { fill: var(--ink-text-2); font-size: 15px; letter-spacing: 0.6px; }

/* ---- the forecast line · power-line pylons carrying the weeks ---- */
.rt-timeline { animation: rtBootFade 700ms var(--ease-out) 420ms backwards; }
.rt-pylon { transition: opacity 500ms var(--ease-out); }
.rt-pylon.is-past { opacity: 0.42; }
.rt-pylon-mast, .rt-pylon-arm, .rt-pylon-lat, .rt-cable {
  fill: none; vector-effect: non-scaling-stroke; stroke-linecap: round; stroke-linejoin: round;
}
.rt-pylon-mast { stroke: rgba(var(--ink-text-3-rgb) / 0.62); stroke-width: 1.6; transition: stroke 500ms var(--ease-out); }
.rt-pylon-arm { stroke: rgba(var(--ink-text-3-rgb) / 0.62); stroke-width: 1.4; transition: stroke 500ms var(--ease-out); }
.rt-pylon-lat { stroke: rgba(var(--ink-text-3-rgb) / 0.32); stroke-width: 1; }
.rt-pylon-ins { fill: rgba(var(--ink-text-2-rgb, 175 189 208) / 0.7); transition: fill 500ms var(--ease-out); }
.rt-pylon-wk { fill: rgba(var(--ink-text-3-rgb) / 0.72); font-size: 9px; letter-spacing: 1px; transition: fill 500ms var(--ease-out); }
.rt-cable { stroke: rgba(var(--ink-text-3-rgb) / 0.4); stroke-width: 1; }
.rt-cable-pulse { fill: var(--sig-green-lift); filter: drop-shadow(var(--glow-live-ink)); }
/* the current week · lit green and glowing */
.rt-pylon.is-now { filter: drop-shadow(var(--glow-live-ink)); }
.rt-pylon.is-now .rt-pylon-mast, .rt-pylon.is-now .rt-pylon-arm { stroke: var(--sig-green-lift); }
.rt-pylon.is-now .rt-pylon-ins { fill: var(--sig-green-lift); }
.rt-pylon.is-now .rt-pylon-wk { fill: var(--sig-green-lift); }
.rt-now-tag { transition: transform 600ms var(--ease-out); }
.rt-now-plate { fill: var(--ink-900); stroke: rgba(var(--sig-green-lift-rgb) / 0.8); stroke-width: 1; }
.rt-now-text { fill: var(--sig-green-lift); font-size: 10px; letter-spacing: 1.3px; }

/* ---- Memory drum ---- */
.rt-mem-face.rt-face-t { transition: fill 320ms var(--ease-out), stroke 320ms var(--ease-out); }
.rt-memory-tick {
  fill: none;
  stroke: rgba(var(--ink-text-3-rgb) / 0.34);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke 320ms var(--ease-out);
}
.rt-memory-label { fill: rgba(var(--ink-text-3-rgb) / 0.75); font-size: 10px; letter-spacing: 0.6px; }
.rt-stage[data-state="resolved"] .rt-mem-face.rt-face-t {
  fill: rgba(var(--sig-green-lift-rgb) / 0.22);
  stroke: var(--sig-green-lift);
  filter: drop-shadow(var(--glow-live-ink));
}
.rt-stage[data-state="resolved"] .rt-memory-tick { stroke: var(--sig-green-lift); }
.rt-stage[data-state="resolved"] .rt-memory-label { fill: var(--sig-green-lift); }

/* ---- the decision ledger · parked low-left on the quiet board floor,
   clear of headline + CTAs and the busier top-right ---- */
.rt-readout {
  position: absolute;
  z-index: 2;
  left: 46%;
  bottom: 13%;
  width: min(342px, 29vw);
  padding: 13px 15px 14px;
  border: 1px solid rgba(255, 255, 255, 0.11);
  border-radius: 12px;
  background: rgba(9, 18, 32, 0.8);
  box-shadow: var(--specular-ink), 0 18px 36px -24px rgba(0, 0, 0, 0.75);
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out);
}
.rt-readout.is-on { opacity: 1; transform: translateY(0); }
.rt-read-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 9px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.rt-read-kicker, .rt-read-label {
  font-family: var(--font-mono);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.13em;
}
.rt-read-kicker { color: var(--ink-text-3); font-size: var(--fs-3xs); }
.rt-read-title {
  color: #fff;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 500;
  letter-spacing: 0.035em;
}
.rt-read-grid { display: block; padding-top: 10px; }
.rt-read-row {
  display: none;
  grid-template-columns: 74px minmax(0, 1fr);
  gap: 8px;
  align-items: start;
  opacity: 0.25;
  transition: opacity 230ms var(--ease-out);
}
.rt-read-row.is-on { opacity: 0.72; }
.rt-read-row.is-current { display: grid; opacity: 1; }
.rt-read-label { color: var(--ink-text-3); font-size: var(--fs-4xs); line-height: var(--lh-tight); }
.rt-read-value { color: var(--ink-text-2); font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: 500; line-height: var(--lh-tight); }
.rt-read-row.is-current .rt-read-label,
.rt-read-row.is-current .rt-read-value { color: var(--sig-green-lift); }

/* ---- scenario · one causal chain at a time ---- */
.rt-scenario { opacity: 0; transition: opacity 200ms var(--ease-out); }
.rt-scenario.is-active { opacity: 1; }
.rt-signal-bed, .rt-signal-path, .rt-exposed-bed, .rt-exposed-path,
.rt-alt-bed, .rt-alt-path, .rt-memory-path, .rt-motion-path {
  fill: none;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.rt-signal-bed, .rt-signal-path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 2.2s linear;
}
.rt-signal-bed { stroke: rgba(var(--f4-warn-rgb) / 0.16); stroke-width: 13; }
.rt-signal-path { stroke: var(--f4-warn); stroke-width: 2; }
.rt-scenario.is-active .rt-signal-bed,
.rt-scenario.is-active .rt-signal-path { stroke-dashoffset: 0; }
.rt-exposed-bed, .rt-exposed-path { opacity: 0; transition: opacity 260ms var(--ease-out); }
.rt-exposed-bed { stroke: rgba(var(--f4-warn-rgb) / 0.09); stroke-width: 13; }
.rt-exposed-path { stroke: rgba(var(--f4-warn-rgb) / 0.56); stroke-width: 1.4; stroke-dasharray: 7 8; }
.rt-scenario.is-detected .rt-exposed-bed { opacity: 1; }
.rt-scenario.is-detected .rt-exposed-path { opacity: 0.86; }
.rt-scenario.is-routed .rt-exposed-bed { opacity: 0.1; }
.rt-scenario.is-routed .rt-exposed-path { opacity: 0.16; }
.rt-alt-bed, .rt-alt-path, .rt-memory-path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1.05s var(--ease-out);
}
.rt-alt-bed { stroke: rgba(var(--sig-green-lift-rgb) / 0.16); stroke-width: 13; }
.rt-alt-path { stroke: var(--sig-green-lift); stroke-width: 2; filter: drop-shadow(var(--glow-live-ink)); }
.rt-scenario.is-routed .rt-alt-bed,
.rt-scenario.is-routed .rt-alt-path { stroke-dashoffset: 0; }
.rt-memory-path { stroke: var(--sig-green-lift); stroke-width: 1.25; filter: drop-shadow(var(--glow-live-ink)); transition-duration: 850ms; }
.rt-scenario.is-resolved .rt-memory-path { stroke-dashoffset: 0; }
.rt-motion-path { stroke: transparent; }

/* ---- origin distress mark ---- */
.rt-origin { opacity: 0; transition: opacity 200ms var(--ease-out); }
.rt-scenario.is-active .rt-origin { opacity: 1; }
.rt-origin-mark { fill: rgba(var(--f4-warn-rgb) / 0.12); stroke: var(--f4-warn); stroke-width: 1.4; }
.rt-origin-label, .rt-junction-label, .rt-sensor-label, .rt-result-label {
  font-size: 9px;
  letter-spacing: 1px;
}
.rt-origin-label { fill: var(--f4-warn); }

/* ---- signal beacon ---- */
.rt-beacon-post { stroke: rgba(var(--f4-warn-rgb) / 0.7); stroke-width: 2; stroke-linecap: round; vector-effect: non-scaling-stroke; opacity: 0; transition: opacity 220ms var(--ease-out); }
.rt-sensor-core { fill: var(--f4-warn); stroke: rgba(255, 255, 255, 0.5); stroke-width: 1; opacity: 0; transition: opacity 220ms var(--ease-out); filter: drop-shadow(0 0 7px rgba(var(--f4-warn-rgb) / 0.55)); }
.rt-scenario.is-detected .rt-beacon-post,
.rt-scenario.is-detected .rt-sensor-core { opacity: 1; }
.rt-sensor-ring {
  fill: none;
  stroke: var(--f4-warn);
  stroke-width: 1.25;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}
.rt-scenario.is-detected .rt-sensor-ring-a { animation: rtSense 1.5s var(--ease-out) both; }
.rt-scenario.is-detected .rt-sensor-ring-b { animation: rtSense 1.5s var(--ease-out) 160ms both; }
.rt-sensor-label { fill: var(--f4-warn); opacity: 0; transition: opacity 220ms var(--ease-out); }
.rt-scenario.is-detected .rt-sensor-label { opacity: 1; }
@keyframes rtSense {
  0% { opacity: 0; transform: scale(0.5); }
  32% { opacity: 0.9; }
  100% { opacity: 0.12; transform: scale(1.18); }
}

/* ---- decision switch ---- */
.rt-junction-ring { fill: var(--ink-900); stroke: rgba(var(--ink-text-3-rgb) / 0.56); stroke-width: 1.3; vector-effect: non-scaling-stroke; transition: stroke 240ms var(--ease-out); }
.rt-switch-arm {
  stroke: var(--ink-text-2);
  stroke-width: 2;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 520ms var(--ease-out), stroke 240ms var(--ease-out);
}
.rt-switch-pin { fill: var(--ink-text-2); }
.rt-junction-label { fill: var(--ink-text-3); }
.rt-scenario.is-weighed .rt-junction-ring { stroke: var(--f4-warn); }
.rt-scenario.is-routed .rt-switch-arm { transform: rotate(90deg); stroke: var(--sig-green-lift); }
.rt-scenario[data-scenario="promotion"].is-routed .rt-switch-arm { transform: rotate(-90deg); }
.rt-scenario[data-scenario="vessel"] .rt-switch-arm { transform: rotate(-90deg); }
.rt-scenario[data-scenario="vessel"].is-routed .rt-switch-arm { transform: rotate(0); }
.rt-scenario.is-routed .rt-junction-ring { stroke: var(--sig-green-lift); filter: drop-shadow(var(--glow-live-ink)); }

/* ---- the moving loads · fruit tokens, coloured in the produce-fruit block ---- */
.rt-capsule { opacity: 0; }
.rt-scenario.is-active .rt-capsule { opacity: 1; }
.rt-plan-token { opacity: 0; transition: opacity 180ms var(--ease-out); }
.rt-scenario.is-routed .rt-plan-token { opacity: 1; }
.rt-result-label { fill: var(--sig-green-lift); opacity: 0; transition: opacity 250ms var(--ease-out); }
.rt-scenario.is-resolved .rt-result-label { opacity: 1; }

@media (max-width: 1279px) {
  .rt-readout { left: 45%; bottom: 11%; width: min(330px, 35vw); padding-inline: 12px; }
  .rt-read-row { grid-template-columns: 68px minmax(0, 1fr); gap: 6px; }
  .rt-memory-label { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .rt-road, .rt-location, .rt-plot, .rt-lattice, .rt-timeline, .rt-sensor-ring,
  .rt-alt-bed, .rt-alt-path, .rt-memory-path, .rt-readout, .rt-switch-arm {
    animation: none !important;
    transition: none !important;
  }
}
/* ===================== HERO VARIANT · DECISION ROUTING · END ============== */

/* ===================== HERO VARIANT · SPACE · BEGIN ====================== */
/* space hero (.sp-*) · a real-rotation wireframe MELON (cantaloupe) seen with
   cinematic camera work. Orthographic sphere projection: the world turns
   through a fixed green NOW terminator (forecast → actual), the orbital tiers
   are inclined 3-D rings with occlusion, freighters are depth-sorted shipments,
   and the camera is a sprung dolly/pan/dutch with speed-ramp. Desktop + motion. */
.sp-stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* fade-only dissolve · no blur (read as "out of focus"; see .rt-stage) */
  opacity: calc(1 - var(--cv, 0) * 1.6);
  /* hero safe zone · only faint ambient bleeds behind the copy column */
  -webkit-mask-image: var(--hero-safe);
          mask-image: var(--hero-safe);
}
/* the camera rig · JS drives translate/scale/rotate; the scene pulls back on scroll */
.sp-camera {
  position: absolute;
  inset: 0;
  will-change: transform;
}
.sp-scene {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  overflow: visible;
  animation: nfBootFade 700ms var(--ease-out) 200ms backwards;
}
.sp-boot { animation: nfBootFade 640ms var(--ease-out) backwards; }

/* the starfield · faint points on the deepest plane */
.sp-star { fill: var(--ink-text-3); }

/* the orbital tiers · inclined 3-D rings; front arcs bright, back arcs dim */
.sp-orbit { fill: none; stroke-width: 1; stroke-linecap: round; }
.sp-orbit.o0 { stroke: rgba(var(--ink-text-3-rgb) / 0.22); }
.sp-orbit.o1 { stroke: rgba(var(--ink-text-3-rgb) / 0.26); }
.sp-orbit.o2 { stroke: rgba(var(--ink-text-3-rgb) / 0.32); }
.sp-orbit.back { stroke-opacity: 0.3; stroke-dasharray: 2 7; }

/* the planet · a wireframe melon (cantaloupe); the lit half is the settled past */
.sp-fill { fill: rgb(var(--f4-ink-rgb) / 0.55); }
.sp-grid { fill: none; stroke-linecap: round; }
.sp-grid.merid { stroke: rgba(var(--ink-text-3-rgb) / 0.34); stroke-width: 0.9; }   /* lobe meridians */
.sp-grid.para  { stroke: rgba(var(--ink-text-3-rgb) / 0.30); stroke-width: 0.9; }   /* parallels · give volume */
.sp-grid.far   { stroke-opacity: 0.14; }   /* the back hemisphere ghosts through */
.sp-limb { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.62); stroke-width: 1.7; }   /* a crisp horizon */
/* the terminator · NOW · flat at rest, faded toward the poles so it lies on the surface */
.sp-term {
  stroke: url(#spNowFade); stroke-width: 1.6;
  filter: drop-shadow(0 0 3px rgb(var(--sig-green-rgb) / 0.3));
  animation: nfBreathe 4s ease-in-out infinite;
}
/* the calyx crown · the blueberry's green star at the pole (sacred green, flat) */
.sp-basin { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.32); stroke-width: 1; }
.sp-sepal { fill: rgb(var(--sig-green-lift-rgb) / 0.42); stroke: var(--sig-green-lift); stroke-width: 1; stroke-linejoin: round; }
.sp-calyxhub { fill: var(--sig-green-lift); }
.sp-nowtag {
  fill: var(--sig-green-lift);
  font-family: var(--font-mono); font-weight: 500; font-size: 15px;
  letter-spacing: 1.4px; text-transform: uppercase;
  paint-order: stroke; stroke: var(--f4-ink, var(--f4-ink)); stroke-width: 3px; stroke-linejoin: round;
}

/* growing regions · hollow while forecast, filled the instant they cross NOW */
.sp-regdot {
  fill: none; stroke: var(--ink-text-2); stroke-width: 1.5;
  transition: fill 260ms var(--ease-out), stroke 260ms var(--ease-out);
}
.sp-region.lit .sp-regdot { fill: var(--ink-text-2); stroke: rgba(255,255,255,0.4); }
.sp-region.cross .sp-regdot { fill: var(--sig-green-lift); stroke: var(--sig-green-lift); filter: drop-shadow(var(--glow-live-ink)); }
.sp-region.hit .sp-regdot { fill: var(--f4-warn); stroke: var(--f4-warn); }

/* the hail asteroid · streaks in and craters kent · amber risk + neutral white-hot */
.sp-asteroid { fill: var(--ink-text-3); stroke: rgba(255, 255, 255, 0.75); stroke-width: 1.2; stroke-linejoin: round; }
.sp-asthot { fill: none; stroke: var(--f4-warn); stroke-width: 2.4; stroke-linecap: round; }
/* stroked with the spAstFade gradient so the streak burns out toward its tail */
.sp-astrail { fill: none; stroke: url(#spAstFade); stroke-width: 3; stroke-linecap: round; }
.sp-flash { fill: #fff; }
.sp-shock { fill: none; stroke: var(--f4-warn); stroke-width: 2; }
.sp-debris { fill: var(--f4-warn); }
/* the crater · amber while the risk is live, neutral once the decision lands */
.sp-crater { fill: rgb(var(--f4-warn-rgb) / 0.12); stroke: var(--f4-warn); stroke-width: 1.6; stroke-dasharray: 3 3; }
.sp-crater.settled { fill: none; stroke: var(--ink-text-3); stroke-dasharray: none; }

/* the promotion rocket · neutral hull, teal volume label, amber exhaust + margin */
.sp-rocket { fill: var(--ink-700); stroke: rgba(255, 255, 255, 0.5); stroke-width: 1.2; stroke-linejoin: round; }
.sp-rocketfin { fill: rgba(255, 255, 255, 0.12); stroke: rgba(255, 255, 255, 0.4); stroke-width: 1; stroke-linejoin: round; }
.sp-payload { fill: rgba(255, 255, 255, 0.12); stroke: rgba(255, 255, 255, 0.45); stroke-width: 1; }
.sp-payload-lab {
  fill: var(--f4-signal);
  font-family: var(--font-mono); font-weight: 500; font-size: 12px; letter-spacing: 0.6px;
  paint-order: stroke; stroke: var(--f4-ink, var(--f4-ink)); stroke-width: 3px; stroke-linejoin: round;
}
.sp-exhaust { fill: none; stroke: var(--f4-warn); stroke-width: 3; stroke-linecap: round; }
.sp-marginbit circle { fill: var(--f4-warn); }
.sp-marginbit text {
  fill: var(--f4-warn);
  font-family: var(--font-mono); font-weight: 500; font-size: 11px; letter-spacing: 0.4px;
  paint-order: stroke; stroke: var(--f4-ink, var(--f4-ink)); stroke-width: 3px; stroke-linejoin: round;
}

/* the moon · a small neutral wireframe body · the import port vessels berth at */
.sp-moon { fill: rgb(var(--f4-ink-rgb) / 0.72); }
.sp-moonlimb { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.5); stroke-width: 1.4; }
.sp-mooncrater { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.34); stroke-width: 1; }
.sp-moonwire { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.28); stroke-width: 0.9; }
.sp-moondock { fill: var(--ink-text-3); }

/* the comet · the PREDICTABLE seasonal peak on a known orbit · info teal, never amber */
.sp-comet-tail { fill: rgb(var(--f4-signal-rgb) / 0.16); stroke: none; }
.sp-comet-head { fill: var(--f4-signal); }
.sp-comet-lab {
  fill: var(--f4-signal);
  font-family: var(--font-mono); font-weight: 500; font-size: 12px;
  letter-spacing: 0.8px; text-transform: uppercase;
  paint-order: stroke; stroke: var(--f4-ink, var(--f4-ink)); stroke-width: 3px; stroke-linejoin: round;
}

/* the scanning satellite · the "sees" layer · a teal scan beam over the world */
.sp-sat { fill: var(--ink-700); stroke: rgba(255, 255, 255, 0.5); stroke-width: 1; }
.sp-satpanel { stroke: rgba(var(--ink-text-3-rgb) / 0.6); stroke-width: 1.4; }
.sp-scan { fill: rgb(var(--f4-signal-rgb) / 0.10); stroke: rgb(var(--f4-signal-rgb) / 0.4); stroke-width: 0.8; }

/* the docking latch · the "protected" beat made physical · flat green, no glow */
.sp-latch { opacity: 0; transition: opacity 200ms var(--ease-out); }
.sp-latch.on { opacity: 1; }
.sp-latchjaw { fill: none; stroke: var(--sig-green); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }

/* memory stars · the "remembers" beat · each caught decision written to the field */
.sp-memstar { opacity: 0; }
.sp-memstar.on { opacity: 1; animation: spMem 620ms var(--ease-out); }
.sp-memdot { fill: var(--sig-green-lift); }
.sp-memleader { stroke: rgb(var(--sig-green-rgb) / 0.5); stroke-width: 1; stroke-dasharray: 2 3; }
@keyframes spMem { from { opacity: 0; } }

/* stations · a machined square riding each tier (right hemisphere) */
.sp-stabox { fill: var(--ink-700); stroke: rgba(255,255,255,0.30); stroke-width: 1.4; }
.sp-station.hit .sp-stabox { fill: rgb(var(--f4-warn-rgb) / 0.2); stroke: var(--f4-warn); }
.sp-stalab {
  fill: var(--ink-text-3);
  font-family: var(--font-mono); font-weight: 500; font-size: 13px;
  letter-spacing: 0.8px; text-transform: uppercase;
  text-anchor: end;
  paint-order: stroke; stroke: var(--f4-ink, var(--f4-ink)); stroke-width: 3px; stroke-linejoin: round;
}

/* freighters · a small chevron with a graded thruster tail; blue is the import */
.sp-fbody { fill: rgb(var(--sig-green-lift-rgb) / 0.16); stroke: var(--sig-green-lift); stroke-width: 1.4; stroke-linejoin: round; }
.sp-ftail { stroke: var(--sig-green-lift); stroke-width: 1.6; stroke-linecap: round; opacity: 0.4; }
.sp-freighter.blue .sp-fbody { fill: rgb(var(--f4-blue-rgb) / 0.16); stroke: var(--f4-blue-lift); }
.sp-freighter.blue .sp-ftail { stroke: var(--f4-blue-lift); }
.sp-freighter.blue.misfire .sp-fbody { stroke: var(--f4-warn); }

/* the transfer arcs · one green reroute per act, drawn on cue */
.sp-arc {
  fill: none; stroke: var(--sig-green); stroke-width: 2.2; stroke-linecap: round;
  stroke-dasharray: 4 4; stroke-dashoffset: 100; opacity: 0;
}
.sp-arc.draw { opacity: 1; animation: mvDraw 700ms var(--ease-out) forwards; }

/* the HUD · video-game corner readouts, flat (not in the camera) */
.sp-hud {
  position: absolute;
  right: 4%; top: 7%;
  display: flex; flex-direction: column; align-items: flex-end; gap: 3px;
  text-align: right;
  animation: nfBootFade 500ms var(--ease-out) 1400ms backwards;
}
.sp-hud b {
  font-family: var(--font-mono); font-weight: 500; font-style: normal;
  letter-spacing: 0.12em; text-transform: uppercase;
  font-size: var(--fs-3xs); color: var(--ink-text-3);
}
.sp-hrisk { color: var(--sig-green-lift) !important; font-size: var(--fs-sm) !important; }
.sp-hrisk.pop { animation: pmPop 420ms var(--ease-out); }

/* drama overlay · pinned inside the camera so chips ride with the world;
   JS (layoutSpMid) sizes it to the svg's slice box so anchors track exactly */
.sp-mid { position: absolute; pointer-events: none; }
.sp-anchor { position: absolute; width: 10px; height: 10px; margin: -5px 0 0 -5px; }
.sp-anchor.solved .nf-reticle::after { opacity: 1; transform: scale(1); }

/* reduced-motion belt-and-braces · the variant never mounts here */
@media (prefers-reduced-motion: reduce) {
  .sp-scene, .sp-boot, .sp-term, .sp-arc.draw, .sp-hud, .sp-hrisk.pop, .sp-memstar.on { animation: none !important; }
}
/* ===================== HERO VARIANT · SPACE · END ======================== */

/* ===================== HERO VARIANT · MOVEMENT · BEGIN =================== */
/* movement hero (.mv-*) · "Precision time" · the supply chain as a precision
   watch movement. The four gear rings ARE the stages (grower → packhouse →
   depot → retail), meshing as one slow coherent train; a single green hand is
   NOW, sweeping a fixed week calendar. Ahead of NOW = live forecast; the instant
   NOW crosses a mark it flips to a settled, locked actual and grays behind a
   trailing wedge. Built desktop + motion only. */
.mv-stage {
  position: absolute;
  inset: 0;
  /* fade + slight shrink dissolve · no blur (read as "out of focus"; see .rt-stage) */
  opacity: calc(1 - var(--cv, 0) * 1.6);
  transform: scale(calc(1 - var(--cv, 0) * 0.05));
  /* hero safe zone · only faint ambient bleeds behind the copy column */
  -webkit-mask-image: var(--hero-safe);
          mask-image: var(--hero-safe);
}
.mv-dialwrap { position: absolute; inset: 0; }
/* the dial and its HTML overlay share one square box · a square viewBox in a
   square box means no letterbox, so the drama grammar (cause chips, reticles,
   deltas) pins exactly onto the SVG rings at every screen size */
.mv-dial, .mv-mid, .mv-top {
  position: absolute;
  left: 64%; top: 50%;
  width: min(86vh, 60vw); height: min(86vh, 60vw);
  /* 2.5D bench-tilt · the instrument lies back on the bench, seen at an angle;
     the SVG dial and its HTML overlay tilt together so the drama stays pinned */
  transform: translate(-50%, -50%) perspective(1700px) rotateX(18deg);
  transform-origin: 50% 50%;
  overflow: visible;
}
.mv-plateg, .mv-wakeg, .mv-traing, .mv-handsg { will-change: transform; }

/* the group boot · each subsystem materialises in a quiet stagger */
.mv-boot { animation: mvBoot 640ms var(--ease-out) backwards; }
@keyframes mvBoot { from { opacity: 0; } }

/* the backplate · a brushed ink disc, hairline chapter circles, jewel screws */
#mvPlateG .a { stop-color: var(--ink-600); }
#mvPlateG .b { stop-color: var(--ink-700); }
#mvPlateG .c { stop-color: var(--ink-900); }
.mv-plate { fill: url(#mvPlateG); stroke: rgba(255,255,255,0.08); stroke-width: 2; }
.mv-hair  { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.14); stroke-width: 1; }
.mv-screw circle { fill: var(--ink-600); stroke: rgba(255,255,255,0.14); stroke-width: 1; }
.mv-screw line   { stroke: rgba(255,255,255,0.22); stroke-width: 1.5; }
.mv-hub { fill: var(--ink-500); stroke: rgba(255,255,255,0.2); stroke-width: 1.5; }
/* watch cues · a winding crown at 3 o'clock and an applied double index at 12 */
.mv-crown rect { fill: var(--ink-600); stroke: rgba(255,255,255,0.18); stroke-width: 1.4; }
.mv-crown line { stroke: rgba(255,255,255,0.16); stroke-width: 1; }
.mv-index line { stroke: var(--ink-text-2); stroke-width: 2.6; stroke-linecap: round; }
/* the bezel · a machined ring with 12 hour notches framing the dial */
.mv-bezel-ring { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.2); stroke-width: 2; }
.mv-bezel-tick { stroke: rgba(var(--ink-text-3-rgb) / 0.38); stroke-width: 2; stroke-linecap: round; }
.mv-bezel-tick.big { stroke: var(--ink-text-2); stroke-width: 3; stroke-linecap: round; }

/* the settlement wedge · the swept-past NOW leaves behind, dim and cool */
.mv-wake { fill: rgb(var(--ink-text-3-rgb) / 0.05); stroke: none; }

/* the stage gears · cool-white teeth, rims and spokes; alpha rises outward */
.mv-gear { fill: none; stroke-linejoin: round; }
.mv-gear.g0 { stroke: rgba(var(--ink-text-3-rgb) / 0.30); stroke-width: 1.3; }
.mv-gear.g1 { stroke: rgba(var(--ink-text-3-rgb) / 0.26); stroke-width: 1.2; }
.mv-gear.g2 { stroke: rgba(var(--ink-text-3-rgb) / 0.22); stroke-width: 1.1; }
.mv-gear.g3 { stroke: rgba(var(--ink-text-3-rgb) / 0.18); stroke-width: 1; }
.mv-rim   { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.12); stroke-width: 1; }
.mv-spoke { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.13); stroke-width: 1; stroke-linecap: round; }

/* stage identity · a small cool glyph per gear ring; the name discloses only
   while that stage's act runs (single-label disclosure keeps the dial calm) */
.mv-stagemark .mv-glyph {
  fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.5);
  stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round;
  transition: stroke 260ms var(--ease-out);
}
.mv-stagelab {
  fill: var(--ink-text-3);
  font-family: var(--font-mono); font-weight: 500; font-size: 15px;
  letter-spacing: 1px; text-transform: uppercase;
  opacity: 0; transition: opacity 260ms var(--ease-out);
}
.mv-stagemark.on .mv-glyph { stroke: var(--ink-text-1); }
.mv-stagemark.on .mv-stagelab { opacity: 1; }

/* transfer pinions + lead-time arcs · the mesh points where produce changes tier */
.mv-gate  { fill: var(--ink-600); stroke: rgba(255,255,255,0.16); stroke-width: 1.4; }
.mv-gatec { fill: rgba(var(--ink-text-3-rgb) / 0.5); }
.mv-lead  { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.3); stroke-width: 1.2; stroke-dasharray: 3 5; }

/* event wheels · meshing gears at the affected stages during a disruption; the
   rim carries the state (amber while the risk ripples through the chain, green
   the instant NOW catches it), the hub carries the stage icon */
.mv-egear { opacity: 0; }
.mv-egear.show { opacity: 1; animation: mvEgearIn 380ms var(--ease-out) backwards; }
@keyframes mvEgearIn { from { opacity: 0; } }
.mv-egear-teeth { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.55); stroke-width: 2; stroke-linejoin: round; }
.mv-egear-rim { fill: rgb(var(--ink-900-rgb) / 0.78); stroke: var(--f4-warn); stroke-width: 2.2; transition: stroke 360ms var(--ease-out); }
.mv-egear-hub { fill: var(--ink-800); stroke: rgba(255,255,255,0.08); stroke-width: 1; }
.mv-egear-ic { fill: none; stroke: var(--ink-text-1); stroke-width: 1.7; stroke-linejoin: round; stroke-linecap: round; }
.mv-egear.ok .mv-egear-rim { stroke: var(--sig-green-lift); }
.mv-egear.ok .mv-egear-teeth { stroke: rgba(var(--sig-green-lift-rgb) / 0.5); }

/* re-routes · one dashed green alternative per act, drawn on cue */
.mv-alt {
  fill: none; stroke: var(--sig-green); stroke-width: 2.4; stroke-linecap: round;
  stroke-dasharray: 4 4;
  stroke-dashoffset: 100;
  opacity: 0;
}
.mv-alt.draw { opacity: 1; animation: mvDraw 700ms var(--ease-out) forwards; }
@keyframes mvDraw { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }

/* the keyless works · the import channel in from the case edge */
.mv-imprail { stroke: rgba(var(--f4-blue-rgb) / 0.5); stroke-width: 1.2; stroke-dasharray: 2 4; }

/* memory · the cap at 6 o'clock that receives the decision */
.mv-memcap { fill: var(--ink-700); stroke: rgba(255,255,255,0.14); stroke-width: 1.4; }
.mv-memin  { fill: none; stroke: rgba(var(--sig-green-lift-rgb) / 0.4); stroke-width: 1.2; }
.mv-caplab {
  fill: var(--ink-text-3);
  font-family: var(--font-mono); font-weight: 500; font-size: 15px;
  letter-spacing: 1.5px; text-transform: uppercase;
}
/* memory written · the cap lights green and pulses as the decision lands */
.mv-memg.written .mv-memcap { stroke: var(--sig-green-lift); animation: mvMemPulse 720ms var(--ease-out); }
.mv-memg.written .mv-memin { stroke: var(--sig-green-lift); }
.mv-memg.written .mv-caplab { fill: var(--sig-green-lift); }
@keyframes mvMemPulse { 0% { stroke-width: 1.4; } 45% { stroke-width: 3.6; } 100% { stroke-width: 1.4; } }

/* produce jewels · hollow green rings working the train; ink once settled */
.mv-jewel {
  fill: rgb(var(--sig-green-lift-rgb) / 0.12);
  stroke: var(--sig-green-lift); stroke-width: 2;
  transition: stroke 400ms var(--ease-out), fill 400ms var(--ease-out);
}
.mv-jewel.settled { fill: none; stroke: rgba(var(--ink-text-3-rgb) / 0.4); }
.mv-jewel.blue  { fill: rgb(var(--f4-blue-rgb) / 0.14); stroke: var(--f4-blue-lift); }
.mv-jewel.blue.held { stroke: var(--f4-warn); }
.mv-jewel.surge { stroke-width: 1.6; }
.mv-jewel.mem   { fill: var(--sig-green-lift); stroke: none; filter: drop-shadow(0 0 7px rgb(var(--sig-green-lift-rgb) / 0.6)); }
.mv-jewel.mem.drop { animation: mvDrop 700ms var(--ease-out) backwards; }
@keyframes mvDrop { from { opacity: 0; transform: translateY(-40px); } }

/* the week calendar · the fixed horizon; forecast cool ahead of NOW, settled
   ink behind it, with a brief green pulse the instant NOW crosses a mark */
.mv-wktick { stroke: rgba(var(--ink-text-3-rgb) / 0.34); stroke-width: 1.2; transition: stroke 500ms var(--ease-out); }
.mv-wktick.big { stroke: rgba(var(--ink-text-3-rgb) / 0.5); stroke-width: 1.4; }
.mv-wktick.settled { stroke: rgba(var(--ink-text-3-rgb) / 0.16); }
.mv-wktick.commit { animation: mvCommit 620ms var(--ease-out); }
@keyframes mvCommit { 0% { stroke: var(--sig-green-lift); } 100% { stroke: rgba(var(--ink-text-3-rgb) / 0.16); } }
.mv-wklab {
  fill: var(--ink-text-3);
  font-family: var(--font-mono); font-weight: 500; font-size: 17px;
  letter-spacing: 0.5px; transition: fill 500ms var(--ease-out);
}
.mv-wklab.settled { fill: rgba(var(--ink-text-3-rgb) / 0.4); }

/* the NOW-hand · the single sweeping now; a flat green blade with a leading
   vane whose tip is the one live glow (glow reserved for the live edge) */
.mv-nowvane {
  stroke: var(--sig-green-lift); stroke-width: 2; stroke-linecap: round;
  filter: drop-shadow(0 0 5px rgb(var(--sig-green-lift-rgb) / 0.5));
}
.mv-hand { fill: var(--sig-green); }
.mv-handcw  { fill: var(--sig-green); }
.mv-handhub { fill: var(--sig-green-lift); stroke: var(--ink-900); stroke-width: 1.5; }
/* the hour hand · a short steel hand (today's coarse position in the year) */
.mv-hour { fill: var(--ink-text-2); }

/* the outer stage-gear brightens a step as the baseline lifts (planning act) */
.mv-stage.lift .mv-gear.g3 { stroke: rgba(var(--sig-green-lift-rgb) / 0.3); transition: stroke 600ms var(--ease-out); }

/* HTML overlays · anchors carry the shared drama grammar */
.mv-mid, .mv-top { pointer-events: none; }
.mv-anchor { position: absolute; width: 10px; height: 10px; margin: -5px 0 0 -5px; }
.mv-anchor.solved .nf-reticle::after { opacity: 1; transform: scale(1); }
.mv-nowdot {
  position: absolute;
  width: 8px; height: 8px; margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: var(--sig-green-lift);
  box-shadow: var(--glow-live-ink);
  animation: nfBreathe 3s ease-in-out infinite;
}
.mv-nowtag {
  position: absolute;
  font-family: var(--font-mono); font-weight: 500;
  font-size: var(--fs-3xs); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--sig-green-lift);
  white-space: nowrap;
  transform: translate(-50%, -50%);
  animation: nfBootFade 400ms var(--ease-out) 1250ms backwards;
}

/* reduced-motion belt-and-braces · the variant never mounts here */
@media (prefers-reduced-motion: reduce) {
  .mv-boot, .mv-alt.draw, .mv-jewel.mem.drop, .mv-wktick.commit, .mv-nowdot { animation: none !important; }
}
/* ===================== HERO VARIANT · MOVEMENT · END ===================== */

/* ============================================================
   10 · S1 · supply-chain ripple timeline
   ============================================================ */
/* The ripple readout is cut from the same ink the hero instrument is made of —
   an inset dark slab seated in the light "printed page" section. Finish, not
   float: a specular top edge + tight contact shadow + hairline so a dark object
   reads as machined into the paper, never a hole punched in it. */
.chain-demo {
  margin-top: var(--space-48);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: var(--radius-card);
  background:
    radial-gradient(900px 420px at 88% -12%, rgb(var(--f4-blue-rgb) / 0.10), transparent 60%),
    linear-gradient(180deg, var(--ink-700), var(--ink-900));
  box-shadow:
    var(--specular-ink),
    0 1px 0 rgb(var(--ink-900-rgb) / 0.5),
    0 28px 56px -30px rgb(var(--ink-900-rgb) / 0.6);
  padding: var(--space-24) var(--space-32) var(--space-28);
  position: relative;
}
/* header · title and the incoming-event label share one line */
.chain-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-16); flex-wrap: wrap;
  margin-bottom: var(--space-18);
}
/* the instrument's own label · a hollow registration dot + mono eyebrow */
.chain-kicker {
  display: flex; align-items: center; gap: var(--space-8);
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-text-2);
}
.chain-kicker::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  border: 1.5px solid var(--ink-text-3);
}
.chain-eyebrow {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-text-3);
}
/* the three incoming events · restyled to the hero's scenario-console idiom */
.chain-events { display: flex; flex-wrap: wrap; gap: var(--space-8); margin-bottom: var(--space-24); }
.chain-event {
  display: inline-flex; align-items: center; gap: var(--space-8);
  padding: var(--space-8) var(--space-16) var(--space-8) var(--space-12);
  border-radius: var(--radius-pill);
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.05);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-text-2);
  transition: border-color 200ms var(--ease-out), color 200ms var(--ease-out), background 200ms var(--ease-out), box-shadow 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.chain-event::before { content: "\25B8"; color: var(--ink-text-3); transition: color 200ms var(--ease-out); }
.chain-event:hover { color: var(--ink-text-1); border-color: var(--sig-green-lift); transform: translateY(-1px); }
.chain-event:hover::before { color: var(--sig-green-lift); }
.chain-event:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--sig-green-lift); }
/* armed = genuinely live · a flat green outline + the one sanctioned live glow */
.chain-event[aria-pressed="true"] {
  color: var(--sig-green-lift);
  border-color: var(--sig-green-lift);
  background: rgb(var(--sig-green-lift-rgb) / 0.08);
  box-shadow: 0 0 0 1px rgb(var(--sig-green-lift-rgb) / 0.4), var(--glow-live-ink);
}
.chain-event[aria-pressed="true"]::before { color: var(--sig-green-lift); }
.chain {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 0;
  position: relative;
}
/* persistent wiring · sagged lanes + faint desk columns, drawn by the engine */
.chain-wires {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: 0;
}
.chain-col { stroke: rgba(255, 255, 255, 0.05); stroke-width: 1px; }
.chain-wire {
  fill: none;
  stroke: rgba(174, 189, 208, 0.22);
  stroke-width: 1.25px;
  transition: stroke 350ms var(--ease-out), stroke-opacity 350ms var(--ease-out);
}
.chain-wire.dashed { stroke-dasharray: 5 4; }
/* trouble on the lane · amber residue, and it stays (nothing catches it here) */
.chain-wire.surge { stroke: var(--f4-warn); stroke-opacity: 0.8; }
.chain-node { position: relative; text-align: center; padding-top: 0; z-index: 3; }
.chain-node .cn-dot {
  width: 52px; height: 52px;
  margin: 0 auto;
  border-radius: 50%;
  border: 1.5px solid rgb(var(--ink-text-1-rgb) / 0.26);
  background: var(--ink-700);
  box-shadow: var(--specular-ink), 0 6px 16px -8px rgba(0, 0, 0, 0.5);
  display: grid; place-items: center;
  color: var(--ink-text-2);
  position: relative;
  z-index: 1;
  transition: border-color 250ms var(--ease-out), color 250ms var(--ease-out), box-shadow 250ms var(--ease-out), background 250ms var(--ease-out);
}
.chain-node .cn-dot svg { width: 22px; height: 22px; }
/* node grammar borrowed from the hero · circles are fields/shelves, squares are
   facilities, and the depot carries the one blue reference/logistics accent */
.chain-node.cn-square .cn-dot { border-radius: var(--radius-xs); }
.chain-node.cn-depot .cn-dot {
  color: var(--f4-blue-lift);
  border-color: rgba(127, 184, 242, 0.5);
  box-shadow: var(--specular-ink), 0 0 0 4px rgb(var(--f4-blue-rgb) / 0.12), 0 6px 16px -8px rgba(0, 0, 0, 0.5);
}
.chain-node .cn-name { display: block; margin-top: 0.5rem; font-size: var(--fs-cap); font-weight: 600; color: var(--ink-text-1); }
/* lead-time made visible · the hero's DAY grammar, rotated onto the chain */
.chain-node .cn-day {
  display: block;
  margin-top: 0.1875rem;
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-text-3);
}
/* shelf-life · restyled from a flat pill into a recessed instrument gauge with
   a baked terminal redline; the fill stays flat signal-green (the one live green
   on the panel) and drains green -> amber -> red in the packet's wake */
.chain-node .cn-shelf {
  display: block;
  margin: 0.5rem auto 0;
  width: 66%;
  height: 4px;
  border-radius: var(--radius-xs);
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.06) 0 82%, rgb(var(--f4-warn-rgb) / 0.16) 90%, rgb(var(--f4-crit-rgb) / 0.28) 100%);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.4);
  overflow: hidden;
}
.chain-node .cn-shelf i {
  display: block; height: 100%; width: 100%;
  background: var(--sig-green-lift);
  border-radius: var(--radius-xs);
  transform: scaleX(var(--sh, 1));
  transform-origin: left;
  transition: transform 700ms var(--ease-out), background 400ms var(--ease-out);
}
.chain-node .cn-shelf.low i { background: var(--f4-warn); }
.chain-node .cn-shelf.crit i { background: var(--f4-crit); }
.chain-node .cn-delta {
  display: block;
  margin-top: 0.375rem;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  color: var(--ink-text-2);
  min-height: 1.2em;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 300ms var(--ease-out), transform 300ms var(--ease-out);
}
.chain-node.hit .cn-dot {
  border-color: var(--f4-warn);
  color: var(--warn-ink);
  background: rgb(var(--f4-warn-rgb) / 0.14);
  box-shadow: 0 0 0 5px rgb(var(--f4-warn-rgb) / 0.12), 0 0 16px rgb(var(--f4-warn-rgb) / 0.5);
}
.chain-node.hit .cn-delta { opacity: 1; transform: none; color: var(--warn-ink); }
/* severity escalates with distance from the origin */
.chain-node.hit.sev-crit .cn-dot {
  border-color: var(--f4-crit);
  color: var(--crit-ink);
  background: rgb(var(--f4-crit-rgb) / 0.16);
  box-shadow: 0 0 0 5px rgb(var(--f4-crit-rgb) / 0.14), 0 0 18px rgb(var(--f4-crit-rgb) / 0.55);
}
.chain-node.hit.sev-crit .cn-delta { color: var(--crit-ink); font-weight: 600; }
/* the origin wears the cause, not a consequence · a neutral cool-white strike
   (defined last so it wins over .hit / .sev-crit on the origin node) */
.chain-node.origin .cn-dot {
  border-color: rgb(var(--ink-text-1-rgb) / 0.9);
  color: var(--ink-text-1);
  background: var(--ink-700);
  box-shadow: 0 0 0 5px rgb(var(--ink-text-1-rgb) / 0.1), 0 0 14px rgb(var(--ink-text-1-rgb) / 0.35);
}
.chain-node.origin .cn-delta { color: var(--ink-text-1); font-weight: 600; }

/* the packet cracks each node as it passes · amplitude set per node in JS */
.chain-node .cn-dot::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  border: 2px solid currentColor;
  opacity: 0;
  pointer-events: none;
}
.chain-node.jolt .cn-dot { animation: chainJolt 900ms var(--ease-out); }
.chain-node.jolt .cn-dot::after { animation: chainShock 750ms var(--ease-out); }
@keyframes chainJolt {
  0%   { transform: translateY(0) rotate(0deg); }
  16%  { transform: translateY(calc(var(--jolt, 6px) * -1)) rotate(calc(var(--jrot, 3deg) * -1)); }
  38%  { transform: translateY(calc(var(--jolt, 6px) * 0.6)) rotate(var(--jrot, 3deg)); }
  62%  { transform: translateY(calc(var(--jolt, 6px) * -0.3)) rotate(calc(var(--jrot, 3deg) * -0.5)); }
  82%  { transform: translateY(calc(var(--jolt, 6px) * 0.12)) rotate(0deg); }
  100% { transform: translateY(0) rotate(0deg); }
}
@keyframes chainShock {
  0%   { transform: scale(0.9); opacity: 0.8; }
  100% { transform: scale(var(--ring, 2)); opacity: 0; }
}
.chain-consequence {
  margin-top: var(--space-20);
  padding-top: var(--space-16);
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  font-size: var(--fs-md);
  color: var(--ink-text-2);
  min-height: 2.5em;
}
.chain-consequence strong { color: var(--ink-text-1); font-weight: 600; }
@media (max-width: 767px) {
  .chain { grid-template-columns: repeat(5, 1fr); }
  .chain-node .cn-name { font-size: var(--fs-xs); }
  .chain-node .cn-dot { width: 40px; height: 40px; }
  .chain-node .cn-dot svg { width: 16px; height: 16px; }
  .chain-node .cn-day { display: none; }
  .chain-node .cn-delta { display: none; }
}

/* ============================================================
   11 · The six moves · "six moves on one model"
   Spec §4.2 pinned this over ~5.4 viewports. The pin stopped the
   page's scrolling flow dead, so the section now plays itself in
   normal flow on the house story clock (.sj, §"story journey"):
   a six-act rail that seeks, a mono caption, one graph that
   transforms move to move. Mobile + reduced motion keep the 2×3
   small-multiples grid, unchanged.
   ============================================================ */
.sj.mj { grid-template-columns: minmax(260px, 5fr) 7fr; }
.mj-stage { position: relative; }
.mj-stage::before {              /* the signal zone · a faint bloom behind the graph */
  content: "";
  position: absolute;
  inset: -8% 0;                  /* no sideways bleed · a full-width stage scrolled the page */
  background: radial-gradient(closest-side, rgb(var(--sig-green-rgb) / 0.09), transparent 75%);
  pointer-events: none;
}
.mj-stage svg { width: 100%; height: auto; display: block; position: relative; }
/* a reader on the rail is reading · the clock hairline holds with the story */
.sj.mj.mj-hold .sj-acts button.on::after { animation-play-state: paused; }
.graph-legend {
  margin-top: 1rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  color: var(--ink-text-2);
}
.graph-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 6px; vertical-align: -1px; }
.graph-legend .lg-demand i { background: var(--sig-green); }
.graph-legend .lg-supply i { background: var(--f4-ink-800); border: 1.5px solid rgba(255,255,255,.6); }
.graph-legend .lg-product i { background: transparent; border: 1.75px solid var(--sig-green); }

/* --- node-graph SVG state machine ---
   elements carry b1..b6 classes = beats where they are visible */
.f4graph .gb { opacity: 0; transition: opacity 550ms var(--ease-out), transform 700ms var(--ease-out); }
.f4graph .gl { transition: opacity 550ms var(--ease-out), stroke-dashoffset 900ms var(--ease-out); }

.f4graph[data-beat="1"] .b1, .f4graph[data-beat="2"] .b2, .f4graph[data-beat="3"] .b3,
.f4graph[data-beat="4"] .b4, .f4graph[data-beat="5"] .b5, .f4graph[data-beat="6"] .b6 { opacity: 1; }
/* dimmed persistence of earlier states */
.f4graph[data-beat="4"] .b3keep, .f4graph[data-beat="5"] .b3keep, .f4graph[data-beat="6"] .b3keep { opacity: 0.16; }
.f4graph[data-beat="5"] .b4keep, .f4graph[data-beat="6"] .b4keep { opacity: 1; }

/* link draw-in */
.f4graph .gl { stroke-dasharray: 420; stroke-dashoffset: 420; opacity: 0; }
.f4graph[data-beat="3"] .gl.b3, .f4graph[data-beat="4"] .gl.b3keep,
.f4graph[data-beat="5"] .gl.b3keep, .f4graph[data-beat="6"] .gl.b3keep { stroke-dashoffset: 0; }
.f4graph[data-beat="3"] .gl.b3 { opacity: 1; }
.f4graph[data-beat="4"] .gl.b4, .f4graph[data-beat="5"] .gl.b4keep, .f4graph[data-beat="6"] .gl.b4keep { stroke-dashoffset: 0; opacity: 1; }
.f4graph[data-beat="5"] .gl.b5, .f4graph[data-beat="6"] .gl.b5keep { stroke-dashoffset: 0; opacity: 1; }

/* beat 2 · Plan moves either point along its own two axes: demand up and
   later, the supply lot lighter and earlier. Both nudges, one verb. */
.f4graph .d0, .f4graph .sp0 { transition: transform 800ms var(--ease-out); }
.f4graph[data-beat="2"] .d0 { transform: translate(22px, -18px); }
.f4graph[data-beat="2"] .sp0 { transform: translate(-17px, 17px); }

/* burst pulse (beat 1) */
.f4graph .burst line { stroke: var(--sig-green); stroke-width: 1.5; opacity: 0.7; }
.f4graph[data-beat="1"] .burst { animation: burstPulse 1.6s ease-in-out infinite; }
@keyframes burstPulse { 0%,100% { opacity: 0.35; } 50% { opacity: 1; } }

/* static variants (mobile cards + reduced-motion small multiples) */
.f4graph.static .gb, .f4graph.static .gl { transition: none; animation: none; }
.f4graph.static .gl { stroke-dasharray: none; stroke-dashoffset: 0; }
.f4graph.static.s1 .b1, .f4graph.static.s2 .b2, .f4graph.static.s3 .b3,
.f4graph.static.s4 .b4, .f4graph.static.s5 .b5, .f4graph.static.s6 .b6 { opacity: 1; }
.f4graph.static.s2 .d0 { transform: translate(22px, -18px); }
.f4graph.static.s2 .sp0 { transform: translate(-17px, 17px); }
.f4graph.static.s4 .b3keep { opacity: 0.16; }
.f4graph.static.s5 .b3keep, .f4graph.static.s6 .b3keep { opacity: 0.16; }
.f4graph.static.s5 .b4keep, .f4graph.static.s6 .b4keep { opacity: 1; }
.f4graph.static.s5 .gl.b4keep, .f4graph.static.s6 .gl.b4keep,
.f4graph.static.s6 .gl.b5keep { opacity: 1; }
/* the six moves, drawn as the business sees them (24 Oct review) · the
   marks of the new graph; the beat machine above still decides when each
   shows. Ribbons are stroked curves as wide as the cases they carry, so
   the house draw-in (stroke-dashoffset on .gl) still runs them in. */
.f4graph.mv { overflow: visible; }
.f4graph .mv-hd { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 0.14em; fill: var(--ink-text-3); }
.f4graph .mv-card { fill: var(--ink-700); stroke: rgb(255 255 255 / 0.12); }
.f4graph .mv-card.is-warn { stroke: rgb(var(--f4-warn-rgb) / 0.6); }
.f4graph .mv-card.is-prod { fill: var(--ink-600); stroke: var(--sig-green); stroke-width: 1.5; }
.f4graph .mv-t { font-size: 12.5px; font-weight: 600; fill: var(--ink-text-1); }
.f4graph .mv-dim { font-weight: 400; fill: var(--ink-text-3); }
.f4graph .mv-n { font-family: var(--font-mono); font-size: 10px; fill: var(--ink-text-2); }
.f4graph .mv-n.is-warn { fill: var(--warn-ink); }
.f4graph .mv-track { fill: rgb(255 255 255 / 0.1); }
.f4graph .mv-life { fill: var(--sig-green-lift); }
.f4graph .mv-life.is-warn { fill: var(--f4-warn); }
.f4graph .mv-port { fill: var(--ink-900); stroke: rgb(255 255 255 / 0.45); stroke-width: 1.25; }
.f4graph .mv-port.is-out { stroke: var(--sig-green); }
.f4graph .mv-rib { fill: none; stroke: rgb(var(--sig-green-rgb) / 0.3); stroke-linecap: butt; }
.f4graph .mv-rib.is-out { stroke: rgb(var(--sig-green-rgb) / 0.36); }
.f4graph .mv-rib.is-warn { stroke: rgb(var(--f4-warn-rgb) / 0.32); }
.f4graph .mv-rib.is-direct { stroke: rgb(var(--sig-green-rgb) / 0.4); }
.f4graph .mv-rib.is-direct.is-warn { stroke: rgb(var(--f4-warn-rgb) / 0.4); }
.f4graph .mv-fruit circle { fill: rgb(var(--sig-green-rgb) / 0.14); stroke: var(--sig-green-lift); stroke-width: 1.5; }
.f4graph .mv-fruit path { fill: none; stroke: var(--sig-green-lift); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.f4graph .mv-spark { fill: none; stroke: var(--f4-blue-lift); stroke-width: 1.5; stroke-linejoin: round; }
.f4graph .mv-spark.is-ghost { stroke: rgb(var(--f4-blue-lift-rgb) / 0.4); stroke-dasharray: 3 3; }
.f4graph .mv-chip { fill: rgb(9 18 32 / 0.92); stroke: rgb(var(--sig-green-lift-rgb) / 0.55); }
.f4graph .mv-chip-t { font-family: var(--font-mono); font-size: 10px; font-weight: 600; fill: var(--sig-green-lift); }
.f4graph .mv-chip.is-low { stroke: var(--f4-warn); }
.f4graph .mv-chip-t.is-low { fill: var(--warn-ink); }
.f4graph .mv-chip.is-plan, .f4graph .mv-chip.is-cost { stroke: rgb(var(--f4-blue-lift-rgb) / 0.55); }
.f4graph .mv-chip-t.is-plan, .f4graph .mv-chip-t.is-cost { font-weight: 500; fill: var(--f4-blue-pale); }
.f4graph .mv-chip-t.is-lock { font-weight: 500; }
.f4graph .mv-lock { fill: none; stroke: var(--sig-green-lift); stroke-width: 1.5; stroke-linejoin: round; }
.f4graph .mv-frame { fill: rgb(var(--sig-green-rgb) / 0.03); stroke: rgb(var(--sig-green-lift-rgb) / 0.45); stroke-width: 1; stroke-dasharray: 5 7; }
.f4graph .mv-pt { fill: var(--sig-green-pulse); }
.f4graph .burst rect { fill: none; stroke: var(--sig-green); stroke-width: 1.5; }
/* the product steps back once the lots run direct */
.f4graph[data-beat="4"] .mv-prod, .f4graph[data-beat="5"] .mv-prod, .f4graph[data-beat="6"] .mv-prod,
.f4graph.static.s4 .mv-prod, .f4graph.static.s5 .mv-prod, .f4graph.static.s6 .mv-prod { opacity: 0.35; }
/* move 2 on the drawn graph · a smaller nudge, so the demand card stays inside
   the frame on its way up and later */
.f4graph.mv[data-beat="2"] .d0, .f4graph.mv.static.s2 .d0 { transform: translate(14px, -14px); }
.f4graph.mv[data-beat="2"] .sp0, .f4graph.mv.static.s2 .sp0 { transform: translate(-14px, 14px); }

/* fallback cards (mobile + reduced motion) · the 2×3 small multiples */
.mj-fallback { display: none; margin-top: 2.5rem; }
.mj-fallback .fb-card {
  background: var(--ink-card-grad);
  border: 1px solid var(--ink-card-line);
  border-radius: var(--radius-card);
  box-shadow: var(--specular-ink);
  padding: 1.625rem;
}
.mj-fallback .fb-card .kicker { margin-bottom: 0.75rem; font-size: var(--fs-2xs); }
.mj-fallback .fb-card h3 { color: #fff; font-size: var(--fs-xl); }
.mj-fallback .fb-card p { font-size: var(--fs-base); color: var(--text-on-ink-dim); margin-top: 0.375rem; }
.mj-fallback .fb-card svg { margin-top: 1rem; border-radius: var(--radius-sm); background: rgba(10, 20, 35, 0.7); }
.mj-fallback-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gutter); }
@media (max-width: 640px) { .mj-fallback-grid { grid-template-columns: 1fr; } }

/* the graph is a state machine, not a scene: lighting every beat at once
   would read as mush, so the static audience keeps the labelled grid */
@media (max-width: 767px), (prefers-reduced-motion: reduce) {
  .sj.mj { display: none; }
  .mj-fallback { display: block; }
}
/* stacked · the graph leads, the rail reads underneath it */
@media (max-width: 899px) {
  .sj.mj { grid-template-columns: 1fr; }
  .mj-stagewrap { order: -1; }
}

/* ============================================================
   12 · Interactive product examples
   ============================================================ */
.demo-shell {
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.07);
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.bg-ink .demo-shell {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.015));
  border-color: var(--ink-card-line);
  box-shadow: var(--shadow-ink-lg);
}
.demo-head {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  flex-wrap: wrap;
  padding: var(--space-16) var(--space-24);
  border-bottom: 1px solid var(--f4-line);
  background: linear-gradient(180deg, var(--surface-1), var(--f4-paper));
}
.bg-ink .demo-head { background: rgba(10, 20, 35, 0.45); border-bottom-color: var(--f4-line-dark); }
.demo-head .demo-title { font-weight: 600; font-size: var(--fs-md); letter-spacing: -0.005em; }
.bg-ink .demo-head .demo-title { color: #fff; }
.demo-body { padding: var(--space-24); }
/* the concise illustrative-view caption · the counterpart to the
   `product view ·` caption on a real screenshot. It is deliberately not a
   .reveal, so it never waits on a scroll position to become readable. */
.demo-disclosure {
  display: flex;
  align-items: baseline;
  gap: var(--space-8);
  margin-top: var(--space-14);
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  line-height: var(--lh-body-l);
  color: var(--f4-slate);
}
.demo-disclosure::before {
  content: "";
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  border: 1px solid currentColor;
  transform: translateY(-1px);
}
.bg-ink .demo-disclosure { color: var(--ink-text-3); }
.demo-meta {
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  color: var(--f4-slate);
  display: flex; gap: var(--space-20); flex-wrap: wrap;
  padding: var(--space-14) var(--space-24);
  border-top: 1px solid var(--f4-line);
  background: linear-gradient(180deg, var(--f4-paper), var(--surface-1));
}
.bg-ink .demo-meta { border-top-color: var(--f4-line-dark); background: rgba(10, 20, 35, 0.45); color: var(--ink-text-2); }

/* the S&OP sandbox for visitors (week 44): a pre-blurred still of it under a
   walkthrough card. Staff get the live sandbox in its place (demos.js). */
.sop-still { display: grid; }
.sop-still > img { grid-area: 1 / 1; width: 100%; height: auto; opacity: 0.55; }
/* the still's opacity gives it its own layer, so the card is raised above it */
.sop-still-card {
  position: relative; z-index: 1;
  grid-area: 1 / 1; place-self: center; max-width: 32rem; margin: var(--space-24);
  padding: var(--space-24) clamp(1.25rem, 3vw, 2.4rem); text-align: center;
  border-radius: 18px; background: rgb(9 16 29 / 0.86); border: 1px solid rgb(255 255 255 / 0.12);
  box-shadow: 0 30px 80px -30px rgb(0 0 0 / 0.75);
}
.sop-still-card .kicker { justify-content: center; }
.sop-still-card h3 { margin-top: var(--space-12); font-family: var(--font-display); font-size: var(--fs-2xl); font-weight: 400; color: var(--ink-text-1); }
.sop-still-card p { margin-top: var(--space-10); color: var(--ink-text-2); }
.sop-still-card .btn { margin-top: var(--space-20); }

/* scenario picker */
.scenario-row { display: flex; flex-wrap: wrap; gap: var(--space-10); }
.scenario-btn {
  padding: var(--space-8) var(--space-16);
  border-radius: var(--radius-pill);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.12);
  font-family: var(--font-mono);
  font-size: var(--fs-cap-s);
  color: var(--f4-slate);
  background: var(--surface);
  transition: color 200ms var(--ease-out), background 200ms var(--ease-out), border-color 200ms var(--ease-out), box-shadow 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.scenario-btn:hover { border-color: var(--sig-green); color: var(--sig-green-text); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.scenario-btn[aria-pressed="true"] {
  background: var(--f4-ink);
  border-color: var(--f4-ink);
  color: #fff;
  box-shadow: 0 8px 18px -8px rgb(var(--f4-ink-rgb) / 0.5);
}
.bg-ink .scenario-btn { border-color: var(--f4-line-dark); color: var(--ink-text-2); background: rgba(255, 255, 255, 0.03); }
/* the session's escape hatch · a dashed rim so it never reads as a fourth
   transform you could apply. It is the only pill that undoes rather than does. */
.scenario-btn.sc-undo { border-style: dashed; }
.bg-ink .scenario-btn.sc-undo { color: var(--ink-text-3); }

/* Plan demo · the chart legend, in HTML rather than inside the viewBox. Marks
   drawn in SVG scale with the drawing, so on a 390px screen a 9.5px label
   renders at about 4px; here it keeps its type size and simply reflows. Its own
   namespace rather than the forecast bench's, so the two demos can be reworked
   independently. */
.pl-legend {
  display: flex; flex-wrap: wrap;
  gap: var(--space-8) var(--space-18);
  margin-top: var(--space-24);
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  color: var(--f4-slate);
}
.bg-ink .pl-legend { color: var(--ink-text-3); }
.pl-key { display: inline-flex; align-items: center; gap: var(--space-8); }
/* horizon and transforms share one rail (24 Oct review) */
/* left-aligned on purpose · Discard appears at the end of the rail, so
   nothing a planner is about to click moves when a session opens */
.pl-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-12) var(--space-40); }
.pl-tx { align-items: center; }
.pl-tx-k { font-family: var(--font-mono); font-size: var(--fs-kicker); letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-text-3); margin-right: var(--space-4); }
.pl-key i { display: block; width: 22px; height: 2px; border-radius: var(--radius-pill); }
.pk-act i   { background: var(--ink-text-1); }
.pk-plan i  { background: var(--sig-green-lift); height: 2.5px; }
.pk-sup i   { background: var(--f4-signal); }
.pk-mac i   { background: repeating-linear-gradient(90deg, var(--f4-blue-lift) 0 5px, transparent 5px 9px); }
.pk-ly i    { background: repeating-linear-gradient(90deg, #63728A 0 2px, transparent 2px 5px); }
/* literal, not rgb(var(--ink-text-1-rgb) / .26): only --ink-text-3-rgb is
   declared, and an undefined var() takes the whole declaration down silently */
.pk-ghost i { background: rgb(var(--ink-text-1-rgb) / 0.26); }
/* 2px, not the pill the other keys inherit · this one stands for an area fill
   with square corners, and a lozenge misdescribes it */
.pk-gap i   { height: 9px; border-radius: var(--radius-xs); background: rgb(var(--f4-warn-rgb) / 0.17); border: 1px solid rgb(var(--f4-warn-rgb) / 0.34); }

/* the forward half of the plan draws itself in · the same idiom the forecast
   bench uses for its published signal. Suppressed on the first paint and under
   reduced motion, so the panel is still when it is screenshotted or opted out. */
.pl-planline { stroke-dashoffset: 0; }
[data-demo-plan]:not([data-noanim]) .pl-planline { animation: plDraw 520ms var(--ease-out) backwards; }
@keyframes plDraw { from { stroke-dashoffset: var(--pl-len, 900px); } }
.bg-ink .scenario-btn:hover { border-color: var(--sig-green-lift); color: var(--sig-green-lift); box-shadow: none; }
.bg-ink .scenario-btn[aria-pressed="true"] {
  background: linear-gradient(180deg, var(--sig-green-face-a), var(--sig-green-face-b));
  border-color: transparent;
  color: var(--sig-green-ink);
  font-weight: 500;
  box-shadow: 0 8px 22px -8px rgb(var(--ink-900-rgb) / 0.37);
}

/* KPI tiles inside demos */
/* ---- S&OP · the cover grid ----
   The real Simulation screen is a grid, not a chart: products down the side,
   dates across, each cell carrying days of cover over the volume behind it and
   traffic-lit against that product's shelf life. A real <table>, because that
   is what it is — row and column headers included, so the numbers are
   navigable rather than a picture of numbers. */
.cov-legend {
  display: flex; flex-wrap: wrap;
  gap: var(--space-8) var(--space-18);
  margin-top: var(--space-20);
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  color: var(--f4-slate);
}
.bg-ink .cov-legend { color: var(--ink-text-3); }
.cov-key { display: inline-flex; align-items: center; gap: var(--space-8); }
.cov-key i { display: block; width: 10px; height: 10px; border-radius: var(--radius-xs); border: 1px solid; }

/* scrolls on narrow screens, and is focusable so it can be reached and scrolled
   from the keyboard · a scroll region nobody can tab to is the one axe rule
   that actually locks people out */
.cov-wrap {
  margin-top: var(--space-12);
  overflow-x: auto;
  border-radius: var(--radius-sm);
  /* Sticky table cells otherwise escape Chromium's root overflow calculation
     even though this region clips and scrolls them correctly. */
  contain: inline-size paint;
}
.cov-wrap:focus-visible { outline: 2px solid var(--sig-green-deep); outline-offset: 3px; }
.cov-grid { border-collapse: collapse; width: 100%; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.cov-grid th, .cov-grid td { text-align: right; white-space: nowrap; }

.cov-grid .cg-wk {
  padding: 0 var(--space-10) var(--space-8);
  font-size: var(--fs-xs); font-weight: 500; letter-spacing: 0.08em;
  color: var(--f4-slate);
}
.bg-ink .cov-grid .cg-wk { color: var(--ink-text-3); }
.cov-grid .cg-act { display: block; font-size: var(--fs-4xs); letter-spacing: 0.1em; opacity: 0.62; }
.cov-grid .cg-corner {
  padding: 0 var(--space-16) var(--space-8) 0;
  text-align: left;
  font-size: var(--fs-xs); font-weight: 500; letter-spacing: 0.08em;
  color: var(--f4-slate);
}
.bg-ink .cov-grid .cg-corner { color: var(--ink-text-3); }

/* the row header carries the two things that decide how a cell reads · what it
   is, and how long it lasts */
.cov-grid .cg-prod { text-align: left; padding: 0 var(--space-16) 0 0; }
/* flex on the inner span, not the th · a display:flex table cell drops out of
   the table layout and takes the sticky column with it */
.cov-grid .cg-prod-in { display: flex; align-items: center; gap: var(--space-14); }
.cov-grid .cg-id { flex: 1 1 auto; min-width: 0; }
.cov-grid .cg-spark { flex: none; width: 80px; height: 22px; display: block; opacity: 0.9; }
@media (max-width: 640px) { .cov-grid .cg-spark { display: none; } }

/* it also pins while the weeks scroll under it · on a phone, losing track of
   which row a red cell belongs to is what makes a wide grid unreadable. The
   ink value is the section colour with the shell's own white lift folded in,
   so the pinned column reads as the same surface, not a panel on top of it. */
.cov-grid .cg-prod, .cov-grid .cg-corner {
  position: sticky; left: 0; z-index: 1;
  background: var(--surface);
  box-shadow: 1px 0 0 var(--f4-line);
}
.bg-ink .cov-grid .cg-prod, .bg-ink .cov-grid .cg-corner {
  background: #152134;
  box-shadow: 1px 0 0 rgb(var(--ink-text-1-rgb) / 0.12);
}
.cov-grid .cg-name { display: block; font-family: var(--font-body); font-size: var(--fs-cap); font-weight: 600; color: var(--f4-ink); }
.bg-ink .cov-grid .cg-name { color: var(--text-on-ink); }
.cov-grid .cg-shelf { display: block; font-size: var(--fs-3xs); letter-spacing: 0.08em; color: var(--f4-slate); }
.bg-ink .cov-grid .cg-shelf { color: var(--ink-text-3); }

.cov-grid .cg-cell {
  padding: var(--space-8) var(--space-10);
  border: 1px solid transparent;
  border-radius: var(--radius-xs);
}
.cov-grid .cg-cell b { display: block; font-size: var(--fs-md); font-weight: 500; }
.cov-grid .cg-cell b i { font-style: normal; font-size: var(--fs-xs); opacity: 0.72; margin-left: var(--space-2); }
.cov-grid .cg-cell span { display: block; font-size: var(--fs-3xs); opacity: 0.66; }

/* the settled columns hold still while the forward ones recolour · the same
   wash the plan chart puts behind its actuals, and the same heavier rule at
   the boundary that the now line draws there */
.cov-grid .cg-settled { opacity: 0.72; }
.bg-ink .cov-grid td.cg-settled { background: rgba(255, 255, 255, 0.022); }
.cov-grid .cg-first-fwd { border-left: 1px solid var(--f4-line); }
.bg-ink .cov-grid .cg-first-fwd { border-left-color: rgb(var(--ink-text-1-rgb) / 0.32); }

/* Four states, and the number in the cell always says what the colour says.
   On-policy carries NO fill: the page's own claim is managing by exception, and
   tinting the eighty per cent of cells that are fine buries the handful that
   are not. Only a departure from policy gets a wash. */
.cov-grid .cg-ok    { color: var(--f4-slate); }
.cov-grid .cg-low   { color: var(--warn-text); background: rgb(var(--f4-warn-rgb) / 0.13); }
.cov-grid .cg-short { color: var(--crit-text); background: rgb(var(--f4-crit-rgb) / 0.15); border-color: rgb(var(--f4-crit-rgb) / 0.38); }
.cov-grid .cg-over  { color: var(--signal-text); background: rgb(var(--f4-signal-rgb) / 0.11); }
.bg-ink .cov-grid .cg-ok    { color: var(--ink-text-2); }
.bg-ink .cov-grid .cg-low   { color: var(--f4-warn); background: rgb(var(--f4-warn-rgb) / 0.14); }
.bg-ink .cov-grid .cg-short { color: var(--crit-ink); background: rgb(var(--f4-crit-rgb) / 0.18); border-color: rgb(var(--f4-crit-rgb) / 0.46); }
.bg-ink .cov-grid .cg-over  { color: var(--signal-ink); background: rgb(var(--f4-signal-rgb) / 0.12); }
.cov-key.cg-ok i    { background: none; border-color: var(--f4-line); }
.bg-ink .cov-key.cg-ok i { border-color: rgb(var(--ink-text-1-rgb) / 0.34); }
.cov-key.cg-low i   { background: rgb(var(--f4-warn-rgb) / 0.18); border-color: rgb(var(--f4-warn-rgb) / 0.5); }
.cov-key.cg-short i { background: rgb(var(--f4-crit-rgb) / 0.2); border-color: rgb(var(--f4-crit-rgb) / 0.55); }
.cov-key.cg-over i  { background: rgb(var(--f4-signal-rgb) / 0.18); border-color: rgb(var(--f4-signal-rgb) / 0.5); }
/* what the scenario changed (24 Oct demos audit) · a dot on each cell whose
   state moved, named once in the legend, and the shortage as the grid's last
   row, week by week, adding up to the readout's total */
.cov-key.cov-moved { margin-left: auto; padding: 3px 10px 3px 9px; border-radius: var(--radius-pill); border: 1px solid rgb(var(--ink-text-1-rgb) / 0.16); color: var(--ink-text-2); }
.cov-key.cov-moved[hidden] { display: none; }
.cov-key.cov-moved i { width: 6px; height: 6px; border: 0; border-radius: 50%; background: var(--ink-text-1); }
.cov-grid td.cg-cell { position: relative; }
.cov-grid .cg-moved::before {
  content: ""; position: absolute; top: 7px; left: 7px; width: 6px; height: 6px; border-radius: 50%;
  background: var(--ink-text-1); box-shadow: 0 0 0 2px rgb(var(--ink-900-rgb) / 0.8);
}
.cov-grid tfoot th, .cov-grid tfoot td { border-top: 1px solid rgb(var(--ink-text-1-rgb) / 0.16); }
.cov-grid .cg-sr-h { display: block; font-size: var(--fs-sm); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--warn-ink); }
.cov-grid td.cg-sr { padding: var(--space-12) var(--space-10) var(--space-8); vertical-align: bottom; }
.cov-grid .cg-sr-bar { display: flex; align-items: flex-end; justify-content: flex-end; height: 34px; }
.cov-grid .cg-sr-bar i { display: block; width: 100%; max-width: 56px; border-radius: 3px 3px 0 0; background: var(--f4-warn); }
.cov-grid .cg-sr-bar i.is-z { height: 2px; background: rgb(var(--ink-text-1-rgb) / 0.14); }
.cov-grid .cg-sr-v { display: block; margin-top: 5px; font-size: var(--fs-sm); font-weight: 500; color: var(--warn-ink); }
.cov-grid .cg-sr-v.is-z { color: var(--ink-text-3); }

.demo-kpis { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-14); margin-top: var(--space-24); }
.demo-kpis.k4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 899px) { .demo-kpis.k4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .demo-kpis { grid-template-columns: 1fr 1fr; } }
.demo-kpi {
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.08);
  border-radius: var(--radius-btn);
  padding: var(--space-16) var(--space-16);
  background: linear-gradient(180deg, var(--surface), var(--f4-paper));
}
.bg-ink .demo-kpi { border-color: var(--ink-card-line); background: rgba(255, 255, 255, 0.03); }
/* Deliberately NOT the .ct-kpi mono-uppercase engraving. That label is a short
   metric name on a product dashboard; this one carries prose ("Deviation vs
   target (what the account manager sees)"), and a tracked uppercase sentence is
   unreadable. The two components share the number and delta sizes, which is
   where they actually used to disagree. */
.demo-kpi .k-label { font-size: var(--fs-sm); color: var(--f4-slate); display: flex; align-items: center; gap: var(--space-6); }
.bg-ink .demo-kpi .k-label { color: var(--ink-text-2); }
.demo-kpi .k-val {
  font-family: var(--font-mono);
  font-size: var(--fs-kpi);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  margin-top: var(--space-4);
  transition: color 300ms var(--ease-out);
}
.bg-ink .demo-kpi .k-val { color: #fff; }
.demo-kpi .k-delta { font-family: var(--font-mono); font-size: var(--fs-2xs); margin-top: var(--space-6); min-height: 1.1em; color: var(--f4-slate); }
.bg-ink .demo-kpi .k-delta { color: var(--ink-text-3); }
.k-good { color: var(--sig-green-text) !important; }
.k-warn { color: var(--warn-text) !important; }
.k-crit { color: var(--crit-text) !important; }

/* Every demo · what changed, and what to try next (24 Oct demos audit).
   After the visitor's own move a KPI tile that changed keeps its previous
   value struck through; the next control worth trying wears a dashed blue
   ring (the words "now try" ride at the end of its row where there is room);
   on a phone a decision log folds behind one line. Blue, because it is a
   hint about the page, not a signal in the plan. */
.demo-kpi { position: relative; }
.k-was {
  position: absolute; top: var(--space-12); right: var(--space-14);
  font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--ink-text-3);
  text-decoration-color: rgb(var(--ink-text-3-rgb) / 0.8);
  animation: logIn 320ms var(--ease-out) backwards;
}
.pw-kpis .k-was { position: static; display: block; margin-top: 2px; }
.demo-body button.is-try, .demo-body .slider-field.is-try input[type="range"] {
  outline: 1.5px dashed rgb(var(--f4-blue-lift-rgb) / 0.8); outline-offset: 3px;
}
.demo-body .slider-field.is-try output::before {
  content: "now try"; margin-right: var(--space-8);
  font-size: 9.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--f4-blue-pale);
}
.try-pill {
  align-self: center; margin-left: var(--space-4);
  padding: 4px 10px; border-radius: var(--radius-pill); white-space: nowrap;
  font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--f4-blue-pale);
  background: rgb(var(--f4-blue-lift-rgb) / 0.14); border: 1px solid rgb(var(--f4-blue-lift-rgb) / 0.4);
  animation: logIn 320ms var(--ease-out) backwards;
}
.fold-btn { display: none; }
@media (max-width: 640px) {
  .try-pill { display: none; }
  .decision-log .fold-btn {
    display: inline-flex; margin: 0 0 var(--space-8); padding: 6px 12px; border-radius: var(--radius-pill); cursor: pointer;
    font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--f4-blue-pale);
    background: transparent; border: 1px solid rgb(var(--f4-blue-lift-rgb) / 0.4);
  }
  .decision-log:not(.is-open) > ul { display: none; }
}
@media (prefers-reduced-motion: reduce) { .k-was, .try-pill { animation: none; } }
.bg-ink .k-good { color: var(--sig-green-lift) !important; }
.bg-ink .k-warn { color: var(--f4-warn) !important; }
.bg-ink .k-crit { color: var(--crit-ink) !important; }

/* state chips inside demos */
.state-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-6) var(--space-14);
  border-radius: var(--radius-pill);
  font-size: var(--fs-cap-s);
  font-weight: 600;
  transition: color 250ms var(--ease-out), background 250ms var(--ease-out), border-color 250ms var(--ease-out);
}
.state-chip::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; box-shadow: 0 0 8px currentColor; }
.state-ok   { background: rgb(var(--sig-green-rgb) / 0.13); color: var(--sig-green-text); }
.state-warn { background: rgb(var(--f4-warn-rgb) / 0.16); color: var(--warn-text); }
.state-crit { background: rgb(var(--f4-crit-rgb) / 0.13); color: var(--crit-text); }
.bg-ink .state-ok { background: rgb(var(--sig-green-rgb) / .18); color: var(--sig-green-lift); }
.bg-ink .state-warn { background: rgb(var(--f4-warn-rgb) / .16); color: var(--f4-warn); }
.bg-ink .state-crit { background: rgb(var(--f4-crit-rgb) / .18); color: var(--crit-ink); }

/* demo chart svg */
.demo-chart { margin-top: var(--space-24); }
.demo-chart svg { width: 100%; height: auto; }
.demo-chart .bar { transition: fill 400ms var(--ease-out); }

/* decision log inside sop demo */
.decision-log { margin-top: var(--space-24); border-top: 1px solid var(--f4-line); padding-top: var(--space-18); }
.bg-ink .decision-log { border-top-color: var(--f4-line-dark); }
.decision-log h4 { font-size: var(--fs-cap-s); font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.12em; font-weight: 500; color: var(--f4-slate); margin-bottom: var(--space-14); }
.bg-ink .decision-log h4 { color: var(--ink-text-2); }
/* the forecast bench keeps its record one click away, so the bench reads
   top to bottom without five rows of log under every step */
.fx-log summary {
  display: flex; align-items: center; gap: var(--space-8);
  cursor: pointer; list-style: none;
  font-size: var(--fs-cap-s); font-family: var(--font-mono); text-transform: uppercase;
  letter-spacing: 0.12em; font-weight: 500; color: var(--ink-text-2);
}
.fx-log summary::-webkit-details-marker { display: none; }
.fx-log summary::before {
  content: ""; width: 6px; height: 6px; flex: none;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); transition: transform 200ms var(--ease-out);
}
.fx-log[open] summary::before { transform: rotate(45deg); }
.fx-log summary span { text-transform: none; letter-spacing: 0.02em; color: var(--ink-text-3); }
.fx-log[open] summary span { display: none; }
.fx-log[open] ul { margin-top: var(--space-14); }
.fx-log summary:focus-visible { outline: 2px solid var(--sig-green-lift); outline-offset: 4px; border-radius: 2px; }
.decision-log ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-10); }
.decision-log li {
  display: flex; gap: var(--space-10); align-items: baseline;
  font-size: var(--fs-base);
  animation: logIn 400ms var(--ease-out) backwards;
}
.decision-log li:nth-child(2) { animation-delay: 90ms; }
.decision-log li:nth-child(3) { animation-delay: 180ms; }
@keyframes logIn { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) { .decision-log li { animation: none; } }
.decision-log .lane {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--f4-blue);
  min-width: 74px;
}
.bg-ink .decision-log .lane { color: var(--f4-blue-lift); }
.bg-ink .decision-log li { color: var(--text-on-ink); }

/* sliders (pricing demo) */
.slider-row { display: grid; gap: var(--space-18); margin-top: var(--space-4); }
.slider-field label {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--fs-cap); font-weight: 600; margin-bottom: var(--space-8);
}
.slider-field label output { font-family: var(--font-mono); font-weight: 500; color: var(--sig-green-text); }
.bg-ink .slider-field label { color: var(--text-on-ink); }
.bg-ink .slider-field label output { color: var(--sig-green-lift); }
input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 4px; border-radius: var(--radius-xs);
  background: var(--f4-line);
  outline-offset: 6px;
}
.bg-ink input[type="range"] { background: rgba(255, 255, 255, 0.14); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 19px; height: 19px; border-radius: 50%;
  background: linear-gradient(180deg, var(--sig-green-face-a), var(--sig-green-face-b));
  border: 2.5px solid #fff;
  box-shadow: 0 1px 4px rgb(var(--f4-ink-rgb) / 0.35);
  cursor: grab;
  transition: transform 150ms var(--ease-out);
}
input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.12); }
input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%;
  background: linear-gradient(180deg, var(--sig-green-face-a), var(--sig-green-face-b));
  border: 2.5px solid #fff;
  box-shadow: 0 1px 4px rgb(var(--f4-ink-rgb) / 0.35);
  cursor: grab;
}

/* waterfall */
.waterfall svg rect { transition: opacity 400ms var(--ease-out); }
/* on a phone the waterfall keeps a readable size and pans, like the MRP flow */
@media (max-width: 640px) { .waterfall { overflow-x: auto; } .waterfall svg { min-width: 540px; } }

/* Pricing · the waterfall as an instrument (24 Oct demos audit): the controls
   beside the chart, the target band across the plot, the gap bracketed, and
   who approves as one deviation scale under it */
.pw-grid { display: grid; grid-template-columns: 290px minmax(0, 1fr); gap: var(--space-28); align-items: start; }
.pw-ctl .slider-row { gap: var(--space-18); padding: var(--space-18); border-radius: 14px; background: rgb(255 255 255 / 0.03); border: 1px solid rgb(255 255 255 / 0.08); margin: 0; }
.pw-note { margin: var(--space-10) 0 0; font-size: var(--fs-sm); line-height: 1.5; color: var(--ink-text-3); }
.pw-kpis { display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-24); margin: 0 0 var(--space-6); }
.bg-ink .pw-kpis .demo-kpi { padding: 0; border: 0; border-radius: 0; background: none; }
.pw-kpis .k-val { margin: 0; font-size: 24px; line-height: 1.1; }
.pw-kpis .k-label, .bg-ink .pw-kpis .k-label { display: block; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-3); }
.pw-kpis .k-delta { margin-top: 2px; min-height: 0; }
.pw-main .demo-chart { margin-top: var(--space-6); }
.pw-main .demo-chart svg { display: block; overflow: visible; }
.pw-grid-l { stroke: rgb(255 255 255 / 0.07); }
.pw-base { stroke: rgb(255 255 255 / 0.22); }
.pw-ax { font-family: var(--font-mono); font-size: 10px; fill: var(--ink-text-3); }
.pw-band { fill: rgb(var(--sig-green-rgb) / 0.12); }
.pw-target { stroke: var(--sig-green-lift); stroke-width: 1.5; stroke-dasharray: 5 4; }
.pw-band-t { font-family: var(--font-mono); font-size: 10.5px; font-weight: 500; fill: var(--sig-green-lift); }
.pw-cost { fill: var(--f4-blue); }
.pw-conn { stroke: rgb(255 255 255 / 0.3); stroke-width: 1; stroke-dasharray: 2 3; }
.pw-val { font-family: var(--font-mono); font-size: 10.5px; font-weight: 500; fill: var(--ink-text-2); }
.pw-val.is-in { fill: var(--sig-green-ink); font-weight: 600; }
.pw-val.is-margin { fill: var(--sig-green-lift); font-weight: 600; }
.pw-name { font-family: var(--font-mono); font-size: 10px; fill: var(--ink-text-3); }
.pw-name.is-margin { fill: var(--sig-green-lift); }
.pw-name.is-price { fill: var(--ink-text-1); font-weight: 600; }
.pw-tick { stroke: rgb(255 255 255 / 0.35); }
.pw-cost-t { font-family: var(--font-mono); font-size: 10px; fill: var(--ink-text-2); }
.pw-margin { fill: var(--sig-green); }
.pw-margin.is-loss { fill: var(--f4-crit); }
.pw-val.is-loss, .pw-name.is-loss { fill: var(--crit-ink); }
.pw-price { fill: var(--ink-600); stroke-width: 1.5; stroke: var(--sig-green-lift); }
.pw-price.is-over, .pw-price.is-warn { stroke: var(--f4-warn); }
.pw-price.is-crit, .pw-price.is-blocked { stroke: var(--f4-crit); }
.pw-price-v { font-family: var(--font-mono); font-size: 13px; font-weight: 600; fill: var(--sig-green-pulse); }
.pw-price-v.is-over, .pw-price-v.is-warn { fill: var(--warn-ink); }
.pw-price-v.is-crit, .pw-price-v.is-blocked { fill: var(--crit-ink); }
.pw-gap { fill: none; stroke-width: 1.5; stroke: var(--f4-warn); }
.pw-gap-l { stroke-width: 1.25; stroke: var(--f4-warn); }
.pw-gap.is-crit, .pw-gap.is-blocked, .pw-gap-l.is-crit, .pw-gap-l.is-blocked { stroke: var(--f4-crit); }
.pw-gap-chip rect { fill: rgb(var(--ink-900-rgb) / 0.95); stroke: var(--f4-warn); }
.pw-gap-chip text { font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; fill: var(--warn-ink); }
.pw-gap-chip.is-crit rect, .pw-gap-chip.is-blocked rect { stroke: var(--f4-crit); }
.pw-gap-chip.is-crit text, .pw-gap-chip.is-blocked text { fill: var(--crit-ink); }
/* who approves · four zones, the one this price falls in lit */
.pw-route { grid-column: 1 / -1; padding-top: var(--space-18); border-top: 1px solid rgb(255 255 255 / 0.08); }
.pw-k { font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-text-3); }
.pw-scale { position: relative; margin-top: var(--space-14); padding-top: 38px; }
.pw-chip {
  position: absolute; top: 0; white-space: nowrap;
  padding: 4px 12px; border-radius: var(--radius-pill);
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 600;
  background: rgb(var(--ink-900-rgb) / 0.95); border: 1px solid var(--f4-warn); color: var(--warn-ink);
}
.pw-chip.is-ok { border-color: rgb(var(--sig-green-lift-rgb) / 0.7); color: var(--sig-green-pulse); }
.pw-chip.is-crit { border-color: var(--f4-crit); color: var(--crit-ink); }
.pw-chip.is-over { border-color: rgb(var(--f4-blue-lift-rgb) / 0.7); color: var(--f4-blue-pale); }
.pw-zones { position: relative; display: flex; gap: 2px; height: 14px; }
.pw-zones i { flex: 1 1 0; border-radius: 2px; opacity: 0.4; transition: opacity 260ms var(--ease-out); }
.pw-zones i.is-on { opacity: 1; }
.pw-zones .is-crit { background: rgb(var(--f4-crit-rgb) / 0.75); }
.pw-zones .is-warn { background: rgb(var(--f4-warn-rgb) / 0.75); }
.pw-zones .is-ok { background: rgb(var(--sig-green-rgb) / 0.7); }
.pw-zones .is-over { background: rgb(var(--f4-blue-lift-rgb) / 0.55); }
.pw-pin {
  position: absolute; bottom: 100%; width: 0; height: 0; margin-left: -7px; margin-bottom: 1px;
  border-left: 7px solid transparent; border-right: 7px solid transparent; border-top: 12px solid var(--f4-warn);
  transition: left 200ms var(--ease-out);
}
.pw-pin.is-ok { border-top-color: var(--sig-green-lift); }
.pw-pin.is-crit { border-top-color: var(--f4-crit); }
.pw-pin.is-over { border-top-color: var(--f4-blue-lift); }
.pw-ticks { position: relative; height: 18px; }
.pw-ticks span { position: absolute; top: 4px; transform: translateX(-50%); font-family: var(--font-mono); font-size: 10px; color: var(--ink-text-3); }
.pw-who { list-style: none; margin: 4px 0 0; padding: 0; display: flex; gap: 2px; }
.pw-who li { flex: 1 1 0; min-width: 0; text-align: center; }
.pw-who b { display: block; font-size: var(--fs-cap); font-weight: 600; color: var(--ink-text-2); }
.pw-who small { display: block; font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--ink-text-3); }
.pw-who li.is-on b { color: var(--ink-text-1); }
.pw-who li.is-on.is-warn b { color: var(--warn-ink); }
.pw-who li.is-on.is-crit b { color: var(--crit-ink); }
.pw-who li.is-on.is-ok b { color: var(--sig-green-pulse); }
.pw-who li.is-on.is-over b { color: var(--f4-blue-pale); }
.pw-approval { margin: var(--space-14) 0 0; font-size: var(--fs-base); line-height: 1.5; color: var(--ink-text-2); }
@media (max-width: 959px) {
  .pw-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) { .pw-main .waterfall svg { min-width: 640px; } }
@media (max-width: 560px) {
  .pw-who b { font-size: var(--fs-2xs); }
  .pw-who small { display: none; }
}

/* allocation demo */
.alloc-stage svg { width: 100%; height: auto; }
.alloc-stage path { transition: stroke-width 600ms var(--ease-out), opacity 600ms var(--ease-out); }
.alloc-rules { margin-top: var(--space-18); }
/* adjust on the drawing (24 Oct demos audit) · every one of the twelve links
   can be picked, the empty ones drawn faint, and the picked one steps in the
   bar under the picture with its consequence in words */
.aw-link { cursor: pointer; outline: none; }
.alloc-stage .aw-hit { fill: none; stroke: transparent; stroke-width: 16; stroke-dasharray: none; animation: none; }
.aw-line { fill: none; stroke: var(--sig-green); stroke-opacity: 0.55; stroke-linecap: round; }
.aw-link.is-under .aw-line { stroke: var(--f4-warn); stroke-opacity: 0.8; }
.alloc-stage .aw-link.is-empty .aw-line { stroke: var(--ink-text-1); stroke-opacity: 0.16; stroke-dasharray: 1.5 3; }
.aw-link:hover .aw-line { stroke-opacity: 0.85; }
.aw-link.is-picked .aw-line { stroke-opacity: 1; }
.alloc-stage .aw-link.is-picked.is-empty .aw-line { stroke-opacity: 0.55; }
.aw-link:focus-visible .aw-hit { stroke: rgb(var(--sig-green-lift-rgb) / 0.3); }
/* the picked link is lit from underneath · its own weight still says the tonnes */
.aw-link.is-picked .aw-hit { stroke: rgb(var(--sig-green-lift-rgb) / 0.16); stroke-width: 12; }
.aw-link.is-picked.is-under .aw-hit { stroke: rgb(var(--f4-warn-rgb) / 0.22); }
/* on a phone the drawing keeps a size a finger can pick from, and pans */
@media (max-width: 640px) { .alloc-stage { overflow-x: auto; } .alloc-stage svg { min-width: 560px; } }
.aw-handle { fill: var(--sig-green-lift); stroke: var(--ink-900); stroke-width: 2; pointer-events: none; }
.aw-handle.is-under { fill: var(--f4-warn); }
.aw-hint { margin: var(--space-6) 0 0; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-3); }
.alloc-work .aw-edit {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-10) var(--space-16);
  padding: var(--space-12) var(--space-16); border-radius: 12px;
  background: rgb(var(--ink-900-rgb) / 0.6); border: 1px solid rgb(255 255 255 / 0.12);
}
.aw-edit.is-warn { border-color: rgb(var(--f4-warn-rgb) / 0.6); }
.aw-edit.is-crit { border-color: rgb(var(--f4-crit-rgb) / 0.7); }
.aw-edit.is-ok { border-color: rgb(var(--sig-green-lift-rgb) / 0.45); }
.aw-edit-link { font-size: var(--fs-base); font-weight: 600; color: var(--ink-text-1); }
.aw-stepper { display: inline-flex; align-items: center; border: 1px solid rgb(255 255 255 / 0.16); border-radius: 9px; overflow: hidden; }
.aw-stepper button {
  width: 34px; height: 34px; border: 0; cursor: pointer;
  background: rgb(255 255 255 / 0.05); color: var(--ink-text-1);
  font-family: var(--font-mono); font-size: var(--fs-lg);
}
.aw-stepper button:hover { background: rgb(255 255 255 / 0.1); }
.aw-stepper button:focus-visible { outline: 2px solid var(--sig-green-lift); outline-offset: -2px; }
.aw-stepper output { min-width: 44px; text-align: center; font-family: var(--font-mono); font-size: var(--fs-base); font-weight: 600; color: var(--warn-ink); }
.aw-edit.is-ok .aw-stepper output, .aw-edit:not([class*="is-"]) .aw-stepper output { color: var(--ink-text-1); }
.aw-edit.is-crit .aw-stepper output { color: var(--crit-ink); }
.aw-edit-of { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-3); }
.aw-edit-say { flex: 1 1 220px; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-2); }
.aw-edit.is-warn .aw-edit-say { color: var(--warn-ink); }
.aw-edit.is-crit .aw-edit-say { color: var(--crit-ink); }
.aw-edit.is-ok .aw-edit-say { color: var(--sig-green-pulse); }
/* the twelve-cell table, folded behind one line */
.aw-table { margin-top: var(--space-16); border: 1px dashed rgb(255 255 255 / 0.16); border-radius: 12px; }
.aw-table > summary {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-4) var(--space-12); padding: var(--space-12) var(--space-16);
  cursor: pointer; list-style: none;
}
.aw-table > summary::-webkit-details-marker { display: none; }
.aw-table > summary b { font-size: var(--fs-cap); font-weight: 600; color: var(--ink-text-1); }
.aw-table > summary span { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-3); }
.aw-table > summary i { margin-left: auto; font-style: normal; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--f4-blue-pale); }
.aw-table > summary i::after { content: " ▾"; }
.aw-table[open] > summary i::after { content: " ▴"; }
.aw-table > summary:focus-visible { outline: 2px solid var(--sig-green-lift); outline-offset: 2px; border-radius: 12px; }
.aw-table > :not(summary) { margin-inline: var(--space-16); }
.aw-table[open] { padding-bottom: var(--space-16); }

/* ---- the allocation workspace · the pane where the model is overridden ----
   The three numbered steps are the page's claim made walkable: run the model,
   read the proposal, adjust it. The grid is a real <table> because it IS one —
   lots against customers — and the row/column headers are what let each cell's
   aria-label stay short instead of restating its coordinates.
   Green is spent on exactly one thing here: a cell the planner has changed.
   That is a decision, which is the allowlist's own definition; the model's own
   proposal stays cool, because a machine's suggestion is not yet a decision.
   Amber marks a line under its life spec and red a lot allocated past what
   exists · both are always paired with a written warning below, never colour
   alone. */
.aw-step {
  display: flex; align-items: center; gap: var(--space-10);
  font-family: var(--font-mono);
  font-size: var(--fs-cap-s);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--f4-slate);
  margin-bottom: var(--space-12);
}
.bg-ink .aw-step { color: var(--ink-text-2); }
.aw-step b {
  flex: none;
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.18);
  border-radius: 50%;
  font-weight: 500;
  letter-spacing: 0;
}
.bg-ink .aw-step b { border-color: var(--ink-card-line); color: var(--ink-text-1); }

.alloc-work { margin-top: var(--space-28); border-top: 1px solid var(--f4-line); padding-top: var(--space-20); }
.bg-ink .alloc-work { border-top-color: var(--f4-line-dark); }
.aw-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-16); flex-wrap: wrap; }
.aw-head .aw-step { margin-bottom: 0; }

/* below its content width the grid scrolls sideways rather than crushing the
   mono figures · the same idiom the demand-signal bench and the S&OP coverage
   grid use. It needs no tabindex of its own: it is full of focusable inputs. */
.aw-wrap { margin-top: var(--space-16); overflow-x: auto; }
.aw-grid { width: 100%; min-width: 520px; border-collapse: collapse; }
.aw-grid th, .aw-grid td { padding: var(--space-8) var(--space-6); text-align: center; }
.aw-grid thead th, .aw-grid tfoot th, .aw-grid tbody th {
  font-weight: 500;
  font-size: var(--fs-2xs);
  color: var(--f4-slate);
}
.bg-ink .aw-grid thead th, .bg-ink .aw-grid tfoot th, .bg-ink .aw-grid tbody th { color: var(--ink-text-2); }
.aw-grid th span { display: block; font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: 0.02em; }
.bg-ink .aw-grid th span { color: var(--ink-text-1); }
.aw-grid th i { display: block; font-style: normal; font-family: var(--font-mono); font-size: var(--fs-4xs); opacity: 0.7; margin-top: var(--space-2); }
.aw-grid tbody th, .aw-grid tfoot th { text-align: left; padding-left: 0; white-space: nowrap; }
.aw-grid thead th { border-bottom: 1px solid var(--f4-line); vertical-align: bottom; }
.bg-ink .aw-grid thead th { border-bottom-color: var(--f4-line-dark); }
.aw-grid tfoot th, .aw-grid tfoot td { border-top: 1px solid var(--f4-line); padding-top: var(--space-12); }
.bg-ink .aw-grid tfoot th, .bg-ink .aw-grid tfoot td { border-top-color: var(--f4-line-dark); }
.aw-grid .aw-end { border-left: 1px solid var(--f4-line); }
.bg-ink .aw-grid .aw-end { border-left-color: var(--f4-line-dark); }

.aw-grid input {
  width: 3.25rem;
  padding: var(--space-6) var(--space-4);
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: inherit;
  background: var(--surface-2);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.12);
  border-radius: var(--radius-xs);
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.bg-ink .aw-grid input { background: rgba(255, 255, 255, 0.04); border-color: var(--ink-card-line); color: var(--ink-text-1); }
.aw-grid input:hover { border-color: rgb(var(--f4-ink-rgb) / 0.3); }
.bg-ink .aw-grid input:hover { border-color: rgb(var(--ink-text-3-rgb) / 0.55); }
.aw-grid input:focus-visible { outline: 2px solid var(--sig-green-deep); outline-offset: 2px; }
.bg-ink .aw-grid input:focus-visible { outline-color: var(--sig-green-lift); }
/* the planner's own decision · flat green, never a halo */
.aw-grid input.is-edited { border-color: var(--sig-green); color: var(--sig-green-text); font-weight: 500; }
.bg-ink .aw-grid input.is-edited { border-color: var(--sig-green-lift); color: var(--sig-green-lift); background: rgb(var(--sig-green-rgb) / 0.10); }
.aw-grid input.is-under { border-color: var(--f4-warn); color: var(--warn-text); }
.bg-ink .aw-grid input.is-under { border-color: var(--f4-warn); color: var(--f4-warn); background: rgb(var(--f4-warn-rgb) / 0.10); }

.aw-grid b, .aw-chip b {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.aw-hold { color: var(--f4-slate); }
.bg-ink .aw-hold { color: var(--ink-text-1); }
.aw-nil { color: var(--f4-slate); opacity: 0.5; }
.bg-ink .aw-nil { color: var(--ink-text-3); }
.aw-bad { color: var(--crit-text); }
.bg-ink .aw-bad { color: var(--crit-ink); }
.aw-over { color: var(--warn-text); }
.bg-ink .aw-over { color: var(--f4-warn); }

.aw-rail { display: flex; flex-wrap: wrap; gap: var(--space-10); margin-top: var(--space-18); }
.aw-chip {
  display: inline-flex; align-items: baseline; gap: var(--space-8);
  padding: var(--space-8) var(--space-14);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.1);
  border-radius: var(--radius-pill);
  font-size: var(--fs-2xs);
  color: var(--f4-slate);
}
.bg-ink .aw-chip { border-color: var(--ink-card-line); color: var(--ink-text-2); }

.aw-warns { list-style: none; margin: var(--space-14) 0 0; padding: 0; display: grid; gap: var(--space-8); }
.aw-warns li {
  display: flex; gap: var(--space-10); align-items: baseline;
  font-size: var(--fs-sm);
  color: var(--f4-slate);
}
.bg-ink .aw-warns li { color: var(--ink-text-2); }
.aw-warns li span {
  flex: none;
  min-width: 4.75rem;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.aw-warns li.aw-crit span { color: var(--crit-text); }
.aw-warns li.aw-warn span { color: var(--warn-text); }
.aw-warns li.aw-ok span { color: var(--sig-green-text); }
.aw-warns li.aw-more span { opacity: 0.6; }
.bg-ink .aw-warns li.aw-crit span { color: var(--crit-ink); }
.bg-ink .aw-warns li.aw-warn span { color: var(--f4-warn); }
.bg-ink .aw-warns li.aw-ok span { color: var(--sig-green-lift); }

@media (max-width: 640px) {
  .aw-head { align-items: flex-start; flex-direction: column; }
}

/* ---- the constraint engine · a before/after SYSTEM, not two lists ----
   The old section made this argument in nine chips and two paragraphs, which
   is the one shape that cannot show it: chips are a list, and the claim is
   about where a list LIVES. So the two states are drawn instead. Left, nine
   loose sheets, each rotated a hair off true and carrying the place its rule
   actually lives; they connect to nothing, which is the point. Right, a dark
   machined slab on the light section (the .ctower / .chain-demo finish, self
   contained and never leaning on a bg-ink ancestor) that takes supply and
   orders in at the top, holds the same nine rules, and emits one governed
   allocation at the foot. Green is spent once, on that output: it is the
   decision the whole drawing exists to produce. */
.cengine {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  margin-top: var(--space-32);
}
.ce-cap {
  font-family: var(--font-mono);
  font-size: var(--fs-cap-s);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--f4-slate);
  margin-bottom: var(--space-16);
}
.ce-note { margin-top: var(--space-14); font-size: var(--fs-sm); color: var(--f4-slate); }

/* the scatter · loose paper, each sheet a tab strip and a filename */
.ce-sheets {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-10);
}
.ce-sheets li {
  position: relative;
  padding: var(--space-16) var(--space-12) var(--space-12);
  background: var(--surface);
  border: 1px solid var(--f4-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}
/* the tab strip · what makes a rectangle read as a sheet rather than a card */
.ce-sheets li::before {
  content: "";
  position: absolute; inset: var(--space-6) auto auto var(--space-12);
  width: 22px; height: 2px;
  border-radius: var(--radius-pill);
  background: var(--f4-line);
}
/* off true, deterministically · a scatter that reshuffles on every reveal
   reads as noise, and one that is perfectly square is not a scatter */
.ce-sheets li:nth-child(3n+1) { transform: rotate(-1.1deg); }
.ce-sheets li:nth-child(3n+2) { transform: rotate(0.7deg); }
.ce-sheets li:nth-child(3n)   { transform: rotate(-0.4deg); }
.ce-sheets li:nth-child(even) { margin-top: var(--space-8); }
.ce-sheets b { display: block; font-size: var(--fs-2xs); font-weight: 600; line-height: var(--lh-tight); }
.ce-sheets i {
  display: block; margin-top: var(--space-6);
  font-style: normal;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  color: var(--f4-slate);
}

/* the flow · one hairline with a head, the only thing joining the two states */
.ce-flow { align-self: center; display: grid; place-items: center; }
.ce-flow span {
  display: block;
  width: clamp(28px, 4vw, 56px); height: 1px;
  background: var(--f4-line);
  position: relative;
}
.ce-flow span::after {
  content: "";
  position: absolute; right: -1px; top: 50%;
  width: 7px; height: 7px;
  border-top: 1px solid var(--f4-slate);
  border-right: 1px solid var(--f4-slate);
  transform: translateY(-50%) rotate(45deg);
}

/* the engine · finish, not float. Self-contained dark styling. */
.ce-core {
  border-radius: var(--radius-card);
  border: 1px solid rgb(255 255 255 / 0.10);
  background: linear-gradient(180deg, var(--ink-700), var(--ink-800));
  box-shadow: inset 0 1px 0 var(--specular-ink), var(--shadow-md);
  padding: var(--space-16);
}
.ce-in { display: flex; flex-wrap: wrap; gap: var(--space-8); margin-bottom: var(--space-14); }
.ce-in span {
  padding: var(--space-4) var(--space-10);
  border: 1px dashed rgb(var(--ink-text-3-rgb) / 0.45);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.06em;
  color: var(--ink-text-2);
}
.ce-rules {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2) var(--space-10);
  border-top: 1px solid rgb(var(--ink-text-3-rgb) / 0.18);
  border-bottom: 1px solid rgb(var(--ink-text-3-rgb) / 0.18);
  padding: var(--space-12) 0;
}
.ce-rules li {
  display: flex; align-items: baseline; gap: var(--space-8);
  font-size: var(--fs-2xs);
  color: var(--ink-text-1);
  padding: var(--space-4) 0;
}
/* the registration mark the kicker uses · these rules are held, not decided */
.ce-rules li::before {
  content: "";
  flex: none;
  width: 5px; height: 5px;
  border: 1px solid rgb(var(--ink-text-3-rgb) / 0.8);
  border-radius: 50%;
}
.ce-out {
  margin: var(--space-14) 0 0;
  padding: var(--space-10) var(--space-12);
  border-radius: var(--radius-sm);
  background: rgb(var(--sig-green-rgb) / 0.14);
  border: 1px solid rgb(var(--sig-green-lift-rgb) / 0.45);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.06em;
  color: var(--sig-green-lift);
  text-align: center;
}

@media (max-width: 1023px) {
  .cengine { grid-template-columns: 1fr; }
  /* the arrow turns down with the stack · a sideways head over a vertical
     hand-off points at nothing */
  .ce-flow span { width: 1px; height: 40px; }
  .ce-flow span::after { right: auto; left: 50%; top: auto; bottom: -1px; transform: translateX(-50%) rotate(135deg); }
}
@media (max-width: 560px) {
  .ce-sheets { grid-template-columns: 1fr 1fr; }
  .ce-rules { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------------
   Forecast · the demand-signal bench
   A five-step authoring tool rather than a scenario picker: the
   step rail states the whole method at a glance and doubles as
   random access, the panel below it carries only the controls for
   the step you are on. Green is spent exactly where the house
   allows it — the aria-current step, the checked switches, the
   selected model and the published signal itself. The champion
   badge is deliberately cool: it is a backtest fact, not a
   decision, and only the selection state gets to be green.
   ------------------------------------------------------------ */
.fx-steps {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-8);
  list-style: none;
  margin: 0;
  padding: 0;
}
/* stepped rather than auto-fit · auto-fit lands on a ragged 4 + 1 at tablet
   widths, and a five-step method reads better as 3 + 2 than as an orphan */
@media (max-width: 1023px) { .fx-steps { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 640px) { .fx-steps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .fx-steps { grid-template-columns: 1fr; } }
.fx-steps > li { display: flex; }
.fx-steps button {
  flex: 1;
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: var(--space-2) var(--space-8);
  text-align: left;
  padding: var(--space-10) var(--space-12);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.1);
  border-radius: var(--radius-btn);
  background: var(--surface);
  transition: border-color 200ms var(--ease-out), background 200ms var(--ease-out), color 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.bg-ink .fx-steps button { border-color: var(--f4-line-dark); background: rgba(255, 255, 255, 0.03); }
/* the bench reads short: each step is its number and its name; the hint
   stays for screen readers, and the step's panel says the rest */
.fx-steps .fx-hint { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#forecast-demo .demo-kpi { padding-block: var(--space-12); }
.fx-steps button:hover { border-color: var(--sig-green); transform: translateY(-1px); }
.bg-ink .fx-steps button:hover { border-color: var(--sig-green-lift); }
.fx-steps button.on { border-color: rgb(var(--sig-green-rgb) / 0.55); background: rgb(var(--sig-green-rgb) / 0.1); }
.fx-steps .fx-n {
  width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 500;
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.16);
  color: var(--f4-slate);
}
.bg-ink .fx-steps .fx-n { border-color: rgba(255, 255, 255, 0.2); color: var(--ink-text-3); }
.fx-steps button.on .fx-n { background: var(--sig-green); border-color: transparent; color: var(--sig-green-ink); }
.fx-steps b { font-size: var(--fs-cap); font-weight: 600; line-height: 1.25; }
.bg-ink .fx-steps b { color: var(--text-on-ink); }
.bg-ink .fx-steps button.on b { color: var(--sig-green-lift); }
.fx-steps .fx-hint {
  grid-column: 2;
  font-family: var(--font-mono); font-size: var(--fs-2xs); line-height: 1.35;
  color: var(--f4-slate);
}
.bg-ink .fx-steps .fx-hint { color: var(--ink-text-3); }

/* legend · built from the series actually on the plot */
.fx-legend {
  display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-18);
  margin-top: var(--space-24);
  font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: 0.06em;
  color: var(--f4-slate);
}
.bg-ink .fx-legend { color: var(--ink-text-3); }
.fx-key { display: inline-flex; align-items: center; gap: var(--space-8); }
.fx-key i { display: block; width: 22px; height: 2px; border-radius: var(--radius-pill); }
.fx-key-raw i { background: repeating-linear-gradient(90deg, var(--ink-text-3) 0 3px, transparent 3px 6px); }
.fx-key-hist i { background: var(--ink-text-1); }
.fx-key-base i { background: repeating-linear-gradient(90deg, var(--f4-blue-lift) 0 5px, transparent 5px 9px); }
.fx-key-sig i { background: var(--sig-green-lift); height: 2.5px; }
.fx-key-sense i { width: 9px; height: 9px; border-radius: 50%; background: none; border: 1.5px solid var(--f4-signal); }
.fx-chart { margin-top: var(--space-10); }
.fx-sigline { stroke-dasharray: 100; }
[data-demo-forecast]:not([data-noanim]) .fx-sigline { animation: sparkDraw 900ms var(--ease-out) 100ms backwards; }

/* the step's own controls */
.fx-panel {
  margin-top: var(--space-24);
  padding-top: var(--space-20);
  border-top: 1px solid var(--f4-line);
  min-height: 172px;
}
.bg-ink .fx-panel { border-top-color: var(--f4-line-dark); }
.fx-lede { font-size: var(--fs-md); line-height: var(--lh-ui); max-width: 76ch; color: var(--f4-slate); }
.bg-ink .fx-lede { color: var(--text-on-ink-dim); }
.fx-note { margin-top: var(--space-14); font-size: var(--fs-base); line-height: var(--lh-ui); max-width: 76ch; color: var(--f4-slate); }
.bg-ink .fx-note { color: var(--ink-text-3); }
.fx-warn { margin-top: var(--space-14); font-size: var(--fs-base); line-height: var(--lh-ui); color: var(--warn-text); }
.bg-ink .fx-warn { color: var(--f4-warn); }

.fx-opts { display: grid; gap: var(--space-8); margin-top: var(--space-16); grid-template-columns: repeat(auto-fit, minmax(264px, 1fr)); }
.fx-opts-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.fx-toggle {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-12);
  align-items: start;
  text-align: left;
  padding: var(--space-12) var(--space-14);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.1);
  border-radius: var(--radius-btn);
  background: var(--surface);
  transition: border-color 200ms var(--ease-out), background 200ms var(--ease-out);
}
.bg-ink .fx-toggle { border-color: var(--ink-card-line); background: rgba(255, 255, 255, 0.03); }
.fx-toggle:hover { border-color: var(--sig-green); }
.bg-ink .fx-toggle:hover { border-color: var(--sig-green-lift); }
.fx-toggle > i {                       /* the track */
  position: relative;
  width: 30px; height: 17px; border-radius: var(--radius-pill);
  margin-top: 1px;
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.2);
  background: var(--surface-2);
  transition: background 200ms var(--ease-out), border-color 200ms var(--ease-out);
}
.fx-toggle > i::after {                /* the knob */
  content: "";
  position: absolute; top: 2px; left: 2px;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--f4-slate);
  transition: transform 200ms var(--ease-out), background 200ms var(--ease-out);
}
.bg-ink .fx-toggle > i { border-color: rgba(255, 255, 255, 0.22); background: rgba(255, 255, 255, 0.06); }
.bg-ink .fx-toggle > i::after { background: var(--ink-text-3); }
.fx-toggle[aria-checked="true"] { border-color: rgb(var(--sig-green-rgb) / 0.38); }
.fx-toggle[aria-checked="true"] > i { background: var(--sig-green); border-color: transparent; }
.fx-toggle[aria-checked="true"] > i::after { transform: translateX(13px); background: var(--sig-green-ink); }
.fx-toggle b { display: block; font-size: var(--fs-base); font-weight: 600; }
.bg-ink .fx-toggle b { color: var(--text-on-ink); }
.fx-toggle em { display: block; font-style: normal; font-size: var(--fs-cap-s); line-height: var(--lh-tight); margin-top: var(--space-4); color: var(--f4-slate); }
.bg-ink .fx-toggle em { color: var(--ink-text-3); }
.fx-swing { text-decoration: none; font-family: var(--font-mono); font-size: var(--fs-kicker); white-space: nowrap; color: var(--warn-text); }
.bg-ink .fx-swing { color: var(--f4-warn); }
.fx-toggle.is-locked { opacity: 0.66; cursor: default; }
.fx-toggle.is-locked:hover, .bg-ink .fx-toggle.is-locked:hover { border-color: rgb(var(--sig-green-rgb) / 0.38); }

/* the model leaderboard · why this sku forecasts the way it does. Ranked rows
   rather than a card grid: five models in a grid wrap to a ragged 4 + 1, and a
   ranking wants to be read down a column anyway. */
.fx-models { display: grid; gap: var(--space-6); margin-top: var(--space-16); }
.fx-model {
  display: grid;
  grid-template-columns: minmax(196px, 1.05fr) minmax(0, 1.7fr) auto;
  align-items: center;
  gap: var(--space-4) var(--space-18);
  text-align: left;
  padding: var(--space-12) var(--space-14);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.1);
  border-radius: var(--radius-btn);
  background: var(--surface);
  transition: border-color 200ms var(--ease-out), background 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.fx-model u {
  justify-self: end; white-space: nowrap;
  text-decoration: none; font-family: var(--font-mono); font-size: var(--fs-kicker);
  font-variant-numeric: tabular-nums; color: var(--f4-slate);
}
@media (max-width: 767px) {
  .fx-model { grid-template-columns: 1fr; align-items: start; }
  .fx-model u { justify-self: start; }
}
.bg-ink .fx-model { border-color: var(--ink-card-line); background: rgba(255, 255, 255, 0.03); }
.fx-model:hover { border-color: var(--sig-green); transform: translateY(-1px); }
.bg-ink .fx-model:hover { border-color: var(--sig-green-lift); }
.fx-model b { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-8); font-size: var(--fs-base); font-weight: 600; }
.bg-ink .fx-model b { color: var(--text-on-ink); }
.fx-model em { font-style: normal; font-size: var(--fs-cap-s); line-height: var(--lh-tight); color: var(--f4-slate); }
.bg-ink .fx-model em { color: var(--ink-text-3); }
.bg-ink .fx-model u { color: var(--ink-text-2); }
.fx-model[aria-pressed="true"] { border-color: rgb(var(--sig-green-rgb) / 0.55); background: rgb(var(--sig-green-rgb) / 0.1); }
.bg-ink .fx-model[aria-pressed="true"] b { color: var(--sig-green-lift); }
.fx-champ {
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding: var(--space-2) var(--space-8); border-radius: var(--radius-pill);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.18);
  color: var(--f4-slate);
}
.bg-ink .fx-champ { border-color: rgba(255, 255, 255, 0.24); color: var(--ink-text-3); }

.fx-modes { margin-top: var(--space-16); }
.fx-slider { margin-top: var(--space-18); max-width: 26rem; }

.fx-nav { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-10); margin-top: var(--space-20); }
.fx-count { margin-left: auto; font-family: var(--font-mono); font-size: var(--fs-kicker); color: var(--f4-slate); }
.bg-ink .fx-count { color: var(--ink-text-3); }
.fx-nav .scenario-btn[aria-disabled="true"] { opacity: 0.42; }
.fx-nav .scenario-btn[aria-disabled="true"]:hover {
  transform: none; box-shadow: none;
  border-color: var(--f4-line-dark); color: var(--ink-text-2);
}
.fx-log li:nth-child(4) { animation-delay: 270ms; }
.fx-log li:nth-child(5) { animation-delay: 360ms; }
/* the log stages itself on first sight · once the visitor is driving the bench
   it must stop re-flying in on every click, or the panel never settles */
[data-fx-touched] .fx-log li { animation: none; }

/* the plot is composed for a wide canvas · below that it scrolls at a
   legible size rather than shrinking its mono labels into noise */
/* content-measured, not a ladder step: below 720 the plot scrolls sideways rather
   than shrinking its mono labels into noise. Mirrored at demos.js:1263. */
@media (max-width: 720px) {
  .fx-chart { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .fx-chart svg { min-width: 620px; }
  .fx-panel { min-height: 0; }
}

/* advisor tabs */
.tabs { display: flex; gap: var(--space-6); border-bottom: 1px solid var(--f4-line); padding: 0 var(--space-24); background: linear-gradient(180deg, var(--surface-1), var(--f4-paper)); }
.bg-ink .tabs { background: rgba(10, 20, 35, 0.45); border-bottom-color: var(--f4-line-dark); }
.tab-btn {
  padding: var(--space-14) var(--space-18);
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--f4-slate);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 180ms var(--ease-out), border-color 180ms var(--ease-out);
}
.bg-ink .tab-btn { color: var(--ink-text-2); }
.tab-btn:hover { color: var(--f4-ink); }
.bg-ink .tab-btn:hover { color: #fff; }
.tab-btn[aria-selected="true"] { color: var(--sig-green-text); border-bottom-color: var(--sig-green); }
.bg-ink .tab-btn[aria-selected="true"] { color: var(--sig-green-lift); border-bottom-color: var(--sig-green-lift); }
.tab-panel { padding: var(--space-24); }
.tab-panel[hidden] { display: none; }

/* mock email / report artefacts inside demos */
.mock-doc {
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.08);
  border-radius: var(--radius-btn);
  overflow: hidden;
  font-size: var(--fs-base);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.bg-ink .mock-doc { background: rgba(255, 255, 255, 0.03); border-color: var(--ink-card-line); box-shadow: none; }
.mock-doc .md-head {
  padding: var(--space-14) var(--space-16);
  background: var(--f4-paper);
  border-bottom: 1px solid var(--f4-line);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--f4-slate);
  display: grid; gap: var(--space-2);
}
.bg-ink .mock-doc .md-head { background: rgba(10, 20, 35, 0.5); border-bottom-color: var(--f4-line-dark); color: var(--ink-text-2); }
.mock-doc .md-body { padding: var(--space-16); display: grid; gap: var(--space-10); }
.mock-doc .md-body p { font-size: var(--fs-base); color: var(--f4-ink); }
.bg-ink .mock-doc .md-body p { color: var(--text-on-ink); }
.extract-row {
  display: flex; justify-content: space-between; gap: var(--space-16);
  padding: var(--space-8) var(--space-12);
  background: var(--f4-mist);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}
.bg-ink .extract-row { background: rgb(var(--sig-green-lift-rgb) / 0.08); }
.extract-row .er-field { color: var(--f4-slate); }
.bg-ink .extract-row .er-field { color: var(--ink-text-2); }
.extract-row .er-val { color: var(--f4-ink); font-weight: 500; }
.bg-ink .extract-row .er-val { color: #fff; }

/* Saga · ingest, report, advise (24 Oct demos audit). Three steps in the order
   the work runs, one card each: a name, one picture that does something, one
   line. Advice is the direction, so its card is drawn dashed and cannot be run. */
.sgw-run { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-16); }
.sgw-card {
  display: grid; grid-template-rows: auto 1fr auto; gap: var(--space-14);
  padding: var(--space-18); border-radius: 14px;
  background: rgb(255 255 255 / 0.035); border: 1px solid rgb(255 255 255 / 0.1);
}
.sgw-h { display: flex; align-items: center; gap: var(--space-10); }
.sgw-h h3 { margin: 0; font-size: var(--fs-xl); font-weight: 600; color: var(--ink-text-1); }
.sgw-n {
  display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%;
  border: 1px solid rgb(255 255 255 / 0.22);
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-2);
}
.sgw-live {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-text-3);
}
.sgw-live::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--sig-green-lift); }
.sgw-c { margin: 0; font-size: var(--fs-base); line-height: 1.45; color: var(--ink-text-2); }
.sgw-v { display: grid; align-content: start; gap: var(--space-10); min-width: 0; }
/* 1 · ingest: the email and its sheet, parsed into one row that waits for you */
.sgw-mail { display: grid; grid-template-columns: 30px minmax(0, 1fr) auto; gap: var(--space-10); align-items: center; }
.sgw-av {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  background: rgb(var(--f4-blue-lift-rgb) / 0.2); color: var(--f4-blue-pale);
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 600;
}
.sgw-mail b { display: block; font-size: var(--fs-cap); font-weight: 600; color: var(--ink-text-1); }
.sgw-dim { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-3); }
.sgw-att {
  display: flex; align-items: center; gap: var(--space-8); padding: 8px 10px; border-radius: 8px;
  background: rgb(255 255 255 / 0.05); font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-2);
}
.sgw-xls { padding: 2px 5px; border-radius: 4px; background: var(--sig-green-text); color: rgb(255 255 255); font-size: 9.5px; font-weight: 600; }
.sgw-down { justify-self: center; position: relative; width: 1px; height: 16px; background: rgb(255 255 255 / 0.3); }
.sgw-down::after { content: ""; position: absolute; left: -3px; bottom: -1px; border: 3.5px solid transparent; border-top: 5px solid rgb(255 255 255 / 0.45); border-bottom: 0; }
.sgw-row {
  display: grid; grid-template-columns: 1fr 1.3fr 1fr; border-radius: 9px; overflow: hidden;
  border: 1px solid rgb(var(--f4-blue-lift-rgb) / 0.45);
  transition: border-color 260ms var(--ease-out);
}
.sgw-row > div {
  padding: 8px 10px; background: rgb(var(--f4-blue-lift-rgb) / 0.08);
  font-family: var(--font-mono); font-size: var(--fs-cap); font-weight: 500; color: var(--ink-text-1); white-space: nowrap;
  transition: background 260ms var(--ease-out);
}
.sgw-row > div + div { border-left: 1px solid rgb(var(--f4-blue-lift-rgb) / 0.25); }
.sgw-row small { display: block; margin-bottom: 3px; font-size: 9.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-text-3); }
.sgw-row.is-done { border-color: rgb(var(--sig-green-lift-rgb) / 0.6); }
.sgw-row.is-done > div { background: rgb(var(--sig-green-rgb) / 0.1); }
.sgw-row.is-done > div + div { border-left-color: rgb(var(--sig-green-lift-rgb) / 0.25); }
.sgw-step { display: inline-flex; gap: 4px; margin-left: 6px; vertical-align: middle; }
.sgw-step[hidden] { display: none; }
.sgw-step button {
  width: 22px; height: 22px; border-radius: 6px; cursor: pointer; line-height: 1;
  border: 1px solid rgb(255 255 255 / 0.2); background: rgb(255 255 255 / 0.06); color: var(--ink-text-1);
  font-family: var(--font-mono); font-size: var(--fs-sm);
}
.sgw-acts { display: flex; gap: var(--space-8); }
.sgw-ok, .sgw-edit {
  min-height: 36px; padding: 0 14px; border-radius: 9px; cursor: pointer;
  font-family: var(--font-body); font-size: var(--fs-cap); font-weight: 600;
}
.sgw-ok { border: 0; background: var(--sig-green); color: var(--sig-green-ink); }
.sgw-ok:disabled { cursor: default; background: rgb(var(--sig-green-rgb) / 0.2); color: var(--sig-green-pulse); }
.sgw-edit { border: 1px solid rgb(255 255 255 / 0.2); background: transparent; color: var(--ink-text-1); font-weight: 500; }
.sgw-ok:focus-visible, .sgw-edit:focus-visible, .sgw-step button:focus-visible, .sgw-langs button:focus-visible { outline: 2px solid var(--sig-green-lift); outline-offset: 2px; }
.sgw-status { margin: 0; min-height: 1.4em; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--sig-green-pulse); }
/* 2 · report: one analysis, in the language you pick */
.sgw-langs { display: inline-flex; justify-self: start; padding: 3px; border-radius: var(--radius-pill); border: 1px solid rgb(255 255 255 / 0.14); }
.sgw-langs button {
  padding: 5px 11px; border: 0; border-radius: var(--radius-pill); cursor: pointer; background: transparent;
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 500; color: var(--ink-text-3);
}
.sgw-langs button[aria-pressed="true"] { background: rgb(var(--f4-blue-lift-rgb) / 0.22); color: var(--f4-blue-pale); }
.sgw-rep { display: grid; gap: var(--space-10); }
.sgw-big { display: flex; align-items: baseline; gap: var(--space-10); }
.sgw-big b { font-family: var(--font-mono); font-size: 34px; font-weight: 500; line-height: 1; color: var(--sig-green-lift); white-space: nowrap; }
.sgw-big span { font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.35; color: var(--ink-text-3); }
.sgw-spark { display: block; width: 100%; max-width: 360px; height: auto; overflow: visible; }
.sgw-spark .ar { fill: rgb(var(--f4-blue-lift-rgb) / 0.12); }
.sgw-spark .ln { fill: none; stroke: var(--f4-blue-pale); stroke-width: 1.75; }
.sgw-spark .dt { fill: var(--ink-800); stroke: var(--f4-blue-pale); stroke-width: 1.5; }
.sgw-spark .dt.is-now { fill: var(--sig-green-lift); stroke: none; }
.sgw-spark text { font-family: var(--font-mono); font-size: 10px; fill: var(--ink-text-3); }
.sgw-note { margin: 0; font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--ink-text-2); }
/* 3 · connect: one scheduled message to the growers, and who has answered it */
.sgw-sent { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.sgw-sent li {
  display: flex; justify-content: space-between; align-items: center; gap: var(--space-10);
  padding: 8px 10px; border-radius: 8px; border: 1px solid rgb(255 255 255 / 0.1); background: rgb(255 255 255 / 0.03);
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-1);
}
.sgw-sent li > span { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; color: var(--ink-text-3); }
.sgw-sent li > span::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.sgw-sent li > span.is-in { color: var(--sig-green-lift); }
.sgw-sent li > span.is-chased { color: var(--f4-warn); }
.sgw-yours { justify-self: start; padding: 8px 14px; border-radius: 9px; border: 1px dashed rgb(255 255 255 / 0.28); font-size: var(--fs-cap); font-weight: 500; color: var(--ink-text-2); }
@media (max-width: 1099px) {
  .sgw-run { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sgw-card:nth-child(3) { grid-column: 1 / -1; }
}
@media (max-width: 699px) {
  .sgw-run { grid-template-columns: minmax(0, 1fr); }
}

/* Memory · the answer as a chain (24 Oct demos audit): what was decided, what
   the plan did with it and what happened, linked left to right, the outcome as
   a small chart, the sources under it as document chips */
.mem-q {
  display: flex; align-items: center; gap: var(--space-12);
  padding: var(--space-14) var(--space-18); border-radius: var(--radius-btn);
  border: 1px solid rgb(var(--sig-green-lift-rgb) / 0.34);
  background: linear-gradient(135deg, rgb(var(--sig-green-rgb) / 0.09), rgba(255, 255, 255, 0.03));
  box-shadow: var(--specular-ink);
}
.mem-q svg { flex: none; width: 18px; height: 18px; fill: none; stroke: var(--sig-green-lift); stroke-width: 2; stroke-linecap: round; }
.mem-q p { flex: 1; min-width: 0; margin: 0; font-family: var(--font-display); font-size: var(--fs-2xl); line-height: var(--lh-tight); color: var(--ink-text-1); }
.mem-q span { flex: none; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-3); }
.mem-suggest { display: flex; flex-wrap: wrap; gap: var(--space-8); margin-top: var(--space-12); }
.mem-suggest .scenario-btn { text-align: left; }
.mem-suggest .scenario-btn[aria-pressed="true"] {
  color: var(--sig-green-lift);
  border-color: rgb(var(--sig-green-lift-rgb) / 0.5);
  background: rgb(var(--sig-green-rgb) / 0.1);
}
.mem-links { display: grid; grid-template-columns: minmax(0, 1fr) 36px minmax(0, 1fr) 36px minmax(0, 1fr); margin-top: var(--space-20); }
.mem-node {
  display: grid; align-content: start; gap: var(--space-6);
  padding: var(--space-16); border-radius: 14px;
  background: var(--ink-card-grad); border: 1px solid var(--ink-card-line); box-shadow: var(--specular-ink);
  animation: logIn 400ms var(--ease-out) backwards;
}
.mem-node:nth-of-type(2) { animation-delay: 120ms; }
.mem-node:nth-of-type(3) { animation-delay: 240ms; }
.mem-node.is-out { border-color: rgb(var(--sig-green-lift-rgb) / 0.5); background: rgb(var(--sig-green-rgb) / 0.08); }
.mem-node .k { font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; color: var(--f4-blue-lift); }
.mem-node.is-out .k { color: var(--sig-green-lift); }
.mem-node .when { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-3); }
.mem-node b { margin-top: var(--space-4); font-size: var(--fs-lg); font-weight: 600; line-height: 1.3; color: var(--ink-text-1); }
.mem-node p { margin: 0; font-size: var(--fs-cap); line-height: 1.45; color: var(--ink-text-2); }
.mem-who { display: inline-flex; align-items: center; gap: var(--space-8); margin-top: var(--space-4); font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-text-2); }
.mem-who i {
  display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  background: rgb(255 255 255 / 0.1); font-size: 9px; font-style: normal; font-weight: 600; color: var(--ink-text-1);
}
.mem-arrow { align-self: center; justify-self: center; width: 22px; height: 12px; fill: none; stroke: var(--sig-green-lift); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.mem-out { display: block; width: 100%; height: auto; margin-top: var(--space-6); overflow: visible; }
.mem-out .win { fill: rgb(var(--sig-green-rgb) / 0.14); }
.mem-out .tgt { stroke: rgb(var(--ink-text-3-rgb) / 0.7); stroke-width: 1; stroke-dasharray: 3 3; }
.mem-out .ln { fill: none; stroke: var(--sig-green-lift); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.mem-out .bar { fill: rgb(var(--sig-green-lift-rgb) / 0.7); }
.mem-out .base { stroke: rgb(255 255 255 / 0.18); stroke-width: 1; }
.mem-out text { font-family: var(--font-mono); font-size: 10px; fill: var(--ink-text-3); }
.mem-out text.v { font-size: 11px; font-weight: 600; fill: var(--sig-green-pulse); }
.mem-docs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-8); margin-top: var(--space-14); }
.mem-docs-k { font-family: var(--font-mono); font-size: var(--fs-3xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-text-3); }
.mem-doc {
  display: inline-flex; align-items: center; gap: var(--space-8);
  padding: 6px 12px; border-radius: 10px;
  border: 1px solid rgb(var(--f4-blue-lift-rgb) / 0.35); background: rgb(var(--f4-blue-lift-rgb) / 0.06);
  font-size: var(--fs-cap); color: var(--ink-text-1);
}
.mem-doc svg { width: 12px; height: 14px; fill: none; stroke: var(--ink-text-2); stroke-width: 1.4; stroke-linejoin: round; }
.mem-doc small { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--ink-text-3); }
@media (max-width: 860px) {
  .mem-links { grid-template-columns: minmax(0, 1fr); }
  .mem-arrow { transform: rotate(90deg); margin: 6px 0; }
}
@media (prefers-reduced-motion: reduce) { .mem-node { animation: none; } }

/* ============================================================
   Company belief flow · four decisions on one connected line
   ============================================================ */
.belief-statement .section-head { max-width: 760px; }
.belief-flow {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 2.75rem);
  margin-top: var(--space-48);
  padding-top: var(--space-36);
}
.belief-flow::before,
.belief-flow::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
}
.belief-flow::before { background: var(--f4-line); }
.belief-flow::after {
  background: linear-gradient(90deg, var(--sig-green-deep), var(--sig-green), var(--sig-green-deep));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 1100ms var(--ease-out);
}
.belief-flow.in::after { transform: scaleX(1); }
.belief-point { position: relative; }
.belief-point::before {
  content: "";
  position: absolute;
  top: calc(-2.25rem - 5px);
  left: 0;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 2px solid var(--sig-green-deep);
  background: var(--f4-paper);
  box-shadow: 0 0 0 4px var(--f4-paper);
  transition: background 260ms var(--ease-out), box-shadow 260ms var(--ease-out);
}
.belief-flow.in .belief-point::before { background: var(--sig-green); }
.belief-flow.in .belief-point:nth-child(2)::before { transition-delay: 180ms; }
.belief-flow.in .belief-point:nth-child(3)::before { transition-delay: 360ms; }
.belief-flow.in .belief-point:nth-child(4)::before { transition-delay: 540ms; }
.belief-index {
  display: block;
  margin-bottom: var(--space-12);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .12em;
  color: var(--sig-green-text);
}
.belief-point h3 { font-size: var(--fs-2xl); }
.belief-point p { margin-top: var(--space-10); font-size: var(--fs-md); color: var(--f4-slate); }
@media (max-width: 767px) {
  .belief-flow {
    grid-template-columns: 1fr;
    gap: var(--space-32);
    padding-top: 0;
    padding-left: var(--space-32);
  }
  .belief-flow::before,
  .belief-flow::after {
    top: 0;
    bottom: 0;
    left: 0;
    right: auto;
    width: 1px;
    height: auto;
  }
  .belief-flow::after { transform: scaleY(0); transform-origin: top; }
  .belief-flow.in::after { transform: scaleY(1); }
  .belief-point::before { top: .25rem; left: calc(-2rem - 5px); }
}
/* What we believe, run (24 Oct review) · a playhead walks the rail, each
   belief's node fills as it arrives and its glyph draws: shelf life
   draining, three desks joining one picture, rules leaving a head for a
   card, waste and concessions down while margin rises. Every glyph's resting
   style is its last frame, so reduced motion shows the finished picture. */
.belief-flow { --bf-gap: clamp(1.5rem, 3vw, 2.75rem); }
.bf-fill, .bf-head, .bp-node { display: none; }
@media (min-width: 768px) {
  .belief-flow[data-story]:not(.is-static) .bf-fill {
    display: block; position: absolute; top: 0; left: 5.5px; z-index: 1; height: 1px;
    width: calc(var(--bp, 0) * (100% - (100% - 3 * var(--bf-gap)) / 4));
    background: var(--sig-green-deep);
  }
  .belief-flow[data-story]:not(.is-static) .bf-head {
    display: block; position: absolute; top: -6px; z-index: 2; width: 12px; height: 12px; margin-left: -0.5px;
    left: calc(var(--bp, 0) * (100% - (100% - 3 * var(--bf-gap)) / 4));
    border-radius: 50%; background: var(--sig-green); box-shadow: 0 0 0 4px var(--f4-paper);
    transition: opacity 300ms var(--ease-out);
  }
  /* the rail's one-shot reveal hands over to the run */
  .belief-flow[data-story]:not(.is-static)::after { opacity: 0; }
  .belief-flow[data-story]:not(.is-static).in .belief-point::before { background: var(--f4-paper); }
  .belief-flow[data-story]:not(.is-static) .bp-node {
    display: block; position: absolute; top: calc(-2.25rem - 5px); left: 0; z-index: 1;
    width: 11px; height: 11px; border-radius: 50%; background: var(--sig-green);
  }
}
.bp-art { display: block; margin: 0 0 var(--space-14); }
.bp-glyph { display: block; width: 100%; max-width: 180px; height: auto; overflow: visible; }
.bg-t { font-family: var(--font-mono); font-size: 8.5px; fill: var(--f4-slate); }
.bg-track { fill: rgb(var(--f4-ink-rgb) / 0.07); }
/* 01 · shelf life drains from fresh to two days left */
.bg-life { fill: var(--f4-warn); transform-box: fill-box; transform-origin: 0 50%; transform: scaleX(0.28); }
.bg-late { fill: var(--warn-text); font-weight: 500; }
.bp-art.is-on .bg-life { animation: bgDrain 2.6s ease-in-out backwards; }
.bp-art.is-on .bg-late { animation: bgLate 2.6s var(--ease-out) backwards; }
@keyframes bgDrain { from { transform: scaleX(1); fill: var(--sig-green); } }
@keyframes bgLate { 0%, 80% { opacity: 0; } }
/* 02 · three desks, one decision picture */
.bg-desk { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.4); stroke-width: 1.25; }
.bg-ini { font-family: var(--font-mono); font-size: 9px; font-weight: 600; fill: var(--f4-ink); }
.bg-join { fill: none; stroke: var(--sig-green-deep); stroke-width: 1.5; stroke-dasharray: 1; stroke-dashoffset: 0; }
.bg-one circle { fill: var(--sig-green); }
.bg-one text { fill: var(--sig-green-text); font-weight: 500; }
.bp-art.is-on .bg-join { animation: bgJoin 1.6s var(--ease-out) 0.3s backwards; }
.bp-art.is-on .bg-one { animation: bgPop 0.5s var(--ease-out) 1.8s backwards; }
@keyframes bgJoin { from { stroke-dashoffset: 1; } }
@keyframes bgPop { from { opacity: 0; transform: translateY(3px); } }
/* 03 · the rules leave a few heads and land in a card */
.bg-who { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.55); stroke-width: 1.5; stroke-linecap: round; }
.bg-hand { fill: none; stroke: var(--sig-green-deep); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.bg-card { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.14); }
.bg-rule path { fill: none; stroke: var(--sig-green-deep); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.bg-rule text { font-family: var(--font-mono); font-size: 8.5px; fill: var(--f4-ink); }
.bp-art.is-on .bg-rule { animation: bgPop 0.5s var(--ease-out) backwards; }
.bp-art.is-on .bg-rule.r1 { animation-delay: 0.5s; }
.bp-art.is-on .bg-rule.r2 { animation-delay: 1.1s; }
.bp-art.is-on .bg-rule.r3 { animation-delay: 1.7s; }
/* 04 · the measurable test: two bars fall, one rises */
.bg-bar { transform-box: fill-box; transform-origin: 0 50%; }
.bg-down { fill: rgb(var(--f4-ink-rgb) / 0.38); }
.bg-down.b1 { transform: scaleX(0.58); }
.bg-down.b2 { transform: scaleX(0.52); }
.bg-up { fill: var(--sig-green); transform: scaleX(0.94); }
.bp-art.is-on .bg-down { animation: bgFall 2.2s ease-in-out backwards; }
.bp-art.is-on .bg-up { animation: bgRise 2.2s ease-in-out backwards; }
@keyframes bgFall { from { transform: scaleX(1); } }
@keyframes bgRise { from { transform: scaleX(0.62); } }
[data-story].is-static .bp-art * { animation: none !important; }


/* ============================================================
   12b · The October 2026 modules · network, recipes, season, feeds
   Four working models and the page compositions around them: the
   four-tier logistics network (Allocate), recipe flex (S&OP · MRP), the
   season curve (Forecast · yield) and a file becoming a feed (Connect).
   Each reuses the demo vocabulary above (aw-step, demo-kpis, aw-warns,
   aw-grid) so the four read as the same instrument family.
   ============================================================ */

/* ---- logistics · four layers of dots ----
   Green is the plan's flow: what the optimiser decided to move. Amber is
   the slow boat and anything landing short of life, always doubled by a
   dash and a written line below. The diagram scrolls sideways below its
   content width, the same idiom as the grids, so its mono labels never
   shrink to illegibility on a phone. */
.lg-controls { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-12) var(--space-24); }
/* a rule the planner can switch · shared by the network and recipe demos.
   Dashed while off, so it never reads as a fourth scenario: it changes a
   rule the scenarios all run under. */
.rule-toggle {
  display: inline-flex; align-items: center; gap: var(--space-10);
  padding: var(--space-6) var(--space-12) var(--space-6) var(--space-8);
  border-radius: var(--radius-pill);
  border: 1px dashed var(--f4-line-dark);
  font-family: var(--font-mono);
  font-size: var(--fs-cap-s);
  color: var(--ink-text-2);
  transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.rule-toggle .sw {
  position: relative; flex: none;
  width: 30px; height: 16px;
  border-radius: var(--radius-pill);
  border: 1px solid rgb(var(--ink-text-3-rgb) / 0.6);
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.rule-toggle .sw::after {
  content: "";
  position: absolute; top: 2px; left: 2px;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--ink-text-2);
  transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.rule-toggle:hover { color: var(--ink-text-1); border-color: rgb(var(--ink-text-3-rgb) / 0.7); }
.rule-toggle:focus-visible { outline: 2px solid var(--sig-green-lift); outline-offset: 3px; }
/* a rule switched on is the planner's decision · flat green, no halo */
.rule-toggle[aria-pressed="true"] { color: var(--sig-green-lift); border-style: solid; border-color: rgb(var(--sig-green-lift-rgb) / 0.5); }
.rule-toggle[aria-pressed="true"] .sw { background: rgb(var(--sig-green-rgb) / 0.22); border-color: var(--sig-green-lift); }
.rule-toggle[aria-pressed="true"] .sw::after { transform: translateX(14px); background: var(--sig-green-lift); }
.lg-lead { font-size: var(--fs-base); min-height: 1.6em; }

.lg-stage { overflow-x: auto; margin-top: var(--space-4); }
.lg-stage svg { display: block; width: 100%; min-width: 640px; height: auto; }
.lg-stage .lg-flow { stroke: var(--sig-green); stroke-opacity: 0.55; transition: stroke-width 600ms var(--ease-out); }
.lg-stage .lg-late { stroke: var(--f4-warn); stroke-opacity: 0.85; }
.lg-stage .lg-flow:not(.lg-dash) { stroke-dasharray: 100; stroke-dashoffset: 0; animation: linkDraw 800ms var(--ease-out) backwards; }
.lg-stage .lg-dash { animation: lgFade 700ms var(--ease-out) backwards; }
@keyframes lgFade { from { opacity: 0; } }
.lg-stage .lg-lane { letter-spacing: 0.04em; }

.lg-list td { text-align: left; font-size: var(--fs-2xs); }
.lg-list td i { display: block; font-style: normal; font-family: var(--font-mono); font-size: var(--fs-4xs); opacity: 0.7; margin-top: var(--space-2); }
.bg-ink .lg-list td { color: var(--ink-text-2); }
.lg-list thead th { text-align: left; }
.lg-list thead th.aw-end, .lg-list td.aw-end { text-align: right; padding-right: 0; }
.lg-list tbody tr + tr th, .lg-list tbody tr + tr td { border-top: 1px solid var(--f4-line); }
.bg-ink .lg-list tbody tr + tr th, .bg-ink .lg-list tbody tr + tr td { border-top-color: var(--f4-line-dark); }
.lg-list { min-width: 440px; }

@media (prefers-reduced-motion: reduce) {
  /* matched selector for selector · :not() carries its argument's weight,
     so a plain .lg-flow here would lose to the draw-in rule above */
  .lg-stage .lg-flow:not(.lg-dash), .lg-stage .lg-dash { animation: none; }
  .rule-toggle, .rule-toggle .sw, .rule-toggle .sw::after { transition: none; }
}

/* ---- the four tiers · four stations on one run, a hairline between each ----
   The cards are the four layers of dots the demo below draws; the mono foot
   of each names what passes to the next layer, so the row reads as a chain
   rather than four features side by side. The link hairlines only exist
   while the four sit on one line. */
.tiers {
  list-style: none; margin: var(--space-32) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--gutter);
}
.tiers > li {
  position: relative;
  display: flex; flex-direction: column;
  padding: var(--space-24);
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.07);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
}
.tiers .tr-n {
  display: grid; place-items: center;
  width: 26px; height: 26px;
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.22);
  border-radius: 50%;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--f4-ink);
}
.tiers h3 { margin-top: var(--space-14); font-size: var(--fs-2xl); }
.tiers p { margin-top: var(--space-8); font-size: var(--fs-md); color: var(--f4-slate); flex: 1; }
.tiers .tr-link {
  display: flex; align-items: center; gap: var(--space-8);
  margin-top: var(--space-16); padding-top: var(--space-12);
  border-top: 1px dashed var(--f4-line);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.04em;
  color: var(--f4-blue-deep);
}
.tiers .tr-link::after { content: "→"; margin-left: auto; }
/* the last station hands nothing on · it closes the run */
.tiers .tr-link.tr-end { color: var(--f4-slate); }
.tiers .tr-link.tr-end::after { content: none; }
@media (min-width: 1024px) {
  .tiers > li:not(:last-child)::after {
    content: "";
    position: absolute; top: 37px; left: 100%;
    width: var(--gutter); height: 1px;
    background: rgb(var(--f4-ink-rgb) / 0.22);
  }
}
@media (max-width: 1023px) { .tiers { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px)  { .tiers { grid-template-columns: 1fr; } }
/* five stations · the Forecast Studio journey. Only one line at 1280+, so
   the link hairlines are kept there and dropped wherever the row wraps. */
.tiers.t5 { grid-template-columns: repeat(5, 1fr); }
/* Allocate · four layers of dots, drawn (24 Oct review) · the network the
   section names, kept simple: a few dots per layer, the links the plan
   decides, one lot's route lit and the decision under each hop. A token
   rides the lit route while the section is in view ([data-mini]); under
   reduced motion it never starts and the drawing rests complete. */
.tnet { margin-top: var(--space-40); }
.tnet-stage { overflow-x: auto; }
.tnet svg { display: block; width: 100%; min-width: 760px; height: auto; overflow: visible; }
.tn-num { font-family: var(--font-mono); font-size: 11px; fill: var(--f4-slate); }
.tn-name { font-size: 15px; font-weight: 600; fill: var(--f4-ink); }
.tn-link { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.13); stroke-width: 2; }
.tn-path { fill: none; stroke: var(--sig-green-deep); stroke-width: 3.5; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 0; }
.reveal.in .tn-path { animation: tnDraw 1.6s var(--ease-out) 0.3s backwards; }
@keyframes tnDraw { from { stroke-dashoffset: 1; } }
.tn-dot { fill: var(--f4-ink); stroke: var(--f4-paper); stroke-width: 3; }
.tn-dot.is-lit { fill: var(--sig-green); }
.tn-lab { font-size: 13px; fill: var(--f4-ink); }
.tn-dec rect { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.18); }
.tn-dec text { font-family: var(--font-mono); font-size: 11.5px; font-weight: 500; fill: var(--f4-ink); }
.tn-token { offset-rotate: 0deg; offset-distance: 0%; opacity: 0; }
.tn-token circle { fill: var(--surface); stroke: var(--sig-green-deep); stroke-width: 3; }
.tnet.is-on .tn-token { animation: tnRide 6s cubic-bezier(0.45, 0, 0.25, 1) 1.2s infinite; }
@keyframes tnRide {
  0% { offset-distance: 0%; opacity: 0; }
  6% { opacity: 1; }
  78% { offset-distance: 100%; opacity: 1; }
  88%, 100% { offset-distance: 100%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .reveal.in .tn-path, .tnet.is-on .tn-token { animation: none; } }
.tiers.t5 > li { padding: var(--space-20); }
.tiers.t5 h3 { font-size: var(--fs-xl); }
@media (max-width: 1279px) {
  .tiers.t5 { grid-template-columns: repeat(3, 1fr); }
  .tiers.t5 > li::after { display: none; }
}
@media (max-width: 767px) { .tiers.t5 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 480px) { .tiers.t5 { grid-template-columns: 1fr; } }

/* ---- the two forecast suites · what runs today, then the newest surface ---- */
.suite-card { display: flex; flex-direction: column; padding: var(--space-32); }
.suite-card .su-lead { font-size: var(--fs-lg); color: var(--f4-ink); }
.suite-card .su-list {
  margin: var(--space-16) 0 0; padding-left: var(--space-18);
  display: grid; gap: var(--space-8);
  font-size: var(--fs-md); color: var(--f4-slate);
  flex: 1;
}
.suite-card .su-new {
  margin-top: var(--space-24); padding-top: var(--space-16);
  border-top: 1px dashed var(--f4-line);
  font-size: var(--fs-base);
}
.suite-card .su-new b { color: var(--f4-ink); font-weight: 600; }
/* the two suites' mini stories (24 Oct review) · demand: heat and a
   promotion lift the forecast and the retailers' orders follow; yield: a
   planting moved earlier takes its harvest curve with it. Each loops only
   while on screen and rests on its last frame under reduced motion, so
   the still always tells the story */
.su-mini {
  margin: var(--space-16) 0 var(--space-4);
  padding: var(--space-12) var(--space-14) var(--space-8);
  border-radius: var(--radius-sm);
  background: rgb(var(--f4-ink-rgb) / 0.025);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.06);
}
.su-mini svg { display: block; width: 100%; height: auto; overflow: visible; }
.su-mini figcaption { margin-top: var(--space-6); font-family: var(--font-mono); font-size: var(--fs-4xs); letter-spacing: 0.04em; color: var(--f4-slate); }
.sm-axis { stroke: rgb(var(--f4-ink-rgb) / 0.18); stroke-width: 1; }
.sm-wk { font-family: var(--font-mono); font-size: 10px; fill: var(--f4-slate); }
.sm-bar { fill: rgb(var(--f4-ink-rgb) / 0.16); transform-box: fill-box; transform-origin: 50% 100%; }
.sm-bar.is-up { fill: rgb(var(--sig-green-rgb) / 0.5); }
.sm-area { fill: rgb(var(--sig-green-rgb) / 0.18); }
.sm-base { fill: none; stroke: var(--f4-slate); stroke-width: 1.5; stroke-dasharray: 4 4; }
.sm-lift { fill: none; stroke: var(--sig-green-deep); stroke-width: 2.25; stroke-linejoin: round; stroke-linecap: round; stroke-dasharray: 100; }
.sm-heat circle { fill: none; stroke: var(--warn-text); stroke-width: 1.5; }
.sm-heat path { fill: none; stroke: var(--warn-text); stroke-width: 1.5; stroke-linecap: round; }
.sm-heat text { font-family: var(--font-mono); font-size: 10px; fill: var(--warn-text); }
.sm-promo rect { fill: var(--surface); stroke: var(--sig-green-deep); stroke-width: 1; }
.sm-promo text { font-family: var(--font-mono); font-size: 10px; fill: var(--sig-green-text); }
.sm-note { font-family: var(--font-mono); font-size: 10px; font-weight: 500; fill: var(--sig-green-text); }
.ym-a { fill: rgb(var(--f4-ink-rgb) / 0.06); stroke: var(--f4-slate); stroke-width: 1.75; stroke-linejoin: round; }
.ym-bcurve { fill: rgb(var(--sig-green-rgb) / 0.14); stroke: var(--sig-green-deep); stroke-width: 2; stroke-linejoin: round; }
.ym-b { transform: translateX(var(--dx)); }
.ym-ta, .ym-tb0, .ym-tb1 { font-family: var(--font-mono); font-size: 10px; }
.ym-ta { fill: var(--f4-slate); }
.ym-tb0, .ym-tb1 { fill: var(--sig-green-text); }
.ym-tb0 { opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
  .su-mini .sm-heat, .su-mini .sm-promo, .su-mini .sm-lift, .su-mini .sm-area,
  .su-mini .sm-bar, .su-mini .sm-note, .su-mini .ym-b, .su-mini .ym-tb0, .su-mini .ym-tb1 {
    animation-duration: 9s; animation-iteration-count: infinite; animation-timing-function: ease-in-out;
    animation-play-state: paused;
  }
  .su-mini.is-on .sm-heat, .su-mini.is-on .sm-promo, .su-mini.is-on .sm-lift, .su-mini.is-on .sm-area,
  .su-mini.is-on .sm-bar, .su-mini.is-on .sm-note, .su-mini.is-on .ym-b, .su-mini.is-on .ym-tb0, .su-mini.is-on .ym-tb1 {
    animation-play-state: running;
  }
  .su-mini .sm-heat { animation-name: smHeat; }
  .su-mini .sm-promo { animation-name: smPromo; }
  .su-mini .sm-lift { animation-name: smLift; }
  .su-mini .sm-area { animation-name: smArea; }
  .su-mini .sm-bar { animation-name: smBar; }
  .su-mini .sm-bar.is-up { animation-name: smBarUp; }
  .su-mini .sm-note { animation-name: smNote; }
  .su-mini .ym-b { animation-name: ymB; }
  .su-mini .ym-tb0 { animation-name: ymTb0; }
  .su-mini .ym-tb1 { animation-name: ymTb1; }
}
@keyframes smHeat { 0%, 4% { opacity: 0; transform: translateY(4px); } 10%, 88% { opacity: 1; transform: none; } 96%, 100% { opacity: 0; } }
@keyframes smPromo { 0%, 12% { opacity: 0; transform: translateY(4px); } 18%, 88% { opacity: 1; transform: none; } 96%, 100% { opacity: 0; } }
@keyframes smLift { 0%, 20% { stroke-dashoffset: 100; opacity: 1; } 38%, 88% { stroke-dashoffset: 0; opacity: 1; } 96%, 100% { stroke-dashoffset: 0; opacity: 0; } }
@keyframes smArea { 0%, 30% { opacity: 0; } 42%, 88% { opacity: 1; } 96%, 100% { opacity: 0; } }
@keyframes smBar { 0%, 44% { transform: scaleY(var(--from)); } 56%, 88% { transform: none; } 97%, 100% { transform: scaleY(var(--from)); } }
@keyframes smBarUp {
  0%, 44% { transform: scaleY(var(--from)); fill: rgb(var(--f4-ink-rgb) / 0.16); }
  56%, 88% { transform: none; fill: rgb(var(--sig-green-rgb) / 0.5); }
  97%, 100% { transform: scaleY(var(--from)); fill: rgb(var(--f4-ink-rgb) / 0.16); }
}
@keyframes smNote { 0%, 54% { opacity: 0; } 60%, 88% { opacity: 1; } 96%, 100% { opacity: 0; } }
@keyframes ymB { 0%, 24% { transform: none; } 40%, 86% { transform: translateX(var(--dx)); } 96%, 100% { transform: none; } }
@keyframes ymTb0 { 0%, 26% { opacity: 1; } 32%, 88% { opacity: 0; } 96%, 100% { opacity: 1; } }
@keyframes ymTb1 { 0%, 26% { opacity: 0; } 32%, 88% { opacity: 1; } 96%, 100% { opacity: 0; } }
/* Harvest Studio on the map (24 Oct review) · the farm as a planner reads
   it: fields drawn as plots, tunnels as rows, each planting labelled with
   its block, week and hectares, the heat lens and two harvest curves
   pinned where they grow, and the planting schedule beside it */
.hs-shell { max-width: 1080px; margin: var(--space-32) auto 0; }
.hs-body { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: var(--space-20); padding: var(--space-20); }
.hs-map { min-width: 0; overflow-x: auto; }
.hs-map svg { display: block; width: 100%; min-width: 640px; height: auto; }
/* Harvest Studio map (24 Oct review, redrawn) · drawn the way the product
   draws it: the ground's photograph underneath (muted, under a slight shade),
   each planting a see-through tint with a crisp edge and a light halo so the
   tunnels still show, frosted chrome, small harvest curves on stems and the
   season strip along the bottom. The aerial tones are a photograph's, not
   the palette's, so they live here as named triplets and nowhere else. */
.hs-map {
  --hs2-base: 122 126 98;
  --hs2-wheat: 184 170 124;
  --hs2-barley: 168 166 118;
  --hs2-stubble: 176 160 122;
  --hs2-grass: 112 128 88;
  --hs2-pasture: 104 122 84;
  --hs2-headland: 132 140 104;
  --hs2-soil: 128 110 88;
  --hs2-yardgrass: 118 126 94;
  --hs2-woodfloor: 52 62 42;
  --hs2-hedge: 58 70 46;
  --hs2-crown-0: 70 86 56;
  --hs2-crown-1: 60 76 48;
  --hs2-crown-2: 80 96 62;
  --hs2-crown-hi: 120 134 92;
  --hs2-water: 52 68 76;
  --hs2-bank: 164 158 132;
  --hs2-road: 176 170 154;
  --hs2-road-edge: 128 122 104;
  --hs2-apron: 188 186 178;
  --hs2-underlay: 84 90 74;
  --hs2-tun-lit: 228 232 233;
  --hs2-tun-shade: 186 194 198;
  --hs2-tun-old-lit: 222 222 214;
  --hs2-tun-old-shade: 182 184 176;
  --hs2-straw: 196 182 142;
  --hs2-bed: 66 86 56;
  border-radius: 10px;
}
.hs2-base { fill: rgb(var(--hs2-base)); }
.hs2-p { stroke: none; }
.hs2-p.wheat { fill: rgb(var(--hs2-wheat)); }
.hs2-p.barley { fill: rgb(var(--hs2-barley)); }
.hs2-p.stubble { fill: rgb(var(--hs2-stubble)); }
.hs2-p.grass { fill: rgb(var(--hs2-grass)); }
.hs2-p.pasture { fill: rgb(var(--hs2-pasture)); }
.hs2-p.headland { fill: rgb(var(--hs2-headland)); }
.hs2-p.soil { fill: rgb(var(--hs2-soil)); }
.hs2-p.yardgrass { fill: rgb(var(--hs2-yardgrass)); }
.hs2-p.woodfloor { fill: rgb(var(--hs2-woodfloor)); }
.hs2-drill { stroke: rgb(0 0 0 / 0.06); stroke-width: 0.9; }
.hs2-trl { stroke: rgb(0 0 0 / 0.16); stroke-width: 0.9; }
.hs2-fur { stroke: rgb(0 0 0 / 0.13); stroke-width: 1; }
.hs2-bed { fill: rgb(var(--hs2-bed)); }
.hs2-bank { fill: rgb(var(--hs2-bank)); }
.hs2-water { fill: rgb(var(--hs2-water)); }
.hs2-sheen-a { stop-color: rgb(255 255 255); stop-opacity: 0.16; }
.hs2-sheen-b { stop-color: rgb(255 255 255); stop-opacity: 0; }
.hs2-lane-e { fill: none; stroke: rgb(var(--hs2-road-edge)); stroke-width: 9; stroke-linecap: round; }
.hs2-lane { fill: none; stroke: rgb(var(--hs2-road)); stroke-width: 6.5; stroke-linecap: round; }
.hs2-track-e { fill: none; stroke: rgb(var(--hs2-road-edge) / 0.7); stroke-width: 8; }
.hs2-track { fill: none; stroke: rgb(var(--hs2-road) / 0.9); stroke-width: 6; }
.hs2-apron { fill: rgb(var(--hs2-apron)); }
.hs2-bshadow { fill: rgb(0 0 0 / 0.32); }
.hs2-roof.r1 { fill: rgb(204 208 210); }
.hs2-roof.r2 { fill: rgb(226 228 228); }
.hs2-roof.r3 { fill: rgb(118 124 128); }
.hs2-roof.r4 { fill: rgb(148 104 84); }
.hs2-ridge { stroke: rgb(255 255 255 / 0.4); stroke-width: 1; }
.hs2-car.c1 { fill: rgb(232 234 236); }
.hs2-car.c2 { fill: rgb(40 44 50); }
.hs2-car.c3 { fill: rgb(96 112 132); }
.hs2-car.c4 { fill: rgb(150 70 64); }
.hs2-underlay { fill: rgb(var(--hs2-underlay)); }
.hs2-tun-lit { fill: rgb(var(--hs2-tun-lit)); }
.hs2-tun-shade { fill: rgb(var(--hs2-tun-shade)); }
.hs2-tun-lit.is-old { fill: rgb(var(--hs2-tun-old-lit)); }
.hs2-tun-shade.is-old { fill: rgb(var(--hs2-tun-old-shade)); }
.hs2-tun-ridge { fill: none; stroke: rgb(255 255 255 / 0.85); stroke-width: 0.7; }
.hs2-tun-end { fill: none; stroke: rgb(0 0 0 / 0.14); stroke-width: 1.4; }
.hs2-straw { fill: rgb(var(--hs2-straw)); }
.hs2-hedge { fill: none; stroke: rgb(var(--hs2-hedge)); stroke-width: 3.6; stroke-linecap: round; stroke-linejoin: round; }
.hs2-tshadow, .hs2-crown, .hs2-thi { fill: none; stroke-linecap: round; }
.hs2-tshadow { stroke: rgb(0 0 0 / 0.3); }
.hs2-crown.t0 { stroke: rgb(var(--hs2-crown-0)); }
.hs2-crown.t1 { stroke: rgb(var(--hs2-crown-1)); }
.hs2-crown.t2 { stroke: rgb(var(--hs2-crown-2)); }
.hs2-thi { stroke: rgb(var(--hs2-crown-hi) / 0.42); }
.hs2-mottle, .hs2-grain { pointer-events: none; }
.hs2-shade { fill: rgb(var(--f4-ink-rgb) / 0.1); }
/* the blocks over the photograph: a light halo outside, a see-through tint
   and a crisp edge in the lens colour inside it; the selected one stronger */
.hs2-halo { fill: none; stroke: rgb(255 255 255 / 0.78); stroke-width: 3.4; stroke-linejoin: round; }
.hs2-halo.is-sel { stroke: rgb(255 255 255); stroke-width: 5.5; }
.hs2-blk { fill-opacity: 0.3; stroke-width: 1.6; stroke-linejoin: round; }
.hs2-blk.is-sel { stroke-width: 2.4; }
.hs2-blk.v-a { fill: var(--sig-green); stroke: var(--sig-green); }
.hs2-blk.v-b { fill: var(--f4-blue); stroke: var(--f4-blue); }
.hs2-blk.v-c { fill: var(--f4-warn); stroke: var(--f4-warn); }
/* the curves: a small card above its place, on a stem; picked weeks in the
   actuals' ink, the rest as forecast in the planner's blue, now marked */
.hs2-card-box { fill: rgb(var(--f4-paper-rgb) / 0.95); stroke: rgb(var(--f4-ink-rgb) / 0.16); filter: drop-shadow(0 1px 3px rgb(var(--f4-ink-rgb) / 0.2)); }
.hs2-card.is-sel .hs2-card-box { stroke: rgb(var(--f4-ink-rgb) / 0.42); }
.hs2-stem { stroke: rgb(255 255 255 / 0.9); stroke-width: 1.2; }
.hs2-place { fill: var(--f4-ink); stroke: rgb(255 255 255); stroke-width: 1.2; }
.hs2-ct { font-size: 11px; font-weight: 600; fill: var(--f4-ink); }
.hs2-cv { font-weight: 400; fill: var(--f4-slate); }
.hs2-ck { font-weight: 500; fill: var(--f4-ink); }
.hs2-cs { font-family: var(--font-mono); font-size: 9.5px; fill: var(--f4-slate); }
.hs2-cbase { stroke: rgb(var(--f4-ink-rgb) / 0.12); }
.hs2-fc-area { fill: rgb(var(--f4-blue-rgb) / 0.16); }
.hs2-fc { fill: none; stroke: var(--f4-blue); stroke-width: 1.2; stroke-linejoin: round; }
.hs2-pk-area { fill: rgb(var(--f4-ink-rgb) / 0.3); }
.hs2-pk { fill: none; stroke: var(--f4-ink); stroke-width: 1.2; stroke-linejoin: round; }
.hs2-cnow { stroke: rgb(var(--f4-ink-rgb) / 0.5); stroke-width: 1; }
.hs2-flag rect { fill: var(--surface); stroke: var(--warn-text); stroke-width: 1; }
.hs2-flag text { font-family: var(--font-mono); font-size: 9px; font-weight: 500; fill: var(--warn-text); }
/* the chrome: frosted glass, one treatment on every piece; the lens switch
   stays neutral so the only colour in view belongs to the map */
.hs2-glass { filter: drop-shadow(0 2px 6px rgb(var(--f4-ink-rgb) / 0.22)); }
.hs2-gl { fill: rgb(var(--f4-paper-rgb) / 0.9); stroke: rgb(var(--f4-ink-rgb) / 0.1); }
.hs2-seg-on { fill: var(--surface); stroke: rgb(var(--f4-ink-rgb) / 0.1); }
.hs2-seg { font-size: 11px; fill: var(--f4-slate); }
.hs2-seg.is-on { font-weight: 600; fill: var(--f4-ink); }
.hs2-tog-on { fill: rgb(var(--f4-blue-rgb) / 0.12); }
.hs2-tog { font-size: 11px; font-weight: 600; fill: var(--f4-blue-deep); }
.hs2-tog-ic { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1.6; stroke-linecap: round; }
.hs2-ic { fill: none; stroke: var(--f4-ink); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.hs2-sep { stroke: rgb(var(--f4-ink-rgb) / 0.1); }
.hs2-thumb { fill: var(--f4-paper); stroke: rgb(var(--f4-ink-rgb) / 0.08); }
.hs2-tb { fill-opacity: 0.85; }
.hs2-tb.v-a { fill: var(--sig-green); }
.hs2-tb.v-b { fill: var(--f4-blue); }
.hs2-tb.v-c { fill: var(--f4-warn); }
.hs2-tlab-bg { fill: rgb(var(--f4-paper-rgb) / 0.92); }
.hs2-tlab { font-size: 9.5px; font-weight: 600; fill: var(--f4-ink); }
.hs2-scl { fill: none; stroke: var(--f4-ink); stroke-width: 1.2; }
.hs2-scl-t { font-family: var(--font-mono); font-size: 9.5px; fill: var(--f4-ink); }
.hs2-credit { font-family: var(--font-mono); font-size: 9px; fill: rgb(255 255 255 / 0.92); paint-order: stroke; stroke: rgb(var(--f4-ink-rgb) / 0.55); stroke-width: 2.4px; stroke-linejoin: round; }
.hs2-play { fill: var(--f4-ink); }
.hs2-play-ic { fill: var(--surface); }
.hs2-st-k { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; fill: var(--f4-slate); }
.hs2-st-v { font-family: var(--font-mono); font-size: 13px; font-weight: 500; fill: var(--f4-ink); }
.hs2-sb.is-picked { fill: rgb(var(--f4-ink-rgb) / 0.78); }
.hs2-sb.is-open { fill: rgb(var(--f4-blue-rgb) / 0.55); }
.hs2-sw { font-family: var(--font-mono); font-size: 9px; fill: var(--f4-slate); }
.hs2-snow { stroke: var(--f4-ink); stroke-width: 1.2; }
.hs2-snow-t { font-family: var(--font-mono); font-size: 9px; fill: var(--f4-ink); }
.hs-side { min-width: 0; display: grid; align-content: start; gap: var(--space-12); }
.hs-k { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--f4-slate); }
.hs-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-8); margin: 0; }
.hs-stats div { padding: var(--space-8) var(--space-10); border-radius: var(--radius-sm); background: rgb(var(--f4-ink-rgb) / 0.035); }
.hs-stats dt { font-size: var(--fs-2xs); color: var(--f4-slate); }
.hs-stats dd { margin: 2px 0 0; font-family: var(--font-mono); font-size: var(--fs-lg); font-weight: 500; color: var(--f4-ink); }
.hs-key { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-6); font-size: var(--fs-sm); color: var(--f4-ink); }
.hs-key li { display: flex; align-items: center; gap: var(--space-8); }
.hs-key i { width: 14px; height: 10px; border-radius: 3px; border: 1.25px solid; flex: none; }
.hs-key i.v-a { background: rgb(var(--sig-green-rgb) / 0.3); border-color: var(--sig-green); }
.hs-key i.v-b { background: rgb(var(--f4-blue-rgb) / 0.3); border-color: var(--f4-blue); }
.hs-key i.v-c { background: rgb(var(--f4-warn-rgb) / 0.3); border-color: var(--f4-warn); }
.hs-sched svg { display: block; width: 100%; height: auto; }
.hs-sg { stroke: rgb(var(--f4-ink-rgb) / 0.08); }
.hs-sw, .hs-sb { font-family: var(--font-mono); font-size: 9.5px; fill: var(--f4-slate); }
.hs-sp.v-a { fill: rgb(var(--sig-green-rgb) / 0.22); }
.hs-sh.v-a { fill: var(--sig-green-deep); }
.hs-sp.v-b { fill: rgb(var(--f4-blue-rgb) / 0.2); }
.hs-sh.v-b { fill: var(--f4-blue-deep); }
.hs-sp.v-c { fill: rgb(var(--f4-warn-rgb) / 0.25); }
.hs-sh.v-c { fill: var(--warn-text); }
.hs-legend { display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-14); font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--f4-slate); }
.hs-legend span { display: inline-flex; align-items: center; gap: var(--space-6); }
.hs-legend i { width: 14px; height: 8px; border-radius: 2px; }
.hs-legend .hs-lp { background: rgb(var(--sig-green-rgb) / 0.22); }
.hs-legend .hs-lh { background: var(--sig-green-deep); }
@media (max-width: 899px) { .hs-body { grid-template-columns: 1fr; } }
.hs-shell + .demo-disclosure { justify-content: center; margin-bottom: var(--space-40); }

/* ---- MRP · recipe flex ----
   Peppers are merchandise, not signals, so the colours of the fruit are
   never painted: each is a letter in a ring, the recipe code the product
   itself uses (RYG, ROG). The bars stay in the cool-white ladder; amber is
   giveaway and fruit held for want of a partner, red is a pack that cannot
   be made, and every one of them is written out in the notes below. */
.mr-rows { display: grid; gap: var(--space-10); }
.mr-row {
  display: grid;
  grid-template-columns: minmax(150px, 1.1fr) 2.4fr minmax(150px, 1fr);
  align-items: center;
  gap: var(--space-8) var(--space-18);
  padding: var(--space-10) 0;
  border-bottom: 1px solid var(--f4-line-dark);
}
.mr-rows .mr-row:last-child { border-bottom: 0; }
.mr-name span { display: flex; align-items: center; gap: var(--space-8); font-size: var(--fs-base); font-weight: 600; color: var(--ink-text-1); }
.mr-name i { display: block; font-style: normal; font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-3); margin-top: var(--space-4); }
.mr-badge {
  display: inline-grid; place-items: center;
  width: 20px; height: 20px;
  border: 1px solid rgb(var(--ink-text-3-rgb) / 0.7);
  border-radius: 50%;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  font-weight: 500;
  color: var(--ink-text-1);
}
.mr-bar {
  display: flex; height: 14px;
  border-radius: var(--radius-xs);
  background: rgb(var(--ink-text-3-rgb) / 0.08);
  overflow: hidden;
}
.mr-seg { display: block; height: 100%; transition: width 500ms var(--ease-out); }
.mr-seg + .mr-seg { box-shadow: inset 1px 0 0 var(--ink-800); }
.mr-made, .mr-in { background: rgb(var(--ink-text-1-rgb) / 0.78); }
/* a backup recipe is still a made pack, so it keeps the made tone and only
   takes a hatch · it is a substitution to notice, not a problem */
.mr-sub { background: repeating-linear-gradient(135deg, rgb(var(--ink-text-1-rgb) / 0.78) 0 3px, rgb(var(--ink-text-1-rgb) / 0.3) 3px 6px); }
.mr-short { background: rgb(var(--f4-crit-rgb) / 0.22); box-shadow: inset 0 0 0 1px rgb(var(--f4-crit-rgb) / 0.7) !important; }
.mr-give { background: repeating-linear-gradient(135deg, rgb(var(--f4-warn-rgb) / 0.85) 0 3px, rgb(var(--f4-warn-rgb) / 0.35) 3px 6px); }
.mr-held { background: rgb(var(--f4-warn-rgb) / 0.16); box-shadow: inset 0 0 0 1px rgb(var(--f4-warn-rgb) / 0.7) !important; }
.mr-spare { background: transparent; box-shadow: inset 0 0 0 1px rgb(var(--ink-text-3-rgb) / 0.4) !important; }
.mr-pills { display: flex; flex-wrap: wrap; gap: var(--space-6); }
.mr-pill {
  padding: var(--space-2) var(--space-8);
  border: 1px solid var(--ink-card-line);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  font-weight: 500;
  color: var(--ink-text-2);
  white-space: nowrap;
}
.mr-pill.is-sub { border-style: dashed; }
.mr-pill.is-short { color: var(--crit-ink); border-color: rgb(var(--f4-crit-rgb) / 0.55); }
.mr-pill.is-held, .mr-pill.is-give { color: var(--f4-warn); border-color: rgb(var(--f4-warn-rgb) / 0.5); }
.mr-legend {
  display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-18);
  margin-top: var(--space-12);
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  color: var(--ink-text-3);
}
.mr-legend .mk { display: inline-flex; align-items: center; gap: var(--space-8); }
.mr-legend .mk i { display: block; width: 18px; height: 9px; border-radius: var(--radius-xs); }
/* MRP as a flow (24 Oct review) · raw lots, raw material by calibre,
   recipes, packs by customer: the dualism of finished product and raw
   material on one drawing, with the shortage drawn where it bites */
.mf-wrap { overflow-x: auto; margin-top: var(--space-10); }
.mf-wrap svg { display: block; width: 100%; min-width: 760px; height: auto; }
.mf-head { font-size: 9px; letter-spacing: 0.14em; fill: var(--ink-text-3); }
.mf-t { font-size: 11px; font-weight: 500; fill: var(--ink-text-1); }
.mf-s { font-size: 9.5px; fill: var(--ink-text-3); }
.mf-s.is-held { fill: var(--f4-blue-lift); }
.mf-v { font-size: 10px; fill: var(--ink-text-2); }
.mf-v.is-short { fill: var(--crit-ink); }
.mf-box { fill: rgba(22, 35, 58, 0.94); stroke: rgba(255, 255, 255, 0.13); stroke-width: 1; }
.mf-node.is-short .mf-box { stroke: rgb(var(--f4-crit-rgb) / 0.75); }
.mf-rec.is-off { opacity: 0.45; }
.mf-rec.is-off .mf-box { stroke-dasharray: 4 4; }
.mf-lot rect { fill: rgba(255, 255, 255, 0.03); stroke: rgba(255, 255, 255, 0.12); stroke-dasharray: 3 3; }
.mf-lot.is-late rect { stroke: var(--f4-warn); }
.mf-lot.is-late .mf-s { fill: var(--f4-warn); }
.mf-cal { stroke: rgba(255, 255, 255, 0.22); stroke-width: 1.5; stroke-dasharray: 2 3; }
.mf-cal.is-late { stroke: var(--f4-warn); }
.mf-flow { fill-opacity: 0.42; }
.mf-out { fill: rgb(var(--sig-green-rgb) / 0.32); }
.mf-refused { fill: none; stroke: var(--f4-warn); stroke-width: 1.5; stroke-dasharray: 3 4; opacity: 0.8; }
.mf-track { fill: rgba(255, 255, 255, 0.08); }
.mf-seg.is-in { fill: var(--sig-green-lift); }
.mf-seg.is-give { fill: var(--f4-warn); }
.mf-seg.is-held { fill: var(--f4-blue-lift); }
.mf-seg.is-spare { fill: rgba(255, 255, 255, 0.22); }
.mf-seg.is-made { fill: var(--sig-green-lift); }
.mf-seg.is-shortbar { fill: var(--f4-crit); }
.mf-buy rect { fill: rgb(var(--f4-crit-rgb) / 0.18); stroke: var(--f4-crit); }
.mf-buy text { font-size: 9.5px; fill: var(--crit-ink); }
.mk-in i { background: var(--sig-green-lift); }
.mk-give i { background: var(--f4-warn); }
.mk-held i { background: var(--f4-blue-lift); }
.mk-spare i { background: rgba(255, 255, 255, 0.22); }
@media (max-width: 767px) {
  .mr-row { grid-template-columns: 1fr; gap: var(--space-8); }
}
@media (prefers-reduced-motion: reduce) { .mr-seg { transition: none; } }

/* ---- yield · one planting, one season ----
   The instrument-dial grammar of the plan and forecast benches: picked
   weeks are settled fact (cool-white bars), the frozen promise is a dashed
   reference, and the forecast is the one live green line, with its likely
   range as the only fill. */
.yd-controls { display: flex; flex-wrap: wrap; gap: var(--space-16) var(--space-40); }
.yd-chart { overflow-x: auto; margin-top: var(--space-24); }
.yd-chart svg { min-width: 560px; }
.yd-grid { stroke: rgb(var(--ink-text-3-rgb) / 0.13); stroke-width: 1; }
.yd-axis { fill: var(--ink-text-3); letter-spacing: 0.04em; }
.yd-band { fill: rgb(var(--sig-green-rgb) / 0.13); }
.yd-pick { fill: rgb(var(--ink-text-1-rgb) / 0.72); }
.yd-prom { fill: none; stroke: var(--ink-text-3); stroke-width: 1.75; stroke-dasharray: 5 5; opacity: 0.8; }
.yd-fc { fill: none; stroke: var(--sig-green-lift); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.yd-dot { fill: var(--sig-green-lift); }
.yd-now { stroke: var(--sig-green-lift); stroke-width: 1.25; stroke-dasharray: 2 3; opacity: 0.65; }
.yd-nowtag { fill: var(--sig-green-lift); }
.yk-pick i { height: 9px; border-radius: var(--radius-xs); background: rgb(var(--ink-text-1-rgb) / 0.72); }
.yk-prom i { background: repeating-linear-gradient(90deg, var(--ink-text-3) 0 5px, transparent 5px 9px); }
.yk-band i { height: 9px; border-radius: var(--radius-xs); background: rgb(var(--sig-green-rgb) / 0.2); }

/* ---- Control Tower · ten questions ----
   A catalogue read as questions, not chart names: the business question
   carries the tile, the lenses that answer it sit underneath in mono. */
.qgrid {
  list-style: none; margin: var(--space-32) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(5, 1fr);
  gap: var(--space-14);
  counter-reset: q;
}
.qgrid > li {
  counter-increment: q;
  display: flex; flex-direction: column;
  padding: var(--space-20) var(--space-18);
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.07);
  border-radius: var(--radius-btn);
  box-shadow: var(--shadow-sm);
}
.qgrid > li::before {
  content: counter(q, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.1em;
  color: var(--f4-slate);
}
.qgrid h3 { margin-top: var(--space-10); font-size: var(--fs-lg); line-height: var(--lh-tight); flex: 1; }
.qgrid p {
  margin-top: var(--space-14); padding-top: var(--space-10);
  border-top: 1px solid var(--f4-line);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  line-height: var(--lh-ui);
  letter-spacing: 0.02em;
  color: var(--f4-slate);
}
/* each question shows the chart its lens picks (24 Oct review) · drawn
   from the real Control Tower's own chart set (year on year, the bridge,
   the treemap, cover by day, variance and bias, price over volume, growth
   against the market, the aftermath, season shift, the grid), all on one
   blue ramp with amber only where something is short */
.qg-ch { display: block; width: 100%; height: auto; margin: var(--space-12) 0 var(--space-4); overflow: visible; }
.qg-base { stroke: rgb(var(--f4-ink-rgb) / 0.18); }
.qg-axis { stroke: rgb(var(--f4-ink-rgb) / 0.14); }
.qg-ty { fill: none; stroke: var(--f4-blue); stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.qg-ly { fill: none; stroke: rgb(var(--f4-ink-rgb) / 0.38); stroke-width: 1.5; stroke-dasharray: 4 3; }
.qg-gap { fill: rgb(var(--f4-blue-rgb) / 0.12); }
.qg-dot { fill: var(--f4-blue); stroke: var(--surface); stroke-width: 1.5; }
.qg-v { font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; fill: var(--f4-blue-deep); }
.qg-k { font-family: var(--font-mono); font-size: 8.5px; fill: var(--f4-slate); }
.qg-k.is-ty { fill: var(--f4-blue-deep); }
.qg-k.is-warn { fill: var(--warn-text); }
.qg-w.is-tot { fill: rgb(var(--f4-ink-rgb) / 0.72); }
.qg-w.is-up { fill: var(--f4-blue); }
.qg-w.is-dn { fill: rgb(var(--f4-blue-rgb) / 0.28); }
.qg-conn { stroke: rgb(var(--f4-ink-rgb) / 0.35); stroke-dasharray: 2 2; }
.qg-tile { stroke: var(--surface); stroke-width: 1; }
.qg-tl { font-size: 8.5px; font-weight: 600; fill: var(--f4-ink); }
.qg-tv { font-family: var(--font-mono); font-size: 8px; fill: var(--f4-slate); }
.qg-tl.is-on, .qg-tv.is-on { fill: var(--surface); }
.qg-box { fill: rgb(var(--f4-blue-rgb) / 0.07); stroke: rgb(var(--f4-blue-rgb) / 0.35); stroke-dasharray: 3 3; }
.qg-sku { fill: var(--f4-blue); opacity: 0.85; }
.qg-sku.is-out { fill: none; stroke: var(--f4-ink); stroke-width: 1.4; opacity: 1; }
.qg-diag { stroke: rgb(var(--f4-blue-rgb) / 0.5); stroke-dasharray: 4 3; }
.qg-bub { fill: rgb(var(--f4-ink-rgb) / 0.16); stroke: rgb(var(--f4-ink-rgb) / 0.3); }
.qg-bub.is-gain { fill: rgb(var(--f4-blue-rgb) / 0.55); stroke: var(--f4-blue-deep); }
.qg-win { fill: rgb(var(--f4-blue-rgb) / 0.06); }
.qg-upa { fill: rgb(var(--f4-blue-rgb) / 0.22); }
.qg-give { fill: rgb(var(--f4-ink-rgb) / 0.14); }
.qg-shift { stroke: var(--f4-blue-deep); stroke-width: 1.5; }
.qg-shift-h { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.qg-row { stroke: var(--f4-line); }
.qg-cell { font-family: var(--font-mono); font-size: 9px; fill: var(--f4-ink); }
.qg-cell.is-on { fill: var(--surface); font-weight: 600; }
.qg-spark { fill: none; stroke: var(--f4-blue); stroke-width: 1.4; stroke-linejoin: round; }
.reveal-group.in .qg-ty { stroke-dasharray: 1; animation: qgDraw 1.1s var(--ease-out) 0.3s backwards; }
@keyframes qgDraw { from { stroke-dashoffset: 1; } }
@media (prefers-reduced-motion: reduce) { .reveal-group.in .qg-ty { animation: none; } }
@media (max-width: 1100px) { .qgrid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 767px)  { .qgrid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 420px)  { .qgrid { grid-template-columns: 1fr; } }

/* the boards list beside the phone · icon, then a bold lead-in */
.ct-points { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-14); }
.ct-points li { display: flex; gap: var(--space-14); align-items: flex-start; font-size: var(--fs-md); color: var(--ink-text-2); }
.ct-points b { color: var(--ink-text-1); font-weight: 600; }
.ct-points .icon-tile { width: 28px; height: 28px; }
.ct-points .icon-tile svg { width: 19px; height: 19px; }
.ct-promise { margin: 0; padding-left: var(--space-18); display: grid; gap: var(--space-8); font-size: var(--fs-md); color: var(--f4-slate); }

/* ---- Control Tower on a phone · a drawn device, the .ctower finish ----
   Self-contained dark styling like .ctower, so it never leans on its
   section. Sized as a real phone (a 390pt screen at roughly 80%) and
   centred in its column; on narrow screens it simply scales with it. */
.ct-device { display: flex; justify-content: center; }
.ct-device + .demo-disclosure { justify-content: center; }
.cd-phone {
  width: min(320px, 100%);
  border-radius: 34px;
  padding: var(--space-12) var(--space-12) var(--space-10);
  background: linear-gradient(180deg, var(--ink-700) 0%, var(--f4-ink) 55%, var(--ink-900) 100%);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow:
    var(--specular-ink),
    inset 0 0 0 5px rgba(5, 11, 21, 0.85),
    0 42px 84px -38px rgba(5, 11, 21, 0.74),
    0 10px 26px -18px rgba(5, 11, 21, 0.6);
  color: var(--ink-text-1);
}
.cd-status {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-6) var(--space-14) var(--space-8);
  font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-2);
}
.cd-notch { width: 74px; height: 18px; border-radius: var(--radius-pill); background: var(--ink-900); }
.cd-bar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-8);
  padding: var(--space-10) var(--space-10);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  font-family: var(--font-mono);
}
.cd-q {
  padding: var(--space-2) var(--space-8);
  border-radius: var(--radius-pill);
  background: rgb(var(--f4-warn-rgb) / 0.15);
  color: var(--f4-warn);
  font-size: var(--fs-4xs);
  letter-spacing: 0.04em;
}
.cd-screen { display: grid; gap: var(--space-8); padding: var(--space-10) var(--space-4); }
.cd-card {
  padding: var(--space-12);
  border-radius: var(--radius-sm);
  border: 1px solid rgba(255, 255, 255, 0.07);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.012));
}
.cd-label { display: block; font-family: var(--font-mono); font-size: var(--fs-4xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-text-3); }
.cd-kpi { display: flex; align-items: center; gap: var(--space-14); }
.cd-kpi svg { width: 58px; height: 58px; flex: none; }
.cd-ring-bg { fill: none; stroke: rgb(var(--ink-text-3-rgb) / 0.2); stroke-width: 6; }
.cd-ring { fill: none; stroke: var(--sig-green-lift); stroke-width: 6; stroke-linecap: round; }
.cd-target { stroke: var(--ink-text-1); stroke-width: 1.5; }
.cd-val { display: block; margin-top: var(--space-4); font-family: var(--font-mono); font-size: var(--fs-h3); font-weight: 500; line-height: 1; color: #fff; font-variant-numeric: tabular-nums; }
.cd-sub { display: block; margin-top: var(--space-6); font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-3); }
.cd-moves { list-style: none; margin: var(--space-8) 0 0; padding: 0; display: grid; gap: var(--space-6); }
.cd-moves li { display: flex; justify-content: space-between; gap: var(--space-8); font-size: var(--fs-2xs); color: var(--ink-text-2); }
.cd-moves b { font-family: var(--font-mono); font-size: var(--fs-4xs); font-weight: 500; white-space: nowrap; }
.cd-moves .k-risk::before, .cd-moves .k-up::before { content: none; }
.cd-comment { border-left: 2px solid var(--f4-blue-lift); }
.cd-comment p { margin-top: var(--space-6); font-size: var(--fs-2xs); color: var(--ink-text-1); line-height: var(--lh-tight); }
.cd-comment .cd-reply { color: var(--ink-text-3); padding-left: var(--space-10); border-left: 1px solid rgba(255, 255, 255, 0.1); }
.cd-tabs {
  display: flex; justify-content: space-between;
  margin-top: var(--space-4); padding: var(--space-10) var(--space-8) var(--space-4);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-3);
}
.cd-tabs .on { color: var(--sig-green-lift); }

/* ---- the foundation under the four layers ----
   Connect is not a fifth verb: the four layer verbs keep the green, so the
   foundation row and band read in cool ink with a dashed rule, and the
   travelling pulse that lights each layer does not run along it. */
.layer-row.layer-base {
  opacity: 1; transform: none;
  border-style: dashed;
  border-color: rgb(var(--ink-text-3-rgb) / 0.45);
  background: rgba(255, 255, 255, 0.02);
  box-shadow: none;
}
.layer-row.layer-base .lr-verb { color: var(--ink-text-3); }
.layer-row.layer-base .lr-cap { opacity: 1; }
/* the name never splits: the caption beside it wraps instead */
.layer-row.layer-base .lr-name { white-space: nowrap; }
/* where the stack folds to two columns, the foundation still runs under both */
.layer-row.layer-base { grid-column: 1 / -1; }
/* the platform hero's stack is static: no scroll sequence ever lights it, so
   its rows must rest visible. They used to inherit the home pin's opacity 0
   and only appeared under reduced motion or on narrow screens. Scoped to
   .page-hero so the home hero's assembly keeps its choreography. */
.page-hero .layer-stack .layer-row { opacity: 1; transform: none; }
.layer-band.lb-base { border-top-style: dashed; border-top-color: var(--f4-line); }
.layer-band.lb-base:last-child { border-bottom-color: var(--f4-line); }
.layer-band.lb-base .lb-verb,
.layer-band.lb-base.lit .lb-verb { color: var(--f4-slate); }
.layer-band.lb-base .lb-verb svg,
.layer-band.lb-base.lit .lb-verb svg { color: var(--f4-slate); filter: none; }
.layer-band.lb-base::before { background: linear-gradient(90deg, var(--f4-slate), rgb(var(--f4-slate-rgb) / 0.08)); }
.layer-band.lb-base::after { display: none; }

/* ---- Connect & Craft · the foundation page ----
   Rebuilt on Michele's review (24 Oct 2026): fewer words, more drawing.
   Its AI marks (the hero tag, the map's key) are the sitewide .ai-tag at
   the end of this file: the green pill they replaced read as the AI deciding. */

/* proof · five live counts under the hero, each with its own mark.
   "250,000" needs ~255px at the stock 4rem, so the row runs a size
   smaller; under 1024px the files count leads on its own */
.cx-proof { grid-template-columns: repeat(5, 1fr); margin-top: var(--space-20); }
.cx-proof .stat-num { font-size: clamp(2rem, 3.75vw, 3rem); }
/* the mark sits flush on the number's left edge, glyph to glyph: a tile
   centred the glyph 10px in from the figure and the caption under it */
.cx-stat-icon {
  width: auto; height: auto;
  place-items: start;
  margin-bottom: var(--space-12);
  color: var(--sig-green-text);
  transform-origin: left center;
}
.cx-stat-icon svg { width: 26px; height: 26px; margin-left: -3px; }
.reveal-group .cx-stat-icon { opacity: 0; transform: scale(0.6); transition: opacity 520ms var(--ease-out), transform 520ms var(--ease-out); }
.reveal-group.in .cx-stat-icon { opacity: 1; transform: none; }
.reveal-group.in .stat:nth-child(2) .cx-stat-icon { transition-delay: 120ms; }
.reveal-group.in .stat:nth-child(3) .cx-stat-icon { transition-delay: 240ms; }
.reveal-group.in .stat:nth-child(4) .cx-stat-icon { transition-delay: 360ms; }
.reveal-group.in .stat:nth-child(5) .cx-stat-icon { transition-delay: 480ms; }
@media (prefers-reduced-motion: reduce) { .reveal-group .cx-stat-icon { opacity: 1; transform: none; transition: none; } }
@media (max-width: 1023px) {
  .cx-proof { grid-template-columns: repeat(4, 1fr); }
  .cx-proof .stat:first-child { grid-column: 1 / -1; }
}
@media (max-width: 899px) { .cx-proof { grid-template-columns: 1fr 1fr; } }

/* yesterday → today · three shifts, one row each: the old way struck
   through in slate, the new one on a drawn green check */
.cx-shift-head, .cx-shift li { display: grid; grid-template-columns: 34px 1fr 48px 1fr; align-items: center; column-gap: var(--space-16); }
.cx-shift-head {
  margin: var(--space-32) 0 var(--space-10);
  padding: 0 var(--space-20);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--f4-slate);
}
.cx-shift-head span:first-child { grid-column: 2; }
.cx-shift-head span:last-child { grid-column: 4; color: var(--sig-green-text); }
.cx-shift { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-10); }
.cx-shift li {
  padding: var(--space-16) var(--space-20);
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.06);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
}
.cs-was { font-size: var(--fs-md); color: var(--f4-slate); text-decoration: line-through; text-decoration-color: rgb(var(--f4-slate-rgb) / 0.45); }
.cs-now { display: flex; align-items: baseline; gap: var(--space-10); font-size: var(--fs-md); font-weight: 600; color: var(--f4-ink); }
.cs-now::before {
  content: "";
  flex: none;
  width: 10px; height: 5px;
  border-left: 2px solid var(--sig-green-deep);
  border-bottom: 2px solid var(--sig-green-deep);
  transform: translateY(-3px) rotate(-45deg);
}
.cs-arrow { position: relative; height: 1px; background: var(--f4-line); }
.cs-arrow::after {
  content: "";
  position: absolute; right: -1px; top: 50%;
  width: 7px; height: 7px;
  border-top: 1px solid var(--f4-slate);
  border-right: 1px solid var(--f4-slate);
  transform: translateY(-50%) rotate(45deg);
}
@media (max-width: 720px) {
  .cx-shift-head { display: none; }
  .cx-shift li { grid-template-columns: 34px 1fr; row-gap: var(--space-6); margin-top: 0; }
  .cx-shift li .icon-tile { grid-row: span 2; align-self: start; }
  .cs-arrow { display: none; }
}

/* the four promises · mark, label, and the promise's line as the heading */
.cx-promise .card-icon { margin-bottom: var(--space-14); }
.cx-promise .cx-pn {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--sig-green-text);
  margin-bottom: var(--space-10);
}

/* where it fits · the constraint engine's system drawing run one stage
   further: sources on the left, the machined slab in the middle with the
   AI line as its key, the plans and systems it feeds on the right */
.cengine.cx-map { grid-template-columns: 1.1fr auto 1fr auto 0.9fr; }
.cx-src { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-10); }
.cx-src li {
  display: flex; gap: var(--space-10); align-items: flex-start;
  padding: var(--space-12);
  background: var(--surface);
  border: 1px solid var(--f4-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}
.cx-src .icon-tile { width: 26px; height: 26px; }
.cx-src .icon-tile svg { width: 18px; height: 18px; }
.cx-src b { display: block; font-size: var(--fs-base); font-weight: 600; }
.cx-src i { display: block; margin-top: var(--space-2); font-style: normal; font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--f4-slate); }
/* the home band's compact version · four promises as a 2×2 */
.cx-src-2 { grid-template-columns: 1fr 1fr; }
@media (max-width: 560px) { .cx-src-2 { grid-template-columns: 1fr; } }
.cx-core { grid-template-columns: 1fr; }
/* what comes out · the same tiles as the sources, with the output's green
   rule on the left so the two sides of the drawing read as in and out */
.cx-src.cx-out li { border-left: 2px solid rgb(var(--sig-green-rgb) / 0.5); }
.cx-src i a { color: var(--f4-blue-deep); }
@media (max-width: 1023px) {
  .cengine.cx-map { grid-template-columns: 1fr; }
}

/* the rules the story never breaks · three facts and the privacy line,
   on ink under the demo */
.cx-facts {
  list-style: none;
  margin: var(--space-48) 0 0;
  padding: var(--space-32) 0 0;
  border-top: 1px solid var(--f4-line-dark);
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-24);
}
.cx-facts li { display: flex; gap: var(--space-12); align-items: flex-start; }
.cx-facts h3, .cx-privacy h3 { font-size: var(--fs-lg); color: var(--ink-text-1); margin-bottom: var(--space-6); }
.cx-facts p, .cx-privacy p { font-size: var(--fs-base); color: var(--ink-text-2); }
.cx-privacy {
  display: grid; grid-template-columns: 34px 1fr auto; align-items: center; gap: var(--space-16);
  margin-top: var(--space-24);
  padding: var(--space-20) var(--space-24);
  border-radius: var(--radius-card);
  border: 1px solid var(--ink-card-line);
  background: var(--ink-card-grad);
}
.cx-privacy .link-quiet { white-space: nowrap; }
@media (max-width: 1023px) { .cx-facts { grid-template-columns: 1fr; gap: var(--space-16); } }
@media (max-width: 720px) {
  .cx-privacy { grid-template-columns: 34px 1fr; }
  .cx-privacy .link-quiet { grid-column: 2; }
}

/* what it runs · the lead job, the ERP both ways: data in on the signal
   green, agreed figures back on the reference blue */
.cx-sync {
  display: grid; grid-template-columns: 1fr 1.15fr; align-items: center; gap: var(--space-32);
  margin-top: var(--space-32);
  padding: var(--space-28) var(--space-32);
  background: var(--surface);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.06);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-md);
}
.cx-sync-copy .icon-tile { color: var(--sig-green-text); }
.cx-sync h3 { font-size: var(--fs-2xl); margin: var(--space-10) 0 var(--space-8); }
.cx-sync p { color: var(--f4-slate); }
.cx-sync-art { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-12); }
.cxy-node {
  padding: var(--space-12) var(--space-16);
  border-radius: var(--radius-sm);
  border: 1px solid var(--f4-line);
  background: var(--f4-paper);
  font-size: var(--fs-base);
  font-weight: 600;
  white-space: nowrap;
}
.cxy-node.is-f4 { background: var(--f4-ink); border-color: var(--f4-ink); color: var(--ink-text-1); }
.cxy-lanes { display: grid; gap: var(--space-40); padding: var(--space-24) 0; }
.cxy-lane {
  position: relative; display: block; height: 2px;
  background-image: repeating-linear-gradient(90deg, rgb(var(--sig-green-rgb) / 0.95) 0 8px, transparent 8px 14px);
  background-size: 14px 2px;
}
.cxy-lane.is-back { background-image: repeating-linear-gradient(90deg, rgb(var(--f4-blue-rgb) / 0.85) 0 8px, transparent 8px 14px); }
.cxy-lane::after {
  content: "";
  position: absolute; top: 50%;
  width: 7px; height: 7px;
  border-top: 2px solid var(--sig-green-deep);
  border-right: 2px solid var(--sig-green-deep);
}
.cxy-lane.is-in::after { right: -2px; transform: translateY(-50%) rotate(45deg); }
.cxy-lane.is-back::after { left: -2px; border-color: var(--f4-blue-deep); transform: translateY(-50%) rotate(-135deg); }
.cxy-lane i {
  position: absolute; left: 0; right: 0; bottom: var(--space-8);
  text-align: center;
  font-style: normal;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.04em;
  color: var(--sig-green-text);
}
.cxy-lane.is-back i { bottom: auto; top: var(--space-8); color: var(--f4-blue-deep); }
@media (prefers-reduced-motion: no-preference) {
  .cxy-lane { animation: cxyFlow 900ms linear infinite; }
  .cxy-lane.is-back { animation-direction: reverse; }
}
@keyframes cxyFlow { to { background-position: 14px 0; } }
@media (max-width: 900px) { .cx-sync { grid-template-columns: 1fr; padding: var(--space-24); } }
@media (max-width: 480px) { .cxy-node { padding: var(--space-10); font-size: var(--fs-sm); } }
.cx-jobs { margin-top: var(--space-20); }

/* the jobs · the in → out line is the card's signature */
.cx-case { display: flex; flex-direction: column; }
.cx-case p:not(.cx-io) { flex: 1; }
.cx-case .card-icon { margin-bottom: var(--space-14); }
.card .cx-io {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-6) var(--space-8);
  margin-top: var(--space-16); padding-top: var(--space-12);
  border-top: 1px dashed var(--f4-line);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.04em;
}
.cx-io span:first-child { color: var(--f4-slate); }
.cx-io span:first-child::after { content: "→"; margin-left: var(--space-8); color: var(--f4-slate); }
.cx-io span:last-child { color: var(--sig-green-text); }

/* ---- Connect & Craft demo · a retailer changes its file ----
   Five beats on three panels: the inbox, the assistant, your tools. The
   panel the story is on carries the green rim; the rest wait their turn.
   Nothing on the tools panel moves until the approval beat, and under
   reduced motion nothing plays until the reader asks. */
.cxs-shell { max-width: 1120px; margin-inline: auto; }
.cxs-ctrl { margin-left: auto; display: flex; gap: var(--space-8); }
.cxs-rail { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-8); }
.cxs-rail .scenario-btn b { font-weight: 500; opacity: 0.7; margin-right: var(--space-4); }
.bg-ink .cxs-rail .scenario-btn[aria-current="step"] {
  background: linear-gradient(180deg, var(--sig-green-face-a), var(--sig-green-face-b));
  border-color: transparent;
  color: var(--sig-green-ink);
  font-weight: 500;
}
.cxs-prog { height: 2px; margin-top: var(--space-14); border-radius: var(--radius-pill); background: var(--f4-line-dark); overflow: hidden; }
.cxs-prog i { display: block; width: 0; height: 100%; background: var(--sig-green-lift); }
.cxs-stage { display: grid; grid-template-columns: 1.05fr 1fr 1fr; gap: var(--space-14); margin-top: var(--space-16); }
.cxs-panel {
  display: flex; flex-direction: column; gap: var(--space-10);
  min-width: 0;
  padding: var(--space-14);
  border-radius: var(--radius-sm);
  border: 1px solid var(--f4-line-dark);
  background: rgba(255, 255, 255, 0.02);
  transition: border-color 400ms var(--ease-out), background 400ms var(--ease-out);
}
.cxs-panel.is-active { border-color: rgb(var(--sig-green-lift-rgb) / 0.55); background: rgba(255, 255, 255, 0.045); }
.cxs-ph {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-8);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-text-3);
}
.cxs-ph span { display: inline-flex; align-items: center; gap: var(--space-6); }
.cxs-ph svg { width: 14px; height: 14px; color: var(--sig-green-lift); }
.cxs-ph i { font-style: normal; letter-spacing: 0.04em; text-transform: none; }
/* the inbox */
.cxs-from { font-size: var(--fs-sm); color: var(--ink-text-1); }
.cxs-from b { font-weight: 600; }
.cxs-att { display: inline-flex; align-items: center; gap: var(--space-6); font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-2); }
.cxs-att svg { width: 14px; height: 14px; }
.cxs-tbl { width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-1); }
.cxs-tbl th, .cxs-tbl td {
  padding: var(--space-4) var(--space-6);
  text-align: left;
  border-bottom: 1px solid var(--f4-line-dark);
  transition: color 300ms var(--ease-out), background 300ms var(--ease-out), box-shadow 300ms var(--ease-out);
}
.cxs-tbl th:last-child, .cxs-tbl td:last-child { text-align: right; }
.cxs-tbl th { font-weight: 500; color: var(--ink-text-2); }
/* the new layout is what stops the file · its headers carry the warning
   until the assistant has read them */
.cxs[data-beat="0"] .cxs-tbl th, .cxs[data-beat="1"] .cxs-tbl th { color: var(--f4-warn); box-shadow: inset 0 -2px 0 rgb(var(--f4-warn-rgb) / 0.7); }
.cxs[data-beat="2"] .cxs-tbl .is-flag td, .cxs[data-beat="3"] .cxs-tbl .is-flag td { color: var(--f4-warn); background: rgb(var(--f4-warn-rgb) / 0.08); }
.cxs-more { margin-top: var(--space-4); font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-3); }
.cxs-status {
  align-self: flex-start;
  padding: var(--space-4) var(--space-10);
  border-radius: var(--radius-pill);
  border: 1px solid var(--f4-line-dark);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  color: var(--ink-text-2);
}
.cxs-status.is-warn { color: var(--f4-warn); border-color: rgb(var(--f4-warn-rgb) / 0.45); }
.cxs-status.is-good { color: var(--sig-green-lift); border-color: rgb(var(--sig-green-lift-rgb) / 0.5); }
.cxs-route { display: flex; flex-wrap: wrap; gap: var(--space-8); margin-top: auto; padding-top: var(--space-6); }
.cxs-route span {
  display: inline-flex; align-items: center; gap: var(--space-6);
  padding: var(--space-6) var(--space-12);
  border-radius: var(--radius-pill);
  border: 1px dashed var(--f4-line-dark);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  color: var(--ink-text-3);
  transition: color 300ms var(--ease-out), border-color 300ms var(--ease-out), opacity 300ms var(--ease-out);
}
.cxs-route svg { width: 13px; height: 13px; }
.cxs:not([data-beat="0"]) .cxs-ticket { text-decoration: line-through; }
.cxs:not([data-beat="0"]) .cxs-askb { border-style: solid; border-color: rgb(var(--sig-green-lift-rgb) / 0.6); color: var(--sig-green-lift); }
/* the assistant */
.cxs-chat { display: flex; flex-direction: column; gap: var(--space-8); }
.cxs-empty { font-size: var(--fs-sm); color: var(--ink-text-3); }
.cxs-empty.is-off { display: none; }
.cxs [data-from] {
  opacity: 0; transform: translateY(6px); visibility: hidden;
  transition: opacity 380ms var(--ease-out), transform 380ms var(--ease-out), visibility 0s linear 380ms;
}
.cxs [data-from].is-on { opacity: 1; transform: none; visibility: visible; transition-delay: 0s; }
.cxs-msg {
  max-width: 94%;
  padding: var(--space-8) var(--space-10);
  border-radius: var(--radius-sm);
  border: 1px solid var(--f4-line-dark);
  background: rgba(255, 255, 255, 0.04);
  font-size: var(--fs-sm);
  line-height: 1.45;
  color: var(--ink-text-1);
}
.cxs-msg b { display: block; margin-bottom: var(--space-2); font-family: var(--font-mono); font-size: var(--fs-4xs); font-weight: 500; letter-spacing: 0.04em; color: var(--ink-text-3); }
.cxs-msg.is-you { align-self: flex-end; background: rgb(var(--f4-blue-rgb) / 0.16); border-color: rgb(var(--f4-blue-lift-rgb) / 0.3); }
.cxs-msg.is-ai { align-self: flex-start; }   /* its draft look is in the AI marks block at the end */
.cxs-msg.is-flag { align-self: flex-start; border-color: rgb(var(--f4-warn-rgb) / 0.5); background: rgb(var(--f4-warn-rgb) / 0.07); }
.cxs-msg.is-flag b { color: var(--f4-warn); }
.cxs-msg.is-ok { align-self: flex-end; border-color: rgb(var(--sig-green-lift-rgb) / 0.5); color: var(--sig-green-lift); }
.cxs-sys { padding-left: var(--space-8); border-left: 2px solid var(--f4-line-dark); font-family: var(--font-mono); font-size: var(--fs-4xs); line-height: 1.5; color: var(--ink-text-2); }
.cxs-maps, .cxs-opts { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-top: var(--space-6); }
.cxs-maps i, .cxs-opts i {
  font-style: normal;
  padding: var(--space-2) var(--space-8);
  border-radius: var(--radius-pill);
  border: 1px solid var(--f4-line-dark);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  color: var(--ink-text-2);
  transition: color 300ms var(--ease-out), border-color 300ms var(--ease-out), background 300ms var(--ease-out);
}
.cxs-opts i.is-picked { border-color: var(--sig-green-lift); color: var(--sig-green-lift); background: rgb(var(--sig-green-rgb) / 0.12); }
.cxs-dots { display: none; gap: 4px; padding: var(--space-4) 0; }
.cxs-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--ink-text-3); animation: cxsDot 900ms ease-in-out infinite; }
.cxs-dots i:nth-child(2) { animation-delay: 150ms; }
.cxs-dots i:nth-child(3) { animation-delay: 300ms; }
.cxs-msg.is-typing .cxs-dots { display: inline-flex; }
.cxs-msg.is-typing .cxs-txt, .cxs-msg.is-typing .cxs-maps { display: none; }
@keyframes cxsDot { 0%, 100% { opacity: 0.3; transform: none; } 50% { opacity: 1; transform: translateY(-2px); } }
/* your tools */
.cxs-tools { display: grid; gap: var(--space-10); }
.cxs-ct, .cxs-plan { padding: var(--space-10) var(--space-12); border-radius: var(--radius-xs); border: 1px solid var(--f4-line-dark); background: rgba(10, 20, 35, 0.35); }
.cxs-lbl { margin-bottom: var(--space-8); font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-3); }
.cxs-lbl b { font-weight: 500; color: var(--ink-text-1); }
.cxs-bars { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-8); height: 132px; }
.cxs-bar { display: flex; flex-direction: column; justify-content: flex-end; align-items: center; height: 100%; }
.cxs-bar i { margin-bottom: var(--space-4); font-style: normal; font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-2); }
.cxs-col {
  display: block;
  width: 68%;
  height: calc(var(--h, 0) * (100% - 36px));
  border-radius: 3px 3px 0 0;
  background: rgb(var(--ink-text-3-rgb) / 0.35);
  transition: height 900ms var(--ease-out), background 500ms var(--ease-out);
}
.cxs-bar.is-new .cxs-col { background: var(--sig-green-lift); }
.cxs-bar.is-new i { color: var(--ink-text-1); }
.cxs-bar em { margin-top: var(--space-4); font-style: normal; font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-3); }
.cxs-src { margin-top: var(--space-8); font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-3); }
.cxs-src b { font-weight: 500; color: var(--sig-green-lift); }
.cxs-ptbl { width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--ink-text-1); }
.cxs-ptbl th, .cxs-ptbl td { padding: var(--space-4); text-align: right; border-bottom: 1px solid var(--f4-line-dark); }
.cxs-ptbl th:first-child { text-align: left; }
.cxs-ptbl thead th { font-weight: 500; color: var(--ink-text-3); }
.cxs-ptbl tbody th { font-weight: 500; color: var(--ink-text-2); }
.cxs-ptbl td span { display: block; transition: color 400ms var(--ease-out); }
.cxs-ptbl td i { display: block; min-height: 1.3em; font-style: normal; font-size: 0.9em; color: var(--sig-green-lift); }
.cxs-ptbl td.is-up span { color: var(--sig-green-lift); }
.cxs-ptbl td.is-up { animation: cxsFlash 1.4s var(--ease-out) 1; }
@keyframes cxsFlash { from { background: rgb(var(--sig-green-rgb) / 0.3); } to { background: transparent; } }
.cxs-live { padding: var(--space-2) var(--space-8); border-radius: var(--radius-pill); background: rgb(var(--sig-green-rgb) / 0.16); color: var(--sig-green-lift); }
.cxs-cap { margin-top: var(--space-16); min-height: 3em; font-size: var(--fs-base); line-height: var(--lh-ui); color: var(--ink-text-1); }
.cxs-cap b { margin-right: var(--space-8); font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 500; color: var(--sig-green-lift); }
@media (max-width: 1100px) {
  .cxs-stage { grid-template-columns: 1fr 1fr; }
  .cxs-panel[data-cxs-panel="tools"] { grid-column: 1 / -1; }
  .cxs-tools { grid-template-columns: 1fr 1fr; }
}
/* on a phone the rail folds to numbered stops (the caption names the
   beat) and the chat grows as it goes, instead of holding room for
   messages that have not arrived */
@media (max-width: 700px) {
  .cxs-stage, .cxs-tools { grid-template-columns: 1fr; }
  .cxs-rail .scenario-btn { min-width: 40px; padding-inline: var(--space-12); }
  .cxs-rail .scenario-btn b { margin: 0; opacity: 1; }
  .cxs-rail .cxs-bl { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .cxs-chat [data-from]:not(.is-on) { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cxs *, .cxs *::before, .cxs *::after { transition: none !important; animation: none !important; }
}

/* ============================================================
   13 · Forms (contact)
   ============================================================ */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-24); }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }
.field { display: grid; gap: var(--space-8); }
.field.full { grid-column: 1 / -1; }
.field label { font-size: var(--fs-base); font-weight: 600; }
.field .opt { font-weight: 400; color: var(--f4-slate); }
.field input[type="text"], .field input[type="email"], .field select, .field textarea {
  padding: var(--space-14) var(--space-16);
  border: 1.5px solid rgb(var(--f4-ink-rgb) / 0.12);
  border-radius: var(--radius-btn);
  font: inherit;
  font-size: var(--fs-md);
  background: var(--surface);
  color: var(--f4-ink);
  width: 100%;
  box-shadow: 0 1px 2px rgb(var(--f4-ink-rgb) / 0.04);
  transition: border-color 180ms var(--ease-out), box-shadow 220ms var(--ease-out);
}
.field textarea { min-height: 130px; resize: vertical; }

/* The three selects were rendering native OS chrome — a Windows chevron in a
   Windows blue — on the one page that asks a prospect to commit. The glyph is the
   site's own 1.75px line language, inlined because var() does not resolve inside a
   data URI. Under forced colours the native affordance has to come back: with
   appearance:none the UA stops painting the control and a background image is
   dropped, which would leave a select with no visible chevron at all. */
.field select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--space-40);
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="%2354646F" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 5.25 7 8.75l3.5-3.5"/></svg>');
  background-repeat: no-repeat;
  background-position: right var(--space-16) center;
  background-size: 14px 14px;
}
@media (forced-colors: active) {
  .field select { appearance: auto; background-image: none; padding-right: var(--space-16); }
}
/* The ring is the global :focus-visible rule (2px --sig-green-deep, the only green
   that clears 3:1 on paper). This rule only tints the border, so a pointer click
   still gets feedback. What used to be here was `outline: none` plus a 14%-alpha
   bloom standing in for an indicator: weaker than the house ring on the one control
   that most needs it, and a bloom, which DESIGN.md reserves for things that are live. */
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--sig-green-deep);
}
.field .hint { font-size: var(--fs-cap); color: var(--f4-slate); }
.field .error-msg { font-size: var(--fs-cap); color: var(--crit-text); display: none; }
.field.invalid .error-msg { display: block; }
.field.invalid input, .field.invalid select, .field.invalid textarea { border-color: var(--f4-crit); }
.field.invalid .check-grid { outline: 1px solid var(--f4-crit); outline-offset: 6px; border-radius: var(--radius-xs); }

/* the error summary · states the whole picture once, takes focus, links to each field */
.error-summary {
  border: 1px solid var(--f4-crit);
  border-left-width: 3px;
  border-radius: var(--radius-btn);
  background: rgb(var(--f4-crit-rgb) / 0.06);
  padding: var(--space-16) var(--space-20);
  margin-bottom: var(--space-24);
}
.error-summary strong { display: block; color: var(--crit-text); font-size: var(--fs-md); }
.error-summary ul { margin: var(--space-8) 0 0; padding-left: var(--space-20); }
.error-summary li { font-size: var(--fs-md); }
.error-summary a { color: var(--crit-text); }
.error-summary:focus-visible { outline: 2px solid var(--crit-text); outline-offset: 3px; }

/* Without JS the header and footer never mount, so this is the only navigation
   on the page. Styled to look intended rather than like a stylesheet failure. */
.noscript-nav {
  display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-20);
  padding: var(--space-14) var(--gutter);
  background: var(--f4-ink); color: var(--ink-text-1);
  font-size: var(--fs-md);
}
.noscript-nav a { color: var(--ink-text-1); text-decoration: underline; text-underline-offset: 3px; }
.noscript-nav a:last-child { color: var(--sig-green-lift); }

.check-grid { display: flex; flex-wrap: wrap; gap: var(--space-10); }
.check-pill { position: relative; }
.check-pill input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.check-pill span {
  display: inline-block;
  padding: var(--space-8) var(--space-16);
  border-radius: var(--radius-pill);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.12);
  font-size: var(--fs-base);
  color: var(--f4-slate);
  background: var(--surface);
  transition: color 180ms var(--ease-out), background 180ms var(--ease-out), border-color 180ms var(--ease-out);
  cursor: pointer;
}
.check-pill:hover span { border-color: var(--sig-green); color: var(--sig-green-text); }
.check-pill input:checked + span {
  background: var(--f4-ink);
  border-color: var(--f4-ink);
  color: #fff;
  box-shadow: 0 6px 16px -8px rgb(var(--f4-ink-rgb) / 0.5);
}
.check-pill input:focus-visible + span { outline: 2px solid var(--sig-green-deep); outline-offset: 3px; }

.consent-row { display: flex; gap: var(--space-12); align-items: flex-start; font-size: var(--fs-cap); color: var(--f4-slate); }
.consent-row input { margin-top: var(--space-4); width: 17px; height: 17px; accent-color: var(--sig-green); flex: none; }

.form-success {
  border: 1px solid rgb(var(--sig-green-rgb) / 0.35);
  background: linear-gradient(180deg, var(--surface-2), var(--f4-mist));
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-md);
  padding: var(--space-48);
}
.form-success h2 { font-size: var(--fs-panel-title); }
.form-success .prep { margin-top: var(--space-24); display: grid; gap: var(--space-12); }
.form-success .prep li { font-size: var(--fs-md); }

/* ---------- 14 · Sub-page hero ---------- */
.page-hero { padding: calc(var(--header-h) + clamp(3.5rem, 8vh, 6rem)) 0 var(--rhythm-md); }
.page-hero.bg-paper {
  background:
    radial-gradient(900px 480px at 88% -20%, rgb(var(--sig-green-rgb) / 0.07), transparent 60%),
    var(--f4-paper);
}
.page-hero.bg-mist {
  background:
    radial-gradient(900px 480px at 88% -20%, rgb(var(--sig-green-rgb) / 0.12), transparent 60%),
    linear-gradient(180deg, var(--surface-3), var(--f4-mist));
}
.page-hero .kicker { margin-bottom: var(--space-24); }
.page-hero .sub { margin-top: var(--space-24); font-size: var(--fs-2xl); color: var(--f4-slate); max-width: 58ch; }
.page-hero.bg-ink .sub { color: var(--text-on-ink-dim); }
.page-hero .hero-actions { margin-top: var(--space-36); display: flex; gap: var(--space-16); flex-wrap: wrap; }

/* ============================================================
   14b · Critique-pass components
   ============================================================ */

/* S9 · the perishability journey · shares the sj visual system.
   Lighting is class-driven: data-on lists an element's acts, JS
   toggles .lit; the sj act rail and node/link entrances carry over. */
.sj.pj { grid-template-columns: 8fr 4fr; }
.pj-stagewrap, .mj-stagewrap { min-width: 0; }
.pj-stage svg { width: 100%; height: auto; display: block; }
/* the caption bar is shared with the six-moves story (§11) */
.pj-caption, .mj-caption {
  margin: 1rem 0 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-cap);
  letter-spacing: 0.03em;
  color: var(--sig-green-lift);
  min-height: 1.5em;
  transition: opacity 180ms var(--ease-out);
}
.pj-caption.fade, .mj-caption.fade { opacity: 0; }
.pj .pj-zone { opacity: 0.42; transition: opacity 500ms var(--ease-out); }
.pj .pj-zone.lit { opacity: 1; }
.pj .z-wx { opacity: 0.28; }
.pj .z-env { opacity: 0.3; }
.pj .sj-link.lit { stroke-opacity: 0.75; }
.pj-pop { opacity: 0; transform: translateY(5px) scale(0.85); transform-box: fill-box; transform-origin: center; transition: opacity 400ms var(--ease-out), transform 400ms var(--ease-out); }
.pj-pop.lit { opacity: 1; transform: none; }
.pj-rule { fill: none; stroke: var(--f4-blue-lift); stroke-opacity: 0; stroke-width: 1.5; stroke-dasharray: 4 5; transition: stroke-opacity 400ms var(--ease-out); }
.pj-rule.lit { stroke-opacity: 0.7; }
.pj-comet { fill: none; stroke: var(--sig-green-pulse); stroke-width: 2.25; stroke-dasharray: 7 93; stroke-dashoffset: 107; opacity: 0; }
.pj-comet.run { animation: sjComet 1.7s var(--ease-out) forwards; }
.pj-comet.rev.run { animation: sjCometRev 1.7s var(--ease-out) forwards; }
/* the supply graph, redrawn on the 24 Oct review: lots and customers as
   cards, ribbons as wide as the volume they carry, every act's mark a pill
   or a small chart on the exact point it belongs to */
.pj2-head { font-size: 9.5px; letter-spacing: 0.14em; fill: var(--ink-text-3); }
.pj2-hr { stroke: rgba(255, 255, 255, 0.1); stroke-width: 1; }
.pj2-lane { fill: rgb(var(--sig-green-rgb) / 0.11); stroke: rgb(var(--sig-green-rgb) / 0.22); stroke-width: 0.75; transition: fill 500ms var(--ease-out), stroke 500ms var(--ease-out); }
.pj2-lane.lit { fill: rgb(var(--sig-green-rgb) / 0.3); stroke: rgb(var(--sig-green-lift-rgb) / 0.6); }
.pj2-cardbox { fill: rgba(22, 35, 58, 0.94); stroke: rgba(255, 255, 255, 0.14); stroke-width: 1; transition: stroke 400ms var(--ease-out); }
.pj2-cardbox.is-demand { stroke: rgb(var(--sig-green-lift-rgb) / 0.3); }
.pj[data-act="0"] .pj2-card.is-first .pj2-cardbox { stroke: var(--sig-green-lift); }
.pj2-t { font-size: 12px; fill: var(--ink-text-1); }
.pj2-v { font-size: 10px; fill: var(--ink-text-3); }
.pj2-v.is-warn { fill: var(--f4-warn); }
.pj2-life { fill: rgba(255, 255, 255, 0.12); }
.pj2-life-fill { fill: var(--sig-green-lift); }
.pj2-life-fill.is-warn { fill: var(--f4-warn); }
.pj2-cap { font-size: 9px; fill: var(--ink-text-3); letter-spacing: 0.02em; }
.pj2-band { fill: rgb(var(--f4-blue-lift-rgb) / 0.16); }
.pj2-wx { fill: none; stroke: var(--f4-warn); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.pj2-pill { fill: rgba(9, 18, 32, 0.92); stroke: rgb(var(--sig-green-lift-rgb) / 0.55); stroke-width: 1; }
.pj2-pill.is-warn { stroke: rgb(var(--f4-warn-rgb) / 0.6); }
.pj2-pill.is-blue { stroke: rgb(var(--f4-blue-lift-rgb) / 0.55); }
.pj2-pill-t { font-size: 9.5px; fill: var(--sig-green-lift); }
.pj2-pill-t.is-warn { fill: var(--f4-warn); }
.pj2-pill-t.is-blue { fill: var(--f4-blue-pale); }
.pj2-env { fill: rgba(22, 35, 58, 0.94); stroke: var(--f4-blue-lift); stroke-width: 1.4; }
.pj2-env-flap { fill: none; stroke: var(--f4-blue-lift); stroke-width: 1.4; }
.pj2-prod { fill: rgb(var(--sig-green-rgb) / 0.16); stroke: var(--sig-green); stroke-width: 2.25; }
.pj2-prod-halo { fill: none; stroke: rgb(var(--sig-green-lift-rgb) / 0.28); stroke-width: 1; stroke-dasharray: 2 4; }
.pj2-spoke { fill: none; stroke: rgb(var(--sig-green-lift-rgb) / 0.55); stroke-width: 1.25; }
.pj2-bom { fill: rgba(22, 35, 58, 0.94); stroke: var(--sig-green-lift); stroke-width: 1.4; }
.pj2-lift { fill: var(--sig-green-lift); }
@media (prefers-reduced-motion: reduce) {
  .pj2-lane, .pj2-cardbox { transition: none; }
}
@keyframes sjCometRev {
  0% { stroke-dashoffset: -7; opacity: 0; }
  12% { opacity: 0.95; }
  82% { opacity: 0.95; }
  100% { stroke-dashoffset: 107; opacity: 0; }
}
@media (max-width: 899px) {
  .sj.pj { grid-template-columns: 1fr; }
}
@media (max-width: 767px) {
  .pj-stage { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .pj-stage svg { min-width: 640px; }
}

/* persistent graph spine (upgraded minimap) */
/* the spine thread · progress fill + a glowing playhead riding the scroll */
.layer-minimap .mm-track {
  position: absolute;
  left: calc(1.125rem + 7px);
  top: 30px;
  bottom: 30px;
  width: 2px;
  background: rgb(var(--f4-slate-rgb) / 0.3);
  border-radius: var(--radius-pill);
  z-index: -1;
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 600ms var(--ease-out) 100ms;
}
.layer-minimap.show .mm-track { transform: scaleY(1); }
.layer-minimap.on-dark .mm-track { background: rgba(206, 216, 228, 0.22); }
.layer-minimap .mm-track i {
  position: absolute;
  left: 0; top: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(to bottom, rgb(var(--ink-text-3-rgb) / 0.7), rgb(var(--ink-text-3-rgb) / 0.35));
  border-radius: var(--radius-pill);
  transform: scaleY(var(--mmp, 0));
  transform-origin: top;
}
/* a faint spark rides the leading edge of the progress fill · tucks behind
   the station node it settles on, so it never collides with the icon */
.layer-minimap .mm-track .mm-head {
  position: absolute;
  left: 50%;
  top: 0;
  width: 5px; height: 5px;
  margin-left: -2.5px;
  border-radius: 50%;
  background: var(--sig-green-pulse);
  box-shadow: var(--glow-live-ink);
  transform: translateY(var(--mmpx, 0px));
}

/* contact · "what happens next" rail */
.contact-grid { display: grid; grid-template-columns: 7fr 5fr; gap: clamp(2rem, 5vw, 4rem); align-items: start; }
@media (max-width: 1023px) { .contact-grid { grid-template-columns: 1fr; } }
.next-rail { position: sticky; top: 96px; display: grid; gap: var(--space-20); }
@media (max-width: 1023px) { .next-rail { position: static; order: -1; } }
.next-steps { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-18); counter-reset: nstep; }
.next-steps li { display: flex; gap: var(--space-16); align-items: flex-start; counter-increment: nstep; }
.next-steps li::before {
  content: counter(nstep);
  flex: none;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--f4-mist);
  border: 1px solid var(--f4-line);
  color: var(--f4-slate);
  font-family: var(--font-mono);
  font-size: var(--fs-cap-s);
  display: grid;
  place-items: center;
  margin-top: var(--space-2);
}
.next-steps strong { display: block; font-size: var(--fs-md); }
.next-steps span { font-size: var(--fs-base); color: var(--f4-slate); }
.reader-card { display: flex; gap: var(--space-16); align-items: center; }
/* Monogram, not a missing photo.
   A grey circle containing the word "photo" reads as an unfinished page; a set
   initials mark reads as a deliberate choice, and drops out cleanly the day real
   headshots arrive. Not green: a person is not a signal, and the allowlist does
   not cover decorative marks. Not a pill either, so it cannot be mistaken for a
   status chip (PRODUCT.md bans those outright). */
.person-mark {
  width: 72px; height: 72px;
  border-radius: var(--radius-circle);
  background: linear-gradient(180deg, var(--surface-1), var(--surface-3));
  border: 1px solid var(--f4-line);
  display: grid;
  place-items: center;
  margin-bottom: var(--space-16);
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--f4-slate);
}
.person-mark.is-open {            /* the Careers card · an invitation, not a person */
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  border-style: dashed;
  background: none;
}

.reader-card .reader-photo {
  flex: none;
  width: 52px; height: 52px;
  border-radius: 50%;
  background: linear-gradient(180deg, var(--surface-2), var(--surface-4));
  border: 1px solid var(--f4-line);
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  color: var(--f4-slate);
}
.reader-card strong { display: block; font-size: var(--fs-md); }
.reader-card span { font-size: var(--fs-cap); color: var(--f4-slate); }

/* chip groups (constraints, grouped) */
.chip-groups { display: grid; gap: var(--space-20); }
.chip-group { display: flex; gap: var(--space-16); align-items: baseline; flex-wrap: wrap; }
.chip-group .cg-label {
  flex: none;
  min-width: 100px;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--f4-slate);
}

/* nav · current-location signal */
.nav-link[aria-current], .nav-link[data-current] { color: var(--sig-green-text); }
.site-header.is-dark .nav-link[aria-current], .site-header.is-dark .nav-link[data-current] { color: var(--sig-green-lift); }
.nav-link[aria-current]::after, .nav-link[data-current]::after {
  content: "";
  position: absolute;
  left: 0.8125rem; right: 0.8125rem; bottom: 2px;
  height: 2px;
  border-radius: var(--radius-pill);
  background: var(--sig-green);
}
.main-nav .nav-link { position: relative; }
@media (max-width: 1023px) {
  .nav-link[aria-current]::after, .nav-link[data-current]::after { display: none; }
  /* the sheet is always paper, even while the header is still .is-dark over an
     ink hero, so the current item has to take the on-light green. The dark
     token (--sig-green-lift, tuned for ink) lands at 1.76:1 here. */
  .nav-link[aria-current], .nav-link[data-current],
  .site-header.is-dark .nav-link[aria-current],
  .site-header.is-dark .nav-link[data-current] { color: var(--sig-green-text); }
}

/* content-measured, not a ladder step: with six primary items the bar runs out
   of room in the last band before the mobile sheet, so the row tightens its
   own padding rather than letting two labels wrap onto a second line. */
@media (max-width: 1099px) and (min-width: 1024px) {
  .main-nav .nav-link {
    padding-left: var(--space-10);
    padding-right: var(--space-10);
    white-space: nowrap;
  }
}

/* header CTA · short label on tight widths */
.btn .cta-short { display: none; }
/* content-measured, not a ladder step: the width at which the full CTA label stops fitting. */
@media (max-width: 1160px) and (min-width: 1024px) {
  .site-header .btn .cta-long { display: none; }
  .site-header .btn .cta-short { display: inline; }
}
@media (max-width: 1023px) {
  .header-actions .btn { display: inline-flex; }
  .site-header .btn .cta-long { display: none; }
  .site-header .btn .cta-short { display: inline; }
}
/* content-measured, not a ladder step: measured against the header bar's own content. */
@media (max-width: 420px) { .header-actions .login-link { display: none; } }

/* real product screenshots · framed glimpses that lift and catch the light */
.product-shot { margin: 0; }
.product-shot img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-lg);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.06);
}
.product-shot .shot-frame {
  position: relative;
  display: block;
  border-radius: var(--radius-card);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.06);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transition: transform 300ms var(--ease-out), box-shadow 320ms var(--ease-out);
}
.product-shot .shot-frame img { border: none; box-shadow: none; border-radius: 0; }
.product-shot:hover .shot-frame {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
}
.shot-frame::after {
  content: "";
  position: absolute;
  top: -20%; bottom: -20%;
  left: 0; width: 45%;
  background: linear-gradient(105deg, transparent 0%, rgba(255, 255, 255, 0.30) 50%, transparent 100%);
  transform: translateX(-140%) rotate(8deg);
  pointer-events: none;
}
.product-shot:hover .shot-frame::after { animation: sheenSweep 700ms var(--ease-out); }
@keyframes sheenSweep { to { transform: translateX(330%) rotate(8deg); } }
.product-shot figcaption {
  margin-top: var(--space-14);
  font-family: var(--font-mono);
  font-size: var(--fs-kicker);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--f4-slate);
  display: flex;
  align-items: flex-start;
  gap: var(--space-8);
}
.product-shot figcaption::before {
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--f4-slate);
  flex: none;
  margin-top: 0.35em; /* sits on the first line even when the caption wraps */
}
.bg-ink .product-shot figcaption { color: var(--ink-text-2); }

/* ============================================================
   logo carousel · seamless infinite marquee of the real client marks

   The logos ride a slow, continuously scrolling track in FULL BRAND
   COLOUR. The track holds N identical groups; site.js measures one
   group, clones it until the track over-fills the viewport, then sets
   --group-w and --dur. The keyframe translates by exactly one group
   width, so the loop is seamless (group 2 lands where group 1 began).
   Speed is a constant px/s, so wide and narrow screens scroll at the
   same pace. Edge fade masks keep marks from hard-clipping at the rim.

   Progressive enhancement: with no JS (or under reduced motion) the
   track is simply a wrapping wall of the same colour logos — the group
   is display:contents so its children wrap directly. site.js only adds
   .is-live when motion is allowed.

   Colour knockouts (BerryWorld script, Tangmere cross+pepper) are baked
   to --f4-paper, so the carousel must sit on a bg-paper section.
   ============================================================ */

/* fallback / reduced-motion state: a plain wrapping wall */
.logo-marquee { padding-block: var(--space-8); }
.logo-marquee__track {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-28) var(--space-56);
}
.logo-marquee__group { display: contents; }

.logo-marquee .client-logo {
  display: inline-flex;
  align-items: center;
  line-height: 0;
  flex: none;
  transform: scale(1);
  transition: transform 380ms var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
.logo-marquee .client-logo img {
  display: block;
  width: auto;
  height: var(--logo-h, 1.9rem);
  -webkit-user-drag: none;
  user-select: none;
}

/* per-brand optical sizing — equalise perceived weight, not raw box height.
   Stacked lockups (Angus, La Linea Verde) and tagline lockups (Jingold) need a
   taller box for their WORDMARK to match a plain wordmark beside it. */
.logo-marquee .cl-driscolls    img { --logo-h: 2.20rem; }
.logo-marquee .cl-angus        img { --logo-h: 3.20rem; }
.logo-marquee .cl-berryworld   img { --logo-h: 3.41rem; }
.logo-marquee .cl-tangmere     img { --logo-h: 1.98rem; }
.logo-marquee .cl-spreafico    img { --logo-h: 1.71rem; }
.logo-marquee .cl-lalineaverde img { --logo-h: 3.30rem; }
.logo-marquee .cl-jingold      img { --logo-h: 2.48rem; }

/* live state · JS has cloned the groups and set --group-w / --dur */
.logo-marquee.is-live {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
}
.logo-marquee.is-live .logo-marquee__track {
  flex-wrap: nowrap;
  width: max-content;
  gap: 0;
  animation: f4LogoMarquee var(--dur, 32s) linear infinite;
}
.logo-marquee.is-live .logo-marquee__group {
  display: flex;
  align-items: center;
  gap: var(--logo-gap, var(--space-56));
  padding-right: var(--logo-gap, var(--space-56));
}

/* translate by exactly one group so the seam is invisible */
@keyframes f4LogoMarquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-1 * var(--group-w, 50%)), 0, 0); }
}

/* pointer only · rest the carousel and lean a mark in when you reach for it */
@media (hover: hover) {
  .logo-marquee.is-live:hover .logo-marquee__track { animation-play-state: paused; }
  .logo-marquee .client-logo:hover { transform: scale(1.14); }
}

@media (max-width: 640px) {
  .logo-marquee { --logo-gap: 2.48rem; }
  .logo-marquee__track { gap: var(--space-24) var(--space-40); }
  .logo-marquee .client-logo img { height: calc(var(--logo-h, 1.9rem) * 0.86); }
}

/* reduced motion: no travel at all — the same marks, static and full colour */
@media (prefers-reduced-motion: reduce) {
  .logo-marquee {
    overflow: visible;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .logo-marquee .logo-marquee__track {
    animation: none !important;
    flex-wrap: wrap;
    width: auto;
    gap: var(--space-28) var(--space-56);
  }
  .logo-marquee .logo-marquee__group { display: contents; }
  .logo-marquee .client-logo { transition: none !important; }
  .logo-marquee .client-logo:hover { transform: none !important; }
}

/* ============================================================
   15 · Motion enrichment · choreography, draw-ins, particles
   ============================================================ */

/* page-load choreography · hero copy arrives in sequence */
@keyframes heroIn { from { opacity: 0; transform: translateY(18px); } }
.hero-copy .kicker   { animation: heroIn 700ms var(--ease-out) 60ms backwards; }
.hero-copy h1        { animation: heroIn 850ms var(--ease-out) 150ms backwards; }
.hero-copy .hero-sub { animation: heroIn 850ms var(--ease-out) 280ms backwards; }
.hero-copy .hero-ctas{ animation: heroIn 850ms var(--ease-out) 410ms backwards; }
.hero-visual         { animation: heroIn 1100ms var(--ease-out) 520ms backwards; }
/* rack-focus load-in · the map pulls into focus once, like an expensive lens */
.node-field          { animation: nfFocus 1100ms var(--ease-out) 380ms backwards; }
@keyframes nfFocus { from { opacity: 0; filter: blur(12px); } }
.page-hero .kicker       { animation: heroIn 700ms var(--ease-out) 60ms backwards; }
.page-hero h1            { animation: heroIn 850ms var(--ease-out) 150ms backwards; }
.page-hero .sub          { animation: heroIn 850ms var(--ease-out) 270ms backwards; }
.page-hero .hero-actions { animation: heroIn 850ms var(--ease-out) 390ms backwards; }

/* chain lanes · routes re-drawn per frame by the field engine, in the language
   of a road map: ramp, level run, ramp, filleted corners, and a road hierarchy
   (trunk · feeder · ferry · track) carried by weight rather than by colour */
.nf-links {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: calc((1 - var(--cv, 0)) * (1 - var(--cv, 0)));
  animation: nfBootFade 900ms var(--ease-out) 1350ms backwards;
}
/* the held breath · while the catch is seen, everything but the drama recedes */
.node-field.held .nf-link.fut:not(.surge):not(.reroute) { stroke-opacity: 0.1; }
.node-field.held .nf-link.past { stroke-opacity: 0.05; }
.node-field.held .nf-link.lead { stroke-opacity: 0.05; }
.node-field.held .nf-link.imp:not(.surge) { stroke-opacity: 0.16; }
.nf-link {
  fill: none;
  stroke: var(--sig-green);
  stroke-width: 1.25px;
  /* a road turns, it does not kink · the fillets are geometry, these are the
     joints and ends that stop a 4-point route reading as folded wire */
  stroke-linejoin: round;
  stroke-linecap: round;
  transition: stroke 300ms var(--ease-out), stroke-opacity 300ms var(--ease-out);
}
/* the road hierarchy · one glance should say which way the volume goes */
.nf-link.trunk  { stroke-width: 1.9px; }
.nf-link.feeder { stroke-width: 1.15px; }
.nf-link.track  { stroke-width: 1px; }

/* Casings · a dark bed under the stroke, the whole layer drawn beneath every
   lane so a road crossing a road resolves. Only SETTLED lanes carry one: a
   projection is a planned road and a map draws those bare, so the bed fading in
   as NOW sweeps past is the forecast turning into built ground. */
.nf-casings path {
  fill: none;
  stroke: rgb(6 13 26 / 0.9);
  stroke-linejoin: round;
  stroke-linecap: round;
  /* Wide and weak, NOT narrow and strong. A bed that sits close to the stroke
     reads as a second line drawn beside the first — the "double line" problem —
     so it is carried well clear of the road and kept faint enough to be ground
     rather than ink. A planned road gets less of it than a built one. */
  stroke-opacity: 0.3;
  transition: stroke-opacity 500ms var(--ease-out);
}
.nf-casings path.past   { stroke-opacity: 0.32; }
.nf-casings path.trunk  { stroke-width: 6px; }
.nf-casings path.feeder { stroke-width: 4.5px; }
.node-field.held .nf-casings path { stroke-opacity: 0.18; }

/* The settled side sits under the headline and must stay ground, not figure.
   It was lifted to 0.22 when the casing was narrow and strong and a 0.12 stroke
   on a hard bed read as black wire; with a wide, weak bed it can go back to a
   whisper — and curves cover far more of the copy than the old chords did, so
   it has to. */
.nf-link.past { stroke-opacity: 0.14; }
/* longer dash, same gap · calmer at a distance, and with the arcs now shallow
   the projected side can afford a touch more presence */
.nf-link.fut  { stroke-opacity: 0.32; stroke-dasharray: 7 4.5; }
.nf-link.imp  {
  stroke: var(--f4-blue);
  stroke-opacity: 0.38;
  stroke-width: 1.5px;
  stroke-dasharray: 5 7;
}
/* chip wiring · every signal chip is PLUGGED INTO the grid, not annotated
   from beside it. The wire is a solid hairline (dots read as decoration, a
   line reads as a connection), it lands in a port dot on the chain mark, and
   a slow pip runs chip → chain: the signal being fed in. Cool-white, blue
   for the blue instruments · signals are information, so never green. */
.nf-link.lead {
  stroke: rgba(226, 234, 242, 0.8);
  stroke-opacity: 0.22;
  stroke-width: 1px;
  stroke-linecap: round;
}
.nf-port { fill: rgba(226, 234, 242, 0.42); }
.nf-sigpip {
  fill: none;
  stroke: rgba(226, 234, 242, 0.9);
  stroke-width: 1.5px;
  stroke-linecap: round;
  stroke-dasharray: 4 96;
  stroke-dashoffset: 100;
  opacity: 0;
  animation: nfSigPip 4.6s linear infinite;
}
.nf-sigpip.blue { stroke: var(--f4-blue-lift); }
/* offset 100 parks the pip at the chip, 0 lands it in the port · the fade
   keeps arrivals and departures from popping */
@keyframes nfSigPip {
  0%   { stroke-dashoffset: 100; opacity: 0; }
  12%  { opacity: 0.55; }
  62%  { opacity: 0.55; }
  74%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
/* the held breath stills the instruments with the rest of the field */
.node-field.held .nf-sigpip { animation-play-state: paused; }
.node-field.held .nf-port { fill: rgba(226, 234, 242, 0.15); }
/* trouble on the lane · amber, and only ever between the strike and the catch */
.nf-link.surge { stroke: var(--f4-warn); stroke-opacity: 0.75; }
/* the decision · a green alternative draws itself while the lane is amber */
.nf-link.reroute {
  stroke: var(--sig-green-lift);
  stroke-width: 1.75px;
  stroke-opacity: 0;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-opacity 400ms var(--ease-out);
}
.nf-link.reroute.draw {
  stroke-opacity: 0.75;
  /* pen intent · slow start, confident finish, like a decision being inked */
  animation: nfDraw 700ms cubic-bezier(0.65, 0, 0.25, 1) forwards;
}
@keyframes nfDraw { to { stroke-dashoffset: 0; } }

/* the travelling packet of trouble · freezes mid-link the moment it is seen */
.nf-pulse {
  fill: none;
  stroke: var(--warn-ink);
  stroke-width: 2px;
  stroke-dasharray: 14 86;
  stroke-dashoffset: 100;
  opacity: 0;
  transition: opacity 250ms var(--ease-out);
}
/* 1200ms travel: the detect beat (≥850ms after the last hop departs) genuinely
   pauses it mid-link; ending at offset 14 (not 0 ≡ one full 100-period lap)
   parks the dash at the far end of the link instead of wrapping to the start */
.nf-pulse.run { opacity: 1; animation: nfPulseRun 1200ms linear forwards; }
.nf-pulse.rev { animation-direction: reverse; }
.nf-pulse.freeze { animation-play-state: paused; }
@keyframes nfPulseRun { to { stroke-dashoffset: 14; } }

/* produce flow · hollow product particles on projected lanes, settled dots on
   actuals; the cutline appears after the packhouse (whole in, sliced out) */
.nf-part { fill: none; stroke: var(--sig-green); stroke-width: 1.25px; }
.nf-part.past { fill: var(--sig-green); stroke: none; }
.nf-part.blue { stroke: var(--f4-blue-lift); }
.nf-part .cutline { opacity: 0; transition: opacity 250ms var(--ease-out); }
.nf-part.cut .cutline { opacity: 1; }
/* pallet units · square logistics glyphs, slower than produce */
.nf-part.nf-pallet { fill: rgba(22, 35, 58, 0.9); stroke: rgba(255, 255, 255, 0.55); stroke-width: 1px; }
/* promo surge · extra demand rushing upstream during scenario B */
.nf-part.burst { stroke: var(--sig-green-lift); stroke-width: 1.5px; }

/* cartographic texture · faint field-row hairlines, lower left */
.nf-hair path { fill: none; stroke: rgba(255, 255, 255, 0.05); stroke-width: 1px; }

/* radar ping · chips broadcast every few seconds */
.f-chip::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  border: 1px solid currentColor;
  opacity: 0;
  animation: chipPing 6.5s ease-out infinite;
  animation-delay: calc(var(--dd, 0s) * 1.6);
}
@keyframes chipPing {
  0%   { transform: scale(1); opacity: 0.5; }
  22%  { transform: scale(2); opacity: 0; }
  100% { transform: scale(2); opacity: 0; }
}

/* typewriter caret on the hero kicker */
.type-caret {
  display: inline-block;
  width: 0.55ch;
  height: 1em;
  margin-left: var(--space-2);
  vertical-align: -0.15em;
  background: currentColor;
  animation: caretBlink 0.85s steps(2, start) infinite;
}
@keyframes caretBlink { 50% { opacity: 0; } }

/* editorial accent inside the display headline */
.display-xl em {
  font-style: italic;
  font-weight: 500;
  letter-spacing: -0.01em;
}
/* per-line stroke-opacity comes from the mesh builder (depth-weighted) */

/* node-graph · nodes pop in with their beat */
.f4graph .nd {
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(0.4);
  transition: transform 700ms var(--ease-out);
}
.f4graph[data-beat="1"] .gb.b1 .nd,
.f4graph[data-beat="2"] .gb.b2 .nd,
.f4graph[data-beat="3"] .gb.b3 .nd,
.f4graph[data-beat="4"] .gb.b4 .nd,
.f4graph[data-beat="5"] .gb.b5 .nd,
.f4graph[data-beat="6"] .gb.b6 .nd { transform: scale(1); }
.f4graph .d0 .nd { transition-delay: 80ms; }
.f4graph.static .nd { transform: none; transition: none; }

/* demo charts · bars grow, links draw, waterfall settles */
@keyframes barIn { from { opacity: 0; transform: scaleY(0.25); } }
.demo-chart .bar {
  transform-box: fill-box;
  transform-origin: bottom;
  animation: barIn 550ms var(--ease-out) backwards;
}
@keyframes wfIn { from { opacity: 0; transform: translateY(10px); } }
.waterfall svg rect { transform-box: fill-box; animation: wfIn 480ms var(--ease-out) backwards; }
[data-noanim] .waterfall svg rect { animation: none; }
@keyframes linkDraw { from { stroke-dashoffset: 100; } }
.alloc-stage svg path {
  stroke-dasharray: 100;
  stroke-dashoffset: 0;
}
/* the links draw in when the model runs · a hand edit redraws without it */
.alloc-stage svg.is-draw path { animation: linkDraw 800ms var(--ease-out) backwards; }

/* sparklines draw themselves on reveal */
.spark { stroke-dasharray: 100; }
.reveal.in .spark, .reveal-group.in .spark { animation: sparkDraw 1300ms var(--ease-out) 250ms backwards; }
@keyframes sparkDraw { from { stroke-dashoffset: 100; } }

/* the bullwhip · injected per run by sequences.js, grows away from origin */
.whip-layer {
  position: absolute;
  inset: 0; /* rides the wiring · same coordinate box as .chain, behind the nodes */
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}
.whip-layer svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* the traced whip stays behind after the energy passes */
.whip-trace {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: whipDraw linear forwards; /* duration set inline per run */
}
@keyframes whipDraw { to { stroke-dashoffset: 0; } }
/* the travelling energy window */
.whip-wave {
  stroke-dasharray: 16 84;
  stroke-dashoffset: 16;
  animation: whipWindow linear forwards;
}
@keyframes whipWindow { from { stroke-dashoffset: 16; } to { stroke-dashoffset: -100; } }
/* the comet head rides the same path, gathering size and heat */
.whip-head {
  position: absolute;
  top: 0; left: 0;
  width: 11px; height: 11px;
  border-radius: 50%;
  offset-rotate: 0deg;
  animation-name: whipHead, whipHeadOut;
  animation-timing-function: linear, ease-out;
  animation-fill-mode: forwards, forwards;
}
@keyframes whipHead {
  from {
    offset-distance: 0%;
    transform: scale(0.5);
    background: #5B6B7B;
    box-shadow: 0 0 8px 1px rgba(91, 107, 123, 0.5);
  }
  45% {
    background: var(--f4-warn);
    box-shadow: 0 0 12px 3px rgb(var(--f4-warn-rgb) / 0.65);
  }
  to {
    offset-distance: 100%;
    transform: scale(1.5);
    background: var(--f4-crit);
    box-shadow: 0 0 20px 6px rgb(var(--f4-crit-rgb) / 0.7);
  }
}
@keyframes whipHeadOut { to { opacity: 0; transform: scale(2.2); } }

/* ============================================================
   16 · Ambient fields, page-hero life, card variants
   ============================================================ */

/* ---- sub-page hero chain (site.js initHeroField) ----
   A quiet reduction of the home hero's live chain: supply flows top-to-bottom
   through tiers, lanes converge into a packhouse gate and fan out again, and a
   few nodes carry the goods as ringed produce medallions. --hero-safe ghosts
   the whole field behind the copy column so it never fights the headline. */
.page-hero { position: relative; }
.page-hero.bg-ink.node-texture > .container { position: relative; z-index: 1; }

/* ---- the quiet host · a sub-page hero running one variant engine ----
   Four routes trade the ambient chain for the real instrument, because on
   those four the drawing IS the page's argument: use-cases catches three
   problems before they land, allocation reroutes a load, S&OP resolves a plan
   against the calendar, and who-it's-for turns a world of regions and lead
   times. Everything the home hero wraps around these engines
   is gone — no deck, no HUD, no pin, no switcher — so the page reads as a page
   and the instrument behaves like the art it now is.

   The engine draws into .node-field exactly as it does on the home hero; the
   only differences are geometry (a hero this size needs a floor under it, or
   the scene is a letterbox) and the fact that --cv never leaves 0, so the
   scroll-dissolve every variant carries simply stays at full strength. */
.page-hero[data-hero-instrument] {
  overflow: hidden;
  /* room for an instrument composed on a 100vh canvas · below this the scene
     crops to a band and stops reading as a drawing of anything */
  min-height: clamp(560px, 74vh, 760px);
  display: flex;
  align-items: center;
  padding-top: calc(var(--header-h) + clamp(2.5rem, 5vh, 4rem));
}
.page-hero[data-hero-instrument] > .container { width: 100%; }
/* the copy column keeps the hero's own reading width · the instrument owns the
   open right, the same division the ambient chain uses */
.page-hero[data-hero-instrument] .sub { max-width: 44ch; }
.page-hero[data-hero-instrument] h1 { max-width: 20ch; }
.page-hero[data-hero-instrument] .node-field {
  /* the home field rides the pin's scroll (--p * 52px); here there is no pin */
  transform: none;
}
/* the readability scrim is tuned for a 100vh pin · on a shorter hero it wants
   to sit higher and tighter, or it washes the instrument instead of the copy */
.page-hero[data-hero-instrument] .node-field::after {
  background: radial-gradient(620px 460px at 24% 50%, rgba(9, 18, 32, 0.66), transparent 68%);
}

/* ---- reframing · every engine was composed for a pinned 100vh canvas ----
   A sub-page hero is about half that height and twice as wide in proportion,
   and each scene's svg covers rather than fits, so left alone they crop through
   their own subject: the routing board loses its grower row off the top, the
   world loses its crown. The fix is per lens and purely geometric — pull the
   scene back until the whole composition is inside the shorter canvas, then
   push it into the open right that the copy is not using. Nothing about the
   engines changes; they do not know they have been reframed.

   Three rules about WHERE the reframe may be applied, each learned the hard way:
   the plane and camera elements carry per-frame inline transforms from the
   engines, so CSS must stay off them; an engine whose svg has an html overlay
   pinned to it must move both by the same ABSOLUTE amount, since the two boxes
   have different widths and a percentage would slide them apart; and an element
   that already carries a transform must be reframed by geometry, not by a
   transform that would silently replace it. */

/* field · the one lens with nothing to push. Every other engine draws a scene
   inside its box and can be translated within it; the Live chain IS its box —
   the week ruler rides the top edge, the zone captions the bottom, and NOW is
   a percentage of the width — so the only honest reframe is to hand it a
   shorter box and let the whole composition re-lay itself into it. The top
   inset clears the fixed header (on the home hero the nav floats over 100vh of
   empty sky above the ruler; here the ruler starts at the very top edge and
   ran straight under the bar), and the bottom inset keeps the "actuals ·
   settled / forecast · 4-week horizon" captions off the section seam. */
.page-hero[data-hero-instrument] .node-field[data-hero-variant="field"] {
  inset: calc(var(--header-h) + 14px) 0 20px;
}
/* the scrim follows the field down, and tightens: this hero's copy block is
   shorter than the home hero's deck-and-rail column, so the 620x460 pool the
   generic rule paints washes the forecast side it does not need to protect */
.page-hero[data-hero-instrument] .node-field[data-hero-variant="field"]::after {
  background: radial-gradient(540px 400px at calc(var(--nf-pad, 0px) + 250px) 46%, rgba(9, 18, 32, 0.72), transparent 70%);
}

/* routing · one svg board, and a readout placed independently below.
   The host refits this board to "meet" first (site.js), so it is one drawing of
   a fixed size whatever the window is doing and it is centred in the field; all
   this rule has to do is place it. The offset is therefore in px, not per cent:
   with a constant-size board a constant offset from centre gives a right margin
   that GROWS with the window, where a percentage would have crowded the narrow
   end and stranded the wide one. The downward push clears the fixed nav, and
   the enlarged board fills the open right while still leaving the bottom
   corner to the readout card, which must not be sat on. */
.page-hero[data-hero-instrument] .rt-map {
  transform: translate(112px, 62px) scale(1.24);
}

/* space · the scene svg and its chip overlay are two boxes sharing one centre.
   The same absolute translate and scale keeps every cause chip on its station. */
.page-hero[data-hero-instrument] .sp-scene,
.page-hero[data-hero-instrument] .sp-mid {
  transform: translate(132px, 26px) scale(0.76);
}
/* the space readout goes entirely. On the home hero it is the lens's own
   status corner; here it would sit in the fixed nav, and the quiet host's
   whole premise is that the instrument narrates through one caption line and
   otherwise says nothing. Dropping it also takes the last counter styled like
   telemetry off a page a buyer actually lands on. */
.page-hero[data-hero-instrument] .sp-hud { display: none; }

/* movement · the dial and its two overlays are one square box by construction,
   and that box already carries the bench-tilt. Resize the box; never transform
   it, or the instrument lies flat and leaves the hero. */
.page-hero[data-hero-instrument] .mv-dial,
.page-hero[data-hero-instrument] .mv-mid,
.page-hero[data-hero-instrument] .mv-top {
  left: 71%;
  height: 90%;
  width: auto;
  aspect-ratio: 1;
}
/* the routing readout is placed for a tall hero, where 46%/13% is the open
   middle. Here that lands under the headline and reads as part of the copy, so
   it goes to the bottom of the open right where it belongs to the board. */
.page-hero[data-hero-instrument] .rt-readout {
  left: auto;
  right: 3.5%;
  bottom: 2.5%;
  width: min(342px, 28vw);
}

/* the kiosk is 100vh, so the refitted board fills it without help · the
   sub-page reframe would shrink it into the corner of a stand screen */
.page-hero.kiosk[data-hero-instrument] .rt-map { transform: none; }

/* ---- the kiosk · the same host, given a room instead of a reader ----
   kiosk.html reuses the quiet host wholesale, and changes only the two things a
   stand screen actually changes: it fills the viewport, and the copy is the
   brand line rather than a page's argument. It deliberately does NOT recentre
   the scene. Every engine is composed with its subject right of a copy column —
   the world's centre, the board's origin and the dial's spindle all sit there —
   so centring them puts the headline through the middle of the instrument. The
   division that works on a page is the division that works on a screen. */
.page-hero.kiosk[data-hero-instrument] {
  min-height: 100vh;
  min-height: 100svh;
  padding-top: 0;
}
/* a booth screen is watched, not scrolled */
body.is-kiosk { overflow: hidden; }
/* the corner readout comes back · with no nav to collide with, it is the one
   place the lens's own status line belongs, and it now names the story it is
   counting rather than implying live telemetry */
.page-hero.kiosk[data-hero-instrument] .sp-hud { display: flex; }

/* the one line the instrument says · the engine's own act narration */
.hi-caption {
  margin: var(--space-28) 0 0;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: 0.04em;
  color: var(--text-on-ink-dim);
  min-height: 1.4em;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 420ms var(--ease-out), transform 420ms var(--ease-out);
}
.hi-caption.show { opacity: 1; transform: none; }
@media (max-width: 1023px), (prefers-reduced-motion: reduce) {
  /* no engine is built below the breakpoint · drop the floor with it, so the
     hero collapses back to an ordinary page hero rather than 560px of empty ink */
  .page-hero[data-hero-instrument] {
    min-height: 0;
    display: block;
    padding-top: calc(var(--header-h) + clamp(3.5rem, 8vh, 6rem));
  }
  .page-hero[data-hero-instrument] h1,
  .page-hero[data-hero-instrument] .sub { max-width: none; }
  .hi-caption { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hi-caption { transition: none !important; }
}
.hero-field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  /* the instrument lives in the open right, so the mask clears the copy column
     outright and fades the panel in at its own left edge */
  --field-safe: linear-gradient(to right, rgba(0,0,0,0) 0, rgba(0,0,0,0) 44%, #000 58%);
  -webkit-mask-image: var(--field-safe);
          mask-image: var(--field-safe);
}
.hero-field .hf-plane { position: absolute; inset: 0; animation: hfPan 64s ease-in-out infinite alternate; }
@keyframes hfPan { to { transform: translate3d(26px, 16px, 0); } }
.hero-field svg { position: absolute; inset: 0; width: 100%; height: 100%; }

/* lanes · sagged quadratics. Solid behind the now mark, dashed ahead of it;
   the faint ones are the cross-shipments that turn strands into a fabric. */
.hf-lane {
  fill: none;
  stroke: var(--sig-green);
  /* the home field runs its lanes at .12/.2 — anything heavier stops being
     texture behind the headline and starts competing with it */
  stroke-opacity: 0.20;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.hf-lane.fut { stroke-dasharray: 5 4; stroke-opacity: 0.15; }
.hf-lane.faint { stroke-opacity: 0.10; }
.hf-lane.faint.fut { stroke-opacity: 0.08; }
.hf-pulse {
  fill: none;
  stroke: var(--sig-green-pulse);
  stroke-opacity: 0.85;
  stroke-width: 1.6;
  stroke-dasharray: 4 96;
  stroke-dashoffset: 100;
  vector-effect: non-scaling-stroke;
  animation: linePulse 5.2s linear infinite;
}
/* Restored. This keyframes block was collateral damage in 73e4b2920, which
   rewrote the HOME hero's pulse (.nf-pulse → nfPulseRun) and deleted the shared
   `linePulse` it no longer needed — while .hf-pulse, added afterwards, still
   named it. The result was silent: animation-name computed to `linePulse`,
   getAnimations() returned 0, and with `4 96` on pathLength 100 an offset of
   100 is one whole period ≡ 0, so "the only live green in the field" sat frozen
   as a 4%-long tick at each lane's origin on all 14 ambient-chain pages.
   Decreasing the offset walks the dash forward: 100 → 0 is exactly one traverse. */
@keyframes linePulse { to { stroke-dashoffset: 0; } }

/* the tier rule each row is registered to · the panel's structural hairline */
.hf-tierrule { stroke: rgb(var(--ink-text-3-rgb) / 0.07); stroke-width: 1; vector-effect: non-scaling-stroke; }

/* product particles · hollow goods riding the lanes */
.hf-part {
  fill: none;
  stroke: var(--sig-green-lift);
  stroke-opacity: 0.28;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* the week ruler · height/offset are set inline so it spans the panel, not the
   whole hero. Hung off .hero-field, so it never drifts with the parallax. */
.hf-wk { position: absolute; width: 1px; background: rgb(var(--ink-text-3-rgb) / 0.09); }
.hf-tick { position: absolute; width: 1px; height: 7px; background: rgb(var(--ink-text-3-rgb) / 0.22); }

/* ghost echoes · this node, a week on */
.hf-ghost { position: absolute; border-radius: 50%; border: 1px solid rgb(var(--ink-text-3-rgb) / 0.12); }

/* tier nodes · the home field's per-tier shapes, quieted */
.hf-node {
  position: absolute;
  background: var(--ink-700);
  border: 1px solid rgba(255, 255, 255, 0.30);
  opacity: 0.6;
}
.hf-node.g { width: 6px; height: 6px; margin: -3px 0 0 -3px; border-radius: 50%; }
.hf-node.p { width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: var(--radius-xs); }
.hf-node.d { width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: var(--radius-xs); border-color: rgba(127, 184, 242, 0.5); }
.hf-node.r { width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%; border-color: rgb(var(--sig-green-lift-rgb) / 0.5); }

/* produce medallions · the goods, in the .f-chip jewel treatment. Most rest in
   the cool-white ladder (merchandise is not a signal); exactly one per hero is
   the live green mark, so the green still means something. */
.hf-med {
  position: absolute;
  width: 44px; height: 44px;
  margin: -22px 0 0 -22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--ink-text-2);
  /* ink base under the tint so lanes do not read through the glyph */
  background: linear-gradient(180deg, rgb(var(--ink-text-3-rgb) / 0.10), rgb(var(--ink-text-3-rgb) / 0.02)),
              rgb(var(--f4-ink-rgb) / 0.55);
  border: 1px solid rgb(var(--ink-text-3-rgb) / 0.30);
  /* the first shadow is a knockout ring: lanes break in a clean annulus around
     the medallion instead of running under it (the drawing-callout convention) */
  box-shadow: 0 0 0 5px rgb(var(--f4-ink-rgb) / 0.55),
              var(--specular-ink-2),
              0 10px 22px -12px rgba(0, 0, 0, 0.7);
  animation: hfBreath var(--dur, 14s) ease-in-out var(--delay, 0s) infinite alternate;
}
.hf-med.live {
  color: var(--sig-green-lift);
  background: linear-gradient(180deg, rgb(var(--sig-green-lift-rgb) / 0.14), rgb(var(--sig-green-lift-rgb) / 0.03)),
              rgb(var(--f4-ink-rgb) / 0.55);
  border-color: rgb(var(--sig-green-lift-rgb) / 0.34);
  box-shadow: 0 0 0 5px rgb(var(--f4-ink-rgb) / 0.55),
              var(--specular-ink-2),
              0 0 22px -6px rgb(var(--sig-green-rgb) / 0.45),
              0 10px 22px -12px rgba(0, 0, 0, 0.7);
}
/* beats the `.hero-field svg { position:absolute; inset:0; width:100% }` rule above */
.hero-field .hf-med svg {
  position: static;
  inset: auto;
  width: 22px; height: 22px;
  display: block;
}
@keyframes hfBreath {
  from { opacity: calc(var(--o, 0.62) * 0.82); }
  to   { opacity: var(--o, 0.62); }
}

/* ---- Plan hero instrument · the planning runway ----
   The page's argument is one plan across four horizons, so the instrument draws
   exactly that and nothing else: a single budget line enters at the left and
   passes three gates, splitting 1 → 3 → 6 → 12 as it goes. Two rules make it
   read as ONE signal resolving rather than four separate tools. The fan is
   bounded and decelerating (±0 → ±30 → ±45 → ±55), so the envelope settles
   instead of running away; and the stroke thins at every split, so the total
   ink stays about constant — what grows is detail, not magnitude. The grain
   ruler underneath states it in the horizon's own period (year · season · week
   · day), which is the claim made measurable rather than asserted.
   Hand-authored geometry, CSS-only life, no JS — the .ctower archetype. It
   replaced the consensus gate, which drew approval (one moment) where the page
   needed continuity (four horizons); the collaboration argument it carried is
   already made by the Collaboration card and the connected-planning demo. */
.planway { width: 100%; max-width: 560px; }
.planway svg { display: block; width: 100%; height: auto; overflow: visible; }

/* the plan grid · one hairline per period the horizon actually holds (3 · 12 ·
   36). The wash that thickens toward execution is therefore the extra detail
   itself, not a gradient painted on to suggest it. */
.pr-cell { stroke-width: 1; vector-effect: non-scaling-stroke; }
.pr-c1 { stroke: rgb(var(--ink-text-3-rgb) / 0.13); }
.pr-c2 { stroke: rgb(var(--ink-text-3-rgb) / 0.09); }
.pr-c3 { stroke: rgb(var(--ink-text-3-rgb) / 0.055); }

/* the lanes · the ambient chain's own register, so the instrument reads as
   that fabric seen at higher magnification. Weight thins per split. */
.pr-lanes path {
  fill: none;
  stroke: var(--sig-green);
  stroke-opacity: 0.30;
  vector-effect: non-scaling-stroke;
}
.pr-s0 { stroke-width: 2.6; stroke-opacity: 0.40; }
.pr-s1 { stroke-width: 1.9; stroke-opacity: 0.34; }
.pr-s2 { stroke-width: 1.4; }
.pr-s3 { stroke-width: 1; stroke-opacity: 0.26; }

/* the gate rules · each one is the height of the fan it opens, so the frame
   visibly widens down the runway (.hf-tierrule's weight) */
.pr-rule {
  stroke: rgb(var(--ink-text-3-rgb) / 0.30);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* the travelling signal · pathLength normalises every lane to 100 units, so a
   stage's dash crosses all of its lanes together however long each really is */
.pr-p {
  fill: none;
  stroke: var(--sig-green-pulse);
  stroke-opacity: 0.9;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-dasharray: 5 195;
  stroke-dashoffset: 5;          /* parked just before the origin · hidden */
  vector-effect: non-scaling-stroke;
  animation: prRun0 14s linear infinite;
}
.pr-p1 { animation-name: prRun1; }
.pr-p2 { animation-name: prRun2; }
.pr-p3 { animation-name: prRun3; }

/* The 0-3% lead-in is load-bearing, not decorative: scripts/qa.mjs screenshots
   with animations still running ~150ms after load and diffs at 0.2%, so the
   panel has to be dead still at t=0 for the visual baseline to hold. */
@keyframes prRun0 {
  0%, 3%       { stroke-dashoffset: 5; }
  15%          { stroke-dashoffset: -100; }
  15.01%, 100% { stroke-dashoffset: 5; }
}
@keyframes prRun1 {
  0%, 16%      { stroke-dashoffset: 5; }
  29%          { stroke-dashoffset: -100; }
  29.01%, 100% { stroke-dashoffset: 5; }
}
@keyframes prRun2 {
  0%, 30%      { stroke-dashoffset: 5; }
  45%          { stroke-dashoffset: -100; }
  45.01%, 100% { stroke-dashoffset: 5; }
}
@keyframes prRun3 {
  0%, 46%      { stroke-dashoffset: 5; }
  62%          { stroke-dashoffset: -100; }
  62.01%, 100% { stroke-dashoffset: 5; }
}

/* the budget · one number for the year, where the signal starts */
.pr-origin {
  fill: var(--ink-700);
  stroke: rgba(255, 255, 255, 0.34);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* the gates · each ticks as the signal crosses it, then goes back to rest.
   The bloom is the live instant only; nothing here glows at rest. */
.pr-gate {
  fill: var(--ink-700);
  stroke: rgb(var(--ink-text-3-rgb) / 0.45);
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
  animation: prGate0 14s linear infinite;
}
.pr-g1 { animation-name: prGate1; }
.pr-g2 { animation-name: prGate2; }
@keyframes prGate0 {
  0%, 14%      { fill: var(--ink-700); stroke: rgb(var(--ink-text-3-rgb) / 0.45); filter: drop-shadow(0 0 0 transparent); }
  16%, 19%     { fill: rgb(var(--sig-green-lift-rgb) / 0.24); stroke: var(--sig-green-lift);
                 filter: drop-shadow(0 0 6px rgb(var(--sig-green-lift-rgb) / 0.45)); }
  24%, 100%    { fill: var(--ink-700); stroke: rgb(var(--ink-text-3-rgb) / 0.45); filter: drop-shadow(0 0 0 transparent); }
}
@keyframes prGate1 {
  0%, 28%      { fill: var(--ink-700); stroke: rgb(var(--ink-text-3-rgb) / 0.45); filter: drop-shadow(0 0 0 transparent); }
  30%, 33%     { fill: rgb(var(--sig-green-lift-rgb) / 0.24); stroke: var(--sig-green-lift);
                 filter: drop-shadow(0 0 6px rgb(var(--sig-green-lift-rgb) / 0.45)); }
  38%, 100%    { fill: var(--ink-700); stroke: rgb(var(--ink-text-3-rgb) / 0.45); filter: drop-shadow(0 0 0 transparent); }
}
@keyframes prGate2 {
  0%, 44%      { fill: var(--ink-700); stroke: rgb(var(--ink-text-3-rgb) / 0.45); filter: drop-shadow(0 0 0 transparent); }
  46%, 49%     { fill: rgb(var(--sig-green-lift-rgb) / 0.24); stroke: var(--sig-green-lift);
                 filter: drop-shadow(0 0 6px rgb(var(--sig-green-lift-rgb) / 0.45)); }
  54%, 100%    { fill: var(--ink-700); stroke: rgb(var(--ink-text-3-rgb) / 0.45); filter: drop-shadow(0 0 0 transparent); }
}

/* the operational grain · twelve loads leaving the runway. Exactly one is the
   live mark, flat green: merchandise is not a signal, the load running is. */
.pr-end {
  fill: var(--ink-700);
  stroke: rgb(var(--ink-text-3-rgb) / 0.42);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.pr-end-live {
  fill: rgb(var(--sig-green-lift-rgb) / 0.28);
  stroke: var(--sig-green-lift);
  stroke-width: 1.25;
}

/* the grain ruler · hangs off the drawing and never moves, so the measure it
   states stays true (the sub-page chain's week ruler, same rule) */
.pr-base { stroke: rgb(var(--ink-text-3-rgb) / 0.18); stroke-width: 1; vector-effect: non-scaling-stroke; }
.pr-tick { stroke: rgb(var(--ink-text-3-rgb) / 0.30); stroke-width: 1; vector-effect: non-scaling-stroke; }
.pr-tick-e { stroke: rgb(var(--ink-text-3-rgb) / 0.55); }
.pr-tick-f { stroke: rgb(var(--ink-text-3-rgb) / 0.22); }

.pr-labels text {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  fill: var(--ink-text-3);
}
/* each stage name lifts as its own leg of the signal runs · the label is the
   narration, so it must be driven by the same clock as the pulse */
.pr-stage { animation: prLab0 14s linear infinite; }
.pr-l1 { animation-name: prLab1; }
.pr-l2 { animation-name: prLab2; }
.pr-l3 { animation-name: prLab3; }
@keyframes prLab0 {
  0%, 3%    { fill: var(--ink-text-3); }
  6%, 15%   { fill: var(--ink-text-1); }
  22%, 100% { fill: var(--ink-text-3); }
}
@keyframes prLab1 {
  0%, 16%   { fill: var(--ink-text-3); }
  19%, 29%  { fill: var(--ink-text-1); }
  36%, 100% { fill: var(--ink-text-3); }
}
@keyframes prLab2 {
  0%, 30%   { fill: var(--ink-text-3); }
  33%, 45%  { fill: var(--ink-text-1); }
  52%, 100% { fill: var(--ink-text-3); }
}
@keyframes prLab3 {
  0%, 46%   { fill: var(--ink-text-3); }
  49%, 62%  { fill: var(--ink-text-1); }
  70%, 100% { fill: var(--ink-text-3); }
}
.pr-grain { font-size: 9.5px; fill: rgb(var(--ink-text-3-rgb) / 0.62); }
.pr-narrow { display: none; }

/* Mobile · the instrument holds its settled state, matching the dial and the
   story journeys, which are also replaced rather than lit below 768px. It also
   keeps visual-mobile-plan.png deterministic. The type is sized up in viewBox
   units because the svg scales to the column: at 342px a 11px glyph would land
   at about 7px on glass. */
@media (max-width: 767px) {
  .planway .pr-pulses { display: none; }
  .pr-gate { animation: none; fill: rgb(var(--sig-green-lift-rgb) / 0.24); stroke: var(--sig-green-lift); filter: none; }
  .pr-stage { animation: none; fill: var(--ink-text-2); }
  .pr-labels text { font-size: 15px; }
  .pr-grain { font-size: 12.5px; }
  .pr-wide { display: none; }
  .pr-narrow { display: block; }
  .pr-tick-f, .pr-c3 { display: none; }
}

/* off-screen ambients pause (site.js IntersectionObserver adds .asleep) */
.asleep, .asleep *, .asleep *::before, .asleep *::after { animation-play-state: paused !important; }

/* paper/mist page heroes · the registration mark locks on once on arrival.
   A cool ring, not a green one: arrival is not a decision, and green spent
   on 17 sub-page heroes is green spent on nothing. */
@keyframes kickerPing {
  0%   { box-shadow: 0 0 0 3px rgb(var(--ink-text-3-rgb) / 0.28); }
  35%  { box-shadow: 0 0 0 11px rgb(var(--ink-text-3-rgb) / 0); }
  100% { box-shadow: 0 0 0 0 rgb(var(--ink-text-3-rgb) / 0); }
}
.page-hero:not(.bg-ink) .kicker::before { animation: kickerPing 1.6s var(--ease-out) 750ms 1; }

/* card variants · break the identical-grid rhythm on content-led pages */
.feature-row {
  display: flex;
  gap: var(--space-24);
  align-items: flex-start;
  padding: var(--space-28) var(--space-4);
  border-top: 1px solid var(--f4-line);
}
.feature-row:last-child { border-bottom: 1px solid var(--f4-line); }
.feature-row .icon-tile { transition: transform 240ms var(--ease-out), color 240ms var(--ease-out); }
.feature-row:hover .icon-tile {
  transform: translateX(2px);
  color: var(--sig-green-deep);
}
.bg-ink .feature-row:hover .icon-tile { color: var(--sig-green-lift); }
.feature-row h3 { font-size: var(--fs-2xl); margin-bottom: var(--space-6); }
.feature-row p { font-size: var(--fs-md); color: var(--f4-slate); max-width: 58ch; }
.bg-ink .feature-row { border-top-color: var(--f4-line-dark); }
.bg-ink .feature-row:last-child { border-bottom-color: var(--f4-line-dark); }
.bg-ink .feature-row p { color: var(--text-on-ink-dim); }

/* technology foundations · quiet evidence cards on the white section */
.foundation-card .card-icon { color: var(--sig-green-text); margin-bottom: var(--space-16); }
.foundation-card h3 { font-size: var(--fs-3xl); }
.foundation-card::before { transform: scaleX(1); opacity: 0.58; }

/* ============================================================
   Use cases · three ways in, three different shapes
   The page used to be one grid of five cards, each three paragraphs of prose,
   which is why it read as basic: everything was the same shape and the shape
   was a paragraph. It now offers the same material by challenge, by horizon
   and by role, and each grouping is drawn differently so a reader can tell at
   a glance which one they are in.
   ============================================================ */

/* by challenge · the sentence we hear, the workflow that answers it, the
   decision it ends in. The workflow strip is the card's spine: four moves on
   one hairline, the site's chain language at card scale. */
.uc-grid { align-items: stretch; }
/* a.card sets display:block at (0,1,1) · these need to out-specify it */
a.uc-card { display: flex; flex-direction: column; }
.uc-wide { grid-column: 1 / -1; }
.uc-said {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
}
.uc-card h3 { margin-top: var(--space-14); font-size: var(--fs-md); color: var(--f4-slate); font-weight: 600; }
.uc-flow {
  list-style: none;
  margin: var(--space-18) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-6) 0;
}
.uc-flow li {
  display: flex; align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.04em;
  color: var(--f4-slate);
  white-space: nowrap;
}
.uc-flow li::before {
  content: "";
  flex: none;
  width: 5px; height: 5px;
  margin-right: var(--space-6);
  border: 1px solid var(--f4-slate);
  border-radius: 50%;
}
/* the hairline between moves · on the item that FOLLOWS, so it never trails
   off the end of the run */
.uc-flow li + li::after { content: none; }
.uc-flow li + li { margin-left: 0; }
.uc-flow li:not(:last-child)::after {
  content: "";
  width: clamp(10px, 2vw, 22px);
  height: 1px;
  margin: 0 var(--space-6);
  background: var(--f4-line);
}
.uc-dec {
  margin-top: var(--space-16);
  padding-top: var(--space-14);
  border-top: 1px solid var(--f4-line);
  font-size: var(--fs-sm);
  color: var(--f4-slate);
}
.uc-dec b {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: var(--space-4);
}
.uc-card .link-quiet { margin-top: auto; padding-top: var(--space-16); }
/* every challenge card is one full-width split: left the sentence we hear,
   right the answer. It began as the treatment for a single odd card in a
   two-up grid, and reads better as the rule than as the exception · six cards
   at half width made the reader compare two problems at once, when the point
   of the page is that they arrive one at a time. */
a.uc-card.uc-wide { display: grid; grid-template-columns: 1fr 1fr; column-gap: clamp(2rem, 5vw, 4.5rem); align-items: start; }
.uc-wide > div { display: flex; flex-direction: column; height: 100%; }
.uc-wide > div > .uc-flow { margin-top: 0; }
.uc-wide > div > .link-quiet { margin-top: auto; padding-top: var(--space-16); }
@media (max-width: 767px) {
  a.uc-card.uc-wide { grid-template-columns: 1fr; row-gap: var(--space-18); }
}

/* by horizon · one run from a year out to tomorrow, in the same direction as
   the Plan hero's runway so the two read as one language. The rail stops at
   the last node, and every station names the decision rather than the tool. */
.uc-hz {
  --uc-gap: clamp(1rem, 2vw, 1.75rem);
  list-style: none;
  margin: var(--space-32) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--uc-gap);
  position: relative;
}
.uc-hz::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 6.5px;
  right: calc((100% - 4 * var(--uc-gap)) / 5 - 6.5px);
  height: 1px;
  background: rgb(var(--ink-text-3-rgb) / 0.32);
}
.uc-hz li { position: relative; padding-top: var(--space-32); }
.uc-hz li::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 13px; height: 13px;
  border: 1px solid var(--ink-text-3);
  border-radius: 50%;
}
/* tomorrow is the only station that is already happening · one live mark */
.uc-hz li:last-child::before { border-color: var(--sig-green-lift); background: rgb(var(--sig-green-lift-rgb) / 0.28); }
.uc-hz-when {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-text-3);
}
.uc-hz h3 { margin-top: var(--space-10); font-size: var(--fs-xl); color: var(--ink-text-1); }
.uc-hz p { margin-top: var(--space-8); font-size: var(--fs-sm); color: var(--ink-text-2); }
.uc-hz .link-quiet { margin-top: var(--space-12); display: inline-flex; }

/* by role · a scan table, not cards. The question is the row's subject, so it
   is set in the reading face and the role name in mono beside it. */
.uc-roles { margin: var(--space-32) 0 0; }
.uc-roles > div {
  display: grid;
  grid-template-columns: 15rem 1fr auto;
  gap: var(--space-8) clamp(1.5rem, 3vw, 3rem);
  align-items: baseline;
  padding: var(--space-16) 0;
  border-top: 1px solid var(--f4-line);
}
.uc-roles > div:first-child { border-top: 0; }
.uc-roles dt {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  color: var(--f4-slate);
}
.uc-roles dd { margin: 0; }
.uc-roles dd:not(.uc-where) { font-size: var(--fs-md); }
.uc-where { display: flex; flex-wrap: wrap; gap: var(--space-8); }
.uc-where a {
  padding: var(--space-4) var(--space-12);
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.12);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.06em;
  color: var(--f4-blue-deep);
  text-decoration: none;
  white-space: nowrap;
}
.uc-where a:hover, .uc-where a:focus-visible { border-color: var(--f4-blue); background: rgb(var(--f4-blue-rgb) / 0.08); }

.uc-cat { margin-top: var(--space-40); padding-top: var(--space-28); border-top: 1px solid var(--f4-line); }

/* ---- home S10 · the delivery model as one slab ----
   It was three bare paragraph columns on paper, and the third carried twice
   the copy of the other two, so the composition leaned right and the whole
   band read as filler between two ink sections. One dark machined slab gives
   it the tonal weight it was missing, and three equal bays divided by
   hairlines mean no bay can outgrow its neighbours. Self-contained dark
   styling on a light section, the same call .ctower makes on #sees: it never
   relies on a bg-ink ancestor. */
.hw-slab {
  margin-top: var(--space-32);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-radius: var(--radius-card);
  border: 1px solid rgb(255 255 255 / 0.10);
  background: linear-gradient(180deg, var(--ink-700), var(--ink-800));
  box-shadow: inset 0 1px 0 var(--specular-ink), var(--shadow-lg);
  overflow: hidden;
}
.hw-bay { padding: clamp(1.5rem, 3vw, 2.25rem); border-left: 1px solid rgb(var(--ink-text-3-rgb) / 0.18); }
.hw-bay:first-child { border-left: 0; }
.hw-n {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.14em;
  color: var(--ink-text-3);
}
.hw-bay h3 { margin-top: var(--space-12); font-size: var(--fs-xl); color: var(--ink-text-1); }
.hw-bay p { margin-top: var(--space-10); font-size: var(--fs-sm); color: var(--ink-text-2); }
/* four bays: two by two on a tablet, where a quarter of the slab is too narrow */
@media (min-width: 768px) and (max-width: 1099px) {
  .hw-slab { grid-template-columns: repeat(2, 1fr); }
  .hw-bay:nth-child(odd) { border-left: 0; }
  .hw-bay:nth-child(n+3) { border-top: 1px solid rgb(var(--ink-text-3-rgb) / 0.18); }
}
@media (max-width: 767px) {
  .hw-slab { grid-template-columns: 1fr; }
  .hw-bay { border-left: 0; border-top: 1px solid rgb(var(--ink-text-3-rgb) / 0.18); }
  .hw-bay:first-child { border-top: 0; }
}

/* a card's one line of provenance · what the thing IS, not what it argues.
   Used on /results, where describing each paper by the capability it covers
   restated the module pages inside the section about evidence. */
.card-meta {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.04em;
  color: var(--f4-slate);
}

@media (max-width: 1023px) {
  .uc-hz { grid-template-columns: repeat(2, 1fr); row-gap: var(--space-32); }
  .uc-hz::before { display: none; }
  .uc-roles > div { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .uc-hz { grid-template-columns: 1fr; }
}

/* ---- Company · the engagement as one connected run ----
   Six commitments that used to sit in a 3x2 grid of cards, which is precisely
   the shape that made them read as six unrelated selling points. Each one only
   earns its place because of the one before it, so they hang off a single
   spine instead: index, name, and the reason, with the copy in its own column
   so the run fills the measure rather than stacking a narrow ribbon down the
   left. Deliberately vertical · the belief flow directly above it is a
   four-across horizontal rail, and two horizontal rails in one section would
   read as the same diagram drawn twice. */
.pcx { list-style: none; margin: var(--space-32) 0 0; padding: 0; }
.pcx li {
  position: relative;
  padding: var(--space-20) 0 var(--space-20) var(--space-32);
  display: grid;
  grid-template-columns: 16rem 1fr;
  gap: var(--space-12) clamp(1.5rem, 3vw, 3rem);
  align-items: baseline;
  border-top: 1px solid var(--f4-line);
}
.pcx li:first-child { border-top: 0; }
.pcx li::before {
  content: "";
  position: absolute;
  top: calc(var(--space-20) + 6px);
  left: 0;
  width: 13px; height: 13px;
  border: 1px solid var(--f4-slate);
  border-radius: 50%;
  background: var(--f4-paper);
}
/* the spine · each station draws its own link to the next, which is what lets
   the run stop dead at node six. A single line on the list would have to know
   the last row's height to avoid overshooting it. */
.pcx li::after {
  content: "";
  position: absolute;
  left: 6px;
  top: calc(var(--space-20) + 13px);
  bottom: calc((var(--space-20) + 6px) * -1);
  width: 1px;
  background: var(--f4-line);
}
.pcx li:last-child::after { display: none; }
.pcx-n {
  grid-column: 1;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.14em;
  color: var(--f4-slate);
  align-self: start;
}
.pcx h3 { grid-column: 1; grid-row: 2; font-size: var(--fs-xl); margin-top: calc(var(--space-6) * -1); }
.pcx p { grid-column: 2; grid-row: 1 / span 2; color: var(--f4-slate); }
@media (max-width: 767px) {
  .pcx li { grid-template-columns: 1fr; padding-left: var(--space-28); }
  .pcx h3, .pcx p { grid-column: 1; }
  .pcx h3 { grid-row: auto; }
  .pcx p { grid-row: auto; }
}
/* Planning, connected · the spine fills in ink as the reader moves down the
   run: a station lights once its row has passed the reading line, and the
   link above it draws down to meet it. Reduced motion shows the run done. */
.pcx li::before { transition: background-color 300ms var(--ease-out), border-color 300ms var(--ease-out); }
.pcx li::after {
  background: linear-gradient(var(--f4-ink), var(--f4-ink)) no-repeat top / 1px 0%, var(--f4-line);
  transition: background-size 600ms var(--ease-out);
}
.pcx li.is-reached::before { background: var(--f4-ink); border-color: var(--f4-ink); }
.pcx li.is-linked::after { background-size: 1px 100%, auto; }
@media (prefers-reduced-motion: reduce) {
  .pcx li::before, .pcx li::after { transition: none; }
}

/* ---- Meetings · the four moves as one run ----
   This section used to be four full-width .feature-row items, which put every
   word of it in the left half of the page and left the right half empty. It is
   a sequence, so it is drawn as one: a rail carries the eye left to right in
   the order the meeting actually happens, each card registered to it by its
   own hollow node (the kicker's registration mark, at card scale). The rail
   stops at the last node and points on, because the fourth move hands over to
   Memory rather than ending. No green: nothing here is live, and four lit
   nodes would spend the signal on a diagram of a calendar. */
.mwf {
  --mwf-gap: clamp(1.25rem, 2.5vw, 2rem);
  list-style: none;
  margin: var(--space-32) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--mwf-gap);
  position: relative;
}
/* the rail · first node centre to last node centre and no further. The gap is
   a custom property purely so the right inset can be computed from it: a rail
   that overshoots the last node reads as a step that was cut off. */
.mwf::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 6.5px;
  right: calc((100% - 3 * var(--mwf-gap)) / 4 - 6.5px);
  height: 1px;
  background: var(--f4-line);
}
.mwf li { position: relative; padding-top: var(--space-32); }
.mwf li::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 13px; height: 13px;
  border: 1px solid var(--f4-slate);
  border-radius: 50%;
  background: var(--f4-paper);
}
.mwf .mwf-when {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-4xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--f4-slate);
}
.mwf .icon-tile { margin: var(--space-14) 0 var(--space-12); color: var(--f4-slate); }
.mwf h3 { font-size: var(--fs-xl); }
.mwf p { margin-top: var(--space-8); font-size: var(--fs-sm); color: var(--f4-slate); }

@media (max-width: 899px) {
  .mwf { grid-template-columns: 1fr 1fr; row-gap: var(--space-32); }
  /* the rail only ever described one row · with two, it would be a lie */
  .mwf::before { display: none; }
}
@media (max-width: 560px) {
  .mwf { grid-template-columns: 1fr; }
}
/* the four moves, run (24 Oct review) · a token rides the rail from node
   to node carrying what the last move made: the pack into the room, the
   decisions out of it, the actions on to next cycle. Each node fills as the
   token arrives, its move lights and a receipt drops into it. Still no
   green: the token and the nodes are ink, because this is the meeting's
   calendar rather than a live signal. Below 900px the rail is gone, so the
   token goes with it and the moves light in turn on their own. */
.mwf-story { --mwf-gap: clamp(1.25rem, 2.5vw, 2rem); position: relative; margin-top: var(--space-32); }
.mwf-story .mwf { margin-top: 0; }
.mwf-fill {
  position: absolute; top: 6px; left: 6.5px; z-index: 1; height: 1px;
  width: calc(var(--hp, 0) * (100% - (100% - 3 * var(--mwf-gap)) / 4));
  background: var(--f4-ink);
}
.mwf-head {
  position: absolute; top: -3px; z-index: 2;
  left: calc(6.5px + var(--hp, 0) * (100% - (100% - 3 * var(--mwf-gap)) / 4));
  transform: translateX(-50%);
  display: grid; padding: 3px 10px; border-radius: var(--radius-pill);
  background: var(--f4-ink); color: var(--surface);
  font-family: var(--font-mono); font-size: var(--fs-4xs); letter-spacing: 0.08em; line-height: 1.2;
  box-shadow: var(--shadow-sm);
  transition: opacity 300ms var(--ease-out);
}
.mwf-head > span { grid-area: 1 / 1; text-align: center; }
.mwf li::before { transition: background-color 300ms var(--ease-out), border-color 300ms var(--ease-out), box-shadow 300ms var(--ease-out); }
.mwf li.is-lit::before { background: var(--f4-ink); border-color: var(--f4-ink); box-shadow: 0 0 0 4px rgb(var(--f4-ink-rgb) / 0.08); }
.mwf .icon-tile { transition: color 300ms var(--ease-out), transform 300ms var(--ease-out); }
.mwf li.is-lit .icon-tile { color: var(--f4-ink); transform: translateY(-2px); }
.mwf-rc {
  display: inline-flex; margin-top: var(--space-12); padding: 3px 10px;
  border: 1px solid rgb(var(--f4-ink-rgb) / 0.14); border-radius: var(--radius-pill);
  background: var(--surface);
  font-family: var(--font-mono); font-size: var(--fs-4xs); color: var(--f4-ink);
}
/* a node the token has reached stays filled until the loop resets */
.mwf-node { position: absolute; top: 0; left: 0; z-index: 1; width: 13px; height: 13px; border-radius: 50%; background: var(--f4-ink); }
.mwf-story.is-static .mwf-fill, .mwf-story.is-static .mwf-node { display: none; }
@media (max-width: 899px) { .mwf-head, .mwf-fill { display: none; } }
@media (prefers-reduced-motion: reduce) { .mwf li::before, .mwf .icon-tile { transition: none; } }

/* Meetings · the prepack is a first-class stage before the room */
.prepack-section { align-items: center; }
.prepack-flow { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-10); margin-top: var(--space-28); }
.prepack-flow span {
  padding: var(--space-8) var(--space-12); border: 1px solid rgb(var(--f4-ink-rgb) / .1); border-radius: var(--radius-pill);
  background: var(--surface); font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--f4-slate);
}
.prepack-flow span.active { color: var(--sig-green-text); border-color: rgb(var(--sig-green-rgb) / .42); background: rgb(var(--sig-green-rgb) / .08); }
.prepack-flow i { font-style: normal; color: var(--f4-slate); }
.prepack-card {
  overflow: hidden; border: 1px solid rgb(var(--f4-ink-rgb) / .08); border-radius: var(--radius-card);
  background: var(--surface); box-shadow: var(--shadow-lg);
}
.prepack-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-16); padding: var(--space-18) var(--space-20); border-bottom: 1px solid var(--f4-line); }
.prepack-head > div { display: grid; gap: var(--space-4); }
.prepack-head strong { font-size: var(--fs-xl); }
.prepack-eyebrow, .prepack-foot, .prepack-ready, .prepack-item > b {
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--f4-slate); font-weight: 500;
}
.prepack-eyebrow { letter-spacing: .08em; text-transform: uppercase; }
.prepack-ready { display: inline-flex; align-items: center; gap: var(--space-8); color: var(--sig-green-text); white-space: nowrap; }
.prepack-ready i { width: 7px; height: 7px; border-radius: 50%; background: var(--sig-green); box-shadow: 0 0 0 4px rgb(var(--sig-green-rgb) / .12); }
.prepack-list { padding: 0 var(--space-20); }
.prepack-item { display: grid; grid-template-columns: 34px 1fr auto; gap: var(--space-12); align-items: center; padding: var(--space-16) 0; border-top: 1px solid var(--f4-line); }
.prepack-item:first-child { border-top: 0; }
.prepack-item .icon-tile { width: 30px; height: 30px; color: var(--f4-slate); }
.prepack-item .icon-tile svg { width: 19px; height: 19px; }
.prepack-item div { display: grid; gap: var(--space-2); }
.prepack-item div > strong { font-size: var(--fs-base); }
.prepack-item div > span { font-size: var(--fs-cap-s); color: var(--f4-slate); }
.prepack-item > b { color: var(--sig-green-text); white-space: nowrap; }
.prepack-foot { display: flex; justify-content: space-between; gap: var(--space-16); padding: var(--space-12) var(--space-20); border-top: 1px solid var(--f4-line); background: var(--f4-paper); }

/* ---- the distribution · the pack leaving the card ----
   "The team arrives prepared to decide" is only true if the pack reaches them,
   so the send is drawn rather than asserted. It is the org-chart connector in
   CSS, which is what lets it survive any column width without an svg that
   would have to be re-measured: one drop out of the card into a horizontal
   bus, then one drop per role. The roles are functions, not people · the
   letter is the function's own initial and the word beneath says which, so
   nothing here invents a job title or a face. */
.prepack-send { padding: var(--space-20) var(--space-20) var(--space-24); border-top: 1px solid var(--f4-line); background: var(--f4-paper); }
.ps-line {
  display: flex; align-items: center; gap: var(--space-10);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--f4-slate);
}
.ps-line .icon-tile { flex: none; width: 26px; height: 26px; color: var(--f4-slate); }
.ps-line .icon-tile svg { width: 17px; height: 17px; }

.ps-people {
  list-style: none;
  margin: 0; padding: var(--space-24) 0 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-8);
  position: relative;
}
/* the drop out of the card, then the bus across · one pseudo-element each */
.ps-people::before {
  content: "";
  position: absolute;
  top: 0; left: 50%;
  width: 1px; height: var(--space-10);
  background: var(--f4-line);
}
.ps-people::after {
  content: "";
  position: absolute;
  top: var(--space-10);
  left: 10%; right: 10%;
  height: 1px;
  background: var(--f4-line);
}
.ps-people li {
  display: grid;
  justify-items: center;
  gap: var(--space-8);
  padding-top: var(--space-20);
  position: relative;
  font-size: var(--fs-4xs);
  color: var(--f4-slate);
  text-align: center;
}
/* the drop from the bus into each face */
.ps-people li::before {
  content: "";
  position: absolute;
  top: var(--space-10); left: 50%;
  width: 1px; height: var(--space-10);
  background: var(--f4-line);
}
.ps-face {
  width: 34px; height: 34px;
  border-radius: var(--radius-circle);
  background: linear-gradient(180deg, var(--surface-1), var(--surface-3));
  border: 1px solid var(--f4-line);
  display: grid; place-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--f4-slate);
}
/* below this the five roles wrap to two rows, and a bus drawn across one row
   would connect the wrong half of them · the whole connector goes, drop
   included, rather than leaving a hairline pointing at nothing */
@media (max-width: 420px) {
  .ps-people { grid-template-columns: repeat(3, 1fr); row-gap: var(--space-16); padding-top: var(--space-18); }
  .ps-people::before, .ps-people::after, .ps-people li::before { display: none; }
  .ps-people li { padding-top: 0; }
}
@media (max-width: 480px) {
  .prepack-head, .prepack-foot { align-items: flex-start; flex-direction: column; }
  .prepack-item { grid-template-columns: 28px 1fr; }
  .prepack-item > b { grid-column: 2; }
}

/* meetings demo · agenda beside the live log */
.meet-grid { display: grid; grid-template-columns: 5fr 7fr; gap: clamp(1.5rem, 3vw, 2.5rem); }
@media (max-width: 767px) { .meet-grid { grid-template-columns: 1fr; } }
.meet-agenda h4 {
  font-size: var(--fs-cap-s); font-family: var(--font-mono); text-transform: uppercase;
  letter-spacing: 0.12em; font-weight: 500; color: var(--ink-text-2); margin-bottom: var(--space-14);
}
.meet-agenda ol { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-10); counter-reset: ag; }
.meet-agenda li {
  counter-increment: ag;
  position: relative;
  padding: var(--space-14) var(--space-16) var(--space-14) var(--space-40);
  border: 1px solid var(--ink-card-line);
  border-radius: var(--radius-btn);
  background: rgba(255, 255, 255, 0.02);
  transition: border-color 300ms var(--ease-out), background 300ms var(--ease-out);
}
.meet-agenda li::before {
  content: counter(ag);
  position: absolute;
  left: 0.9375rem; top: 0.9375rem;
  width: 20px; height: 20px;
  border-radius: 50%;
  border: 1.5px solid rgba(206, 216, 228, 0.4);
  color: var(--ink-text-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  display: grid; place-items: center;
  transition: border-color 300ms var(--ease-out), background 300ms var(--ease-out), color 300ms var(--ease-out);
}
.meet-agenda li strong { display: block; font-size: var(--fs-md); color: var(--text-on-ink); }
.meet-agenda li span { font-size: var(--fs-cap); color: var(--text-on-ink-dim); font-family: var(--font-mono); }
.meet-agenda li.active { border-color: rgb(var(--sig-green-lift-rgb) / 0.45); background: rgb(var(--sig-green-rgb) / 0.07); }
.meet-agenda li.active::before { border-color: var(--sig-green-lift); color: var(--sig-green-lift); box-shadow: var(--glow-live); }
.meet-agenda li.done::before { content: "✓"; background: var(--sig-green); border-color: var(--sig-green); color: var(--sig-green-ink); }
.meet-log { margin-top: 0; border-top: none; padding-top: 0; }
.meet-log ul { min-height: 220px; align-content: start; }
/* before the first step lands, the log says what it is about to do */
.meet-log ul:empty::before {
  content: "The agenda resolves step by step · the log writes itself.";
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--ink-text-3);
}
.meet-meta { display: block; font-style: normal; font-family: var(--font-mono); font-size: var(--fs-kicker); color: var(--ink-text-3); margin-top: var(--space-2); }
.meet-log li.meet-memory { border-top: 1px dashed var(--f4-line-dark); padding-top: var(--space-14); margin-top: var(--space-6); }
.meet-log li.meet-memory .lane { color: var(--sig-green-lift); }
.meet-controls { display: flex; align-items: center; gap: var(--space-10); margin-top: var(--space-24); }
.meet-controls .meet-step { margin-left: auto; font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--ink-text-3); }
/* the pack, more graphical (24 Oct review) · each agenda item carries its
   evidence chart; each log row its lane icon, owner, chip and the item it
   settles; the step count becomes a strip of the seven entries */
.meet-agenda li { display: grid; grid-template-columns: minmax(0, 1fr) 132px; column-gap: var(--space-14); align-items: center; }
.meet-agenda li strong, .meet-agenda li > span { grid-column: 1; }
.meet-mc { grid-column: 2; grid-row: 1 / span 2; display: block; width: 132px; height: 56px; }
.mc-bar { fill: rgb(var(--ink-text-1-rgb) / 0.24); }
.mc-hot { fill: var(--f4-warn); }
.mc-ref { stroke: rgb(var(--ink-text-1-rgb) / 0.5); stroke-dasharray: 1.5 2.5; }
.mc-axis { stroke: rgb(var(--ink-text-1-rgb) / 0.3); }
.mc-mark { stroke: rgb(var(--ink-text-1-rgb) / 0.16); }
.mc-t { font-family: var(--font-mono); font-size: 8.5px; fill: var(--ink-text-3); }
.mc-t.is-warn { fill: var(--warn-ink); }
.mc-slip { fill: none; stroke: var(--f4-warn); stroke-width: 1.25; stroke-dasharray: 2 2; }
.mc-slip.is-tip { stroke-dasharray: none; stroke-linecap: round; stroke-linejoin: round; }
.mc-plan { fill: var(--ink-700); stroke: rgb(var(--ink-text-1-rgb) / 0.6); stroke-width: 1.25; }
.mc-late { fill: var(--f4-warn); }
.mc-was { fill: none; stroke: rgb(var(--ink-text-1-rgb) / 0.4); stroke-width: 1.25; stroke-dasharray: 3 2; }
.mc-now { fill: none; stroke: var(--f4-warn); stroke-width: 1.5; stroke-linejoin: round; }
.meet-log li { align-items: flex-start; }
.meet-log .lane { display: inline-flex; align-items: center; gap: var(--space-6); min-width: 96px; padding-top: 3px; }
.meet-log li.is-act .lane { color: var(--signal-ink); }
.ml-ic { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.ml-body { flex: 1; min-width: 0; }
.ml-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4) var(--space-8); margin-top: var(--space-4); font-family: var(--font-mono); font-size: var(--fs-kicker); color: var(--ink-text-3); }
.ml-av { display: inline-grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; font-style: normal; font-size: 9px; font-weight: 600; letter-spacing: 0.02em; color: var(--ink-text-1); background: rgb(var(--ink-text-1-rgb) / 0.12); }
.ml-chip { display: inline-flex; align-items: center; gap: var(--space-4); padding: 1px var(--space-8); border-radius: var(--radius-pill); border: 1px solid rgb(var(--f4-blue-lift-rgb) / 0.35); font-weight: 400; color: var(--f4-blue-lift); }
.ml-chip.is-due { border-color: rgb(var(--f4-warn-rgb) / 0.4); color: var(--warn-ink); }
.ml-chip .ml-ic { width: 12px; height: 12px; }
.ml-ag { flex: none; display: grid; place-items: center; width: 20px; height: 20px; margin-top: 1px; border-radius: 50%; border: 1px solid var(--ink-card-line); font-family: var(--font-mono); font-size: 10px; color: var(--ink-text-3); }
.meet-prog { display: inline-flex; gap: 3px; margin-left: auto; }
.meet-prog i { width: 22px; height: 6px; border-radius: 3px; background: rgb(var(--ink-text-1-rgb) / 0.12); transition: background-color 300ms var(--ease-out); }
.meet-prog i.is-on.is-dec { background: var(--f4-blue-lift); }
.meet-prog i.is-on.is-act { background: var(--signal-ink); }
.meet-prog i.is-on.is-mem { background: var(--sig-green-lift); }
.meet-controls .meet-prog + .meet-step { margin-left: var(--space-8); }
@media (max-width: 560px) { .meet-agenda li { grid-template-columns: 1fr; } .meet-mc { grid-column: 1; grid-row: auto; margin-top: var(--space-8); } .meet-prog { display: none; } }
@media (prefers-reduced-motion: reduce) { .meet-prog i { transition: none; } }

/* ============================================================
   technology · the signal journey ("How the signal travels")
   a four-act story clock on the ink surface · act rail seeks it
   ============================================================ */
.sj {
  display: grid;
  grid-template-columns: minmax(250px, 4fr) 8fr;
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: center;
  margin-top: var(--space-40);
}
.sj-stage svg { width: 100%; height: auto; display: block; }

/* act rail · the four insights, readable without watching the clock */
.sj-acts { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.375rem; }
.sj-acts button {
  position: relative;
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  padding: 0.8125rem 1rem 0.9375rem 2.125rem;
  cursor: pointer;
  transition: border-color 300ms var(--ease-out), background 300ms var(--ease-out);
}
.sj-acts button::before {          /* the node-dot · lights with the act */
  content: "";
  position: absolute;
  left: 0.9375rem; top: 1.25rem;
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1.5px solid rgba(206, 216, 228, 0.45);
  transition: background 300ms var(--ease-out), border-color 300ms var(--ease-out), box-shadow 300ms var(--ease-out);
}
.sj-acts b { display: block; font-weight: 600; font-size: var(--fs-md); color: rgba(255, 255, 255, 0.88); }
.sj-acts span { display: block; margin-top: 0.25rem; font-size: var(--fs-base); line-height: var(--lh-ui); color: var(--text-on-ink-dim); }
.sj-acts button:hover { border-color: rgba(206, 216, 228, 0.22); }
.sj-acts button.on {
  border-color: rgb(var(--sig-green-lift-rgb) / 0.4);
  background: linear-gradient(180deg, rgb(var(--sig-green-lift-rgb) / 0.09), rgb(var(--sig-green-lift-rgb) / 0.02));
}
.sj-acts button.on::before { background: var(--sig-green); border-color: var(--sig-green); box-shadow: var(--glow-live-ink); }
.sj-acts button.on b { color: var(--sig-green-lift); }
.sj-acts button::after {           /* clock hairline · fills across the act */
  content: "";
  position: absolute;
  left: 2.125rem; right: 1rem; bottom: 0.5rem;
  height: 1px;
  background: rgb(var(--sig-green-lift-rgb) / 0.55);
  transform: scaleX(0);
  transform-origin: left;
}
.sj:not(.sj-static) .sj-acts button.on::after { animation: sjClock 4.2s linear forwards; }
@keyframes sjClock { to { transform: scaleX(1); } }

/* boundary + links */
.sj-bound { fill: none; stroke: rgba(255, 255, 255, 0.13); stroke-dasharray: 3 7; stroke-width: 1.25; }
.sj-bound-cap { fill: var(--ink-text-3); letter-spacing: 0.08em; }
.sj-link { fill: none; stroke: var(--sig-green); stroke-opacity: 0.28; stroke-width: 1.5; stroke-dasharray: 100; stroke-dashoffset: 0; transition: stroke-opacity 500ms var(--ease-out); }
.reveal.in .sj-link { animation: linkDraw 900ms var(--ease-out) backwards; }
.sj-node { transform-box: fill-box; transform-origin: center; transform: scale(0.4); opacity: 0; transition: transform 600ms var(--ease-out), opacity 400ms var(--ease-out); }
.reveal.in .sj-node { transform: scale(1); opacity: 1; }

/* the compute layer · glyph rings, so transformation, forecasting and
   optimisation read as three kinds of work and not as three green dots
   (the surfaces keep the solid disc) */
.sj-comp-ring { fill: rgb(var(--sig-green-rgb) / 0.16); stroke: var(--sig-green); stroke-width: 2; }
.sj-comp-glyph { fill: none; stroke: var(--sig-green-lift); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

/* the write-back · transformed output returns to the versioned layer */
.sj-back-tip {
  fill: none; stroke: var(--sig-green); stroke-opacity: 0.28;
  stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
  transition: stroke-opacity 500ms var(--ease-out);
}
.sj-back-cap { fill: var(--ink-text-3); opacity: 0.42; transition: opacity 500ms var(--ease-out); }
.sj[data-act="2"] .sj-back-cap, .sj-static .sj-back-cap { opacity: 1; }

/* act lighting · the active leg burns, the rest hold at readable dim */
.sj-zone { opacity: 0.42; transition: opacity 500ms var(--ease-out); }
.sj[data-act="0"] .z-src, .sj[data-act="1"] .z-its, .sj[data-act="0"] .z-its,
.sj[data-act="2"] .z-its, .sj[data-act="2"] .z-mod,
.sj[data-act="3"] .z-mod, .sj[data-act="3"] .z-surf { opacity: 1; }
.sj[data-act="0"] .la0, .sj[data-act="2"] .la2, .sj[data-act="3"] .la3 { stroke-opacity: 0.75; }

/* comets · one pulse of signal per active leg */
.sj-comet { fill: none; stroke: var(--sig-green-pulse); stroke-width: 2.25; stroke-dasharray: 7 93; stroke-dashoffset: 107; opacity: 0; }
.sj:not(.sj-static)[data-act="0"] .ca0,
.sj:not(.sj-static)[data-act="2"] .ca2,
.sj:not(.sj-static)[data-act="3"] .ca3 { animation: sjComet 1.7s var(--ease-out) forwards; }
@keyframes sjComet {
  0% { stroke-dashoffset: 107; opacity: 0; }
  12% { opacity: 0.95; }
  82% { opacity: 0.95; }
  100% { stroke-dashoffset: -7; opacity: 0; }
}

/* the version shelf · v48 stamps in on act 1 */
.sj-v48 { opacity: 0; transform: translateY(5px); transform-box: fill-box; transition: opacity 400ms var(--ease-out), transform 400ms var(--ease-out); }
.sj[data-act="1"] .sj-v48, .sj[data-act="2"] .sj-v48, .sj[data-act="3"] .sj-v48, .sj-static .sj-v48 { opacity: 1; transform: none; }
.sj[data-act="1"] .sj-vault { filter: drop-shadow(0 0 14px rgb(var(--sig-green-rgb) / 0.45)); }
.sj-vault { transition: filter 500ms var(--ease-out); }

/* pills · the hero's caption language, lit per act */
.sj-pill rect { fill: rgba(9, 18, 32, 0.88); stroke: rgb(var(--sig-green-lift-rgb) / 0.45); }
.sj-pill text { fill: var(--sig-green-lift); }
.sj-pill.blue rect { stroke: rgba(127, 184, 242, 0.45); }
.sj-pill.blue text { fill: var(--f4-blue-pale); }
.sj-pill { opacity: 0; transform: translateY(5px); transform-box: fill-box; transition: opacity 450ms var(--ease-out), transform 450ms var(--ease-out); }
.sj[data-act="0"] .pa0, .sj[data-act="1"] .pa1, .sj[data-act="2"] .pa2, .sj[data-act="3"] .pa3,
.sj-static .sj-pill { opacity: 1; transform: none; }

/* the payoff · the same number lands beside every surface */
.sj-num rect { fill: rgba(9, 18, 32, 0.88); stroke: rgb(var(--sig-green-lift-rgb) / 0.55); }
.sj-num text { fill: var(--sig-green-lift); font-weight: 600; }
.sj-num { opacity: 0; transform: translateY(5px) scale(0.9); transform-box: fill-box; transform-origin: center; transition: opacity 400ms var(--ease-out), transform 400ms var(--ease-out); }
.sj[data-act="3"] .sj-num, .sj-static .sj-num { opacity: 1; transform: none; }
/* the architecture as cards and ribbons (24 Oct review) · these marks are
   the Technology chart's own; the shared .sj grammar above is untouched */
.sa-card { fill: var(--ink-700); stroke: rgba(255, 255, 255, 0.12); stroke-width: 1; }
.sa-card.is-comp { stroke: rgb(var(--sig-green-rgb) / 0.35); }
.sa-card.is-surf { stroke: rgb(var(--sig-green-lift-rgb) / 0.3); }
.sa-lab { fill: var(--ink-text-2); }
.sa-lab.is-comp, .sa-lab.is-surf { fill: var(--ink-text-1); }
.sa-ic { fill: none; stroke: var(--ink-text-2); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.z-surf .sa-ic { stroke: var(--sig-green-lift); }
.sa-dots { fill: var(--sig-green-lift); }
.sa-port { fill: var(--ink-900); stroke: rgba(255, 255, 255, 0.4); stroke-width: 1.25; }
.sa-port.is-its, .sa-port.is-surf { stroke: var(--sig-green); }
.sa-flow { fill: none; stroke: var(--sig-green); stroke-opacity: 0.06; stroke-width: 7; stroke-linecap: round; transition: stroke-opacity 500ms var(--ease-out); }
.sj[data-act="0"] .sa-flow.f0, .sj[data-act="2"] .sa-flow.f2, .sj[data-act="3"] .sa-flow.f3 { stroke-opacity: 0.14; }
.sa-lock { fill: none; stroke: var(--ink-text-3); stroke-width: 1.2; stroke-linejoin: round; }
.sa-sheet-box { fill: var(--ink-700); stroke: rgba(255, 255, 255, 0.14); }
.sa-sheet.is-old .sa-sheet-box { fill: var(--ink-800); stroke: rgba(255, 255, 255, 0.08); }
.sa-sheet.is-new .sa-sheet-box { fill: var(--ink-600); stroke: var(--sig-green); stroke-width: 1.5; }
.sa-sheet-v { fill: var(--ink-text-3); }
.sa-sheet.is-new .sa-sheet-v { fill: var(--sig-green-lift); font-weight: 600; }
.sa-sheet-rule { stroke: rgba(255, 255, 255, 0.1); }
.sa-row { fill: var(--ink-text-3); }
.sa-sheet.is-new .sa-row { fill: var(--ink-text-2); }
.sa-row.is-new { fill: var(--sig-green-lift); font-weight: 600; }
/* once v48 lands on top, v47 is a kept tab, not a second table showing through */
.sa-sheet.is-kept .sa-row, .sa-sheet.is-kept .sa-sheet-rule { transition: opacity 300ms var(--ease-out); }
.sj[data-act="1"] .sa-sheet.is-kept .sa-row, .sj[data-act="2"] .sa-sheet.is-kept .sa-row, .sj[data-act="3"] .sa-sheet.is-kept .sa-row, .sj-static .sa-sheet.is-kept .sa-row,
.sj[data-act="1"] .sa-sheet.is-kept .sa-sheet-rule, .sj[data-act="2"] .sa-sheet.is-kept .sa-sheet-rule, .sj[data-act="3"] .sa-sheet.is-kept .sa-sheet-rule, .sj-static .sa-sheet.is-kept .sa-sheet-rule { opacity: 0; }

@media (max-width: 899px) {
  .sj { grid-template-columns: 1fr; }
  .sj-acts { grid-template-columns: 1fr 1fr; gap: 0.5rem; }
}
@media (max-width: 767px) {
  /* the stage keeps its readable size and pans inside its own container */
  .sj-stage { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .sj-stage svg { min-width: 760px; }
}
@media (max-width: 640px) {
  .sj-acts { grid-template-columns: 1fr; }
}

/* ============================================================
   platform · the system dial ("everything is connected")
   a dark instrument slab machined into the mist section: six
   module nodes on one closed ring, the Saga hub spoked to all
   six, a Control Tower arc above and a Memory arc below. At rest
   everything is hairline cool; green is spent only twice — the
   circulating pulse (the one glow) and the flat highlight of
   whichever beat the Sees->Advises->Acts->Remembers clock plays.
   ============================================================ */
.sysdial {                          /* the .chain-demo finish · a landscape instrument on mist */
  max-width: 1080px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(288px, 344px);
  gap: var(--space-16) var(--space-40);
  align-items: center;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: var(--radius-card);
  background:
    radial-gradient(900px 460px at 88% -12%, rgb(var(--f4-blue-rgb) / 0.10), transparent 60%),
    linear-gradient(180deg, var(--ink-700), var(--ink-900));
  box-shadow:
    var(--specular-ink),
    0 1px 0 rgb(var(--ink-900-rgb) / 0.5),
    0 28px 56px -30px rgb(var(--ink-900-rgb) / 0.6);
  padding: var(--space-28) var(--space-32);
  position: relative;
}
.sysdial.sd-bare {                  /* slab-less · sits raw on an ink section (home "The shift") */
  background: none; border: 0; box-shadow: none;
  padding: 0;
  /* one object, not three: the claim and the layer rail hold the left column and
     the dial fills the right. max-width:none because the container is already the
     measure — the old 1120px cap inset the grid 16px inside a section head that
     started at the container edge, so the head, the grid, #problem's cards above
     and #sees's grid below never shared a line, and the dial stopped 48px short of
     the container on the right. 5fr/7fr is .ct-split's ratio, so this band and
     #sees read as the same grid. minmax(0, ·) and not a bare fr: an fr track's
     floor is auto, so one long unbroken word in the claim would take the dial's
     column rather than wrap (measured 700/379 instead of 450/630). */
  max-width: none;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  grid-template-rows: auto 1fr;
  align-items: start;
  column-gap: clamp(2rem, 5vw, 4.5rem);   /* the .grid-split gap · the same split as #sees */
  row-gap: var(--space-32);
}
/* every child takes a ROW as well as a column. Naming only the column left
   .sd-console asking for track 1 after .sd-stage had already taken track 2, which
   is behind the sparse auto-placement cursor, so it opened a second row: the panel
   stood 933px tall to hold 562px of instrument, with each column empty for the
   other's height. Row 2 is 1fr and the console ends it, so the rail's last line
   lands on the dial's bottom edge and the column's slack falls in one deliberate
   break under the claim rather than scattered above and below. */
.sysdial.sd-bare .sd-brief   { grid-column: 1; grid-row: 1; max-width: 62ch; }   /* .section-head's own reading measure · inert in the 450px column, it is what stops the claim running to 851px once the panel stacks */
.sysdial.sd-bare .sd-console { grid-column: 1; grid-row: 2; align-self: end; }
/* start, not centre. The dial's height is aspect-locked to its own track while
   the left column's is set by text, so which of the two is taller flips at about
   1052px: above it the dial is, and both edges lock; below it the left column is,
   and a centred dial floats free of both, with the rail's last line hanging past
   the bottom of the drawing (73px of it at 900). Starting it keeps the ONE lock
   that the eye actually reads at every width, the claim and the dial sharing a
   top edge, and collects the surplus as a single quiet gap under the drawing
   instead of splitting it above and below. Stacking early was the other way out
   and it is worse: measured, it takes the section from 714px to 1299px at 1024
   to buy back 20px of alignment, which is the opposite of what this band is for. */
.sysdial.sd-bare .sd-stage   { grid-column: 2; grid-row: 1 / -1; align-self: start; }
/* the drawing's own width · every two-column track is narrower than this, so the
   cap only bites once the panel stacks, which since the 1023 rung below is where
   the dial is at its largest. It stops the mono labels being scaled past the size
   they were drawn at. Note this selector (0,3,1) beats the <=767
   `.sd-stage svg { max-width: 100% }` (0,1,1); harmless only because the
   container is under 720px below 768, so raising the cap means revisiting that. */
.sysdial.sd-bare .sd-stage svg { max-width: 720px; }
.sd-stage { position: relative; grid-column: 1; }
.sd-stage svg { width: 100%; height: auto; display: block; max-width: 560px; margin: 0 auto; }

/* the console · the four layers listed beside the dial, the active one lit */
.sd-console { grid-column: 2; display: flex; flex-direction: column; gap: 0.875rem; min-width: 0; }
.sd-kicker {
  display: flex; align-items: center; gap: 0.5rem; margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-xs); font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-text-2);
}
.sd-kicker::before {
  content: ""; width: 7px; height: 7px;
  border-radius: 50%; border: 1.5px solid var(--ink-text-3);
}
/* the beat rail · a legend when static, a seek control when live */
.sd-rail { display: flex; flex-direction: column; gap: 0.25rem; }
.sd-tab {
  appearance: none; -webkit-appearance: none;
  display: block; width: 100%; text-align: left; margin: 0;
  background: none; border: 0; border-left: 2px solid transparent;
  padding: 0.55rem 0.5rem 0.6rem 0.8rem;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  cursor: pointer; transition: background 200ms var(--ease-out), border-color 200ms var(--ease-out);
}
.sd-tab-k {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs); font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-text-2); transition: color 200ms var(--ease-out);
}
.sd-tab-d {
  display: block; margin-top: 0.2rem;
  font-family: var(--font-mono);
  font-size: var(--fs-kicker); line-height: var(--lh-ui);
  color: var(--ink-text-3); transition: color 200ms var(--ease-out);
}
.sd-tab:hover:not(:disabled) { background: rgba(255, 255, 255, 0.03); }
.sd-tab:hover:not(:disabled) .sd-tab-k { color: var(--ink-text-1); }
.sd-tab.on { border-left-color: var(--sig-green-lift); background: rgb(var(--sig-green-lift-rgb) / 0.06); }   /* the layer currently playing */
.sd-tab.on .sd-tab-k { color: var(--sig-green-lift); }
.sd-tab.on .sd-tab-d { color: var(--ink-text-1); }
.sd-tab:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--sig-green-lift); }
.sd-tab:disabled { cursor: default; }   /* static: the four layers read as a legend */

/* below ~900px the platform panel stacks · dial, then the console as a centred
   legend. This rung is the SLAB's, not the bare panel's: the slab's left column
   carries the dial alone, so its two columns stay balanced right down to 900. */
@media (max-width: 899px) {
  .sysdial { grid-template-columns: 1fr; row-gap: var(--space-20); }
  .sd-stage, .sd-console { grid-column: 1; }
  .sd-console { max-width: 560px; margin: 0 auto; width: 100%; }
}

/* The bare panel stacks on the same 899 rung, and stacking is what costs height
   rather than what saves it: measured, the stack takes the section from 714px to
   1299px at 1024, because three full-width blocks are taller than two columns.
   So the two-column arrangement is held as far down as it reads, and the price of
   holding it (the dial narrowing to 470px at 900) is paid back the moment it
   stacks and the drawing takes its full 720px cap.

   .sysdial.sd-bare (0,2,0) out-specifies the plain .sysdial rules above (0,1,0),
   which is why the bare panel never stacked at all before this: it kept two
   tracks all the way down and pinned the dial to the 344px console track with up
   to 462px of the second one empty (measured 462 at 899, 336 at 768, 208 at 640).
   It has to restate the track list at matching specificity and hand back the rows
   and the self-alignment, which are a two-column arrangement, or all three items
   land in one cell on top of each other. */
@media (max-width: 899px) {
  .sysdial.sd-bare {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    row-gap: var(--space-32);
    align-items: stretch;
  }
  .sysdial.sd-bare .sd-brief,
  .sysdial.sd-bare .sd-stage,
  .sysdial.sd-bare .sd-console { grid-column: 1; grid-row: auto; align-self: auto; }
  /* the legend takes the claim's measure and the claim's left edge. The centring
     above was written for a stack that had no head over it; under one it put a
     145px indent between a flush-left claim and the rail that explains it. */
  .sysdial.sd-bare .sd-console { max-width: 62ch; margin-inline: 0; }
}

/* dial anatomy · everything at rest is hairline cool */
.f4dial text { font-family: var(--font-mono); }
.f4dial .sd-arc      { fill: none; stroke: rgb(var(--ink-text-1-rgb) / 0.24); stroke-width: 1.25; transition: stroke 350ms var(--ease-out), stroke-opacity 350ms var(--ease-out); }
.f4dial .sd-arc-shelf { stroke: rgb(var(--ink-text-1-rgb) / 0.15); }   /* Memory's inner ledger line */
.f4dial .sd-tick     { stroke: rgb(var(--ink-text-3-rgb) / 0.5); stroke-width: 1; }
.f4dial .sd-edge     { fill: none; stroke: rgb(var(--ink-text-1-rgb) / 0.3); stroke-width: 1.4; transition: stroke 350ms var(--ease-out), stroke-opacity 350ms var(--ease-out); }
.f4dial .sd-hubring  { fill: none; stroke: rgb(var(--ink-text-1-rgb) / 0.16); stroke-width: 1; transition: stroke 350ms var(--ease-out), stroke-opacity 350ms var(--ease-out); }
.f4dial .sd-spoke    { stroke: rgb(var(--ink-text-1-rgb) / 0.13); stroke-width: 1; transition: stroke 350ms var(--ease-out), stroke-opacity 350ms var(--ease-out); }
.f4dial .sd-flow     { fill: none; stroke: rgb(var(--ink-text-1-rgb) / 0.16); stroke-width: 1.25; stroke-dasharray: 3 5; transition: stroke 350ms var(--ease-out), stroke-opacity 350ms var(--ease-out); }
.f4dial .sd-node circle,
.f4dial .sd-hubdisc  { fill: var(--ink-700); stroke: rgb(var(--ink-text-1-rgb) / 0.26); stroke-width: 1.5; }
.f4dial .sd-node     { color: var(--ink-text-2); transition: color 350ms var(--ease-out); }   /* icons ride currentColor */
.f4dial .sd-name     { fill: var(--ink-text-1); font-size: 10.5px; }
.f4dial .sd-verb     { fill: var(--ink-text-3); }
.f4dial .sd-hubname  { fill: var(--ink-text-1); font-size: 12px; font-weight: 600; }
.f4dial .sd-hubverb  { fill: var(--ink-text-3); font-size: 8.5px; letter-spacing: 0.14em; }
.f4dial .sd-arclabel   { fill: var(--ink-text-2); font-size: 11px; letter-spacing: 0.14em; }
.f4dial .sd-microlabel { fill: var(--ink-text-3); font-size: 9.5px; letter-spacing: 0.08em; }

/* module nodes are links · blue = navigation (the site's second hue), never green */
.f4dial a.sd-nodelink { cursor: pointer; }
.f4dial a.sd-nodelink:hover .sd-node,
.f4dial a.sd-nodelink:focus-visible .sd-node { color: var(--ink-text-1); }
.f4dial a.sd-nodelink:hover .sd-node circle,
.f4dial a.sd-nodelink:focus-visible .sd-node circle { stroke: var(--f4-blue-lift); stroke-width: 2; }
.f4dial a.sd-nodelink:hover .sd-name,
.f4dial a.sd-nodelink:focus-visible .sd-name { fill: var(--f4-blue-lift); }

/* arc readouts · the dial reads as a live instrument, not a diagram */
.f4dial .sd-readout { fill: var(--ink-text-3); font-size: 8px; letter-spacing: 0.16em; }
.f4dial .sd-livedot { fill: var(--sig-green-lift); opacity: 0; }
/* the Saga echo · a ring that blooms at each module on the Advises beat */
.f4dial .sd-echo { fill: none; stroke: var(--sig-green-lift); stroke-width: 1.25; opacity: 0; transform-box: fill-box; transform-origin: center; }

/* assemble on reveal · the whole instrument settles in, the nodes pop */
.f4dial .sd-build { transform-box: fill-box; transform-origin: center; }
.sysdial.reveal .sd-build { opacity: 0; transform: scale(0.965); }
.sysdial.reveal.in .sd-build { opacity: 1; transform: scale(1); transition: opacity 600ms var(--ease-out), transform 700ms var(--ease-out); }
.sysdial.reveal .sd-node { opacity: 0; }
.sysdial.reveal.in .sd-node { animation: sdPop 500ms var(--ease-out) both; }   /* opacity only · side labels rule out a clean per-node scale origin */
.sysdial.reveal.in a.sd-nodelink:nth-of-type(1) .sd-node { animation-delay: 140ms; }
.sysdial.reveal.in a.sd-nodelink:nth-of-type(2) .sd-node { animation-delay: 220ms; }
.sysdial.reveal.in a.sd-nodelink:nth-of-type(3) .sd-node { animation-delay: 300ms; }
.sysdial.reveal.in a.sd-nodelink:nth-of-type(4) .sd-node { animation-delay: 380ms; }
.sysdial.reveal.in a.sd-nodelink:nth-of-type(5) .sd-node { animation-delay: 460ms; }
.sysdial.reveal.in a.sd-nodelink:nth-of-type(6) .sd-node { animation-delay: 540ms; }
@keyframes sdPop { from { opacity: 0; } to { opacity: 1; } }

/* the one glow · rides the travelling pulse (fill via token, so the green grep holds) */
.f4dial .sd-pulse  { fill: var(--sig-green-pulse); }
.f4dial .sd-rider  { fill: var(--sig-green-lift); }

/* live · zones rest at readable dim (the .sj-zone idiom); the playing zone lights */
.sysdial[data-live] .sd-zone { opacity: 0.6; transition: opacity 500ms var(--ease-out); }
.sysdial[data-beat="1"] .dz-ct,
.sysdial[data-beat="2"] .dz-hub,
.sysdial[data-beat="3"] .dz-ring,
.sysdial[data-beat="4"] .dz-mem { opacity: 1; }

/* the playing element takes a flat semantic green · tokens only, no glow */
.sysdial[data-beat="1"] .sd-arc-ct  { stroke: var(--sig-green-lift); stroke-opacity: 0.85; }
.sysdial[data-beat="2"] .sd-spoke   { stroke: var(--sig-green); stroke-opacity: 0.55; animation: sdSpoke 1.6s ease-in-out infinite; }
.sysdial[data-beat="2"] .sd-ctx     { stroke: var(--sig-green); stroke-opacity: 0.45; }
.sysdial[data-beat="2"] .sd-hubring { stroke: var(--sig-green-lift); stroke-opacity: 0.55; }
.sysdial[data-beat="3"] .sd-edge    { stroke: var(--sig-green); stroke-opacity: 0.55; }
.sysdial[data-beat="3"] .sd-node    { color: var(--ink-text-1); }
.sysdial[data-beat="4"] .sd-arc-mem { stroke: var(--sig-green-lift); stroke-opacity: 0.85; }
.sysdial[data-beat="4"] .sd-drain   { stroke: var(--sig-green); stroke-opacity: 0.5; }
@keyframes sdSpoke { 0%, 100% { stroke-opacity: 0.35; } 50% { stroke-opacity: 0.7; } }

/* Sees · the live signal count pulses · Advises · Saga's ring blooms at every module */
.sysdial[data-beat="1"] .sd-livedot { opacity: 1; animation: sdLive 1.8s ease-in-out infinite; }
.sysdial[data-beat="2"] .sd-echo { animation: sdEcho 1.9s ease-out infinite; }
.sysdial[data-beat="2"] a.sd-nodelink:nth-of-type(2) .sd-echo { animation-delay: 0.12s; }
.sysdial[data-beat="2"] a.sd-nodelink:nth-of-type(3) .sd-echo { animation-delay: 0.24s; }
.sysdial[data-beat="2"] a.sd-nodelink:nth-of-type(4) .sd-echo { animation-delay: 0.36s; }
.sysdial[data-beat="2"] a.sd-nodelink:nth-of-type(5) .sd-echo { animation-delay: 0.48s; }
.sysdial[data-beat="2"] a.sd-nodelink:nth-of-type(6) .sd-echo { animation-delay: 0.6s; }
@keyframes sdLive { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } }
@keyframes sdEcho { 0% { opacity: 0; transform: scale(1.5); } 45% { opacity: 0.6; transform: scale(1); } 100% { opacity: 0; transform: scale(1); } }

/* beat riders · each group is hidden off its beat (the f4graph .gb idiom) */
.f4dial .sd-gb { opacity: 0; transition: opacity 450ms var(--ease-out); }
.sysdial[data-beat="1"] .sd-gb.g1,
.sysdial[data-beat="4"] .sd-gb.g4 { opacity: 1; }

/* static (mobile / reduced motion / no JS): fully drawn, no dimming, no green;
   the console lists all four layers with none lit — a legend */
.sysdial:not([data-live]) .sd-zone { opacity: 1; }

@media (max-width: 767px) {
  .sysdial { padding: var(--space-18) var(--space-12) var(--space-20); }
  /* the whole loop stays visible · fit to width (no pan), then declutter and
     enlarge the labels that carry the story — module names, the two layer arcs
     and the hub — while dropping the node verbs and edge microlabels that get
     cramped at phone scale (the console below names the flows instead). */
  .sd-stage svg { max-width: 100%; }
  .f4dial .sd-verb, .f4dial .sd-microlabel, .f4dial .sd-readout { display: none; }
  .f4dial .sd-name     { font-size: 16px; }
  .f4dial .sd-arclabel { font-size: 15px; letter-spacing: 0.1em; }
  .f4dial .sd-hubname  { font-size: 17px; }
  .f4dial .sd-hubverb  { font-size: 11.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-copy .kicker, .hero-copy h1, .hero-copy .hero-sub, .hero-copy .hero-ctas, .hero-visual,
  .page-hero .kicker, .page-hero h1, .page-hero .sub, .page-hero .hero-actions,
  .demo-chart .bar, .waterfall svg rect, .alloc-stage svg path, .spark, .fx-sigline,
  .whip-trace, .whip-wave, .whip-head,
  .chain-node.jolt .cn-dot, .chain-node.jolt .cn-dot::after { animation: none !important; }
  .whip-trace { stroke-dashoffset: 0 !important; }
  .f4graph .nd { transform: none; transition: none; }

  /* system dial · the live variant never mounts here, so this is insurance;
     the reveal assemble is forced settled so the static dial shows in full */
  .f4dial .sd-gb, .f4dial .sd-spoke, .f4dial .sd-echo, .f4dial .sd-livedot { animation: none !important; }
  .sysdial.reveal .sd-node, .sysdial.reveal.in .sd-node { animation: none !important; opacity: 1 !important; transform: none !important; }
  .sysdial.reveal .sd-build, .sysdial.reveal.in .sd-build { opacity: 1 !important; transform: none !important; transition: none !important; }
  .f4dial .sd-arc, .f4dial .sd-edge, .f4dial .sd-flow, .f4dial .sd-node,
  .sysdial .sd-zone, .sd-tab, .sd-tab-k, .sd-tab-d { transition: none !important; }

  /* new demo surfaces settle instantly */
  .pl-planline { animation: none !important; stroke-dashoffset: 0 !important; }
  .sj-link, .sj-comet, .pj-comet, .sj-acts button.on::after { animation: none !important; }
  .sj-link { stroke-dashoffset: 0 !important; }
  .sj-comet, .pj-comet { opacity: 0 !important; }
  .sj-node, .sj-pill, .sj-num, .sj-v48 { transform: none !important; opacity: 1 !important; transition: none !important; }
  .sj-zone { opacity: 1 !important; transition: none !important; }
  .pj-zone, .pj-pop, .pj-rule { transition: none !important; }
  .sj-vault { filter: none !important; }
  .meet-agenda li, .meet-agenda li::before { transition: none !important; }

  /* ambient layers hold still */
  .node-texture::before, .cta-band::before, .cta-band::after, .pull-strip::after,
  .shot-frame::after, .page-hero .kicker::before, .hf-med, .hero-field .hf-plane,
  .hf-pulse { animation: none !important; }

  /* Plan's runway · rendered as the story's END, not a blank start: the signal
     has run the whole length, every gate has fired, the grain is resolved.
     Flat, and never bloomed — a halo implying motion that never arrives is a
     lie to the one user who opted out. */
  /* display:none is not enough — a hidden element's animation still reports
     playState "running" to getAnimations(), which is what QA counts */
  .planway .pr-pulses { display: none !important; }
  .pr-p, .pr-gate, .pr-stage { animation: none !important; }
  .pr-gate { fill: rgb(var(--sig-green-lift-rgb) / 0.24); stroke: var(--sig-green-lift); filter: none !important; }
  .pr-stage { fill: var(--ink-text-2); }
  /* now-line field · not built under reduced motion, but the shell div exists */
  .node-field, .nf-nowline, .nf-nowline::after, .nf-nowtag, .nf-sweep, .nf-ring, .nf-pulse,
  .nf-link.reroute, .nf-node .nf-ghost, .nf-node, .f-chip, .nf-speck, .nf-links,
  .nf-grid i, .nf-grid b, .nf-tier, .nf-cap, .nf-peak, .nf-wake, .hero-deck,
  .nf-node.hail .nf-fieldmark { animation: none !important; }
  .layer-band::before, .layer-band::after, .layer-band .lb-verb, .layer-band .lb-verb svg,
  .before-after::after, .ba-today li, .stat::before,
  .card::before, .card .card-icon svg, .card .icon-tile svg,
  .feature-row .icon-tile, .product-shot .shot-frame { transition: none !important; }

  /* minimap spine · settled, no choreography */
  .layer-minimap, .layer-minimap a, .layer-minimap a::before, .layer-minimap .mm-track,
  .mm-ic, .layer-minimap a .mm-label { transition: none !important; }
  .layer-minimap a { opacity: 1 !important; transform: none !important; }
  .layer-minimap .mm-track { transform: none !important; }
  .layer-band::after { animation: none !important; opacity: 0 !important; }

  /* nav · panels and sheets appear settled, no choreography */
  .mega-cols > div, .main-nav > ul > li, .drop-panel,
  .mega a, .mega-ic, .mega-ic svg, .nav-toggle span, .chev { transition: none !important; }
  .mega-cols > div, .main-nav > ul > li { opacity: 1 !important; transform: none !important; }
}

/* util */
.mt-1 { margin-top: var(--space-8); } .mt-2 { margin-top: var(--space-16); } .mt-3 { margin-top: var(--space-24); }
.mt-4 { margin-top: var(--space-32); } .mt-6 { margin-top: var(--space-48); } .mt-8 { margin-top: var(--space-64); }
.center { text-align: center; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ============================================================
   AI marks · the plan in the "AI on the 2026 website" doc (24 Oct 2026)
   One mark and one tag carry AI across the site. The mark is the
   product's own Tower AI spark pair, filled blue into green. The tag
   says what the AI does (the blue half: a proposal) beside what a
   person does (the green half: the decision), so green keeps its one
   job and the AI never reads as the one who decides. Marks go only
   where AI works today, and a mark always has a label in view: nobody
   reads a sparkle alone as "AI". Still at rest, never a glow.
   ============================================================ */
:root {
  --ai-spark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 2.6c.8 5.1 3.1 7.4 8.2 8.2-5.1.8-7.4 3.1-8.2 8.2-.8-5.1-3.1-7.4-8.2-8.2 5.1-.8 7.4-3.1 8.2-8.2z'/%3E%3Cpath d='M19.4 14.6c.33 2 1.27 2.94 3.3 3.3-2.03.36-2.97 1.3-3.3 3.3-.33-2-1.27-2.94-3.3-3.3 2.03-.36 2.97-1.3 3.3-3.3z'/%3E%3C/svg%3E");
  --ai-spark-white: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='white' d='M12 3c.85 5.4 3.6 8.15 9 9-5.4.85-8.15 3.6-9 9-.85-5.4-3.6-8.15-9-9 5.4-.85 8.15-3.6 9-9z'/%3E%3C/svg%3E");
  --ai-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4.5 12.5 5 5 10-11'/%3E%3C/svg%3E");
}

/* the mark · an empty span, painted through the spark's shape */
.ai-mark {
  display: inline-block; flex: none;
  width: 15px; height: 15px;
  vertical-align: -2px;
  background: linear-gradient(135deg, var(--f4-blue-deep), var(--sig-green-text));
  -webkit-mask: var(--ai-spark) center / contain no-repeat;
          mask: var(--ai-spark) center / contain no-repeat;
}
.ai-mark.is-ink, .bg-ink .ai-mark, .sysdial .ai-mark, .ai-tag.is-ink .ai-mark {
  background: linear-gradient(135deg, var(--f4-blue-lift), var(--sig-green-lift));
}

/* the tag · what the AI does, then what a person does */
.ai-tag {
  display: inline-flex; align-items: stretch;
  border: 1px solid var(--f4-line); border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: 0.08em; text-transform: uppercase;
  line-height: 1.2; white-space: nowrap; vertical-align: middle;
}
.ai-tag > span { display: inline-flex; align-items: center; gap: var(--space-8); padding: var(--space-8) var(--space-12); }
.ai-tag-a { color: var(--f4-blue-deep); }
.ai-tag-h { color: var(--sig-green-text); border-left: 1px solid var(--f4-line); }
.ai-tag-h::before {
  content: ""; flex: none; width: 12px; height: 12px;
  background: currentColor;
  -webkit-mask: var(--ai-tick) center / contain no-repeat;
          mask: var(--ai-tick) center / contain no-repeat;
}
.ai-tag.is-ink { background: var(--ink-700); border-color: var(--f4-line-dark); box-shadow: none; }
.ai-tag.is-ink .ai-tag-a { color: var(--f4-blue-lift); }
.ai-tag.is-ink .ai-tag-h { color: var(--sig-green-lift); border-left-color: var(--f4-line-dark); }
/* a phone has no room for both halves side by side · they stack */
@media (max-width: 640px) {
  .ai-tag { flex-direction: column; border-radius: var(--radius-sm); white-space: normal; }
  .ai-tag-h { border-left: 0; border-top: 1px solid var(--f4-line); }
  .ai-tag.is-ink .ai-tag-h { border-top-color: var(--f4-line-dark); }
}
.ai-hero-tag { margin: var(--space-20) 0 0; }
.ai-hero-tag .ai-tag > span { padding: var(--space-8) var(--space-14); }
.ai-hero-tag + .hero-actions { margin-top: var(--space-28); }
/* the slab key on the Connect & Craft map · short enough to stay one line */
.ai-key { display: flex; justify-content: center; margin: 0 0 var(--space-14); }
@media (max-width: 640px) {
  .ai-key .ai-tag { flex-direction: row; border-radius: var(--radius-pill); }
  .ai-key .ai-tag-h { border-top: 0; border-left: 1px solid var(--f4-line-dark); }
}

/* one line under a hero's buttons · what the AI is, in a sentence */
.ai-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-6) var(--space-12);
  margin-top: var(--space-24);
  font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--ink-text-2);
}
.ai-line b { color: var(--ink-text-1); font-weight: 500; }
.ai-line i { font-style: normal; color: var(--ink-text-3); }
.ai-line .ai-mark { width: 16px; height: 16px; }
/* the points travel as one group, so a phone breaks the line cleanly:
   the promise on the first line, the points under its words on the second */
.ai-line-p { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-6) var(--space-12); }
@media (max-width: 640px) {
  .ai-line-p { margin-left: calc(16px + var(--space-12)); }
  .ai-line-p > i:first-child { display: none; }
}

/* the menu · a corner mark on the modules where AI works today, and the
   legend that names it (the mark is CSS only, so the icon count holds) */
.mega-ic.has-ai { position: relative; overflow: visible; }
.mega-ic.has-ai::after {
  content: ""; position: absolute; top: -5px; right: -5px;
  width: 16px; height: 16px; border-radius: var(--radius-circle);
  background: var(--ai-spark-white) center / 9px no-repeat, linear-gradient(135deg, var(--f4-blue), var(--sig-green-deep));
  box-shadow: 0 0 0 2px var(--surface);
}
/* the legend rides the overview row's right end, so the row keeps its full
   width; in the phone and tablet sheet it drops under the link instead */
.mega-head { position: relative; }
.ai-legend {
  position: absolute; right: var(--space-20); top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; gap: var(--space-10);
  pointer-events: none;
  font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--f4-slate);
}
.ai-legend::before {
  content: ""; flex: none; width: 16px; height: 16px; border-radius: var(--radius-circle);
  background: var(--ai-spark-white) center / 9px no-repeat, linear-gradient(135deg, var(--f4-blue), var(--sig-green-deep));
}
@media (max-width: 1023px) {
  .ai-legend { position: static; transform: none; margin: var(--space-6) 0 var(--space-4); }
}

/* the home hero's layer stack · Saga's tile carries the corner mark, and
   the AI line under the buttons, on the same screen, is its label */
.seqA .layer-row[href="#advises"] .lr-ic::after {
  content: ""; position: absolute; top: -5px; right: -5px;
  width: 16px; height: 16px; border-radius: var(--radius-circle);
  background: var(--ai-spark-white) center / 9px no-repeat, linear-gradient(135deg, var(--f4-blue), var(--sig-green-deep));
  box-shadow: 0 0 0 2px var(--ink-800);
}

/* the system dial · the spark on the advisor's bezel */
.f4dial .sd-ai-bg { fill: var(--ink-800); stroke: url(#sdaig); stroke-width: 1.2; }
.f4dial .sd-ai-spark { fill: url(#sdaig); }
.sd-tab-k .ai-mark { width: 12px; height: 12px; margin-right: var(--space-6); vertical-align: -1px; }

/* Connect & Craft demo · the AI's answer is a draft, dashed, until a person
   approves it; from the approval on it is solid */
.cxs-msg.is-ai {
  position: relative;
  margin-top: var(--space-12);
  padding-top: var(--space-20);
  border-style: dashed;
  border-color: rgb(var(--f4-blue-lift-rgb) / 0.85);
  background: rgb(var(--f4-blue-lift-rgb) / 0.07);
}
.cxs-draft {
  position: absolute; top: -10px; left: var(--space-10);
  display: inline-flex; align-items: center; gap: var(--space-6);
  padding: var(--space-2) var(--space-8);
  border-radius: var(--radius-pill);
  border: 1px solid rgb(var(--f4-blue-lift-rgb) / 0.55);
  background: var(--ink-700);
  font-family: var(--font-mono); font-size: var(--fs-4xs); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--f4-blue-lift);
}
.cxs-draft .ai-mark { width: 11px; height: 11px; }
.cxs-draft .is-approved { display: none; }
[data-beat="3"] .cxs-msg.is-ai, [data-beat="4"] .cxs-msg.is-ai { border-style: solid; }
[data-beat="3"] .cxs-draft .is-draft, [data-beat="4"] .cxs-draft .is-draft { display: none; }
[data-beat="3"] .cxs-draft .is-approved, [data-beat="4"] .cxs-draft .is-approved { display: inline; }
.cxs-okline { display: inline-flex; align-items: center; gap: var(--space-6); }
.cxs-okline::before {
  content: ""; flex: none; width: 13px; height: 13px;
  background: currentColor;
  -webkit-mask: var(--ai-tick) center / contain no-repeat;
          mask: var(--ai-tick) center / contain no-repeat;
}

/* Technology · the security card as the three pillars */
.ai-pillars { list-style: none; margin: var(--space-16) 0 var(--space-14); padding: 0; display: grid; gap: var(--space-14); }
.ai-pillars li { display: grid; grid-template-columns: auto 1fr; gap: var(--space-12); align-items: start; }
.ai-pillars .icon-tile { width: var(--space-36); height: var(--space-36); color: var(--f4-blue-deep); }
.ai-pillars .icon-tile svg { width: 17px; height: 17px; }
.ai-pillars li.is-team .icon-tile { color: var(--sig-green-text); }
.ai-pillars p { margin: 0; }
.ai-pillars b { display: block; font-weight: 600; color: var(--f4-ink); }

/* Control Tower · "Ask", drawn as the product draws Tower AI: a band on a
   still blue-to-green wash, the tower with its spark, and the board it
   drafts from the tower's own charts */
/* the column may shrink below the question's one-line width (it ellipsises) */
.ai-ask-col { min-width: 0; }
.ai-ask { margin: var(--space-28) 0 0; }
.ai-ask-band {
  display: flex; align-items: center; gap: var(--space-12);
  padding: var(--space-12);
  border-radius: var(--radius-card);
  border: 1px solid rgb(var(--f4-blue-rgb) / 0.22);
  background: linear-gradient(135deg, rgb(var(--f4-blue-rgb) / 0.12), rgb(var(--sig-green-rgb) / 0.12)), var(--surface);
  box-shadow: var(--shadow-md);
}
.ai-ask-emb {
  flex: none; display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: var(--radius-btn);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px rgb(var(--f4-blue-rgb) / 0.14);
}
.ai-ask-emb svg { width: 26px; height: 26px; overflow: visible; }
.ai-ask-emb .tw { fill: none; stroke: url(#ctaig); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.ai-ask-emb .tw-f { fill: url(#ctaig); fill-opacity: 0.22; }
.ai-ask-emb .tw-s { fill: url(#ctaig); stroke: none; }
.ai-ask-field {
  flex: 1; min-width: 0; height: 52px;
  display: flex; align-items: center; gap: var(--space-8);
  padding: 0 var(--space-6) 0 var(--space-16);
  border-radius: var(--radius-btn);
  border: 1px solid rgb(var(--f4-blue-rgb) / 0.25);
  background: var(--surface);
  box-shadow: 0 0 0 2px rgb(var(--f4-blue-rgb) / 0.5);
}
.ai-ask-q { flex: 1; min-width: 0; font-size: var(--fs-md); color: var(--f4-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ai-ask-mic {
  flex: none; display: grid; place-items: center;
  width: 36px; height: 36px; border-radius: var(--radius-circle);
  border: 1px solid rgb(var(--f4-blue-rgb) / 0.25);
  color: var(--f4-slate);
}
.ai-ask-mic svg { width: 16px; height: 16px; }
.ai-ask-go {
  flex: none; display: grid; place-items: center;
  height: 38px; padding: 0 var(--space-16); border-radius: var(--radius-sm);
  background: var(--f4-blue-deep); color: var(--surface);
  font-size: var(--fs-base); font-weight: 600;
}
.ai-ask-cards { display: grid; grid-template-columns: 1.15fr 1fr; gap: var(--space-12); margin-top: var(--space-12); }
.ai-ask-card { padding: var(--space-12) var(--space-14); border-radius: var(--radius-btn); border: 1px solid var(--f4-line); background: var(--surface); box-shadow: var(--shadow-sm); }
.ai-ask-k { margin: 0 0 var(--space-6); font-family: var(--font-mono); font-size: var(--fs-3xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--f4-slate); }
.ai-ask-cap { margin: var(--space-6) 0 0; font-family: var(--font-mono); font-size: var(--fs-3xs); color: var(--f4-slate); }
.ai-ask-cm { margin: var(--space-4) 0 0; font-size: var(--fs-base); line-height: var(--lh-ui); color: var(--f4-ink); }
.ai-ask-card svg { display: block; width: 100%; height: auto; }
.ai-ask-card .ab { fill: rgb(var(--f4-slate-rgb) / 0.5); }
.ai-ask-card .ab.is-risk { fill: var(--f4-warn); }
.ai-ask-card .af { fill: none; stroke: var(--f4-blue-deep); stroke-width: 1.6; stroke-dasharray: 4 4; }
.ai-ask-card .ax { stroke: var(--f4-line); }
.ai-ask-card text { font-family: var(--font-mono); font-size: 9.5px; fill: var(--f4-slate); }
.ai-ask-card text.af-t { fill: var(--f4-blue-deep); }
.ai-ask-card text.ab-t { fill: var(--warn-text); font-size: 10px; }
.ai-cardtag { margin: 0 0 var(--space-16); }
@media (max-width: 640px) {
  .ai-ask-cards { grid-template-columns: 1fr; }
  .ai-ask-mic { display: none; }
}
