/* ============================================================================
   TOKENS — the measured design system
   Derived from craft/teardowns/PATTERNS.md. Every value here traces to
   something observed on a benchmark site, not to taste.

   Usage:  <html data-sector="defense|vc|finance|ops|tactile|foundry|ordnance" data-theme="dark|light">
   ========================================================================= */

/* ---------------------------------------------------------------- fonts --
   Three faces per sector, never more: display / body / mono.
   Self-hosted woff2, variable where available. font-display:swap so text
   paints immediately — a FOIT is a layout-shift and an LCP problem.        */

@font-face {
  font-family: 'Archivo';
  src: url('./fonts/archivo-latin-wght-normal.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: 'Instrument Serif';
  src: url('./fonts/instrument-serif-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: 'Newsreader';
  src: url('./fonts/newsreader-latin-opsz-normal.woff2') format('woff2-variations');
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: 'Inter';
  src: url('./fonts/inter-latin-opsz-normal.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('./fonts/space-grotesk-latin-wght-normal.woff2') format('woff2-variations');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('./fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('./fonts/ibm-plex-mono-latin-500-normal.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* --- Metric-compatible fallbacks -----------------------------------------
   Generated by craft/tools/font-metrics.mjs. font-display:swap paints fallback
   text first and re-lays-out when the webfont arrives; on slow 4G that landed
   as a 19px reflow at ~1.5s and measured CLS 0.198 on a spec page. Scaling the
   fallback to the webfont's metrics makes the swap invisible.
   Regenerate these values if a face changes.                                */

@font-face { font-family: 'Space Grotesk Fallback'; src: local('Arial');
  size-adjust: 105.31%; ascent-override: 81.5%; descent-override: 19.9%; line-gap-override: 0%; }
@font-face { font-family: 'Archivo Fallback'; src: local('Arial');
  size-adjust: 99.16%; ascent-override: 95.0%; descent-override: 23.2%; line-gap-override: 0%; }
@font-face { font-family: 'Instrument Serif Fallback'; src: local('Times New Roman');
  size-adjust: 79.05%; ascent-override: 79.6%; descent-override: 19.5%; line-gap-override: 0%; }
@font-face { font-family: 'Newsreader Fallback'; src: local('Times New Roman');
  size-adjust: 111.32%; ascent-override: 102.5%; descent-override: 25.0%; line-gap-override: 0%; }
@font-face { font-family: 'Inter Fallback'; src: local('Arial');
  size-adjust: 97.8%; ascent-override: 85.5%; descent-override: 20.9%; line-gap-override: 0%; }
@font-face { font-family: 'IBM Plex Mono Fallback'; src: local('Courier New');
  size-adjust: 99.98%; ascent-override: 77.6%; descent-override: 19.0%; line-gap-override: 0%; }

:root {
  /* ------------------------------------------------------------ type scale
     PATTERNS.md §2: a tight 1.25 ladder from 14→52px, then ONE jump to a
     display register at 64–120px. Nobody runs a smooth ratio all the way up;
     the display size is a separate register, not the next step.            */

  --step--2: clamp(0.75rem, 0.73rem + 0.09vw, 0.8125rem);   /* 12→13  legal, captions */
  --step--1: clamp(0.8125rem, 0.79rem + 0.11vw, 0.875rem);  /* 13→14  meta, labels */
  --step-0:  clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);      /* 16→17  body */
  --step-1:  clamp(1.1875rem, 1.14rem + 0.24vw, 1.3125rem); /* 19→21  lead paragraph */
  --step-2:  clamp(1.375rem, 1.28rem + 0.47vw, 1.6875rem);  /* 22→27  h4 */
  --step-3:  clamp(1.625rem, 1.46rem + 0.82vw, 2.0625rem);  /* 26→33  h3 */
  --step-4:  clamp(2rem, 1.72rem + 1.4vw, 2.625rem);        /* 32→42  h2 */
  --step-5:  clamp(2.375rem, 1.9rem + 2.37vw, 3.25rem);     /* 38→52  h1 secondary */

  /* the jump. --display-2 is the default hero size.
     The benchmark figures (64 / 88 / 112) are measured at 1440 and are the
     TOP of each curve. The bottom was never measured, and the original slopes
     resolved to ~69px at 390 — wide enough that an eight-letter word could not
     fit the column, so `overflow-wrap` broke the headline mid-word. These
     curves are re-fitted to land at 34 / 40 / 44px at 390 and hit the measured
     figures at 1440. See the wrapping rule on .display below. */
  --display-1: clamp(2.125rem, 1.43rem + 2.86vw, 4rem);     /* 34→64 */
  --display-2: clamp(2.5rem, 1.39rem + 4.57vw, 5.5rem);     /* 40→88  (Greylock 88) */
  --display-3: clamp(2.75rem, 1.17rem + 6.48vw, 7rem);      /* 44→112 (Helsing 112) */
  --display-4: clamp(3.25rem, 0.9rem + 9.4vw, 11.25rem);    /* 52→180 (Ares 131, Albedo 180) */

  /* ------------------------------------------------------------- leading
     PATTERNS.md §1: sub-1.0 leading on large caps display is the single
     clearest amateur/professional tell. Body sits at 1.5.                 */
  --leading-display: 0.95;
  --leading-tight: 1.1;
  --leading-heading: 1.2;
  --leading-body: 1.5;
  --leading-relaxed: 1.65;

  /* ------------------------------------------------------------- tracking
     Optical compensation: large type needs negative tracking, small caps
     and mono need positive. Measured range on benchmarks: -0.6 to -5.9px. */
  --tracking-display: -0.035em;   /* ~-4px at 112px, matches DCVC/Amplify */
  --tracking-heading: -0.02em;
  --tracking-body: 0;
  --tracking-meta: 0.08em;        /* the mono kicker line */
  --tracking-caps: 0.06em;

  /* --------------------------------------------------------------- weight */
  --weight-light: 300;            /* Amplify sets 71px at w300 — reads expensive */
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;

  /* -------------------------------------------------------------- measure
     PATTERNS.md §2: 51–71ch on the good sites; 139–159ch on the bad ones. */
  --measure: 66ch;
  --measure-tight: 46ch;
  --measure-wide: 78ch;

  /* -------------------------------------------------------------- spacing
     4px base, geometric. Section rhythm is the 3xl/4xl range.             */
  --space-3xs: 0.25rem;   /*  4 */
  --space-2xs: 0.5rem;    /*  8 */
  --space-xs:  0.75rem;   /* 12 */
  --space-s:   1rem;      /* 16 */
  --space-m:   1.5rem;    /* 24 */
  --space-l:   2.5rem;    /* 40 */
  --space-xl:  4rem;      /* 64 */
  --space-2xl: 6rem;      /* 96 */
  --space-3xl: clamp(5rem, 3rem + 10vw, 9rem);    /* section padding */
  --space-4xl: clamp(7rem, 3rem + 18vw, 14rem);   /* major section break */

  /* ------------------------------------------------------------ container
     Benchmarks cluster at 1280–1440 content, 1600–1920 full-bleed.        */
  --container: 1280px;
  --container-wide: 1440px;
  --container-narrow: 720px;   /* prose column */
  --gutter: clamp(1.25rem, 0.6rem + 3.2vw, 3rem);
  --grid-columns: 12;

  /* --------------------------------------------------------------- radii
     Institutional work is square. Radius is a consumer-software signal.   */
  --radius-none: 0;
  --radius-sm: 2px;
  --radius-md: 4px;
  --radius-lg: 12px;

  /* -------------------------------------------------------------- motion
     Mirrored in motion.js. THREE INTERACTION durations, three easings, no
     exceptions: anything a user triggers and waits on comes from these.

     --dur-open is deliberately separate and is NOT a fourth interaction
     duration. A cold open is a camera move, not a state change, and it plays
     once on arrival; at 450ms a shutter reads as a glitch rather than a
     reveal. It lived as a hard-coded 1100 in cold-open.js with a 1200
     override in one scene, which is exactly the drift the token rule exists
     to stop, so it is named here and read from the token. Cinematic
     durations belong in this block; they do not belong in the three. */
  --dur-fast: 150ms;
  --dur-base: 250ms;
  --dur-slow: 450ms;
  --dur-open: 1100ms;
  --ease-enter: cubic-bezier(0.16, 1, 0.3, 1);      /* expo-out: decisive arrival */
  --ease-exit: cubic-bezier(0.7, 0, 0.84, 0);       /* expo-in: quick departure */
  --ease-emphasis: cubic-bezier(0.65, 0, 0.35, 1);  /* symmetric: state changes */

  --border-hairline: 1px;
  --z-nav: 100;
  --z-modal: 200;

  /* ----------------------------------------------------- default identity
     These MUST exist at :root. `font-family: var(--font-body)` is declared on
     `body`; if --font-body is only defined inside [data-sector], the property
     is invalid at computed-value time and silently falls back to Times. That
     bug shipped once — every paragraph rendered serif while the theme block
     looked correct. Sector blocks override these; they never introduce them. */
  --font-display: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-body: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', 'IBM Plex Mono Fallback', ui-monospace, 'SF Mono', Menlo, monospace;

  --surface: #ffffff;
  --surface-raised: #f6f6f4;
  --surface-inverse: #101112;
  --ink: #101112;
  --ink-muted: #5f6360;
  --ink-subtle: #8d918e;
  --rule: #e2e2df;
  --accent: #003399;
  --accent-ink: #ffffff;

  --display-case: none;
  --display-tracking: var(--tracking-display);
  --display-leading: var(--leading-display);
  --display-weight: 500;
}

/* A sector scope is self-applying: setting data-sector on ANY element themes
   that subtree, not just the document root. Without this, sector variables
   defined on a <section> would never reach a font-family declaration. */
[data-sector] {
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
}

/* ============================================================================
   SECTOR THEMES
   PATTERNS.md §1. Two neutrals + exactly one saturated accent, every time.
   ========================================================================= */

/* --- DEFENSE-OPERATIONAL — Anduril / Helsing / Saildrone ------------------

   SCENE: Night range under floodlight. A black field with real hardware in it,
   captioned like instrumentation, where the only colour is the one thing you
   are meant to act on.

   ACCENT MEANS: the single primary action, and live/alert status. Never
   decoration, never a second time in the same viewport.
   SIGNATURE MOVE: caps display at 0.92 leading so the headline reads as a
   machined block rather than a sentence, with a mono telemetry line above it.
   TENSION: documentary imagery (messy, real) against absolutely rigid type.
                                                                           */
[data-sector='defense'] {
  --font-display: 'Archivo', 'Archivo Fallback', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'IBM Plex Mono', 'IBM Plex Mono Fallback', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Void          */ --surface: #000000;          /* the ground everything is measured against */
  /* Gun Metal     */ --surface-raised: #0b0d0e;   /* one step up: nav wells, media plates */
  /* Bone          */ --surface-inverse: #f1f0ea;  /* the light break band — used once or twice a page */
  /* Floodlight    */ --ink: #ffffff;              /* headlines, primary copy, the dominant foreground */
  /* Gunsmoke      */ --ink-muted: #8e9291;        /* captions, spec labels, nav at rest — recedes on purpose */
  /* Cold Ash      */ --ink-subtle: #8b918f;       /* legal, footnotes — the quietest voice that still passes AA */
  /* Hairline      */ --rule: #24272a;             /* dividers only; visible at edges, never as a box */
  /* Signal Orange */ --accent: #ff5000;           /* the one action, and live status. Nothing else. */
                     --accent-ink: #000000;

  --display-case: uppercase;
  --display-tracking: -0.03em;
  --display-leading: 0.92;      /* Anduril's typographic mass */
  --display-weight: 600;
}

/* --- VC-EDITORIAL — Greylock / Radical / DCVC ----------------------------

   SCENE: A quiet reading room in late afternoon. Warm paper, one saturated
   ink, and enough empty wall that the single idea on it has to be worth the
   space.

   ACCENT MEANS: the thesis itself — the headline, and the one link that leads
   further into the firm's thinking. Never a button colour by default.
   SIGNATURE MOVE: a serif display at 88px carrying the accent, centred, with
   nothing else competing in the fold.
   TENSION: literary, almost soft language set with severe typographic control.
                                                                           */
[data-sector='vc'] {
  --font-display: 'Instrument Serif', 'Instrument Serif Fallback', Georgia, serif;
  --font-body: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'IBM Plex Mono', 'IBM Plex Mono Fallback', ui-monospace, monospace;

  /* Warm Paper    */ --surface: #ededed;          /* measured on Greylock — never pure white */
  /* Fresh Sheet   */ --surface-raised: #f7f7f5;   /* cards and raised panels, a half-tone lighter */
  /* Night Study   */ --surface-inverse: #16191e;  /* the inverted band, used sparingly */
  /* Walnut Ink    */ --ink: #2d2d24;              /* body and headings — warm black, not neutral */
  /* Pencil        */ --ink-muted: #6b6b62;        /* meta lines, captions, nav at rest */
  /* Faded Pencil  */ --ink-subtle: #63635c;       /* disclosures and footnotes — light-on-light fails easily, this is the floor */
  /* Rule          */ --rule: #d6d6d2;             /* hairlines under rows; no boxes */
  /* Thesis Blue   */ --accent: #003399;           /* Greylock blue: the idea, and the way further in */
                     --accent-ink: #ffffff;

  --display-case: none;
  --display-tracking: -0.02em;
  --display-leading: 1.02;
  --display-weight: 400;
}

/* --- FINANCE-INSTITUTIONAL — Fifth Wall done properly ---------------------
   PATTERNS.md §1C: the weakest register in the benchmark corpus, so a
   disciplined execution outperforms firms fifty times the size.

   SCENE: A private office with the blinds half drawn. Cream paper, deep green
   baize, brass fittings — old money that keeps its records properly.

   ACCENT MEANS: a figure that carries risk. Negative performance, and the one
   action a visitor is invited to take. Brass, never gold; quiet, never loud.
   SIGNATURE MOVE: a high-contrast serif over tabular figures with stacked
   decimals — the numbers do the persuading, the type says who is speaking.
   TENSION: warm, almost domestic colour under completely unsentimental data.
                                                                           */
[data-sector='finance'] {
  --font-display: 'Newsreader', 'Newsreader Fallback', Georgia, serif;
  --font-body: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'IBM Plex Mono', 'IBM Plex Mono Fallback', ui-monospace, monospace;

  /* Ledger Cream  */ --surface: #f3ebd2;          /* Fifth Wall cream — the page is paper, not screen */
  /* Fresh Ledger  */ --surface-raised: #ffffff;   /* tables and cards lift by going whiter, not by shadow */
  /* Baize Green   */ --surface-inverse: #1a3930;  /* the inverted band and the footer */
  /* Baize Ink     */ --ink: #1a3930;              /* headings and body — the green reads as black at text size */
  /* Slate Muted   */ --ink-muted: #55665f;        /* column headers, captions, meta */
  /* Slate Faint   */ --ink-subtle: #5a6a63;       /* disclosures and methodology notes */
  /* Ledger Rule   */ --rule: #d8d0b8;             /* row hairlines only — no vertical rules in tables, ever */
  /* Brass         */ --accent: #7a5323;           /* risk-bearing figures and the one invited action */
  /* Darkened from #9a6a2f, which was 3.93:1 on cream and failed AA on 14px accent
     text. Now 5.8:1, and 6.8:1 against white when used as a button fill. */
  --accent-ink: #ffffff;

  --display-case: none;
  --display-tracking: -0.015em;
  --display-leading: 1.05;
  --display-weight: 400;
}

/* --- OPS-CONSOLE — instrumentation over a distributed network -------------
   For software that watches or coordinates physical operations. Adjacent to
   the defense register but colder and bluer: this is a screen you sit in front
   of at 0200, not a field you stand in.

   SCENE: A darkened operations floor at 0200. Cold blue instrumentation over a
   continent of nodes, every route lit and accounted for, and the only warm
   light is a gate that has not been signed.

   ACCENT MEANS: an exception in the chain. A gate unsigned, a route at risk, a
   node at capacity. Cold blue is nominal; warm is the thing that needs you.
   Never used for emphasis, decoration, or a second CTA.
   SIGNATURE MOVE: the console is the hero. A live node-and-route constellation
   with one amber exception, captioned in mono like real instrumentation.
   TENSION: an anxious subject — fragmented supply chains, broken chains of
   custody — rendered in a completely unhurried, orderly interface.
                                                                           */
[data-sector='ops'] {
  /* Space Grotesk is the client's existing display face and is more
     characterful than the system default — a licensed or already-owned face
     always beats a neutral fallback. Self-hosted, subset, 22KB. */
  --font-display: 'Space Grotesk', 'Space Grotesk Fallback', 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'IBM Plex Mono', 'IBM Plex Mono Fallback', ui-monospace, monospace;

  /* Deep Watch    */ --surface: #05080e;          /* the room: blue-black, never neutral black */
  /* Console Well  */ --surface-raised: #0b111b;   /* panels, cards, table wells — one step toward the light */
  /* Daylight Brief*/ --surface-inverse: #e8edf2;  /* the one light band, used once a page at most */
  /* Instrument    */ --ink: #e6eef6;              /* primary readout — cool white, never pure */
  /* Standby       */ --ink-muted: #8ba3b8;        /* labels, units, column heads — reads at a glance, recedes on purpose */
  /* Offwatch      */ --ink-subtle: #6d879e;       /* legal, footnotes, sample-data disclaimers */
  /* Grid Line     */ --rule: #1c2836;             /* hairlines and panel edges; the graticule, not a box */
  /* Exception     */ --accent: #ff8a1f;           /* an unsigned gate, a route at risk. One per viewport. */
                     --accent-ink: #05080e;
  /* Nominal       */ --signal: #7fc9e8;           /* live routes, healthy nodes, in-band telemetry */

  /* The inversion — "the console is dark, the record is on paper."
     Neither instrument colour can cross onto the light ground: measured against
     Daylight Brief #e8edf2, Exception Amber lands at 2.00:1 and Nominal at
     1.56:1, both hard fails. A screen colour is not a document colour, so the
     paper gets its own pair, and both are checked rather than eyeballed. */
  /* Document Slate*/ --invert-muted: #3d4f60;     /* meta, node names and column heads ON PAPER — 7.17:1 */
  /* Stamp Rust    */ --invert-accent: #9a4a06;    /* the held gate, once, ON PAPER — 5.31:1. The amber's paper equivalent */

  /* Sentence case at 0.98 was the register's original setting and it read as
     consumer SaaS — the one thing an export-controlled production network
     cannot afford to look like. Caps at 0.92 is Anduril's typographic mass, and
     with no descenders in play the tighter leading is safe. Keep headlines
     short enough to survive it; the long checkable claim belongs in the lead. */
  --display-case: uppercase;
  --display-tracking: -0.03em;
  --display-leading: 0.92;      /* Anduril's mass. Four of the strongest sites in the corpus sit sub-1.0 */
  --display-weight: 500;
}

/* --- PRODUCT-TACTILE — Atlas Motion --------------------------------------

   The register was defined in teardowns/atlas-motion.md and CLAUDE.md, and
   until now had no tokens — so every hardware build was reaching for
   'defense' and getting a blue-black control room instead of a workshop.

   SCENE: A gloved hand under a work lamp. Warm bone type over a warm
   near-black, a macro lens on a real motor at shallow depth of field, and a
   fine measurement graticule laid over everything as if the whole viewport
   were a drawing.

   ACCENT MEANS: **this is the part we are talking about.** Measured off the
   exploded assembly at atlasmotion.com, where the stator windings light
   magenta on exactly the chapter that discusses them. It is a pointer, not an
   action colour and not a status colour — which makes it the only accent in
   the system whose job is deixis. One part, one viewport.
   SIGNATURE MOVE: type overlaps the object and the object wins.
   TENSION: romantic landscape painting against hard engineering line work —
   see teardowns/atlas-motion-narrative.md, the painted→drawn→photographed ramp.
                                                                           */
[data-sector='tactile'] {
  /* ONE family, doing all three jobs. Atlas runs Suisse Int'l at a single
     weight with no second face and no mono counter-voice, and the photography
     carries all the variety the page needs. Archivo is the closest
     neo-grotesque we have licensed. Figures stay aligned through
     font-variant-numeric: tabular-nums, not through a monospace face —
     so --font-mono deliberately resolves to the same family. A real
     engagement should licence a display face; see CLAUDE.md carry-forwards. */
  --font-display: 'Archivo', 'Archivo Fallback', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Archivo', 'Archivo Fallback', 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'Archivo', 'Archivo Fallback', 'Helvetica Neue', Arial, sans-serif;

  /* Workshop Black*/ --surface: #181818;          /* WARM near-black. Every defense site reaches for blue-black; this is tungsten, not a control room. */
  /* Bench Shadow  */ --surface-raised: #212020;   /* plates, nav wells, spec panels — one step toward the lamp */
  /* Bone Sheet    */ --surface-inverse: #eee8e8;  /* the light break band, once a page */
  /* Bone          */ --ink: #eee8e8;              /* headlines and body alike — 14.7:1 */
  /* Machined Grey */ --ink-muted: #bbbbbb;        /* captions, spec labels, nav at rest — 9.3:1 */
  /* Cold Bone     */ --ink-subtle: #8f8f88;       /* legal and footnotes — 5.5:1, the floor */
  /* Graticule     */ --rule: #2e2e2c;             /* the measurement overlay and hairline boxes; never a filled box */
  /* Winding Magenta */ --accent: #fe6ca5;         /* THE PART UNDER DISCUSSION. Sampled off the lit stator windings. 7.4:1 */
                     --accent-ink: #181818;

  --display-case: uppercase;
  --display-tracking: -0.03em;
  --display-leading: 0.906;     /* measured. Four of the strongest sites in the corpus now sit sub-1.0 */
  --display-weight: 500;
}

[data-sector='foundry'] {
  /* DEFENSE-OPERATIONAL ON A WARM GROUND.

     The sector is uniformly blue-black, and blue-black says control room. This
     client's subject is the qualified shop floor, so the ground is tungsten:
     the same warm near-black the tactile register uses, because that decision
     was right and there is no reason to re-derive it.

     Where this parts company with tactile is the second face. Tactile runs ONE
     family and lets photography carry the variety, which is correct when the
     page is photography. This page is photography WITH INSTRUMENTATION OVER IT:
     serials, gate states, node IDs, tolerances, leader-line readings. A mono
     metadata line is the signature move of the defense-operational register,
     and drawing conventions need figures that sit in columns. So a real
     monospace comes back, with a job. */
  --font-display: 'Archivo', 'Archivo Fallback', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Archivo', 'Archivo Fallback', 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  /* Workshop Black  */ --surface: #181818;         /* the shop at shift change. Tungsten, not a control room */
  /* Bench Shadow    */ --surface-raised: #212020;  /* panels, wells, spec plates, one step toward the lamp */
  /* Traveler Bone   */ --surface-inverse: #eee8e8; /* THE PAPER GROUND. The record, and the only inversion on the page */
  /* Instrument Bone */ --ink: #eee8e8;             /* headlines and body alike, 14.7:1 */
  /* Machined Grey   */ --ink-muted: #bbbbbb;       /* captions, callout labels, column heads, 9.3:1 */
  /* Cold Bone       */ --ink-subtle: #8f8f88;      /* legal, footnotes, sample-data disclaimers, 5.5:1, the floor */
  /* Graticule       */ --rule: #2e2e2c;            /* the measurement overlay, title block rules, leader hairlines */

  /* Exception Amber. RESERVED for a break in the chain: a gate unsigned, a
     route blocked, a node at capacity. Never a CTA fill, never a hover, never
     decoration, and never twice in one viewport. 7.5:1 on Workshop Black. */
  /* Exception Amber */ --accent: #ff8a1f;
                        --accent-ink: #181818;

  /* Nominal Cyan. The other half of the rule: COLD IS NOMINAL, WARM IS THE
     THING THAT NEEDS YOU. Live routes, healthy nodes, in-band readings, and
     the leader lines that are merely pointing rather than warning. 9.7:1. */
  /* Nominal Cyan    */ --signal: #7fc9e8;

  --display-case: uppercase;
  --display-tracking: -0.03em;
  --display-leading: 0.906;
  --display-weight: 500;
}

/* Atlas's own muted ink is rgba(204,203,189,.5) over #181818, which composites
   to roughly 3.6:1 and fails AA — one of the 5 contrast failures axe finds on
   their home page. --ink-subtle above is the nearest value that passes. This
   is the register's stated bar: as good as Atlas AND actually usable. */

/* Inverted sections: every theme needs a dark/light counterpart block.
   --invert-ink / --invert-bg mirror the pair so controls inside the band can
   resolve their own colours. Without them, .button kept `color: var(--ink)`
   — white — and rendered white text on the cream inverse ground. That is a
   WCAG hard fail, and it shipped. See the control overrides in components.css. */
[data-invert] {
  background: var(--surface-inverse);
  color: var(--surface);
  --invert-bg: var(--surface-inverse);
  --invert-ink: var(--surface);
}

/* --invert-muted: the SECOND half of the same bug the block above fixed.

   .kicker, .legal, .note and friends set an explicit `color: var(--ink-muted)`
   / `var(--ink-subtle)`. Those two are tuned to sit just above AA on the
   register's normal ground — so the moment they appear inside an inverted band
   they are being measured against the opposite surface and fall through the
   floor. Measured on a client's traveler section: 2.22:1 and 3.17:1, both
   serious axe violations, on a band that otherwise looked completely fine.

   Every register therefore declares a muted value for its inverse, and every
   one is measured rather than eyeballed. Ratios in the comments. */

/* --- ORDNANCE-DOCUMENT — ELAH ---------------------------------------------

   SCENE: An ammunition data card at first light, printed in olive drab and
   stencil. Every figure on it is a real firing table, and the only yellow on
   the page is the band that means the round is live.

   WHY A SEVENTH REGISTER, when defense-operational already exists and is the
   obvious fit for a counter-UAS company:

   Because it is TOO obvious. PATTERNS.md section 1 opens with the warning that
   near-black plus exactly one hot accent is one of the three looks AI design
   defaults to, and it is simultaneously what Anduril, Helsing, Saildrone,
   Capella, Tekever and Silvus all already look like. A new company arriving in
   that palette reads as the fourteenth entry in a category, and reads as
   generated. The brief left this axis open, and the warning's own rule is not
   to spend a free axis on a default.

   So the palette is not chosen, it is SPECIFIED. MIL-STD-709D: high explosive
   ammunition is an olive drab body with a yellow marking band. The ground is
   the body of the round and the page is printed on it.

   ACCENT MEANS: high explosive. It touches the live round, the warhead, and
   the one action. Nothing else, ever. On this client's page there is one whole
   scene with no accent anywhere in it, because at that point in the story
   nothing of theirs is in the air yet.

   TWO ACCENTS, ONE JOB EACH. Measured off Ares, which runs mint on instrument
   furniture and brand red once on the mark, and lets neither drift into
   decoration. A single accent could not do both jobs here: yellow means high
   explosive, so it cannot also draw a graticule, and with no second colour the
   instrument layer simply vanished. Reticle is that second colour. It touches
   the graticule, tick marks, leader lines and readout labels. IT NEVER TOUCHES
   CONTENT.

   TRACKING, AND A CORRECTION. The first draft ran POSITIVE display tracking on
   the theory that ordnance lettering is sprayed through a template and opens
   up. As a differentiator that was real; as typography it was a mistake, and
   the Ares teardown names why. An extra wide grotesque stretched across a full
   viewport is what makes a headline read as a BANNER rather than as a heading,
   and letterspacing a normal width face apart does the exact opposite: it
   removes mass. Measured, the first fold's h1 occupied 31 percent of the
   viewport width.

   So the stencil character moves to where ordnance lettering actually lives:
   the MONO layer, at +0.08em, on data card fields, kickers and every figure.
   The display face gets negative tracking and 0.86 leading and is sized to span
   the viewport, which is how it earns its mass.

   TENSION: the most violent object in the corpus, presented with the flat
   clerical calm of a supply document.                                        */
[data-sector='ordnance'] {
  --font-display: 'Archivo', 'Archivo Fallback', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'IBM Plex Mono', 'IBM Plex Mono Fallback', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Olive Drab   */ --surface: #2e3126;          /* the body of the round. MIL-STD-709D, HE */
  /* Crate        */ --surface-raised: #383b2e;   /* panels, wells, spec plates — one step up */
  /* Card Stock   */ --surface-inverse: #e6e0cc;  /* THE DATA CARD. The printed record, once a page */
  /* Stencil      */ --ink: #f2f0e4;              /* headlines and body — 11.59:1 */
  /* Worn Stencil */ --ink-muted: #bdbba6;        /* field labels, captions, annotations — 6.83:1 base, 5.90:1 raised */
  /* Faded Stencil*/ --ink-subtle: #a6a592;       /* legal, footnotes, concept disclaimers — 5.32:1 base, 4.59:1 RAISED, the floor */

  /* Both muted inks are tuned against --surface-raised, not --surface, and the
     first draft was not: ink-subtle measured 4.60:1 on the ground and 3.97:1
     the moment it sat on a panel. That is the same failure START-HERE section 8
     records as having shipped once. The binding constraint is the LIGHTEST
     surface a muted ink can land on, so both are set from the panel and the
     ramp is re-opened to keep two distinguishable steps. */
  /* Scribe Line  */ --rule: #4a4e3b;             /* title blocks, dotted leaders, the graticule; never a filled box */
  /* HE Yellow    */ --accent: #f0c420;           /* HIGH EXPLOSIVE. The live round, the warhead, the one action. 7.97:1 */
                     --accent-ink: #2e3126;       /* 7.97:1 the other way */
  /* Reticle      */ --instrument: #7cbcab;       /* INSTRUMENT FURNITURE ONLY. 6.06:1 */

  /* On a tactical display red means hostile and nothing else, so the threat
     colour cannot be borrowed from the accent — HE Yellow already means "our
     live round". It splits in two because one value cannot do both jobs:
     Track Red is the MARK (icon strokes, the alert rule, the pulsing dot) at
     4.73:1 on --surface and 4.09:1 on --surface-raised, which is fine for a
     graphic and for display type at 3:1 but NOT for small text; Track Ink is
     what small text actually uses, 7.74:1 base and 6.68:1 raised. Put mono
     telemetry on Track Ink. Reserve Track Red for strokes, fills and headline
     display type. */
  /* Track Red    */ --hostile: #ff6b57;
  /* Track Ink    */ --hostile-ink: #ffb3a6;

  --display-case: uppercase;
  --display-tracking: -0.045em;  /* NEGATIVE. See the note below. */
  --display-leading: 0.86;
  --display-weight: 600;
}

[data-sector='defense'] [data-invert], [data-sector='defense'][data-invert] { --invert-muted: #54574f; }  /* 6.45:1 on #f1f0ea */
[data-sector='vc']      [data-invert] { --invert-muted: #a8aaa5; }  /* 7.52:1 on #16191e */
[data-sector='finance'] [data-invert], [data-sector='finance'][data-invert] { --invert-muted: #a9bdb4; }  /* 6.36:1 on #1a3930 */
[data-sector='tactile'] [data-invert], [data-sector='tactile'][data-invert] { --invert-muted: #645f5f; }  /* 5.19:1 on #eee8e8 */
[data-sector='ordnance'] [data-invert], [data-sector='ordnance'][data-invert] { --invert-muted: #5c6047;  /* 5.03:1 on #e6e0cc */
  /* Stamp Ochre: HE Yellow on card stock is 1.26:1 and simply cannot be read.
     The live-round marking still has to appear on the printed card, so the
     accent gets a paper equivalent, the way an ink stamp differs from paint. */
  --invert-accent: #7a5a06; }                                      /* 4.89:1 */
[data-sector='foundry'] [data-invert], [data-sector='foundry'][data-invert] { --invert-muted: #645f5f;    /* 5.19:1 on #eee8e8 */
  /* Stamp Rust: Exception Amber has no business on paper, where it drops to
     2.1:1 and stops being readable at all. The held gate still has to show
     on the traveler, so the accent gets a paper equivalent. 5.17:1. */
  --invert-accent: #9a4a06; }
/* ops declares its own pair up in the register block (Document Slate / Stamp Rust). */

[data-invert] .kicker,
[data-invert] .legal,
[data-invert] .note,
[data-invert] .footnote,
[data-invert] .small,
[data-invert] figcaption,
[data-invert] caption { color: var(--invert-muted, var(--invert-ink)); }
[data-sector='defense'] [data-invert], [data-sector='defense'][data-invert] { color: #16181a; --invert-ink: #16181a; }
[data-sector='tactile'] [data-invert], [data-sector='tactile'][data-invert] { color: #181818; --invert-ink: #181818; }
[data-sector='foundry'] [data-invert], [data-sector='foundry'][data-invert] { color: #181818; --invert-ink: #181818; }
[data-sector='ordnance'] [data-invert], [data-sector='ordnance'][data-invert] { color: #23261c; --invert-ink: #23261c; }  /* 11.64:1 on card stock */
[data-sector='vc'] [data-invert], [data-sector='vc'][data-invert],
[data-sector='finance'] [data-invert], [data-sector='finance'][data-invert] { color: #f4f3ef; --invert-ink: #f4f3ef; }

/* ============================================================================
   BASE
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--leading-body);
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* PATTERNS.md §0: zero of 26 benchmarks do this. It is our differentiator. */
  font-variant-numeric: tabular-nums;
}

img, picture, video, canvas, svg { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
/* Browsers apply a smaller default size to the generic `monospace` family, so
   inline <code> silently renders ~15% below its inherited size. Reset it. */
code, kbd, samp, pre { font-family: var(--font-mono); font-size: 1em; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }

/* ------------------------------------------------------------- typography */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-heading);
  text-wrap: balance;
}

h1 { font-size: var(--step-5); }
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-3); }
h4 { font-size: var(--step-2); font-family: var(--font-body); font-weight: var(--weight-semibold); }

p { max-width: var(--measure); text-wrap: pretty; }

/* The hero headline. Its own register — see PATTERNS.md §2. */
.display {
  font-family: var(--font-display);
  font-size: var(--display-2);
  font-weight: var(--display-weight);
  line-height: var(--display-leading);
  letter-spacing: var(--display-tracking);
  text-transform: var(--display-case);
  text-wrap: balance;
  max-width: 18ch;
  /* Never break a display headline mid-word. The generic heading rule sets
     overflow-wrap:break-word, which silently produced "COVERAG / E" at the
     hero size on a 390px screen. If a word genuinely cannot fit, the right
     outcome is a loud horizontal overflow that verify.mjs fails on — not a
     hyphen-less break shipped to the client. */
  overflow-wrap: normal;
  word-break: normal;
}
.display--xl { font-size: var(--display-3); }
.display--2xl { font-size: var(--display-4); max-width: none; line-height: 0.9; }
.display--sm { font-size: var(--display-1); }
.display--light { font-weight: var(--weight-light); }  /* the Amplify move */

/* The mono kicker. PATTERNS.md §1A — the signature defense/technical move.
   Saildrone: | THE OCEAN IS CONTESTED. PERSISTENCE WINS. |                */
.kicker {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 400;
  letter-spacing: var(--tracking-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
  display: flex;
  /* A kicker that wraps to two lines centred its accent bar against the whole
     block, leaving the mark floating beside the second line. Pin it to the
     first line instead. */
  align-items: flex-start;
  gap: var(--space-xs);
}
.kicker::before {
  content: '';
  width: 2px;
  height: 1em;
  margin-block-start: 0.25em;
  background: var(--accent);
  flex: none;
}

.lead { font-size: var(--step-1); line-height: var(--leading-relaxed); max-width: var(--measure-tight); }
.meta { font-family: var(--font-mono); font-size: var(--step--1); letter-spacing: var(--tracking-meta); text-transform: uppercase; color: var(--ink-muted); max-width: var(--measure-wide); }
.small { font-size: var(--step--1); color: var(--ink-muted); max-width: var(--measure-wide); }
.legal { font-size: var(--step--2); color: var(--ink-subtle); line-height: var(--leading-body); max-width: var(--measure-wide); }

/* Every text-bearing class carries its own measure ceiling. Learned the hard way:
   the drill that criticised Silvus for a 159ch measure shipped at 158ch, because
   the constraint lived on `p` alone and every helper class escaped it. */
.kicker, .footnote, .note, figcaption, caption, blockquote, li { max-width: var(--measure-wide); }
li { max-width: var(--measure); }

/* Figures. The whole reason tabular-nums exists. */
.figure {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'zero' 1;
}
.figure--display {
  font-family: var(--font-display);
  font-size: var(--step-5);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* ------------------------------------------------------------------ layout */

.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }
.container--wide { max-width: var(--container-wide); }
.container--narrow { max-width: var(--container-narrow); }

.section { padding-block: var(--space-3xl); }
.section--major { padding-block: var(--space-4xl); }
.section--flush { padding-block: 0; }

.grid { display: grid; grid-template-columns: repeat(var(--grid-columns), minmax(0, 1fr)); gap: var(--gutter); }
.stack > * + * { margin-block-start: var(--flow, var(--space-m)); }
.cluster { display: flex; flex-wrap: wrap; gap: var(--space-s); align-items: center; }

.rule { border: 0; border-top: var(--border-hairline) solid var(--rule); }

/* --------------------------------------------------------------- controls */

.button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-xs) var(--space-m);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-meta);
  text-transform: uppercase;
  text-decoration: none;
  border: var(--border-hairline) solid currentColor;
  border-radius: var(--radius-none);
  color: var(--ink);
  background: transparent;
  cursor: pointer;
  transition: background var(--dur-base) var(--ease-emphasis),
              color var(--dur-base) var(--ease-emphasis);
}
.button:hover { background: var(--ink); color: var(--surface); }
.button--accent { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.button--accent:hover { background: transparent; color: var(--accent); }

/* The quiet second action. A fold that offers two buttons of equal weight has
   not answered "what to do next", it has asked the visitor to classify
   themselves first. One button plus this keeps the second route available
   without competing for the same glance. Same mono furniture as .button so it
   reads as a control, underlined so it reads as a link, and --ink-muted rather
   than a lower opacity because --ink-muted sits exactly at AA and anything
   layered on top drops it under. */
.link-quiet {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding-block: var(--space-xs);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
  text-decoration: underline;
  text-underline-offset: 0.35em;
  transition: color var(--dur-base) var(--ease-emphasis);
}
.link-quiet:hover { color: var(--ink); }

a { color: inherit; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }

/* Focus: visible, never removed. Rubric hard fail if missing. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* -------------------------------------------------------------- utilities */

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; top: 0; left: 0; padding: var(--space-s) var(--space-m);
  background: var(--accent); color: var(--accent-ink); z-index: var(--z-modal);
  transform: translateY(-120%);
}
.skip-link:focus { transform: translateY(0); }

/* Reveal targets start hidden in CSS, gated on [data-js] set by an inline head
   script. Letting GSAP hide them after first paint means the browser paints
   them, then removes them — a layout shift attributable to our own animation.
   Gated on data-js so a page whose JS never runs still shows all its content. */
[data-js] [data-reveal] { opacity: 0; }

/* Reduced motion, handled once, at the system level. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
