/*
 * COMPILED ARTIFACT, generated by build/build-styles.mjs. Do not hand-edit.
 * This is the single stylesheet consumers link. It is the modular sources under
 * tokens/ and parts/ concatenated in cascade order. To change it, edit the
 * sources and/or build/styles.manifest.css (the import order), then regenerate:
 *   cd build && npm run build:styles
 * Sources of truth: tokens/*.css, parts/*.css, ordered by build/styles.manifest.css.
 * Concatenated (not @import-ed) so an HTTP-served page makes one request instead
 * of an @import round-trip waterfall; file:// is unaffected either way.
 */

/* ===== tokens/colors.css ===== */
/* Foundational — Color tokens
   Near-black ink on cool near-white paper. ONE selective accent (signal),
   reserved for live / now / recommended wayfinding ONLY.
   Status colors are muted + harmonized; a chip always pairs a dot with a WORD. */

/* scrollbar-width is not inherited. Like a box-sizing reset, this universal
   choke point means every future scroll well is born thin. */
* { scrollbar-width: thin; }

:root {
  /* color-scheme names which NATIVE-UI palette the browser paints — scrollbars,
     form controls, the default focus outline. Native UI ignores our tokens, so
     without this a dark page still paints the browser-default BRIGHT scrollbar,
     the loudest thing on an otherwise calm dark surface. Declared explicitly on
     BOTH sides (light here; dark in each dark path below) so native UI follows
     the theme rather than the reader's OS. */
  color-scheme: light;

  /* scrollbar-color is inherited, so this one root declaration reaches every
     scroller, including the viewport. var() re-resolves per theme, so dark needs
     no twin. color-scheme remains the native floor for engines that ignore CSS
     scrollbar properties. */
  scrollbar-color: var(--line-2) transparent;

  /* Ink ramp — text on paper, darkest to faintest.
     Neutral GRAPHITE ink: a whisper of cool, no navy, never pure black.
     Reads as refined printed ink rather than a saturated screen dark. */
  --ink:      #272a2e; /* primary headings, strongest text */
  --ink-2:    #454952; /* secondary headings, strong body */
  --body:     #636a73; /* default body copy */
  --mut:      #686e77; /* muted / supporting text — meets WCAG AA on paper (4.53) and panel (5.14) */
  --faint:    #aeb2b9; /* faintest text, disabled, hairline labels */

  /* Surfaces — cool near-white paper, white panels, hairlines */
  --paper:    #eef1f3; /* page background, cool near-white (future paper) */
  --panel:    #ffffff; /* flat content card / pane */
  --well:     #e8ecef; /* subordinate island set INTO the flow: code, figure media, callout. Recessed a touch below paper, no shadow (a panel lifts, a well recedes). Holds strong / body / code text at WCAG AA (ink-2 7.6, body 4.6); muted text stays on paper/panel, not here. */
  --line:     #e3e6ea; /* hairline border, default */
  --line-2:   #d5d9df; /* stronger hairline, dividers */
  --line-fine:#edf0f3; /* finer/lighter hairline for schematic rules */
  --scrim:    rgba(20, 21, 26, 0.46); /* dimming wash behind an overlay; theme-aware (dark gets a pure-black, higher-alpha override) */
  --tick:     #c7ccd3; /* minor ruler ticks */
  --tick-2:   #adb2ba; /* major ruler ticks */
  /* Event-marker drop-line colour — the quiet vertical a bar-chart annotation
     drops from its word to the bar it marks. A dedicated semantic name (not a raw
     --line). RF's intent for this indicator, verbatim, is "a very faint thin line";
     the meaning is carried by the WORD directly above it (colour is never alone), so
     the line stays a faint position tick, never a high-contrast rule. Aliased to
     --tick-2, the chart's own MAJOR-RULER-TICK strength (#adb2ba light / #565d66
     dark), so an event marker reads as one of the chart's quiet ruler lines, at home
     with the axis and grid rather than louder than them. It is faintest where it
     matters least (over a filled bar) and clearest over the open plot ground above
     the bar, exactly where the eye picks up the drop from the word. A single flat
     token cannot ALSO clear WCAG's 3:1 non-text floor over every possible bar fill;
     that floor does not bind here because the line conveys no information on its own
     (the word and the screen-reader summary carry the event), so honouring RF's
     faint-hairline intent is correct over forcing a heavier mark. Re-resolves per
     theme and in print (--tick-2 restates in the forced light palette). */
  --chart-mark: var(--tick-2);

  /* Signal accent — Cabin navy. LIVE / NOW / RECOMMENDED wayfinding only.
     Never a status. Never a content fill. */
  --signal:      #294a78; /* primary accent — navy with gravitas */
  --signal-deep: #1d3458; /* pressed / deep accent */
  --signal-soft: #eaedf3; /* faint accent wash (active row, selected) */
  --signal-line: #c6cfe0; /* accent hairline */

  /* Keyboard-focus ring — system-wide :focus-visible colour. Derived from
     --signal so it stays in the one accent family; calm but clearly visible.
     Use as: outline: 2px solid var(--focus); outline-offset: 2px. */
  --focus: color-mix(in srgb, var(--signal) 70%, transparent);

  /* Status — cleared / sage green */
  --ok-ink:  #3f5e4d;
  --ok-bg:   #eaeeeb;
  --ok-line: #d4ddd6;
  --ok-dot:  #5e8468;

  /* Status — in progress / muted ochre (warm, but chroma held to sage's level
     so it never reads as candy amber). */
  --warn-ink:  #7a611c;
  --warn-bg:   #efeae1;
  --warn-line: #ddd5c4;
  --warn-dot:  #9b8350;

  /* Status — blocked / muted clay (warm-red dialled back to the one muted level) */
  --blk-ink:  #74463b;
  --blk-bg:   #efe7e3;
  --blk-line: #ddccc6;
  --blk-dot:  #9f6356;

  /* Status — not started / cool stone (clearly neutral). Ink darkened from
     #6f7177 so the small "not started" word and the journey process kicker
     clear WCAG AA on their own --na-bg tint (was 4.06, now 5.16). */
  --na-ink:  #5f6166;
  --na-bg:   #eceae6;
  --na-line: #d9d7cf;
  --na-dot:  #abb0b4;

  /* Live-state beacon — the status triad for the static status indicator. A notch livelier than the muted chip dots on purpose:
     these are the existing Now-word variants. Still held off candy so it
     sits in the same calm family as the chip dots, never out-shouting --signal. */
  --state-ok:   #538d66; /* healthy / on track */
  --state-warn: #a88948; /* waiting / in progress */
  --state-blk:  #a85348; /* needs action now */

  /* Data-series ramp — a navy-to-faint sequence for share/stacked composition
     only (never status). Anchored on --signal so it stays in the one accent family. */
  --data-1: var(--signal);
  --data-2: #7a8fab;
  --data-3: #a9b7c9;
  --data-4: #d0d7e1;

  /* Semantic aliases — the names a few components happen to read; not a
     preferred layer. Most components read the raw ramp directly. */
  --text-body:    var(--body);
  --text-muted:   var(--mut);
  /* --text-faint is the alias that VISIBLE faint-weight labels read (kickers,
     column heads, measure captions). It must clear WCAG AA, so it resolves to
     --mut (5.14 light / 4.58 dark on panel), NOT the raw --faint (2.12 light /
     2.58 dark — fails AA). --faint stays for genuinely non-text or disabled
     uses only (placeholders, disabled caret/knob, the data-ramp tail). */
  --text-faint:   var(--mut);

  --surface-page:  var(--paper);

  --accent:        var(--signal);
  --accent-deep:   var(--signal-deep);
  --accent-line:   var(--signal-line);
  /* Emphasis-accent TEXT (Recommended marker, selected tab/filter/sidenav,
     open accordion label, pressed segmented control, in-prose accent bold).
     Distinct from --signal-deep (the pressed/deep FILL/border accent): as TEXT,
     --signal-deep clears WCAG AA in light but fails it on the dark surface
     (~3.8-4.2:1), so this alias flips to the brighter --signal in every dark
     path (explicit data-theme="dark" AND OS-driven auto-dark below). Fills and
     borders keep reading --signal-deep directly. */
  --accent-text:   var(--signal-deep);
  --on-accent:     var(--panel); /* text / glyphs on a signal-filled surface (button, live badge) */
}

/* Default paper is COOL "future-white" (the :root values above): a calm, precise,
   low-chroma near-white. data-theme="cool" is the default. The only screen
   theme override is DARK, below. */

/* DARK theme — the full ramp re-declared for a near-black cool graphite surface.
   "Always implement light AND dark." Every text colour resolves to the inverted
   ink ramp, surfaces to dark paper/panel/lines, status keeps the one muted level
   (lightened to read on dark, dot+word still paired), the one accent stays navy
   but lifts so it reads as light wayfinding on dark. Contrast verified:
   ink 15:1, ink-2 10:1, body 6.8:1, signal 6.7:1, status dots 4.8-6:1.

   SELECTION CONTRACT — which theme a page gets:
   • Explicit wins. A page that sets data-theme on <html> ("cool" or "dark")
     is PINNED to that theme; the reader's OS preference is ignored. This is the
     catalog's own behaviour (the runtime always sets data-theme).
   • No attribute = follow the OS. A page that sets NO data-theme auto-darkens
     when the reader's OS is in dark mode, via the @media block below, and stays
     light otherwise. This is the default for a static report or landing page
     handed to a person.
   The @media :root:not([data-theme]) ramp below MUST stay value-identical to this
   [data-theme="dark"] ramp. Plain CSS has no way to reference a declaration set,
   so the two are a synchronized pair: change one, change the other. */
@media screen {
[data-theme="dark"] {
  /* Native UI follows the theme: paint dark scrollbars / form controls, not the
     browser-default bright ones. Twin of the light-path color-scheme in :root. */
  color-scheme: dark;

  /* Ink ramp — light text, darkest (strongest) to faintest */
  --ink:#e9ebee; --ink-2:#c2c6cc; --body:#9aa0a8; --mut:#828892; --faint:#5a606a;

  /* Surfaces — near-black cool graphite paper, lifted panels, dark hairlines */
  --paper:#15171a; --panel:#1d2024; --well:#101216;
  --line:#2c3036; --line-2:#3a3f47; --line-fine:#23262b; --tick:#3f454d; --tick-2:#565d66;
  /* Scrim: pure black at higher alpha. The dark page is already near-black, so the
     light-theme near-black tint would not separate the dimmed area from the panel. */
  --scrim:rgba(0, 0, 0, 0.76);

  /* Signal accent — navy lifted to read as light wayfinding on dark.
     --focus inherits this via color-mix, no separate override needed. */
  --signal:#7da0d4; --signal-deep:#5e82bd; --signal-soft:#202833; --signal-line:#34415a;
  /* Emphasis-accent TEXT flips to the brighter --signal on dark (AA: ~5.6:1);
     --signal-deep stays the FILL/border accent. */
  --accent-text:var(--signal);
  --on-accent:#0f1114; /* dark glyphs on a lifted-navy fill */

  /* Status — cleared / sage (lightened, chroma held to the one muted level) */
  --ok-ink:#a6c9b0; --ok-bg:#222f26; --ok-line:#394c3e; --ok-dot:#6eaa7e;
  /* Status — in progress / muted ochre */
  --warn-ink:#ccbfa4; --warn-bg:#302b21; --warn-line:#4d4638; --warn-dot:#b09b6d;
  /* Status — blocked / muted clay */
  --blk-ink:#cea9a1; --blk-bg:#342623; --blk-line:#513d38; --blk-dot:#b87d6f;
  /* Status — not started / stone */
  --na-ink:#acb2b9; --na-bg:#282b2f; --na-line:#3f454a; --na-dot:#8c949b;

  /* Live-state beacon — a notch livelier than the chip dots, still off candy */
  --state-ok:#69b582; --state-warn:#bfa469; --state-blk:#c37065;

  /* Data-series ramp — anchored on the lifted signal, fading to faint on dark */
  --data-2:#5c7195; --data-3:#46556e; --data-4:#333d4d;

}

}

/* OS-driven auto dark — honour the reader's operating-system preference for any
   page that has NOT pinned a theme. An explicit data-theme always wins because
   [data-theme="dark"] above and the [data-theme="cool"]-implied :root defaults
   both carry the attribute, so :root:not([data-theme]) excludes them. This is the
   synchronized twin of the [data-theme="dark"] ramp above. Keep the values identical. */
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    /* Native UI follows the theme (see the [data-theme="dark"] twin). Keep identical. */
    color-scheme: dark;

    /* Ink ramp — light text, darkest (strongest) to faintest */
    --ink:#e9ebee; --ink-2:#c2c6cc; --body:#9aa0a8; --mut:#828892; --faint:#5a606a;

    /* Surfaces — near-black cool graphite paper, lifted panels, dark hairlines */
    --paper:#15171a; --panel:#1d2024; --well:#101216;
    --line:#2c3036; --line-2:#3a3f47; --line-fine:#23262b; --tick:#3f454d; --tick-2:#565d66;
    --scrim:rgba(0, 0, 0, 0.76);

    /* Signal accent — navy lifted to read as light wayfinding on dark */
    --signal:#7da0d4; --signal-deep:#5e82bd; --signal-soft:#202833; --signal-line:#34415a;
    /* Emphasis-accent TEXT flips to the brighter --signal on dark (AA: ~5.6:1);
       --signal-deep stays the FILL/border accent. */
    --accent-text:var(--signal);
    --on-accent:#0f1114;

    /* Status — cleared / sage */
    --ok-ink:#a6c9b0; --ok-bg:#222f26; --ok-line:#394c3e; --ok-dot:#6eaa7e;
    /* Status — in progress / muted ochre */
    --warn-ink:#ccbfa4; --warn-bg:#302b21; --warn-line:#4d4638; --warn-dot:#b09b6d;
    /* Status — blocked / muted clay */
    --blk-ink:#cea9a1; --blk-bg:#342623; --blk-line:#513d38; --blk-dot:#b87d6f;
    /* Status — not started / stone */
    --na-ink:#acb2b9; --na-bg:#282b2f; --na-line:#3f454a; --na-dot:#8c949b;

    /* Live-state beacon */
    --state-ok:#69b582; --state-warn:#bfa469; --state-blk:#c37065;

    /* Data-series ramp */
    --data-2:#5c7195; --data-3:#46556e; --data-4:#333d4d;
  }
}

/* Print reuses the light ramp above; no copied palette can drift. */
@media print {
  :root { --paper: var(--panel); --well: var(--line-fine); --scrim: transparent; }
}

/* ===== tokens/typography.css ===== */
/* Foundational — Typography tokens
   System neutral sans. No web fonts (offline, timeless, ages well).
   No monospace as a reading or display look (reads sci-fi); mono is for code content only (see docs/USAGE.md). No serif.
   Hierarchy comes from WEIGHT (400 body / 600 headings+labels) and SIZE only. */

:root {
  --font-sans: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* Mono is for CODE CONTENT ONLY (inline code, code blocks, the code viewer;
     see docs/USAGE.md), never a reading or display face. One named stack so
     the three code surfaces in parts/content.css cannot drift apart. */
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Weights — only two */
  --weight-body:    400;
  --weight-strong:  600;

  /* Type scale (px) — calm, limited steps */
  --text-svg-micro: 9px; /* in-SVG axis/donut micro-labels only; one notch below the chrome floor */
  --text-micro: 10px; /* tiny chrome only: tooltip values, meter flags. Not for reading copy. */
  --text-2xs:  11px;
  --text-xs:   12px;
  --text-sm:   13px;
  --text-base: 15px;
  --text-md:   17px;
  --text-lg:   20px;
  --text-xl:   25px;
  --text-2xl:  31px;
  --text-3xl:  39px;

  /* Line heights */
  --leading-none:    1; /* figures, labels, and control glyphs */
  --leading-tight:   1.2;
  --leading-snug:    1.35;
  --leading-normal:  1.5;
  --leading-relaxed: 1.6;

  /* Tracking — single source of truth for letter-spacing across the system.
     Label tracking has three steps (the uppercase-label voice was drifting to
     0.07 / 0.12 / 0.14 raw across parts/ and specimens; these tokens hold it). */
  --tracking-tighter: -0.04em; /* big display figures (countdown, donut centre) */
  --tracking-figure:  -0.03em; /* mid big-figure tightening (hero figure, KPI figure) */
  --tracking-tight:   -0.01em; /* large headlines */
  --tracking-normal:  0;
  --tracking-open:     0.01em; /* small strong mixed-case chrome text (nav tabs, crumbs,
                                  pagination, side-nav, segmented control, avatar initials):
                                  one slight-opening step, so the control voice cannot
                                  drift into per-part raw values again */
  --tracking-label:        0.07em; /* default uppercase label tracking */
  --tracking-label-loose:  0.12em; /* wider eyebrows / app-bar labels */
  --tracking-label-wide:   0.14em; /* widest tracked micro-labels */

  /* Label treatment — uppercase, tracked. Derives from the tracking scale so
     label tracking lives in exactly one place (no duplicate 0.07em literal). */
  --label-size:    var(--text-xs);
  --label-spacing: var(--tracking-label);
  --label-weight:  var(--weight-strong);

  /* Display / figure type — off the reading scale, for the one big number.
     Tokenized so the countdown and large figures retune with the system. */
  --text-display: 56px; /* large countdown / hero figure */
  --text-figure:  22px; /* donut centre value, mid-figure */
}

/* ===== tokens/spacing.css ===== */
/* Foundational — Spacing, radii, shadow, motion tokens
   Spacing on a small consistent scale. Don't hand-place px. */

:root {
  /* Spacing scale (4px base) */
  --space-0:  0;
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-8:  32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-20: 80px;

  /* Radii */
  --radius-sm:   10px;
  --radius-md:   14px;
  --radius-lg:   20px;
  --radius-pill: 999px;

  /* Hairline width */
  --hair: 1px;
  --stroke-plot: 1.75px; /* chart series; document figures reference --hair */
  --arrow-size: var(--caret-rise); /* small connector head */

  /* Tiny graphic marks, distinct from card corners. */
  --radius-mark: calc(var(--hair) * 2);
  --stroke-ring: 14px; /* area-like gauge/donut bands, never connector lines */
  --opacity-disabled: 0.55;
  --opacity-dim: 0.4;
  --opacity-off-path: 0.22;

  /* Instrument frames. SVG viewBoxes remain data geometry. */
  --spark-width: 104px;
  --spark-height: 36px;
  --donut-size: 132px;
  --gauge-width: 150px;
  --plot-height: 96px;
  --road-label-width: 124px;
  --modal-width: 360px;
  --drawer-width: 340px;
  --overlay-min-height: 300px;

  /* Signature dot diameter (status + now dots) */
  --dot: 7px;

  /* Derived micro-dimensions & patterns for rendered and enhanced blocks
     (pacing, vintage, line chart, ledger). Each off-scale raw value lives here
     ONCE, named, so the blocks stay tokens-only and a change propagates from a
     single source. */
  --stroke-2: calc(var(--hair) * 2);         /* a double-hairline: the vintage most-recent-forecast box; also focus-ring width/offset + line-chart legend rule */
  --legend-sw-w: 18px;     /* legend swatch width (pacing + vintage + line chart) */
  --legend-sw-h: 10px;     /* bar-style legend swatch height (pacing fills) */
  --legend-sw-h-box: 14px; /* cell-style legend swatch height (vintage cells, pacing target) */
  --legend-sw-r: var(--radius-mark);      /* legend swatch corner */
  --vintage-min-w: 460px;  /* min table width before it scrolls horizontally on a phone */
  --caret-half: 4px;       /* caret triangle half-base (the ledger section toggle's CSS-border caret) */
  --caret-rise: 5px;       /* caret triangle height (the same caret) */
  --tip-wrap-max: 220px;   /* wrapping hover-tip measure cap: the one .fds-tip that carries a sentence (the journey node tip, parts/journey.css) */
  --pop-w: 232px;          /* popover panel width (block 51). Deliberately NOT unified with --tip-wrap-max: this sizes a PANEL (content plus padding), that caps a TEXT measure; snapping either to the other changes a shipped surface with no design driver. */

  /* Page container — the canonical content max-width (one source for page + app bar). */
  --page-max: 1180px;
  /* Reading-column frame for a composed READING page (document, decision,
     briefing): the one-width column plus its side padding (780px + 2 x space-8).
     Ratified 2026-07-06: a reading page carries ONE content width - prose, cards,
     tables and callouts all share both edges; the two-width layout (narrow prose
     inside wider furniture) read as imbalance. App surfaces (the dashboard) keep
     the wide --page-max frame: they are instruments, not reading columns. */
  --page-measure: 844px;
  /* Sticky app-bar height. An in-page anchor target (a section) leaves this much
     clearance above itself (scroll-margin-top) so a scrolled-to section is not
     hidden under the sticky bar. Tokenised so the value is not a raw magic number. */
  --appbar-clearance: 88px;

  /* Reading measures — the river's lane widths. Ratified 2026-07-06: the measure
     and wide lanes are the SAME 780px, because a reading page carries one content
     width (the one-width doctrine above); the lanes stay as named hooks so a page
     that ever needs a distinct wide lane changes one token, not its markup. Pixels,
     not ch: the column must equal the card/table width exactly, which is a page
     geometry, not a type metric. 780px sits at the wide edge of the reading-column
     convention (Confluence 760, Stripe ~760, Notion ~710/900) because our column
     also carries tables and cards. The lede stays shorter under a display figure. */
  --measure:      780px;  /* the one reading-page content width */
  --measure-wide: var(--measure);  /* same width: one-width doctrine (hook kept) */
  --measure-lede: 620px;  /* a lede line under a statement's display figure */
  --rail-aside:   18rem;  /* the sticky companion beside a main reading column */

  /* Shadows: low elevation on paper and panels. */
  --shadow-flat:  0 1px 2px rgba(20, 21, 26, 0.04);
  --shadow-card:  var(--shadow-flat), 0 10px 30px -14px rgba(20, 21, 26, 0.14);
  --shadow-float: var(--shadow-flat), 0 16px 40px -16px rgba(20, 21, 26, 0.20);
  /* Motion. Calm digital easing, no bounce on content.
     The motion CHARTER (docs/USAGE.md, "Motion charter: three verbs, then
     stillness"): light breathes, feedback answers, a value arrives, and nothing
     else moves. Each token below is tagged with the one verb it PRIMARILY serves
     (@motion ...). A couple of curves are shared, so the tag names the primary
     intent, not the only use; the lint (build/motion-lint.mjs) is what enforces the
     charter. The tag just puts the doctrine where an author reads the token. */
  --ease-out:   cubic-bezier(0.22, 0.61, 0.36, 1); /* @kind other */ /* @motion feedback-answers. the shared calm "out" curve */
  --ease-inout: cubic-bezier(0.45, 0.05, 0.2, 1); /* @kind other */ /* @motion light-breathes. the loading-feedback curve (skeleton, progress) */
  --dur-snap:   120ms; /* @kind other */ /* @motion feedback-answers. instant hover/feedback micro-transition */
  --dur-fast:   140ms; /* @kind other */ /* @motion feedback-answers */
  --dur-base:   220ms; /* @kind other */ /* @motion feedback-answers */
  /* Tooltip position glide (the bar chart's .fds-tip sliding bar to bar). The
     RF-adopted P-B4 pick, deliberately QUICKER than --dur-snap so the tip tracks
     the pointer without lag; named here so the one off-scale duration lives once. */
  --dur-glide:   90ms; /* @kind other */ /* @motion feedback-answers. tooltip bar-to-bar position glide */
  /* Loading feedback has its own cadence; the page and opening stay still. */
  --dur-loading: 2.4s; /* @kind other */ /* @motion light-breathes. loading feedback cadence */
  --dur-wait:    1.5s; /* @kind other */ /* @motion value-arrives. in-flight: indeterminate progress slide, snappier than the loading loop */
}

/* ===== tokens/base.css ===== */
/* Foundational — base resets shared by cards and kits.
   Minimal; tokens carry the design. */

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

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

body {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: var(--weight-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--text-body);
  background: var(--surface-page);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ===== parts/surface-fill.css ===== */
/* Foundational — the panel fill, declared once.
   A large family of components sits on the panel token: form controls, nav
   surfaces, chips, decision options, flow and journey nodes, timeline dots, the
   drawer and popover, the alert and toast. Each paints the SAME background
   (var(--panel)); only its border, radius and shadow differ (those stay with the
   component). Rather than copy that one panel-token fill into thirty-odd rules,
   it is declared ONCE here, as one grouped selector list.

   WHY THIS FILE LOADS FIRST. This is the base fill every listed component's own
   states and modifiers layer over: a journey node's per-type tint, a toggle's
   on/disabled wash, a decision option's selected wash, a link's hover. Declared
   before any of them (first part in build/styles.manifest.css), it is the lowest
   layer, so every later state or modifier (later in source, or higher in
   specificity) still wins exactly as it did when each rule carried its own fill.
   The consolidation is therefore pixel-for-pixel identical (snapshot-proven), not
   a restyle. A single grouped declaration also means a future change to how a
   panel is filled is made in one place, not hunted across eleven files.

   NOT here: `.fds-card`. The public card carries the full panel recipe (fill,
   hairline, radius, shadow) in its own home (parts/composition.css), positioned
   after the decision option, flow node and tooltip so it wins an equal-specificity
   tie against them. Folding its fill into this first-loading group would move it
   BEFORE those and silently flip that order, so the card is deliberately excluded.
   `.fds-surface` / `.fds-pane` (the internal panel recipe) keep their border, radius
   and shadow in parts/pane.css and take only their fill from here. */

.fds-surface, .fds-pane,
.fds-dec__opt, .fds-node,
.fds-seg, .fds-tl-node__dot, .fds-road__nowlabel, .fds-scatter-dot--plain, .fds-dep__node,
.fds-btn--secondary,
.fds-input, .fds-select, .fds-menu, .fds-toggle, .fds-control,
.fds-pager__step, .fds-pager__step[aria-disabled="true"], .fds-sidenav__link:hover, .fds-sidenav__tag,
.fds-alert, .fds-toast,
.fds-code__copy, .fds-code__pre, .fds-figure__tag,
.fds-tag,
.fds-journey__node, .fds-journey__elabel, .fds-journey__loop-label, .fds-journey__pathbtn,
.fds-drawer, .fds-pop__trigger, .fds-popover, .fds-popover::before {
  background: var(--panel);
}

/* ===== parts/atoms.css ===== */
/* Shared drawing primitives. Geometry belongs to the drawing; paint lives here. */
.fds-wire, .fds-flow__arrow {
  fill: none; stroke: var(--connector-ink, var(--line-2)); stroke-width: var(--hair);
  stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.fds-arrowhead, .fds-flow__arrowhead { fill: var(--connector-ink, var(--line-2)); }

/* A quiet paper edge over clipped content. Native scrollbars remain visible. */
.fds-scroll-edge { position: relative; }
.fds-scroll-edge::after {
  content: ""; position: absolute; inset-block: 0; right: 0; width: var(--space-4);
  pointer-events: none; opacity: 0;
  background: linear-gradient(to right, transparent, var(--paper));
  border-right: var(--hair) solid var(--line);
}
.fds-scroll-edge.is-clipped::after { opacity: 1; }

/* Small interface glyphs use the same hairline as rules and connectors. */
.fds-icon-stroke {
  fill: none; stroke: currentColor; stroke-width: var(--hair);
  stroke-linecap: round; stroke-linejoin: round;
}
.fds-icon-box { rx: var(--radius-mark); }

.fds-measuring { position: absolute; visibility: hidden; inset: 0 auto auto 0; pointer-events: none; }

/* ===== parts/schematic.css ===== */
/* Foundational — schematic: thin rules only.
   Decorative corners, crosshairs, ruler ticks, and measure grids are shed. */

.fds-rule        { height: var(--hair); border: 0; margin: 0; background: var(--line); }
.fds-rule--fine  { background: var(--line-fine); }
.fds-rule--strong{ background: var(--line-2); }

.fds-vrule       { width: var(--hair); align-self: stretch; background: var(--line); }
.fds-vrule--fine { background: var(--line-fine); }

/* ===== parts/journey.css ===== */
/* Foundational journey: one rounded card shape, printed node types, and a
   straight continuation. Forward branches occupy neighbouring columns; returns
   to the same node share one rail. Measured words have clear gaps in the wires.
   Only the current node uses --signal. Narrow containers scroll the drawing. */

/* --- Stage: the measured coordinate space ----------------------------------- */
/* Keep the measured stage at native size so type and borders retain their tokens.
   Overflow belongs to this instrument, with its native scrollbar, at every width. */
.fds-journey { position: relative; width: 100%; max-width: 100%; min-width: 0; overflow: auto; }
.fds-journey__stage { position: relative; width: 100%; }
/* Fit the containing instrument to the measured drawing, including its padding.
   Before hydration the card keeps its normal width and the text fallback remains. */
.fds-card:has(.fds-journey) {
  width: calc(var(--journey-width, 100%) + var(--space-5) * 2 + var(--hair) * 2);
  max-width: 100%;
}
.fds-card:has(.fds-journey) .fds-card__head { flex-wrap: wrap; }

/* The journey's hover tip is the one .fds-tip that carries a SENTENCE (a node's
   type and label), so unlike the nowrap value tips it wraps at a capped measure.
   Declared here, not injected by the runtime, so the width is a named token
   (--tip-wrap-max) the token lints can see. */
.fds-journey__stage > .fds-tip { white-space: normal; max-width: var(--tip-wrap-max); text-align: left; }
/* hydrator sets an explicit px width + height on the stage so the
   absolutely-positioned nodes and the SVG share one pixel coordinate space. */
.fds-journey__wires {
  position: absolute; inset: 0; pointer-events: none; overflow: visible; z-index: 0;
}

/* Quiet panel cards. The printed word carries the type. */
.fds-journey__node {
  position: absolute; box-sizing: border-box; z-index: 1;
  width: max-content;
  min-width: calc(var(--space-20) + var(--space-4));
  max-width: calc(var(--space-20) * 2 + var(--space-4));
  display: grid; gap: var(--hair);
  padding: var(--space-2) var(--space-3);
  border: var(--hair) solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-flat);
  text-align: center; cursor: default;
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.fds-journey__node:hover,
.fds-journey__node.is-hot { box-shadow: var(--shadow-card); }
.fds-journey__node:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

.fds-journey__type {
  font-size: var(--text-micro); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label-loose); text-transform: uppercase;
  color: var(--text-faint);
}
.fds-journey__label {
  color: var(--ink-2); font-weight: var(--weight-strong); font-size: var(--text-sm);
  line-height: var(--leading-tight); overflow-wrap: anywhere;
}

/* endpoints prefer a single line: a short ending word stays on one line because
   it fits inside max-width. A long ending (e.g. "Closed: cannot reproduce") is
   allowed to wrap at its spaces rather than spill past the border — overflow-wrap
   stays normal so it only ever breaks between words, never mid-word, and the box
   is the same rounded rectangle as every other type. (A hard white-space:nowrap
   here forced long endings onto one line and clipped them past the right wall.) */
.fds-journey__node--start .fds-journey__label,
.fds-journey__node--terminal .fds-journey__label { overflow-wrap: normal; }

/* The one current node: signal border and the Now word. */
.fds-journey__node--now { border-color: var(--signal-line); }
.fds-journey__node--now .fds-journey__type { color: var(--signal); }
.fds-journey__now {
  font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--signal);
}
.fds-journey__now::before { content: "• "; }

/* Loop targets need no marker: the drawn back-wire and its word carry the return.
   The class is kept for hooks but renders nothing extra. */

/* --- Wires (SVG; colours must come from CSS) -------------------------------- */
/* Shared wire and arrow primitives use the same ink on each route. */
.fds-journey__wire--back,
.fds-journey__arrowhead--back { --connector-ink: var(--line); }

/* Edge words are measured DOM text. Wires stop clear of their bounds. */
.fds-journey__elabel,
.fds-journey__loop-label {
  position: absolute; transform: translate(-50%, -50%); z-index: 2;
  padding: var(--space-0) var(--space-1);
  font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--mut); white-space: nowrap; pointer-events: none;
}
.fds-journey__loop-label { color: var(--ink-2); }

/* --- Path highlighting: dim the off-path subset, leave the path at full read ---
   A pure post-layout overlay toggled by the hydrator when the data carries a
   "paths" array. Identity is carried by the path's word chip in the control bar,
   NOT by colour on the diagram, so this uses NO --signal / --accent (those stay
   unique to the single "now" node). The signal here is contrast of presence:
   off-path elements recede to a low opacity, the chosen path stays present. */
.fds-journey__wire, .fds-journey__arrowhead,
.fds-journey__elabel, .fds-journey__loop-label {
  transition: opacity var(--dur-fast) var(--ease-out);
}
.fds-journey--pathed .fds-journey__node.is-off,
.fds-journey--pathed .fds-journey__wire.is-off,
.fds-journey--pathed .fds-journey__arrowhead.is-off,
.fds-journey--pathed .fds-journey__elabel.is-off,
.fds-journey--pathed .fds-journey__loop-label.is-off { opacity: var(--opacity-off-path); }
/* on-path nodes gain a hair more presence via a stronger shadow only; the panel
   border stays, and the
   off-path opacity-dim already carries the presence contrast. On-path identity is
   the path's control-bar word, never colour, so no accent is added here. */
.fds-journey--pathed .fds-journey__node:not(.is-off) { box-shadow: var(--shadow-card); }
/* on-path WIRES darken so the chosen route (its forward and loop wires alike)
   reads as one connected line instead of the default faint hairline */
.fds-journey--pathed .fds-journey__wire:not(.is-off) { stroke: var(--mut); }
.fds-journey--pathed .fds-journey__arrowhead:not(.is-off) { fill: var(--mut); }

/* The control bar: a row of word chips above the stage. A SIBLING of the stage,
   so it stays visible while the measured drawing scrolls. */
.fds-journey__paths { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }
.fds-journey__pathbtn {
  appearance: none; -webkit-appearance: none; font: inherit; cursor: pointer;
  padding: var(--space-1) var(--space-3);
  border: var(--hair) solid var(--line); border-radius: var(--radius-pill);
  color: var(--mut);
  font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase; white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.fds-journey__pathbtn:hover { color: var(--ink-2); border-color: var(--line-2); }
.fds-journey__pathbtn:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }
/* active chip: raised ink + stronger hairline. The word + this lift + aria-pressed
   all carry the active state; colour is never the sole signal. */
.fds-journey__pathbtn.is-on { color: var(--ink-2); border-color: var(--line-2); }

@media (prefers-reduced-motion: reduce) {
  .fds-journey__node, .fds-journey__wire, .fds-journey__arrowhead,
  .fds-journey__elabel, .fds-journey__loop-label, .fds-journey__pathbtn { transition: none !important; }
}
/* B2 still mode twin (kept identical to the reduced-motion rule by lint-still-mode.mjs) */
:root[data-still] .fds-journey__node, :root[data-still] .fds-journey__wire, :root[data-still] .fds-journey__arrowhead,
:root[data-still] .fds-journey__elabel, :root[data-still] .fds-journey__loop-label, :root[data-still] .fds-journey__pathbtn { transition: none !important; }

/* The same measured topology scrolls in narrow containers. Node type keeps its
   shared size, and .fds-wire preserves --hair through SVG transforms. */

/* DARK THEME — nothing block-specific: every value above is a token that
   re-resolves under [data-theme="dark"]. The forward wire (--line-2) and the
   fainter back wire (--line, one step below) both re-resolve to stay visible on
   the near-black dark --paper; --line-fine would sink into it, so neither wire
   uses it. */

/* ===== parts/overlay.css ===== */
/* Overlay blocks. Modal, drawer, and popover only. Liquid-glass material removed. */

/* ============================================================
   Overlay blocks — component CSS promoted from specimens.
   Shared scrim (.fds-scrim / .fds-scrim--end), close cross (.fds-x) and
   buttons (.fds-btn) live in controls.css; these rules add only what each
   overlay needs beyond those primitives. Tokens only.
   ============================================================ */

/* Block: 49-modal. A titled dialog that rides the floating layer above a
   contained .fds-scrim. Reuses .fds-x for close and .fds-btn for actions. */
.fds-modal {
  position: relative; z-index: 1;
  width: 100%; max-width: var(--modal-width); min-width: 0;
  box-shadow: var(--shadow-float);
}
.fds-modal__head { display: flex; align-items: flex-start; gap: var(--space-4); }
.fds-modal__head .fds-card__heading { flex: 1 1 auto; min-width: 0; }
.fds-modal__body { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.fds-modal__text { font-size: var(--text-sm); color: var(--body); line-height: var(--leading-normal); text-wrap: pretty; margin: 0; }
.fds-modal__actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-3); padding-top: var(--space-4); border-top: var(--hair) solid var(--line); }

/* Block: 50-drawer. A side sheet pinned to the right edge of a contained
   .fds-scrim--end. Reuses .fds-x for close. */
.fds-drawer {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; min-width: 0;
  width: 100%; max-width: var(--drawer-width);
  border-left: var(--hair) solid var(--line-2);
  box-shadow: var(--shadow-float);
}
.fds-drawer__head { display: flex; align-items: flex-start; gap: var(--space-4); padding: var(--space-5) var(--space-5) var(--space-4); border-bottom: var(--hair) solid var(--line); }
.fds-drawer__head .fds-card__heading { flex: 1 1 auto; min-width: 0; }
.fds-drawer__body { display: flex; flex-direction: column; min-width: 0; padding: var(--space-2); }
.fds-drawer__row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); min-width: 0; padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); color: var(--ink-2); font-size: var(--text-sm); text-decoration: none; transition: background var(--dur-snap) var(--ease-out); }
.fds-drawer__row + .fds-drawer__row { border-top: var(--hair) solid var(--line-fine); }
.fds-drawer__row:hover { background: var(--line-fine); }
.fds-drawer__row span:first-child { min-width: 0; overflow-wrap: anywhere; }
.fds-drawer__val { flex: none; color: var(--mut); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); }

/* Block: 51-popover. A trigger button and a small floating panel with a
   pointer, sized to stay within its anchor frame at any width. */
.fds-pop { position: relative; display: inline-block; min-width: 0; }
.fds-pop__trigger {
  appearance: none; -webkit-appearance: none; font: inherit; font-size: var(--text-sm); font-weight: var(--weight-strong);
  display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer;
  color: var(--ink-2); border: var(--hair) solid var(--line-2); border-radius: var(--radius-pill);
  padding: var(--space-2) var(--space-4);
}
.fds-pop__trigger::after { content: ""; width: var(--space-2); height: var(--space-2); border-right: var(--stroke-2) solid currentColor; border-bottom: var(--stroke-2) solid currentColor; transform: translateY(calc(var(--hair) * -1)) rotate(45deg); color: var(--mut); }
.fds-pop__trigger:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }
.fds-popover {
  position: absolute; left: 0; top: calc(100% + var(--space-3)); z-index: 1;
  width: var(--pop-w); max-width: 100%; min-width: 0;
  border: var(--hair) solid var(--line-2); border-radius: var(--radius-md);
  box-shadow: var(--shadow-float); padding: var(--space-4);
}
.fds-popover::before {
  content: ""; position: absolute; top: calc(var(--space-1) * -1); left: var(--space-5); width: var(--space-2); height: var(--space-2);
  border-left: var(--hair) solid var(--line-2); border-top: var(--hair) solid var(--line-2);
  transform: rotate(45deg);
}
.fds-popover__title { margin: 0 0 var(--space-2); font-size: var(--text-sm); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); color: var(--ink-2); }
.fds-popover__text { margin: 0 0 var(--space-3); font-size: var(--text-xs); line-height: var(--leading-normal); color: var(--body); text-wrap: pretty; }
.fds-popover__link { font-size: var(--text-xs); font-weight: var(--weight-strong); color: var(--accent); text-decoration: underline; text-decoration-color: var(--accent-line); text-underline-offset: var(--stroke-2); border-radius: var(--radius-sm); }
.fds-popover__link:hover { text-decoration-color: var(--accent); }
.fds-popover__link:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

/* ===== parts/chip.css ===== */
/* Foundational — status chip (state) + live keyline (now).
   A chip always pairs a small dusty dot with a WORD. Never candy color. */

.fds-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-strong);
  line-height: var(--leading-snug);
  white-space: nowrap;
  color: var(--ink-2);
}
.fds-chip__dot {
  width: var(--dot); height: var(--dot); border-radius: var(--radius-pill); flex: none;
}

.fds-chip--ok   .fds-chip__dot { background: var(--ok-dot); }
.fds-chip--warn .fds-chip__dot { background: var(--warn-dot); }
.fds-chip--blk  .fds-chip__dot { background: var(--blk-dot); }
.fds-chip--na   .fds-chip__dot { background: var(--na-dot); }

/* Live "now" beacon — a PULSING dot for emphasis / attention.
   Neutral blue (--signal) by default = "live, no status claim". Tier it to a
   status with .fds-now--ok / --warn / --blk on the wrapper (or standalone
   .fds-now__dot--ok / --warn / --blk on a bare dot) to ride the live-state beacon
   triad (green / yellow / red). Pulsing only draws the eye; the colour is still
   paired with a WORD, never colour alone. The calm static read layer
   (.fds-chip / .fds-stat dots) stays muted and is deliberately NOT tiered here. */
.fds-now {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--label-size); font-weight: var(--label-weight);
  letter-spacing: var(--label-spacing); text-transform: uppercase;
  color: var(--signal);
}
.fds-now--ok   { color: var(--state-ok); }
.fds-now--warn { color: var(--state-warn); }
.fds-now--blk  { color: var(--state-blk); }
.fds-now__dot {
  --now-color: var(--signal);
  width: var(--dot); height: var(--dot); border-radius: var(--radius-pill); flex: none;
  background: var(--now-color);
}
.fds-now--ok   .fds-now__dot, .fds-now__dot--ok   { --now-color: var(--state-ok); }
.fds-now--warn .fds-now__dot, .fds-now__dot--warn { --now-color: var(--state-warn); }
.fds-now--blk  .fds-now__dot, .fds-now__dot--blk  { --now-color: var(--state-blk); }

/* Neutral tag / label — distinct from the status .fds-chip above.
   A .fds-chip is a STATE primitive (a status dot + a word, --ok/--warn/--blk/--na).
   A .fds-tag carries NO status: it is a calm bordered pill for a plain label,
   category, or applied filter, where the word is the whole meaning. Used by the
   chip-set block (static labels) and the filter-bar block (selectable filters). */
.fds-tag {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-xs); font-weight: var(--weight-strong); line-height: var(--leading-snug);
  white-space: nowrap; color: var(--body);
  padding: var(--space-1) var(--space-3);
  border: var(--hair) solid var(--line-2); border-radius: var(--radius-pill);
}

/* Selectable filter tag — a .fds-tag that can be turned on. Render it as a
   <button> carrying aria-pressed so the state is in the accessibility tree.
   The SELECTED state is marked by an explicit check glyph and bold signal text,
   not by colour alone, so the choice survives greyscale and colourblind viewing
   (mirrors the filled-pill rule of the segmented control). */
.fds-tag--filter {
  appearance: none; font-family: inherit; cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.fds-tag--filter:hover { border-color: var(--signal-line); }
/* Keyboard focus uses the shared system focus ring (keyboard users only). */
.fds-tag--filter:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }
.fds-tag--filter[aria-pressed="true"] {
  background: var(--signal-soft); border-color: var(--signal-line);
  color: var(--accent-text); font-weight: var(--weight-strong);
}
/* A check glyph (CSS-drawn, no glyph font) leads the selected tag so the
   "selected" meaning never rides on the signal tint alone. */
.fds-tag--filter[aria-pressed="true"]::before {
  content: ""; flex: none; width: var(--space-2); height: var(--space-1);
  border-left: var(--stroke-2) solid var(--accent-text); border-bottom: var(--stroke-2) solid var(--accent-text);
  transform: rotate(-45deg); margin-top: calc(var(--space-1) * -1);
}

/* A wrapping row of tags (or chips), used by the chip-set block. The row wraps
   in place at any width (scale-to-fit, never a structural reflow). */
.fds-chipset__row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }

/* ===== parts/pane.css ===== */
/* Foundational — the surface layer. FIVE surfaces, each with one role.
   A surface is chosen by the COMPOSITION, never by the content; paper is the
   default home for everything a person reads. A panel must EARN its border.

     Paper  (--paper)                     The page and ALL reading. The default.
                                          No border, no shadow.
     Well   (--well)                      A subordinate island set into the flow:
                                          code, figure media, a callout. Recessed,
                                          no shadow (a panel lifts, a well recedes).
     Panel  (--panel + hairline + shadow) A discrete entity that earned its border:
                                          a tile, an option, the escalation. What
                                          the public .fds-card gives you.
     Glass  (fds-glass)                    Chrome and the one hero. Never reading.
     Scrim  (--scrim)                     Overlay dimming only.

   THE PANEL RECIPE, in two halves. The FILL (the panel token as a background) is
   declared once for every surface that sits on it, in parts/surface-fill.css (first
   so it is the base every state layers over). The FRAME below (hairline, radius,
   shadow) is the internal recipe .fds-surface; the once-orphaned .fds-pane primitive
   composes it through the same selector group at the same specificity. The public
   .fds-card carries its own copy of this frame in parts/composition.css — after
   the decision option, flow node and tooltip, so it wins an equal-specificity tie
   with them; folding it in here would move it before them and flip that order. The
   layout tier (parts/layout.css) owns the space between panels, never their
   surface. `.fds-surface` is an INTERNAL recipe name; consumers reach a panel
   through `.fds-card`, never by writing `.fds-surface`. */

.fds-surface, .fds-pane {
  position: relative;
  border: var(--hair) solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}

.fds-pane--flat { box-shadow: var(--shadow-flat); }

/* Active / now pane — distinguished by its "• Now" label + a gentle lift,
   not a color border (the left-keyline pattern is overused). */
.fds-pane--now { box-shadow: var(--shadow-float); }

.fds-pane__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: var(--hair) solid var(--line);
}
.fds-pane__title {
  margin: 0;
  font-size: var(--text-md);
  font-weight: var(--weight-strong);
  color: var(--ink-2);
  letter-spacing: var(--tracking-tight);
}
.fds-pane__body { padding: var(--space-5); }

/* Uppercase tracked label helper */
.fds-pane-label {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-spacing);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ===== parts/panes.css ===== */
/* Foundational — understanding-pane classes (flat surfaces). */

/* ---- Gate table: reflows to stacked cards on mobile ---- */
.fds-gate-table { display: flex; flex-direction: column; }
.fds-gate-table__row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-top: var(--hair) solid var(--line);
}
.fds-gate-table__row:first-child { border-top: 0; }
.fds-gate-table__num {
  width: var(--space-6); height: var(--space-6); flex: none;
  display: grid; place-items: center;
  border-radius: var(--radius-pill);
  background: transparent; color: var(--mut);
  border: var(--hair) solid var(--line-2);
  font-size: var(--text-xs); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums;
}
.fds-gate-table__row.is-now .fds-gate-table__num { background: var(--signal-soft); color: var(--signal); border-color: var(--signal-line); }
.fds-gate-table__name { color: var(--ink-2); font-weight: var(--weight-strong); font-size: var(--text-base); }
.fds-gate-table__note { color: var(--mut); font-size: var(--text-sm); }
.fds-gate-table__main { min-width: 0; }
.fds-gate-table__main .fds-gate-table__note { margin-top: calc(var(--space-1) / 2); }

@media (max-width: 460px) {
  .fds-gate-table__row { grid-template-columns: auto 1fr; grid-auto-flow: row; }
  .fds-gate-table__row .fds-chip { grid-column: 1 / -1; justify-self: start; }
}

/* ---- Decision options: recommended = filled signal radio + caps label ---- */
.fds-dec { display: flex; flex-direction: column; gap: var(--space-3); }
.fds-dec__opt {
  display: grid; grid-template-columns: auto 1fr; gap: var(--space-3);
  padding: var(--space-4);
  border: var(--hair) solid var(--line);
  border-radius: var(--radius-sm);
  text-align: left; width: 100%; cursor: pointer; font: inherit; color: inherit;
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.fds-dec__opt:hover { border-color: var(--line-2); }
.fds-dec__opt.is-sel { border-color: var(--signal-line); background: var(--signal-soft); }
.fds-radio {
  width: var(--space-5); height: var(--space-5); border-radius: var(--radius-pill); flex: none; margin-top: var(--hair);
  border: var(--stroke-2) solid var(--line-2);
  display: grid; place-items: center;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.fds-radio.is-on { border-color: var(--signal); }
.fds-radio__dot { width: var(--space-2); height: var(--space-2); border-radius: var(--radius-pill); background: var(--signal); transform: scale(0); transition: transform var(--dur-fast) var(--ease-out); }
.fds-radio.is-on .fds-radio__dot { transform: scale(1); }
/* B2/reduced-motion: the decision-option hover, the radio selection ring, and the
   radio dot are feedback motion — they collapse to instant under BOTH the reader's
   reduced-motion preference and the composer's still mode. Byte-identical twins,
   held in lockstep by build/lint-still-mode.mjs. */
@media (prefers-reduced-motion: reduce) {
  .fds-dec__opt, .fds-radio, .fds-radio__dot { transition: none; }
}
:root[data-still] .fds-dec__opt,
:root[data-still] .fds-radio,
:root[data-still] .fds-radio__dot { transition: none; }
.fds-dec__title { display: block; color: var(--ink-2); font-weight: var(--weight-strong); font-size: var(--text-base); }
.fds-dec__desc { display: block; color: var(--body); font-size: var(--text-sm); margin-top: var(--space-1); }
.fds-dec__rec {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--label-spacing); text-transform: uppercase;
  color: var(--signal); margin-top: var(--space-2);
}
.fds-dec__rec::before { content: "•"; }

/* ---- Comparison table: exactly one Recommended column ---- */
.fds-comparison-pane { width: 100%; border-collapse: collapse; }
.fds-comparison-pane th, .fds-comparison-pane td {
  padding: var(--space-3) var(--space-4);
  text-align: left; font-size: var(--text-sm);
  border-bottom: var(--hair) solid var(--line);
  vertical-align: top;
}
.fds-comparison-pane thead th { color: var(--ink-2); font-weight: var(--weight-strong); font-size: var(--text-base); }
.fds-comparison-pane tbody th { color: var(--mut); font-weight: var(--weight-body); width: 34%; }
.fds-comparison-pane td { color: var(--ink-2); }
/* recommended column reads as one clean vertical band — dividers never cut across it */
.fds-comparison-pane .is-rec { background: var(--signal-soft); border-bottom-color: transparent; }
.fds-comparison-pane thead th.is-rec { border-top-left-radius: var(--radius-sm); border-top-right-radius: var(--radius-sm); }
.fds-comparison-pane tbody tr:last-child td.is-rec { border-bottom-left-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm); }
.fds-comparison-pane__why { color: var(--body); font-size: var(--text-sm); }

/* ---- Flowchart (schematic) ---- */
.fds-flow { display: flex; flex-direction: column; align-items: stretch; }
.fds-node {
  position: relative;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: var(--hair) solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-flat);
}
/* The live step is a signal border. The Now word carries current state. */
.fds-node--now {
  border-color: var(--signal-line);
}
.fds-node__badge {
  width: var(--space-6); height: var(--space-6); flex: none; display: grid; place-items: center;
  border-radius: var(--radius-pill); background: transparent; color: var(--mut);
  border: var(--hair) solid var(--line-2);
  font-size: var(--text-xs); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums;
}
.fds-node--now .fds-node__badge { background: var(--signal); color: var(--on-accent); border-color: var(--signal); }
.fds-node__label { display: block; color: var(--ink-2); font-weight: var(--weight-strong); font-size: var(--text-base); }
.fds-node__sub { display: block; color: var(--mut); font-size: var(--text-xs); margin-top: var(--hair); }
.fds-flow__row { display: grid; gap: var(--space-3); }

@media (prefers-reduced-motion: reduce) {
  .fds-node--now { animation: none !important; }
}
/* B2 still mode twin (kept identical to the reduced-motion rule by lint-still-mode.mjs) */
:root[data-still] .fds-node--now { animation: none !important; }

@media (max-width: 520px) {
  .fds-flow__row { grid-template-columns: 1fr !important; }
}

/* ===== parts/chart.css ===== */
/* Foundational — chart classes.
   SVG paint is owned by these shared CSS classes. */

.fds-chart { display: block; width: 100%; height: auto; font-family: var(--font-sans); font-variant-numeric: tabular-nums; }

/* Structure — a three-step line ladder, faint to strong, that re-resolves in both
   themes: grid (--line-fine) < crosshair (--line) < axis/frame (--tick). Each step
   is one clear luminance move, so structure reads by strength + position, never colour.
   The axis/frame step sits on --tick (the minor ruler-tick ink, the SAME ink the
   document figure grounds its baseline on) rather than --line-2: the bars themselves
   fill with --line-2, so a --line-2 axis vanished into its own bars and the chart
   read as floating. One baseline idiom, every chart grounded. */
.fds-chart__grid   { stroke: var(--line-fine); stroke-width: var(--hair); }
.fds-chart__cross  { stroke: var(--line);      stroke-width: var(--hair); }
.fds-chart__axis   { stroke: var(--tick);      stroke-width: var(--hair); }
.fds-chart__tick   { fill: var(--mut); font-size: var(--text-micro); font-weight: var(--weight-body); letter-spacing: var(--tracking-normal); }

/* Document figures share the rule weight through the chart-stroke atom. */
:where(.fds-prose) figure .fds-chart { --chart-stroke: var(--hair); }

/* Calm monochrome marks */
.fds-chart__line   { fill: none; stroke: var(--ink-2); stroke-width: var(--chart-stroke, var(--stroke-plot)); stroke-linejoin: round; stroke-linecap: round; }
.fds-chart__dot    { fill: var(--panel); stroke: var(--ink-2); stroke-width: var(--chart-stroke, var(--stroke-plot)); }
.fds-chart__cap    { fill: var(--signal); stroke: var(--panel); stroke-width: var(--stroke-2); }
.fds-chart__bar    { fill: var(--line-2); }
.fds-chart__bar-2  { fill: var(--mut); }

/* The ONE accent — the figure that matters */
.fds-chart__line--accent { stroke: var(--signal); stroke-width: var(--chart-stroke, var(--stroke-2)); }
.fds-chart__bar--accent  { fill: var(--signal); }

/* data-lines non-accent series — solid strokes stepping down the navy data ramp.
   The distinction from the accent line is LUMINANCE (the ramp) plus the legend
   word, never a dash or a texture (standing taste rule); each survives greyscale. */
.fds-chart__line--muted  { stroke: var(--data-2); }
.fds-chart__line--muted2 { stroke: var(--data-3); }

/* Stacked bar segments — neutral ramp + one accent */
.fds-chart__seg-1 { fill: var(--data-1); }
.fds-chart__seg-2 { fill: var(--data-2); }
.fds-chart__seg-3 { fill: var(--data-3); }

/* Donut */
.fds-chart__ring     { fill: none; stroke: var(--line); stroke-width: var(--stroke-ring); }
.fds-chart__ring-val { fill: none; stroke: var(--signal); stroke-width: var(--stroke-ring); stroke-linecap: round; }

/* Content-aware highlight — guide line + lit mark, not a background wash */
.fds-chart__guide  { stroke: var(--signal-line); stroke-width: var(--hair); }
.fds-chart__hit    { fill: transparent; cursor: pointer; }
/* Keyboard focus for the now-focusable hit areas (Chart.jsx gives each rect
   tabindex + focus handlers). Shows the shared focus ring without a pointer. */
.fds-chart__hit:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }
.fds-chart__bar.is-dim,
.fds-chart__bar-2.is-dim { opacity: var(--opacity-dim); transition: opacity var(--dur-fast) var(--ease-out); }

/* Gauge hover host — relative wrapper the runtime adds around a [data-gauge] svg so
   its .fds-tip can anchor; the value arc lights on hover (state class, no animation). */
.fds-gauge-wrap { position: relative; display: inline-block; line-height: 0; }
.fds-gauge path.is-hot { stroke-width: calc(var(--stroke-ring) + var(--stroke-2)); }

/* Share-bar hover host — relative wrapper around .fds-share__bar so its .fds-tip can
   anchor; the hovered segment stays lit while the rest dim, the word carries meaning. */
.fds-share-wrap { position: relative; display: block; width: 100%; }
.fds-share-wrap .fds-share__seg { transition: opacity var(--dur-snap) var(--ease-out); }
.fds-share-wrap.is-hovering .fds-share__seg { opacity: var(--opacity-dim); }
.fds-share-wrap.is-hovering .fds-share__seg.is-hot { opacity: 1; }

/* Bar annotations (Wave 5) — event markers + x-axis labels.
   A marker is a faint hairline drop-line plus a word: the colour never carries
   the meaning alone, the word does. The label overlays live in .fds-bars-wrap
   (position: relative, composition.css) and are positioned by percentage, so
   they track the bars through the chart's horizontal stretch. */

/* the drop-line, drawn in SVG space from a bar annotation's word down to the bar
   it marks; non-interactive so it never steals a bar's hover. Per RF it is a very
   faint THIN hairline: a single --hair stroke of --chart-mark (the chart's major
   ruler-tick strength), no casing and no cap. It reads as one of the chart's own
   quiet ruler lines, clearest over the open plot ground above a bar (where the eye
   picks up the drop from the word) and receding where it crosses a filled bar. The
   line carries no meaning on its own: the WORD above it and the screen-reader
   summary do, so it is a position indicator, not a graphic that must clear WCAG's
   3:1 non-text floor against every bar fill. See tokens/colors.css for the token. */
.fds-chart__mark-line { stroke: var(--chart-mark); stroke-width: var(--hair); pointer-events: none; }

/* event-marker label strip, above the chart */
.fds-bars-marks { position: relative; display: block; height: calc(var(--text-micro) * var(--leading-tight) + var(--space-2)); }
.fds-bars-mark   { position: absolute; bottom: 0; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; pointer-events: none; }
/* pointer-events: auto re-enables interaction the parent chip turns off, so a
   label ellipsized past 15ch surfaces its full text via the native title tooltip
   on hover. The word strip sits ABOVE the chart, never over the bars, so a
   hoverable label cannot steal a bar's hover. */
.fds-bars-mark__label { max-width: 15ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-micro); font-weight: var(--weight-strong); line-height: var(--leading-none); color: var(--ink-2); letter-spacing: var(--tracking-normal); text-align: center; pointer-events: auto; }

/* B4 — the bar-chart readout ANSWERS INSTANTLY on the first bar under the pointer,
   then tracks the pointer bar-to-bar like a cursor on an instrument, and releases
   gently on leave. Feedback-answers motion: user-caused, fast. The runtime JUMPS the
   tip into place on first appearance and its opacity SNAPS on with no fade (the first
   answer is never delayed), then keeps .is-gliding on so only bar-to-bar POSITION
   moves slide; on leave the runtime drops .is-gliding so the base rule below dissolves
   the tip out. Only the leave uses the fade — entry is a jump. Constants are the
   RF-adopted P-B4 pick, shipped verbatim: 90ms position glide on the shared --ease-out
   curve, --dur-fast (140ms) leave dissolve. Reduced motion AND still mode collapse
   every transition here to instant, so the value/meaning never depend on the glide —
   the two paths are kept identical by build/lint-still-mode.mjs. The glide duration
   lives once as --dur-glide (tokens/spacing.css). */
.fds-bars-wrap .fds-tip { transition: opacity var(--dur-fast) var(--ease-out); }
.fds-bars-wrap .fds-tip.is-gliding {
  /* POSITION only: opacity is deliberately absent here so the first answer, which the
     runtime paints while .is-gliding is already on, jumps in instantly. This rule
     outranks the base opacity transition (two classes), so no opacity fade on entry;
     the base rule governs opacity only on leave, once the runtime drops .is-gliding. */
  transition: left var(--dur-glide) var(--ease-out),
              top var(--dur-glide) var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
  .fds-bars-wrap .fds-tip, .fds-bars-wrap .fds-tip.is-gliding { transition: none; }
}
:root[data-still] .fds-bars-wrap .fds-tip,
:root[data-still] .fds-bars-wrap .fds-tip.is-gliding { transition: none; }

/* x-axis labels, below the axis, one centred under each bar */
.fds-bars-xaxis { position: relative; display: block; height: calc(var(--text-micro) + var(--space-2)); margin-top: var(--space-1); }
/* max-width is set inline by the runtime to each bar's slot width; overflow +
   ellipsis clip a label that would exceed its slot. */
.fds-bars-xtick { position: absolute; top: 0; transform: translateX(-50%); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-micro); font-weight: var(--weight-body); line-height: var(--leading-none); color: var(--mut); letter-spacing: var(--tracking-normal); text-align: center; }

/* data-lines host + legend. The wrap is the relative box the runtime anchors the
   .fds-readout and sr-only table into. The legend swatch is a short SOLID line in the
   series colour (never a dot or a patterned key), so the legend reads the same in
   greyscale as the chart: luminance ladder + word. */
.fds-lines-wrap { position: relative; display: block; }
.fds-lines-legend { display: flex; flex-wrap: wrap; gap: var(--space-4); margin: 0; padding: 0; list-style: none; }
.fds-lines-legend__item { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-xs); color: var(--mut); }
.fds-lines-legend__sw { width: var(--legend-sw-w); height: 0; flex: none; border-top: var(--stroke-2) solid var(--data-2); border-radius: var(--radius-pill); }
.fds-lines-legend__sw--s1 { border-top-color: var(--data-1); }
.fds-lines-legend__sw--s2 { border-top-color: var(--data-2); }
.fds-lines-legend__sw--s3 { border-top-color: var(--data-3); }
/* tip swatches for the line-chart readout rows — solid squares matching each
   series' ramp colour (the tip states the value in words beside them). */
.fds-readout__sw--s1 { background: var(--data-1); }
.fds-readout__sw--s2 { background: var(--data-2); }
.fds-readout__sw--s3 { background: var(--data-3); }

/* KPI sparkline */
.fds-spark__line { fill: none; stroke: var(--ink-2); stroke-width: var(--stroke-plot); stroke-linejoin: round; stroke-linecap: round; }
.fds-spark__line--accent { stroke: var(--signal); }
.fds-spark__cap  { fill: var(--signal); }
/* Hover data box — opaque panel, ordinary hairline, existing float shadow */
.fds-readout {
  position: absolute;
  z-index: 20;
  transform: translate(-50%, -100%);
  margin-top: calc(var(--space-3) * -1);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--panel);
  color: var(--ink-2);
  border: var(--hair) solid var(--line);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  white-space: nowrap;
  box-shadow: var(--shadow-float);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.fds-readout.is-on { opacity: 1; }
.fds-readout__title { font-weight: var(--weight-strong); margin-bottom: var(--space-2); color: var(--ink-2); }
.fds-readout__row { display: flex; align-items: center; gap: var(--space-2); }
.fds-readout__row + .fds-readout__row { margin-top: var(--space-1); }
.fds-readout__sw { width: var(--space-2); height: var(--space-2); border-radius: var(--radius-mark); flex: none; }
.fds-readout__k { color: var(--mut); font-weight: var(--weight-body); margin-right: var(--space-3); }
.fds-readout__v { font-weight: var(--weight-strong); margin-left: auto; color: var(--ink-2); }
.fds-readout::after {
  content: ""; position: absolute; left: 50%; top: 100%;
  transform: translateX(-50%);
  border: var(--space-1) solid transparent; border-top-color: var(--line);
  filter: drop-shadow(0 var(--hair) 0 var(--line));
}

/* B2 still mode / reduced motion — collapse every motion transition in this file to
   instant, so a reader who asked for stillness gets the same rest state with identical
   meaning: the dim-fade (opacity), the gauge hover glow (filter), the share-segment
   dim (opacity), and the tooltip fade (opacity). Colour crossfades stay; these do not.
   Held in lockstep with the positive origins above by build/lint-still-mode.mjs — the
   reduced-motion and still twins are byte-identical, and neither may drift or vanish. */
@media (prefers-reduced-motion: reduce) {
  .fds-chart__bar.is-dim,
  .fds-chart__bar-2.is-dim,
  .fds-gauge-wrap .fds-gauge,
  .fds-share-wrap .fds-share__seg,
  .fds-readout { transition: none; }
}
:root[data-still] .fds-chart__bar.is-dim,
:root[data-still] .fds-chart__bar-2.is-dim,
:root[data-still] .fds-gauge-wrap .fds-gauge,
:root[data-still] .fds-share-wrap .fds-share__seg,
:root[data-still] .fds-readout { transition: none; }

/* Mark geometry is sized once, shared by authored and hydrated charts. */
.fds-chart__grid, .fds-chart__cross, .fds-chart__axis, .fds-chart__guide,
.fds-chart__line, .fds-chart__dot, .fds-chart__cap, .fds-chart__mark-line {
  vector-effect: non-scaling-stroke;
}
.fds-chart__axis { fill: none; }
.fds-chart__dot, .fds-chart__cap { r: calc(var(--dot) / 2); }
.fds-spark__cap, .fds-spark__hl { r: calc(var(--space-1) / 2); }
.fds-chart__bar, .fds-chart__bar-2 { rx: var(--radius-mark); }
.fds-chart__ring { stroke-linecap: round; }
.fds-chart__ring-segment { fill: none; stroke-width: var(--stroke-ring); stroke-linecap: butt; }

/* ===== parts/footer.css ===== */
/* Foundational — subtle product-credit footer.
   Barely-there by design: a thin hairline above, faint small text, the product
   name only one quiet step darker. Never competes with content. */

.fds-footer {
  display: block;
  text-align: center;
  margin-top: var(--space-12);
  padding: var(--space-5) 0 var(--space-4);
  border-top: var(--hair) solid var(--line);
  color: var(--text-faint);
  font-size: var(--text-2xs);
  font-weight: var(--weight-body);
  letter-spacing: var(--tracking-label);
}
.fds-footer strong { color: var(--text-muted); font-weight: var(--weight-strong); }

/* ===== parts/composition.css ===== */
/* Foundational — composition layer.
   The reusable building blocks the design system composes from:
   app bar + hero shell, section + 12-col grid, the card scaffold, status tags,
   figures, meters, rows, lists, and the data-viz hosts. These are REFERENCES, not
   fill-in templates: compose them freely; never force content to fit a card shape.
   Every value is a token — no raw colors, no hand-placed spacing. */

  /* screen-reader-only — CONTRACT: visually hidden, still announced by assistive tech.
     For labels/captions that the eye gets from layout but a non-visual reader needs. */
  .fds-sr-only {
    position: absolute;
    width: var(--hair); height: var(--hair);
    padding: 0; margin: calc(var(--hair) * -1);
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  /* shared keyboard focus ring — CONTRACT: outline via var(--focus), shown only for
     keyboard users (:focus-visible), never for mouse clicks. */
  .fds-appbar__cta:focus-visible,
  .fds-seg button:focus-visible,
  .fds-seg a:focus-visible,
  .fds-row a:focus-visible,
  .fds-comparison a:focus-visible {
    outline: var(--stroke-2) solid var(--focus);
    outline-offset: var(--stroke-2);
  }

  /* still opening band — layout only, paper, no glass, no ambient motion */
  .fds-hero { margin: var(--space-8) 0 var(--space-10); }
  .fds-hero__body { display: grid; grid-template-columns: 1fr auto; gap: var(--space-8); align-items: start; padding: 0; }
  .fds-hero__main { min-width: 0; }
  .fds-hero__eyebrow { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label-wide); text-transform: uppercase; color: var(--text-faint); }
  .fds-hero__title { margin: var(--space-4) 0 0; font-size: var(--text-2xl); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); color: var(--ink); max-width: 22ch; text-wrap: balance; }
  .fds-hero__lede { margin: var(--space-4) 0 0; max-width: 54ch; font-size: var(--text-base); line-height: var(--leading-snug); color: var(--text-muted); text-wrap: pretty; }
  .fds-hero__side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-6); }
  .fds-hero__figure { text-align: right; }
  .fds-hero .fds-fig { color: var(--ink); }
  .fds-hero .fds-fig__unit { color: var(--mut); }
  .fds-hero__figcap { display: block; margin-top: var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label-loose); text-transform: uppercase; color: var(--text-faint); }
  @media (max-width: 720px) { .fds-hero__body { grid-template-columns: 1fr; } .fds-hero__side { align-items: flex-start; } .fds-hero__figure { text-align: left; } }
  .fds-seg { display: inline-flex; gap: calc(var(--space-1) / 2); border: var(--hair) solid var(--line); border-radius: var(--radius-pill); padding: var(--space-1); box-shadow: var(--shadow-flat); flex: none; }
  /* Two forms share ONE pill grammar: a same-page view switch is a <button>
     radiogroup (aria-checked); a page-navigation switch (period links, tabs that
     load a new URL) is a <nav> of <a> anchors (aria-current="page"). The active
     pill is the same filled shape in both, so the choice never reads as colour
     alone and the two forms stay visually one control. */
  .fds-seg button, .fds-seg a { appearance: none; border: 0; background: none; font: inherit; font-size: var(--text-xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-open); color: var(--text-muted); text-decoration: none; padding: var(--space-2) var(--space-4); border-radius: var(--radius-pill); cursor: pointer; transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out); }
  .fds-seg button[aria-checked="true"], .fds-seg a[aria-current="page"] { background: var(--signal-soft); color: var(--accent-text); }

  .fds-label { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label-wide); text-transform: uppercase; color: var(--text-muted); }
  /* Contained like .fds-appbar__name: a nowrap label that outgrows its container
     ellipsizes instead of widening the page (the page never scrolls sideways).
     Every composed home for this label is a flex container, so the span is
     blockified and the max-width/overflow pair engages; in a rare inline context
     the pair is inert, which only returns the old behaviour. */
  .fds-measure { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label-loose); text-transform: uppercase; color: var(--text-faint); white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }

  /* section header */
  .fds-sec { margin-top: var(--space-12); scroll-margin-top: var(--appbar-clearance); }
  .fds-sec__head { display: flex; align-items: baseline; gap: var(--space-4); margin-bottom: var(--space-5); }
  .fds-sec__no { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label-loose); color: var(--text-faint); font-variant-numeric: tabular-nums; }
  /* One heading rhythm: the section title takes the SAME leading as a prose h2 at
     the same size (parts/content.css), so a page never carries two line heights
     for one heading voice. */
  .fds-sec__title { margin: 0; font-size: var(--text-lg); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); color: var(--ink-2); }
  .fds-sec__line { flex: 1; height: var(--hair); background: var(--line); }
  .fds-sec__count { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label-loose); text-transform: uppercase; color: var(--text-faint); }

  /* grid.
     grid-auto-flow is plain `row` (NOT `dense`): dense backfills a later, smaller
     item into an earlier gap, which reorders the VISUAL sequence against DOM and
     screen-reader order — content must read in the order it is authored.
     grid-auto-columns: 0 is a guard: if a span ever exceeds the current column
     count (e.g. a 12-span row inside the 6-col tablet grid), the implicit tracks it
     spawns collapse to zero width instead of stealing width (as `auto`) from the
     real 1fr columns and squashing a neighbouring tile. Correct compositions never
     create implicit columns, so the guard is inert in normal use. */
  .fds-cat { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--space-5); grid-auto-flow: row; grid-auto-columns: 0; }
  .fds-sp3 { grid-column: span 3; } .fds-sp4 { grid-column: span 4; } .fds-sp6 { grid-column: span 6; }
  .fds-sp8 { grid-column: span 8; } .fds-sp12 { grid-column: span 12; }

  /* The public card declares its FULL panel recipe (fill, hairline, radius, shadow)
     here, in its own home — it is the second justified survivor of the W2-D2 fill
     consolidation, deliberately NOT in the parts/surface-fill.css group. This part
     loads after parts/panes.css (decision option, flow node) and parts/chart.css
     (tooltip), so an element that ever matched .fds-card AND one of those at equal
     specificity resolves to the card — the win order the card must keep. Layout
     identity (flex column) rides on the same rule. */
  .fds-card {
    position: relative;
    display: flex; flex-direction: column; min-width: 0;
    background: var(--panel);
    border: var(--hair) solid var(--line);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
  }
  /* Panel weights — the standard card, plus two named steps. Declared right after
     the card so each modifier outranks the base by source order at equal
     specificity (the accent hairline and the flat shadow must win).
     LEAD: the one panel per page that carries what the reader must act on. It stays
     on the reading-content shadow tier (--shadow-card; the float tier is chrome-only
     per the room contract) and outranks its peers with an accent hairline; its
     greyscale/print-surviving mark is the filled .fds-lead flag (parts/layout.css),
     never colour alone. At most one lead per page.
     QUIET: a compressed, headless panel that reads as one cell of a set (a KPI in a
     flush mosaic), not a card demanding its own attention. Flatter, tighter. */
  .fds-card--lead { border-color: var(--signal-line); }
  .fds-card--quiet { box-shadow: var(--shadow-flat); }
  .fds-card--quiet > .fds-card__body { padding: var(--space-4); gap: var(--space-2); }
  .fds-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); padding: var(--space-5) var(--space-5) 0; }
  .fds-card__heading { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
  .fds-card__title { margin: 0; font-size: var(--text-md); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); color: var(--ink-2); line-height: var(--leading-tight); }
  .fds-card__meta { flex: none; display: flex; align-items: center; gap: var(--space-3); }
  .fds-card__rule { margin: var(--space-4) 0 0; }
  .fds-card__body { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-4); flex: 1; }
  /* The body owns paragraph spacing through its gap, including KPI captions. */
  .fds-card__body p, p.fds-sub { margin: 0; }
  .fds-card__body--flush { gap: var(--space-0); } /* tight row-lists: let .fds-row hairlines meet */

  /* Attachment slots — a control glued to the content it acts on (composition
     rule 6: same surface, no gap between cause and effect). __tools sits ABOVE
     the body (a filter bar over the table it narrows, its count pointing at the
     rows right below); __foot sits BELOW (pagination under the table it pages).
     Each is a strip on the card's own surface, divided from the body by a single
     hairline so the control reads as PART of the card, not a floating sibling.
     The slotted control owns its own inner layout (the filter bar, the pager);
     these rules give only the strip's padding and the dividing hairline. */
  .fds-card__tools { padding: var(--space-4) var(--space-5); border-bottom: var(--hair) solid var(--line); }
  .fds-card__foot  { padding: var(--space-4) var(--space-5); border-top: var(--hair) solid var(--line); }

  /* status tag — borderless dot+word (compact) */
  .fds-stat { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; line-height: var(--leading-none); white-space: nowrap; }
  .fds-stat__dot { width: var(--dot); height: var(--dot); border-radius: var(--radius-pill); flex: none; }
  .fds-stat--ok   { color: var(--ink-2); }   .fds-stat--ok .fds-stat__dot   { background: var(--ok-dot); }
  .fds-stat--warn { color: var(--ink-2); } .fds-stat--warn .fds-stat__dot { background: var(--warn-dot); }
  .fds-stat--blk  { color: var(--ink-2); }  .fds-stat--blk .fds-stat__dot  { background: var(--blk-dot); }
  .fds-stat--na   { color: var(--ink-2); }   .fds-stat--na .fds-stat__dot   { background: var(--na-dot); }
  /* --now: the current / selected marker. Selection is WAYFINDING (where you are),
     not a status outcome, so its dot rides the navy --signal, the same role the
     select's selected dot (parts/forms.css) and every other current marker use;
     green stays reserved for outcomes (cleared, done). */
  .fds-stat--now  { color: var(--ink-2); }  .fds-stat--now .fds-stat__dot  { background: var(--signal); }

  /* Figure lockup — the one big-number primitive. ONE geometry everywhere; only
     the size changes, by variant (--sm, base, --display). Even-width (tabular)
     digits so a changing value never reflows the layout. Consolidates the former
     .fds-hero__fig and .fds-count lockups into this one (AP-9 / C4). */
  .fds-fig { display: inline-flex; align-items: baseline; font-size: var(--text-3xl); font-weight: var(--weight-strong); letter-spacing: var(--tracking-figure); color: var(--ink-2); line-height: var(--leading-none); font-variant-numeric: tabular-nums; }
  .fds-fig--sm { font-size: var(--text-2xl); }
  .fds-fig--display { font-size: var(--text-display); letter-spacing: var(--tracking-tighter); }
  .fds-fig__unit { font-size: var(--text-lg); font-weight: var(--weight-strong); color: var(--mut); margin-left: var(--space-1); letter-spacing: var(--tracking-normal); }
  .fds-fig--display .fds-fig__unit { margin-left: var(--space-3); }
  .fds-fig__row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
  .fds-fig__row .fds-spark { align-self: center; } /* a chart centres against the figure; text qualifiers stay on its baseline */
  .fds-fig__row:has(+ .fds-meter) { margin-bottom: var(--space-4); } /* clear the meter's overhead target flag below a baseline-locked figure row */
  .fds-sub { font-size: var(--text-xs); line-height: var(--leading-snug); color: var(--text-muted); }
  .fds-sub b { color: var(--ink-2); font-weight: var(--weight-strong); }

  /* spark */
  .fds-spark { width: var(--spark-width); height: var(--spark-height); flex: none; }
  .fds-spark-wrap { position: relative; display: inline-block; width: var(--spark-width); height: var(--spark-height); }
  .fds-spark__hl { fill: var(--signal); opacity: 0; transition: opacity var(--dur-snap) var(--ease-out); }

  /* hover data box — opaque panel, ordinary hairline, existing float shadow */
  .fds-tip { position: absolute; z-index: 5; transform: translate(-50%, -150%); padding: var(--space-1) var(--space-2); border-radius: var(--radius-sm); font-size: var(--text-micro); font-weight: var(--weight-strong); line-height: var(--leading-snug); white-space: nowrap; text-align: center; pointer-events: none; opacity: 0; transition: opacity var(--dur-snap) var(--ease-out); font-variant-numeric: tabular-nums; color: var(--ink-2); background: var(--panel); border: var(--hair) solid var(--line); box-shadow: var(--shadow-float); }
  .fds-tip b { font-weight: var(--weight-strong); color: var(--ink-2); }
  .fds-tip__sub { color: var(--mut); font-weight: var(--weight-strong); }

  /* budget meter — explicit scale + named target */
  .fds-meter { display: flex; flex-direction: column; gap: var(--space-2); }
  .fds-meter__track { position: relative; height: var(--space-2); border-radius: var(--radius-pill); background: var(--line); }
  /* The fill renders SETTLED: no width transition, so the meter never grows in on
     load. The runtime paints its final width once, from the inline style, and the
     fill simply IS its value (AP-4 arrival budget, memo B1 — a value arrives already
     at rest, it never performs its arrival, so a page of meters is silent on load). */
  .fds-meter__fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: var(--radius-pill); background: var(--ink-2); }
  /* The plan target is a threshold marker: a faint solid hairline in the house
     --chart-mark idiom (the same neutral marker line the bar charts use for an
     event drop-line), never a dash. The "Plan 83%" flag word above it carries
     the meaning, so the line stays quiet and the colour never carries it alone. */
  .fds-meter__target { position: absolute; top: calc(var(--space-1) * -1); bottom: calc(var(--space-1) * -1); width: 0; border-left: var(--hair) solid var(--chart-mark); }
  .fds-meter__flag { position: absolute; bottom: calc(100% + var(--space-1)); left: 50%; transform: translateX(-50%); font-size: var(--text-micro); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--mut); white-space: nowrap; }
  .fds-meter__scale { display: flex; justify-content: space-between; font-size: var(--text-2xs); font-weight: var(--weight-strong); color: var(--text-faint); font-variant-numeric: tabular-nums; }

  /* target pacing — actual + forecast progress on a milestone scale.
     An EXTENSION of the budget meter, not a parallel system: in the markup the
     track, both fills, the target line and its flag ARE the .fds-meter__
     primitives (the meter class sits on each element); the .fds-pace__ classes
     below carry ONLY the delta (a squared inner fill edge, the forecast's lighter
     ink step, a faint hairline target). A change to a meter primitive therefore
     propagates here for free — nothing is re-implemented. The forecast is a SECOND
     meter fill that continues from the actual one; the two series are told apart by
     a LUMINANCE LADDER (a strong actual, a lighter forecast, the pale unfilled
     track) plus a two-word legend, never by colour alone. The ladder is pure
     neutral ink, so the distinction survives greyscale, print, and colourblind
     viewing without any hue doing the work.
     Milestones sit at authored percentages (the piecewise scale is the author's
     data, exactly as a meter's fill width is). One positioned node per milestone
     carries BOTH its label and its paired annotation value, so the two rows can
     never drift apart. The gap to target is STATED IN WORDS on the block face. */
  .fds-pace { display: flex; flex-direction: column; gap: var(--space-4); }
  .fds-pace__legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); }
  .fds-pace__key { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
  .fds-pace__sw { width: var(--legend-sw-w); height: var(--legend-sw-h); border-radius: var(--legend-sw-r); flex: none; }
  .fds-pace__sw--actual { background: var(--ink-2); }
  /* Forecast: the middle rung of the luminance ladder — a SOLID lighter ink than
     the actual, no texture. Reads clearly softer than the strong actual and
     clearly stronger than the pale unfilled track, in both themes and in print. */
  .fds-pace__sw--fcst { background: var(--faint); }
  /* Target: a thin SOLID faint hairline, the same quiet ruler-tick idiom as the
     chart event-marker (--chart-mark aliases --tick-2). No dash. */
  .fds-pace__sw--target { width: 0; height: var(--legend-sw-h-box); border-radius: 0; border-left: var(--stroke-2) solid var(--chart-mark); }
  /* ONE coordinate system: the track fills, the ticks, the milestone marks and
     the range bands are ALL positioned as a percent of the same __scale width, so
     a given percent lands on the SAME x in the bar, under it, and across the
     bands. (The bands were previously flex-basis of the full width while the marks
     were inset, which overstated every band by the inset end margins.) */
  .fds-pace__scale { position: relative; }
  /* The actual + forecast are .fds-meter__fill in the markup; these rules add only
     the deltas. The actual keeps its outer (left) end rounded and squares the
     inner (right) end so the forecast fill continues flush from it. */
  .fds-pace__actual { border-radius: var(--radius-pill) 0 0 var(--radius-pill); }
  /* Forecast fill: a SOLID lighter-ink continuation of the actual (the middle rung
     of the dark/mid/pale luminance ladder), no texture. --faint sits clearly
     between the strong --ink-2 actual and the pale --line track in both themes. */
  .fds-pace__fcst { background-color: var(--faint); background-image: none; border-radius: 0 var(--radius-pill) var(--radius-pill) 0; }
  /* The annual target is a thin SOLID faint hairline in the chart event-marker
     idiom (--chart-mark, the quiet major-ruler-tick strength): a quiet position
     line, faint not bold, in step with the meter's own solid plan line. The word
     TARGET on its flag carries the meaning; the line is only a position tick. */
  .fds-pace__target { border-left: var(--hair) solid var(--chart-mark); }
  /* A target at the far end of the scale right-anchors its (reused meter) flag so
     the word never overflows the card edge. */
  .fds-pace__flag--end { left: auto; right: 0; transform: none; }
  /* Period checkpoints (P1..P7) are SUBTLE minor-ruler ticks, not full-height cuts.
     Only the annual-target line cuts through the whole bar (--chart-mark, the MAJOR
     ruler-tick strength); the period ticks sit one rung quieter — a short --tick
     (the documented MINOR-ruler-tick ink) stub hanging just below the track base,
     centred on each P coordinate so it aligns with its P label underneath. Two axes
     of subordination to the target (shorter AND fainter) keep the periods as quiet
     reference gradations that no longer compete with the plan line. The border-left
     prints on its own and --tick restates in the print palette, so no print rule is
     needed. */
  .fds-pace__tick { position: absolute; top: 100%; height: var(--space-1); width: 0; border-left: var(--hair) solid var(--tick); transform: translateX(-50%); }
  .fds-pace__marks { position: relative; height: var(--space-12); margin-top: var(--space-1); }
  .fds-pace__mark { position: absolute; top: 0; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: var(--space-1); white-space: nowrap; }
  .fds-pace__mark--first { align-items: flex-start; transform: none; }
  .fds-pace__mark--last { align-items: flex-end; transform: translateX(-100%); }
  .fds-pace__mlabel { font-size: var(--text-2xs); font-weight: var(--weight-strong); color: var(--ink-2); font-variant-numeric: tabular-nums; }
  .fds-pace__mval { font-size: var(--text-2xs); color: var(--mut); font-variant-numeric: tabular-nums; }
  .fds-pace__annk { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
  /* Range bands share the marks' coordinate: each band is placed by the SAME
     percent as the marks it spans — a leading margin to its start mark, a width to
     its end mark — so a band's edges land exactly on its two milestones and it
     never overstates its interval. */
  .fds-pace__ranges { display: flex; }
  .fds-pace__range { flex: none; min-width: 0; padding-top: var(--space-2); border-top: var(--hair) solid var(--line-2); display: flex; flex-direction: column; gap: var(--space-1); }
  .fds-pace__rt { font-size: var(--text-2xs); font-weight: var(--weight-strong); color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .fds-pace__rs { font-size: var(--text-2xs); color: var(--mut); }
  .fds-pace__gap { font-size: var(--text-sm); line-height: var(--leading-snug); color: var(--body); }
  .fds-pace__gap b { color: var(--ink-2); font-weight: var(--weight-strong); }

  /* item rows (lists) */
  .fds-rows { display: flex; flex-direction: column; }
  .fds-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) 0; border-top: var(--hair) solid var(--line-fine); }
  .fds-row:first-child { border-top: 0; }
  .fds-row__main { min-width: 0; display: flex; flex-direction: column; gap: calc(var(--space-1) / 2); }
  .fds-row__t { font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); line-height: var(--leading-snug); }
  .fds-row__s { font-size: var(--text-2xs); color: var(--mut); line-height: var(--leading-snug); }
  .fds-row__r { margin-left: auto; flex: none; display: flex; align-items: center; gap: var(--space-3); }

  /* numbered index node */
  .fds-ix { width: var(--space-6); height: var(--space-6); flex: none; display: grid; place-items: center; border-radius: var(--radius-pill); border: var(--hair) solid var(--line-2); color: var(--mut); font-size: var(--text-2xs); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums; }
  .fds-ix--done { color: var(--ok-dot); border-color: var(--ok-line); }
  .fds-ix--now { color: var(--signal); border-color: var(--signal); }

  /* avatar (initials) */
  .fds-ava { width: var(--space-8); height: var(--space-8); flex: none; display: grid; place-items: center; border-radius: var(--radius-pill); background: var(--paper); border: var(--hair) solid var(--line-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); color: var(--ink-2); letter-spacing: var(--tracking-open); }

  /* trend / signed KPI delta — CONTRACT: a small glyph ALWAYS paired with the value;
     colour is never carried by the word alone (the glyph is the redundant cue).
     Two families, because direction and valence are NOT the same thing:
       VALENCE variants (--up/--down/--flat): the move is judged good or bad, so
         colour asserts it. Risk context only — rising risk is bad (red), falling
         risk is good (green). Reach for these only where up/down carries meaning.
       NEUTRAL variants (--rise/--fall/--steady): the glyph reports which way a
         metric moved; the move itself is NOT judged. Colour stays calm body/mut
         and never claims good or bad. Reach for these for plain metric deltas
         (revenue, headcount, latency) where the reader decides what the move means. */
  .fds-trend { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); display: inline-flex; align-items: center; gap: var(--space-1); color: var(--mut); font-variant-numeric: tabular-nums; }
  .fds-trend::before { font-size: var(--text-micro); line-height: var(--leading-none); }
  .fds-trend--up   { color: var(--blk-ink); } .fds-trend--up::before   { content: "\2191"; } /* ↑ rising = bad (risk) */
  .fds-trend--down { color: var(--ok-ink); }  .fds-trend--down::before { content: "\2193"; } /* ↓ falling = good (risk) */
  .fds-trend--flat { color: var(--mut); }     .fds-trend--flat::before { content: "\2192"; } /* → */
  /* valence-neutral: glyph shows direction, colour stays calm (no good/bad claim) */
  .fds-trend--rise    { color: var(--body); } .fds-trend--rise::before    { content: "\2191"; } /* ↑ */
  .fds-trend--fall    { color: var(--body); } .fds-trend--fall::before    { content: "\2193"; } /* ↓ */
  .fds-trend--steady  { color: var(--mut); }  .fds-trend--steady::before  { content: "\2192"; } /* → */

  /* mini bullet (risk severity / check) */
  .fds-sev { width: var(--space-2); height: var(--space-2); border-radius: var(--radius-mark); flex: none; }
  .fds-sev--hi { background: var(--blk-dot); } .fds-sev--med { background: var(--warn-dot); } .fds-sev--lo { background: var(--na-dot); }
  /* Severity word paired with the square so colour never stands alone (mirrors
     the dot+word pairing in 09-health-matrix). Fixed width aligns the titles. */
  .fds-sevword { flex: none; width: var(--space-16); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--body); }

  /* check mark box */
  .fds-chk { width: var(--space-5); height: var(--space-5); flex: none; border-radius: var(--radius-mark); border: var(--hair) solid var(--line-2); display: grid; place-items: center; }
  .fds-chk--on { background: var(--ok-bg); border-color: var(--ok-line); }
  .fds-chk--on::after { content: ""; width: var(--space-2); height: var(--space-1); border-left: var(--stroke-2) solid var(--ok-dot); border-bottom: var(--stroke-2) solid var(--ok-dot); transform: rotate(-45deg); margin-top: calc(calc(var(--space-1) / 2) * -1); }
  .fds-chk--now { border-color: var(--signal); }

  /* two-column split (scope) */
  .fds-split { display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
  .fds-split__col { padding: 0 var(--space-5); }
  .fds-split__col:first-child { padding-left: 0; border-right: var(--hair) solid var(--line); }
  .fds-split__col:last-child { padding-right: 0; }
  .fds-split__h { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
  .fds-scope-item { display: flex; gap: var(--space-2); align-items: baseline; font-size: var(--text-sm); color: var(--body); line-height: var(--leading-snug); padding: var(--space-2) 0; }
  .fds-scope-item__m { color: var(--text-faint); flex: none; }

  /* RAG matrix */
  .fds-matrix { display: grid; gap: 0; }
  .fds-matrix__row { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); align-items: center; gap: var(--space-3); padding: var(--space-3) 0; border-top: var(--hair) solid var(--line-fine); }
  .fds-matrix__row:first-child { border-top: 0; }
  .fds-matrix__head { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); padding-bottom: var(--space-2); border-top: 0; }
  .fds-matrix__name { font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); }
  .fds-cell { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-2xs); color: var(--mut); }
  .fds-cell__dot { width: var(--space-3); height: var(--space-3); border-radius: var(--radius-pill); flex: none; }

  /* milestone timeline */
  .fds-timeline { position: relative; padding: var(--space-8) 0 var(--space-6); }
  .fds-timeline__track { position: relative; height: var(--hair); background: var(--line-2); }
  .fds-timeline__done { position: absolute; left: 0; top: 0; height: var(--hair); background: var(--ok-dot); }
  .fds-tl-node { position: absolute; top: 50%; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; }
  .fds-tl-node__dot { width: var(--space-3); height: var(--space-3); border-radius: var(--radius-pill); border: var(--stroke-2) solid var(--line-2); }
  .fds-tl-node.is-done .fds-tl-node__dot { background: var(--ok-dot); border-color: var(--ok-dot); }
  .fds-tl-node.is-now .fds-tl-node__dot { border-color: var(--signal); box-shadow: 0 0 0 var(--space-1) var(--signal-soft); }
  .fds-tl-node__lbl { position: absolute; top: var(--space-5); white-space: nowrap; font-size: var(--text-2xs); font-weight: var(--weight-strong); color: var(--ink-2); }
  .fds-tl-node__date { position: absolute; bottom: var(--space-5); white-space: nowrap; font-size: var(--text-2xs); color: var(--text-faint); font-variant-numeric: tabular-nums; }

  /* roadmap lanes. Phase name labels each row; the bar is pure duration.
     The ROW gap is the breathing room the hover tip nests into: a tip lifts above
     its bar and sits in the gutter, so the gutter is sized so the tip clears the
     resting bar in the lane above without grazing it. */
  .fds-road { position: relative; isolation: isolate; display: grid; grid-template-columns: var(--road-label-width) 1fr; gap: var(--space-5) var(--space-4); align-items: center; }
  .fds-road__cols { display: grid; grid-template-columns: repeat(4, 1fr); }
  /* colhead keeps its border-right: it coincides exactly with the overlay's
     quarter rule on screen (so no double line) but, being a BORDER not a
     background, it still prints the quarter divisions when a reader prints with
     backgrounds off — the overlay's interior rules are a background and would
     drop. The now line (a solid accent border) and the "Now" word (text) print too. */
  .fds-road__colhead { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); text-align: center; padding-bottom: var(--space-2); border-right: var(--hair) solid var(--line-fine); }
  .fds-road__lane { font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); white-space: nowrap; }
  .fds-road__cells { position: relative; height: var(--space-6); }
  /* CONTINUOUS quarter grid: ONE plot-spanning layer draws the four-quarter rules
     once, so they run unbroken down every lane instead of restarting as a stub
     inside each row (the old per-row background left tick fragments broken by the
     row gap). It spans the cells column exactly (past the 124px lane column + its
     column gap) and is isolated behind the bars, so it never leaks behind the card. */
  .fds-road__grid, .fds-road__nowtag { position: absolute; top: 0; bottom: 0; left: calc(var(--road-label-width) + var(--space-4)); right: 0; pointer-events: none; }
  .fds-road__grid { z-index: -1; border-left: var(--hair) solid var(--line);
    background-image: repeating-linear-gradient(to right, transparent 0, transparent calc(25% - var(--hair)), var(--line-fine) calc(25% - var(--hair)), var(--line-fine) 25%); }
  /* NOW marker: a vertical accent line (in the grid layer, behind the bars, so it
     reads as a reference passing through the live phase) PLUS the word "Now" above
     the bars. Colour AND word: greyscale keeps the word, so the mark never rides on
     colour alone. --road-now sets the position as a percent of the plot width. */
  .fds-road__now { position: absolute; top: 0; bottom: 0; left: var(--road-now, 58%); border-left: var(--hair) solid var(--signal); }
  .fds-road__nowtag { z-index: 1; }
  .fds-road__nowlabel { position: absolute; left: var(--road-now, 58%); top: 0; transform: translate(-50%, -100%);
    font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label);
    color: var(--signal); padding: 0 var(--space-1); white-space: nowrap; }
  .fds-road__bar { position: absolute; top: 50%; transform: translateY(-50%); height: var(--space-3); border-radius: var(--radius-pill); background: var(--line-2); cursor: default; transition: background var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out); }
  .fds-road__bar--accent { background: var(--signal); }
  /* Calm hover: the bar deepens a step and gains a soft float shadow so it lifts
     off the lane, and a .fds-tip (anchored in the relative .fds-road__cells)
     names the phase and its quarter span in WORDS, so the read never rides on
     the bar's length or colour alone. */
  .fds-road__bar:hover { background: var(--ink-2); box-shadow: var(--shadow-float); }
  .fds-road__bar--accent:hover { background: var(--signal-deep); }
  @media (prefers-reduced-motion: reduce) { .fds-road__bar { transition: none; } }
  /* B2 still mode twin (kept identical to the reduced-motion rule by lint-still-mode.mjs) */
  :root[data-still] .fds-road__bar { transition: none; }

  /* phase gates inline */
  .fds-gates { display: flex; align-items: stretch; gap: 0; }
  .fds-gate { flex: 1; display: flex; flex-direction: column; gap: var(--space-2); position: relative; padding-right: var(--space-4); }
  .fds-gate:last-child { flex: 0 0 auto; padding-right: 0; }
  .fds-gate__top { display: flex; align-items: center; gap: var(--space-2); }
  .fds-gate__line { flex: 1; height: var(--hair); background: var(--line-2); border-radius: var(--radius-pill); }
  /* Progress-colour rule (applies to the gate stepper here, the milestone timeline
     above, and the budget meter): GREEN (--ok-dot) marks a completed OUTCOME (a
     cleared gate, a done milestone, the same green as their check/dot marks);
     NAVY --signal marks only the LIVE position (the now index/ring), never a
     traversed span; NEUTRAL ink carries plain quantity (the budget meter's fill is
     an amount, not an outcome). One rule, three surfaces, no mixed voices. */
  .fds-gate.is-done .fds-gate__line { background: var(--ok-dot); }
  .fds-gate.is-now .fds-gate__line { background: linear-gradient(to right, var(--ok-dot) 0 55%, var(--line-2) 55% 100%); }
  .fds-gate__name { font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); }
  .fds-gate__sub { font-size: var(--text-2xs); color: var(--mut); }

  /* chart host (donut/gauge/bars) */
  .fds-viz { display: flex; align-items: center; justify-content: center; gap: var(--space-5); }
  .fds-viz__svg { display: block; }
  .fds-donut { width: var(--donut-size); height: var(--donut-size); flex: none; }
  .fds-gauge { width: var(--gauge-width); height: var(--plot-height); flex: none; }
  .fds-bars { width: 100%; height: var(--plot-height); }
  .fds-bars-wrap { position: relative; display: block; }
  .fds-bars .fds-chart__bar { transition: opacity var(--dur-snap) var(--ease-out); }
  /* B2/reduced-motion: the hover dim/undim is feedback motion, so it collapses to
     instant under BOTH the reader's reduced-motion preference and the composer's
     still mode. Byte-identical twins, held in lockstep by build/lint-still-mode.mjs. */
  @media (prefers-reduced-motion: reduce) {
    .fds-bars .fds-chart__bar { transition: none; }
  }
  :root[data-still] .fds-bars .fds-chart__bar { transition: none; }
  .fds-bars-wrap.is-hovering .fds-chart__bar { opacity: var(--opacity-dim); }
  .fds-bars-wrap.is-hovering .fds-chart__bar.is-hot { opacity: 1; }
  .fds-scatter { width: 100%; height: auto; display: block; }
  .fds-scatter-wrap { position: relative; width: 100%; }
  .fds-scatter-dot { position: absolute; width: var(--space-3); height: var(--space-3); border-radius: var(--radius-pill); transform: translate(-50%, -50%); box-sizing: border-box; z-index: 2; transition: box-shadow var(--dur-snap) var(--ease-out); cursor: default; }
  .fds-scatter-dot.is-hot { box-shadow: 0 0 0 var(--space-1) var(--signal-soft); }
  .fds-scatter-dot--plain { border: var(--hair) solid var(--tick-2); }
  .fds-sc-axis { fill: var(--faint); font-size: var(--text-svg-micro); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label-loose); }
  .fds-sc-axis--end { fill: var(--mut); }
  .fds-don-val { fill: var(--ink-2); font-size: var(--text-figure); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums; }
  .fds-don-cap { fill: var(--mut); font-size: var(--text-svg-micro); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; }
  .fds-sc-lbl { fill: var(--mut); font-size: var(--text-svg-micro); font-weight: var(--weight-strong); }

  /* composition share bar */
  .fds-share { display: flex; flex-direction: column; gap: var(--space-5); width: 100%; }
  .fds-share__bar { display: flex; height: var(--space-4); gap: calc(var(--space-1) / 2); border-radius: var(--radius-pill); overflow: hidden; }
  .fds-share__seg { height: 100%; min-width: calc(var(--space-1) / 2); }
  .fds-share__legend { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3) var(--space-5); }
  .fds-share__leg { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--text-muted); }
  .fds-share__leg b { color: var(--ink-2); font-weight: var(--weight-strong); margin-left: auto; font-variant-numeric: tabular-nums; }
  .fds-share__sw { width: var(--space-3); height: var(--space-3); border-radius: var(--radius-mark); flex: none; }

  /* pull quote */
  .fds-quote { font-size: var(--text-md); line-height: var(--leading-snug); color: var(--ink-2); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); text-wrap: pretty; }
  .fds-quote__mark { color: var(--signal); }
  .fds-quote__by { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-4); }

  /* comparison matrix */
  .fds-comparison { width: calc(100% + 2 * var(--space-3)); margin-left: calc(-1 * var(--space-3)); margin-right: calc(-1 * var(--space-3)); border-collapse: collapse; }
  .fds-comparison th, .fds-comparison td { text-align: left; padding: var(--space-3) var(--space-3); border-top: var(--hair) solid var(--line-fine); font-size: var(--text-sm); }
  .fds-comparison thead th { border-top: 0; font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
  .fds-comparison td:first-child, .fds-comparison th:first-child { border-top-left-radius: var(--radius-sm); border-bottom-left-radius: var(--radius-sm); }
  .fds-comparison td:last-child, .fds-comparison th:last-child { border-top-right-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm); }
  /* Base row-name cell, shared by the comparison table and the data table (one
     definition, not duplicated per table). The .fds-comparison tr.is-rec override below
     repaints it for the recommended row. */
  .fds-name { font-weight: var(--weight-strong); color: var(--ink-2); }
  .fds-comparison tr.is-rec td { background: var(--signal-soft); border-top-color: transparent; }
  .fds-comparison tr.is-rec + tr td { border-top-color: transparent; }
  .fds-comparison tr.is-rec .fds-name { color: var(--accent-text); }
  /* Recommended marker: the word pairs with the navy band so the recommendation
     survives greyscale and colourblindness (the decision rule: one marked
     Recommended). The one-line why is the .fds-comparison__why caption below the table. */
  .fds-comparison__rec { margin-left: var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--accent-text); white-space: nowrap; }
  .fds-comparison__why { margin: var(--space-4) 0 0; font-size: var(--text-sm); color: var(--body); line-height: var(--leading-snug); }
  .fds-comparison__why b, .fds-comparison__why strong { color: var(--accent-text); font-weight: var(--weight-strong); }

  /* data table — a general numeric/text reporting table.
     Sibling to .fds-comparison but carries NO decision meaning: no is-rec band, no
     Recommended marker. Reach for .fds-matrix for status-at-a-glance, this for
     aligned numeric line items. Numeric columns are right-aligned with
     tabular-nums so digits line up; the header reuses the .fds-matrix__head
     uppercase treatment. The first cell is an optional row name. The phone
     reflow (in the <=640px block below) reuses the .fds-comparison stacked-card
     pattern via data-label, so a wide table never horizontal-scrolls. */
  .fds-data { width: 100%; border-collapse: collapse; color: var(--body); }
  /* Cell colour comes from the table (inherited), NOT a td rule, so the unscoped
     .fds-name base above (a class on the cell) wins for the row-name cell instead
     of losing the cascade to a higher-specificity ".fds-data td" colour. */
  .fds-data th, .fds-data td { padding: var(--space-3) var(--space-3); border-top: var(--hair) solid var(--line-fine); font-size: var(--text-sm); text-align: left; }
  .fds-data thead th { border-top: 0; font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
  .fds-data th:first-child, .fds-data td:first-child { padding-left: 0; }
  .fds-data th:last-child, .fds-data td:last-child { padding-right: 0; }
  /* Numeric column: right-aligned, lined-up digits. Put .fds-data__num on both
     the header cell and the body cells of a numeric column. Scoped to th/td so it
     wins the cascade over the base "text-align: left" cell rule above. */
  .fds-data th.fds-data__num, .fds-data td.fds-data__num { text-align: right; font-variant-numeric: tabular-nums; }

  /* forecast vintage matrix — a stagger grid of how each period's estimate stood
     at successive snapshots, locking to the actual once the period has occurred.
     A REAL table (scope row/col headers + a caption), so it is announced correctly
     and prints as a table. Three cell states, each carried by MORE than colour:
       - locked actuals read by WEIGHT (bold) + a tint, and a legend word;
       - the single most recent forecast is BOXED with an outline (prints, and does
         not shift the grid) plus a legend word;
       - cells beyond a snapshot's forecast horizon carry a faint EN-DASH marker
         glyph (the quiet "no figure here" idiom) plus an off-screen word.
     Born FULL WIDTH. On a narrow screen it does NOT card-stack like the
     data-table: a matrix loses its meaning when the columns are split up, so it
     stays a grid and SCROLLS horizontally instead (the wide-table counterpart to
     the data-table's card stack), with the axis labels kept OUTSIDE the scroll so
     they never scroll away. */
  .fds-vintage__axis { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); margin-bottom: var(--space-3); }
  /* Scrollbar styling is owned by the inherited choke point in tokens/colors.css,
     so this well matches every scroller in both themes. */
  /* SCROLLPORT CONTRACT: every overflow-x scroll well is position:relative, so it
     is the containing block for its own absolutely positioned descendants and its
     clip contains them. Without it an absolute child (here the .fds-sr-only words
     in the empty cells) resolves against the ancestor .fds-card, escapes the
     scroll clip at the table's unscrolled x-offset, and widens the DOCUMENT
     itself: measured as a 619px page at a 390px viewport, a dead pan band and a
     clipped card edge on a phone. .fds-ledger__scroll carries the same rule. */
  .fds-vintage__wrap { position: relative; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .fds-vintage { border-collapse: collapse; width: 100%; min-width: var(--vintage-min-w); color: var(--body); font-variant-numeric: tabular-nums; }
  .fds-vintage caption { text-align: left; font-size: var(--text-xs); line-height: var(--leading-snug); color: var(--mut); margin-bottom: var(--space-3); }
  .fds-vintage th, .fds-vintage td { padding: var(--space-2) var(--space-3); border: var(--hair) solid var(--line-fine); font-size: var(--text-sm); text-align: right; white-space: nowrap; }
  .fds-vintage thead th { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
  .fds-vintage th[scope="row"] { text-align: left; font-weight: var(--weight-strong); color: var(--ink-2); }
  /* locked actual: weight + tint (+ legend word). */
  .fds-vintage__act { background: var(--signal-soft); font-weight: var(--weight-strong); color: var(--ink-2); }
  /* most recent forecast: an inset outline so it prints and never shifts the grid. */
  .fds-vintage__now { outline: var(--stroke-2) solid var(--signal-line); outline-offset: calc(-1 * var(--stroke-2)); font-weight: var(--weight-strong); color: var(--ink-2); }
  /* beyond the forecast horizon: no value yet. A QUIET cell carrying a centred
     en-dash marker glyph (the "no figure here" idiom the scope-split and ledger
     blocks use), plus an off-screen "not yet estimated" word for a screen reader.
     No fill, no texture: the empty cell is simply the calm paper with a faint dash,
     which reads the same in both themes, in greyscale, and in print. */
  .fds-vintage__empty { text-align: center; color: var(--text-faint); }
  .fds-vintage__legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin-top: var(--space-4); }
  .fds-vintage__key { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
  .fds-vintage__sw { width: var(--legend-sw-w); height: var(--legend-sw-h-box); border-radius: var(--legend-sw-r); flex: none; }
  .fds-vintage__sw--act { background: var(--signal-soft); }
  .fds-vintage__sw--now { outline: var(--stroke-2) solid var(--signal-line); outline-offset: calc(-1 * var(--stroke-2)); background: var(--panel); }
  /* Empty key: the same faint en-dash marker glyph the empty cell uses, centred in
     the swatch slot so it lines up with the tint and box keys. No fill. */
  .fds-vintage__sw--empty { display: inline-flex; align-items: center; justify-content: center; background: none; color: var(--text-faint); }
  /* financial statement ledger — a wide, period-by-period statement (a profit and
     loss, a balance sheet) built on the same cell vocabulary as .fds-data but with
     the grammar a statement needs: section bands, indented line items, subtotal and
     calc (result) rows, an all-year total set off by a rule, a marked current
     period, and a variance column. The name column is the only pinned column: the
     year total sits second from the right (the variance column is rightmost), so it
     is distinguished by a strong rule and strong weight, not a position:sticky pin
     that would collide with the variance column. It is the WIDE-TABLE COUNTERPART
     to .fds-data's phone
     card-stack, not a contradiction of it: a narrow report stacks into cards on a
     phone, but a statement has too many period columns to stack, so it stays a
     table and SCROLLS sideways inside .fds-ledger__scroll with the line-item column
     pinned (scale-to-fit, never reflow). House rules held throughout: section
     bands, subtotals and calc rows read by WEIGHT and RULE, never colour; the
     current period, the year total, and the variance direction each carry a WORD so
     nothing rests on colour alone; negative figures keep an explicit minus sign and
     never lean on red; a period with no data shows an en-dash, never a fake zero.
     Ships fully expanded and fully readable with ZERO JavaScript. */

  /* Scroll well: the statement scrolls sideways INSIDE here, capped at the card
     width and momentum-contained, so the wide table never pushes the page itself
     sideways. Reuses the code-block overflow idiom. */
  /* Scrollbar styling is owned by the inherited choke point in tokens/colors.css,
     so this well matches every scroller in both themes. */
  /* position:relative per the SCROLLPORT CONTRACT at .fds-vintage__wrap: the well
     contains its own absolute descendants instead of letting them escape to the
     card and widen the page. The runtime's .fds-readout is unaffected: it mounts on
     .fds-ledger__host, the relative wrapper OUTSIDE this well, so it still
     anchors past the overflow clip. */
  .fds-ledger__scroll { position: relative; max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain; }

  /* Separate borders (not collapse): position:sticky on a cell is reliable across
     Chromium AND Safari/iOS with separate borders, where border-collapse drops the
     sticky cell's borders. border-spacing:0 keeps the grid tight; every rule below
     is a single cell edge, so nothing doubles. */
  .fds-ledger { min-width: 100%; border-collapse: separate; border-spacing: 0; color: var(--body); font-variant-numeric: tabular-nums; }
  .fds-ledger th, .fds-ledger td { padding: var(--space-2) var(--space-3); font-size: var(--text-sm); text-align: left; white-space: nowrap; vertical-align: baseline; }
  /* Numeric columns: right-aligned, lined-up digits. Scoped to th/td so it wins
     over the base left-align (same pattern as .fds-data__num). */
  .fds-ledger th.fds-ledger__num, .fds-ledger td.fds-ledger__num { text-align: right; font-variant-numeric: tabular-nums; }

  /* Column headers: the uppercase eyebrow treatment shared across the system. */
  .fds-ledger thead th { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); border-bottom: var(--hair) solid var(--line-2); vertical-align: bottom; }

  /* Line-item (name) column, PINNED. It stays put while the periods scroll; an
     opaque panel fill and a right-hand rule separate it from the scrolling body. */
  .fds-ledger__name { font-weight: var(--weight-body); color: var(--ink-2); }
  .fds-ledger th[scope="row"], .fds-ledger thead th:first-child {
    position: sticky; left: 0; z-index: 1; background: var(--panel);
    border-right: var(--hair) solid var(--line-2);
  }
  /* Indent by hierarchy depth. th.class beats the base ".fds-ledger th" padding. */
  .fds-ledger th.fds-ledger__name--l0 { padding-left: var(--space-3); }
  .fds-ledger th.fds-ledger__name--l1 { padding-left: var(--space-5); }
  .fds-ledger th.fds-ledger__name--l2 { padding-left: var(--space-8); }
  .fds-ledger th.fds-ledger__name--percent { color: var(--mut); font-size: var(--text-xs); font-weight: var(--weight-body); }

  /* Row hairlines: a fine rule between line items. */
  .fds-ledger__row td, .fds-ledger__row th { border-top: var(--hair) solid var(--line-fine); }

  /* Section band: a full-width label that opens a section. Strong weight, an
     uppercase eyebrow, and a strong rule above carry it. The band CELL spans the
     full width for the rule and fill; the LABEL is an inner sticky element so the
     section name stays pinned at the left while the periods scroll. (A full-width
     sticky cell cannot pin, because it exactly fills its own containing block and
     so has no room to slide; the pin has to live on the inner span.) */
  .fds-ledger__band { padding: 0; background: var(--panel); border-top: var(--hair) solid var(--line-2); text-align: left; }
  .fds-ledger__section:first-of-type .fds-ledger__band { border-top: 0; }
  .fds-ledger__band-label {
    position: sticky; left: 0; z-index: 1;
    display: inline-block;
    padding: var(--space-4) var(--space-3) var(--space-2);
    font-size: var(--text-2xs); font-weight: var(--weight-strong);
    letter-spacing: var(--tracking-label); text-transform: uppercase;
    color: var(--accent-text); background: var(--panel);
  }

  /* Sub-group header (a line that rolls up its indented children): stronger name. */
  .fds-ledger__row--sub .fds-ledger__name { font-weight: var(--weight-strong); color: var(--ink-2); }

  /* Subtotal rows: a strong rule above and strong weight mark the roll-up. */
  .fds-ledger__row--subtotal td, .fds-ledger__row--subtotal th {
    border-top: var(--hair) solid var(--line-2);
    font-weight: var(--weight-strong); color: var(--ink-2);
  }
  /* Calc (result) rows — EBITDA, profit before tax: the darkest ink, ruled above
     and below, so the bottom line reads as the answer. */
  .fds-ledger__row--calc td, .fds-ledger__row--calc th {
    border-top: var(--hair) solid var(--line-2);
    border-bottom: var(--hair) solid var(--line-2);
    font-weight: var(--weight-strong); color: var(--ink);
  }
  /* Placeholder subtotal styling lives after the no-data rule below, so its numeric
     cells win the specificity tie and carry the subtotal's weight (see there). */

  /* Current period — the "now" column. Two accent marks in the system's live/now
     wayfinding carry it: a 2px accent rule across the TOP of the column (the same
     selected-marker weight the active tab uses) and a faint accent wash down its
     length. Every period header stays a SINGLE line ("P6" like its peers) so the
     header rhythm is even; the WORD that keeps colour from standing alone moves out
     of the header line into the caption ("The current period, P6, is the column
     topped by an accent rule") and the reading-conventions note below. */
  .fds-ledger__cell-current { background: var(--signal-soft); }
  /* th.class beats the base ".fds-ledger thead th" colour so the current header
     reads in the accent (AA on the wash), not the faint eyebrow grey (which the
     wash drops below AA). The 2px accent rule sits on the header cell's top edge to
     flag the top of the column; it is a border, so it survives the background-free
     print where the wash drops out. */
  .fds-ledger__colhead--current { background: var(--signal-soft); border-top: var(--stroke-2) solid var(--accent); }
  .fds-ledger thead th.fds-ledger__colhead--current { color: var(--accent-text); }

  /* FY total column: set off by a strong rule and carried in strong weight. */
  .fds-ledger td.fds-ledger__total { border-left: var(--hair) solid var(--line-2); font-weight: var(--weight-strong); color: var(--ink-2); }
  .fds-ledger__colhead--total { border-left: var(--hair) solid var(--line-2); }
  /* th.class beats the base ".fds-ledger thead th" colour (1 class + 2 elements) so
     the FY-total header carries the stronger ink, not the faint eyebrow grey — the
     same compound-selector pattern the current-period header uses above. */
  .fds-ledger thead th.fds-ledger__colhead--total { color: var(--ink-2); }

  /* Variance column: the current period against plan. The SIGN and the WORD carry
     the direction (plus / "ahead" = better than plan, minus / "behind" = worse than
     plan, stated in the caption); the tint reinforces, so the meaning survives
     greyscale, colourblindness, and a background-free print. Ahead and behind sit in
     two clearly separated status families from tokens/colors.css — sage GREEN (ok)
     for ahead, clay RED (blk) for behind — so the difference reads at a glance
     rather than in near-neighbour tints. Every ink-on-tint pair clears WCAG AA in
     both themes: word 6.14 (light) / 7.72 (dark) ahead, 6.42 / 6.78 behind; number
     7.70 / 8.15 ahead, 7.39 / 8.46 behind. This is the repair of the original's
     colour-alone variance signal, not a reproduction of it. */
  .fds-ledger td.fds-ledger__var, .fds-ledger__colhead--var { border-left: var(--hair) solid var(--line); }
  .fds-ledger__var-n { font-variant-numeric: tabular-nums; font-weight: var(--weight-strong); color: var(--ink-2); }
  .fds-ledger__var-w { display: block; font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; }
  .fds-ledger__var--ahead { background: var(--ok-bg); }
  .fds-ledger__var--ahead .fds-ledger__var-w { color: var(--ok-ink); }
  .fds-ledger__var--behind { background: var(--blk-bg); }
  .fds-ledger__var--behind .fds-ledger__var-w { color: var(--blk-ink); }

  /* No-data marker: a muted (AA-legible) en-dash, never a fabricated zero. */
  .fds-ledger td.fds-ledger__na, .fds-ledger__na { color: var(--mut); font-weight: var(--weight-body); }
  /* A no-data en-dash that also falls in the current-period wash: --mut on the wash
     measures 4.38:1 (light) / 4.17:1 (dark), under AA 4.5. Step it up one ink to
     --body (4.66:1 / 5.64:1 on the wash), still a supporting tone, now AA in both
     themes. The compound selector (2 classes + td) beats the plain no-data rule. */
  .fds-ledger td.fds-ledger__cell-current.fds-ledger__na { color: var(--body); }

  /* Placeholder subtotal: a grouping line the source carries with no
     figure of its own — its detail sits on the line below (stated in the caption).
     Weight it like the subtotal it is: the NAME and every NUMERIC cell carry the
     subtotal's strong weight and the --line-2 top rule, while the en-dash markers
     stay. Placed after the no-data rule so the numeric cells (td.fds-ledger__na)
     win the specificity tie and take the strong weight over the muted default. */
  .fds-ledger__row--placeholder th,
  .fds-ledger__row--placeholder td.fds-ledger__na {
    border-top: var(--hair) solid var(--line-2);
    font-weight: var(--weight-strong);
  }
  .fds-ledger__row--placeholder th { color: var(--ink-2); }

  /* Caption: a plain line above the statement stating its units and how to read
     the current-period, variance, and en-dash conventions. */
  .fds-ledger__cap { caption-side: top; text-align: left; margin-bottom: var(--space-3); }

  /* data-fds-ledger progressive enhancements (block 69). The runtime adds all of
     this ONLY when scripts run; with scripts off none of it exists, so the table
     stays complete. The scroll well is wrapped in .fds-ledger__host (position:
     relative) so the per-cell .fds-readout can anchor OUTSIDE the well's overflow clip.
     A collapsed section's detail rows take .fds-ledger__row--hidden (display:none,
     an instant fold, no motion). The section toggle is a real button carrying the
     section name plus a CSS caret (a bordered triangle, no glyph font); it inherits
     the band label's accent-text/eyebrow styling, so a collapsible band reads
     exactly like a static one, only now operable. */
  .fds-ledger__host { position: relative; }
  /* The runtime adds the shared .fds-scroll-edge to the host. */
  .fds-ledger__row--hidden { display: none; }
  .fds-ledger__toggle {
    display: inline-flex; align-items: center; gap: var(--space-2);
    margin: 0; padding: 0; border: 0; background: none; cursor: pointer;
    font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  }
  .fds-ledger__toggle:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); border-radius: var(--radius-sm); }
  /* caret: a small solid triangle from borders — points down when expanded, right
     when collapsed. The state change is a static class swap on click (no motion). */
  .fds-ledger__caret {
    width: 0; height: 0; flex: none;
    border-left: var(--caret-half) solid transparent; border-right: var(--caret-half) solid transparent;
    border-top: var(--caret-rise) solid var(--mut);
  }
  .fds-ledger__toggle.is-collapsed .fds-ledger__caret {
    border-top: var(--caret-half) solid transparent; border-bottom: var(--caret-half) solid transparent;
    border-left: var(--caret-rise) solid var(--mut); border-right: 0;
  }

  /* filter bar — a search field, a row of selectable filter tags (.fds-tag--filter),
     and a result count, to narrow a list or table. The search field reuses
     .fds-input (forms.css) and the tags reuse .fds-tag--filter (chip.css); these
     rules are just the bar's own column layout. The tag row wraps in place on a
     phone (scale-to-fit, never a structural reflow). */
  .fds-filterbar { display: flex; flex-direction: column; gap: var(--space-4); }
  .fds-filterbar__tags { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
  .fds-filterbar__count { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }

  /* escalation (the one lit card), the card-shaped form of the act band: the lead
     and the act band are ONE instrument (parts/layout.css), so the ask and its
     supporting line carry the SAME voice and rhythm as .fds-act__ask / __sub: the
     page's most important ask at --text-md, the pair on the act strip's --space-2
     beat. The body owns the space between the pair (the card doctrine: children own
     nothing outside their box), so the two <p> shed their UA margins here. */
  .fds-esc .fds-card__body { gap: var(--space-2); }
  .fds-esc .fds-card__body > p { margin: 0; }
  .fds-esc__big { font-size: var(--text-md); font-weight: var(--weight-strong); color: var(--ink); line-height: var(--leading-snug); letter-spacing: var(--tracking-tight); text-wrap: pretty; }

  /* dependency mini */
  .fds-dep { display: flex; flex-direction: column; gap: var(--space-3); }
  .fds-dep__row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--space-3); }
  .fds-dep__node { font-size: var(--text-xs); font-weight: var(--weight-strong); color: var(--ink-2); padding: var(--space-2) var(--space-3); border: var(--hair) solid var(--line); border-radius: var(--radius-sm); text-align: center; }
  .fds-dep__node--ext { color: var(--mut); font-weight: var(--weight-body); background: var(--paper); }
  .fds-dep__arrow { color: var(--text-faint); font-size: var(--text-sm); text-align: center; }

  /* glossary */
  .fds-gloss { display: flex; flex-direction: column; }
  .fds-gloss__row { display: grid; grid-template-columns: calc(var(--space-20) + var(--space-10)) 1fr; gap: var(--space-4); padding: var(--space-3) 0; border-top: var(--hair) solid var(--line-fine); }
  .fds-gloss__row:first-child { border-top: 0; }
  .fds-gloss__t { font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); }
  .fds-gloss__d { font-size: var(--text-xs); color: var(--body); line-height: var(--leading-snug); }

  .fds-foot { margin-top: var(--space-16); padding-top: var(--space-6); border-top: var(--hair) solid var(--line); }
  .fds-foot p { font-size: var(--text-sm); line-height: var(--leading-relaxed); color: var(--text-muted); max-width: 80ch; }
  .fds-foot b { color: var(--ink-2); font-weight: var(--weight-strong); }

  /* Tablet band (620-920px): the 12-col grid coarsens to 6 columns. Every span is
     remapped so it never exceeds 6 (a leftover 12- or wider span would spawn
     phantom implicit columns and squash the row). Full and two-thirds go full
     width; half, third and quarter become a half so the band reads as a clean
     2-up. sp6 stays a half (span 3) rather than going full so a side-by-side pair
     survives the tablet band and only stacks at the 620px phone breakpoint below
     (scale-to-fit, never an early reflow). */
  @media (max-width: 920px) {
    .fds-cat { grid-template-columns: repeat(6, 1fr); }
    .fds-sp12 { grid-column: span 6; } .fds-sp8 { grid-column: span 6; }
    .fds-sp6 { grid-column: span 3; } .fds-sp4 { grid-column: span 3; } .fds-sp3 { grid-column: span 3; }
  }
  @media (max-width: 620px) {
    .fds-cat { grid-template-columns: 1fr; }
    .fds-sp3, .fds-sp4, .fds-sp6, .fds-sp8, .fds-sp12 { grid-column: span 1; }
    .fds-split { grid-template-columns: 1fr; }
  }
  /* sticky header bar (full-page): opaque paper, permanent hairline, no glass */
  .fds-appbar { position: sticky; top: 0; z-index: 50; height: auto; border-radius: 0; background: var(--paper); border-bottom: var(--hair) solid var(--line); isolation: isolate; }
  .fds-appbar__inner { position: relative; z-index: 2; max-width: var(--page-max); margin: 0 auto; display: flex; align-items: center; gap: var(--space-5); padding: var(--space-5) var(--space-8); }
  /* Brand: the wordmark grows and TRUNCATES (never pushes the bar wider); the
     optional project label and divider sit beside it and never shrink. */
  .fds-appbar__brand { display: flex; align-items: center; gap: var(--space-3); min-width: 0; flex: 1 1 auto; }
  .fds-appbar__name { font-size: var(--text-md); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); color: var(--ink-2); line-height: var(--leading-none); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .fds-appbar__div { width: var(--hair); height: calc(var(--space-3) + var(--space-1) / 2); background: var(--line-2); flex: none; }
  .fds-appbar__proj { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label-loose); text-transform: uppercase; color: var(--text-faint); line-height: var(--leading-none); white-space: nowrap; flex: none; }
  /* Optional action zone. The bar is BRAND-ONLY by default; add a single action
     here ONLY when the page has a genuine, strong call to action. Most pages won't. */
  .fds-appbar__actions { flex: none; display: flex; align-items: center; gap: var(--space-3); }
  .fds-appbar__cta { appearance: none; border: 0; background: var(--signal); color: var(--on-accent); font: inherit; font-size: var(--text-xs); font-weight: var(--weight-strong); padding: var(--space-2) var(--space-4); border-radius: var(--radius-pill); cursor: pointer; white-space: nowrap; }
  @media (max-width: 600px) { .fds-appbar__proj, .fds-appbar__div { display: none; } }

  /* B2 still mode / reduced motion — collapse every motion transition declared in this
     file to instant, so a reader who asked for stillness gets the same rest state with
     identical meaning: the spark highlight (opacity), the hover tooltip (opacity), the
     scatter-dot hover ring (box-shadow), and the sticky app bar's shadow + glass fade
     (box-shadow, opacity). These sit at the top level (no breakpoint), so their twins do
     too. Held byte-for-byte in lockstep with the origins above by build/lint-still-mode.mjs
     (positive coverage); the reduced-motion and still twins may not drift or vanish. */
  @media (prefers-reduced-motion: reduce) {
    .fds-spark__hl,
    .fds-tip,
    .fds-scatter-dot { transition: none; }
  }
  :root[data-still] .fds-spark__hl,
  :root[data-still] .fds-tip,
  :root[data-still] .fds-scatter-dot { transition: none; }

  /* ============================================================
     Mobile reflow (<=640px) — the desktop row layouts that cannot
     fit a phone are restructured here so nothing clips or overlaps.
     Navy --signal stays exactly where it is on desktop; only layout
     changes. Four fixes: app bar header, comparison table (stacked to
     labelled cards), milestone timeline, gate stepper.
     ============================================================ */
  @media (max-width: 640px) {

    /* --- App bar: the brand-only bar (and its optional single action) fit one
       line at any width because the wordmark truncates, so the bar just tightens
       its padding on a phone. --- */
    .fds-appbar__inner { padding: var(--space-3) var(--space-5); }

    /* --- Comparison table: stack each option into a labelled key/value card so
       every attribute (including the decision-bearing GATE column) is visible on
       a phone with no horizontal scroll. The header row is removed from view but
       kept for assistive tech; each cell self-labels via its data-label. The
       Recommended row keeps its navy tint. --- */
    .fds-comparison { display: block; width: 100%; margin-left: 0; margin-right: 0; }
    .fds-comparison thead { position: absolute; width: var(--hair); height: var(--hair); overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
    /* clip the header CELLS too: clip on <thead> hides the paint but each <th>
       keeps its intrinsic content width, whose box still spills past a narrow
       viewport. Collapse the cell boxes so no element overflows on a phone. */
    .fds-comparison thead th { width: var(--hair); max-width: var(--hair); padding: 0; overflow: hidden; }
    .fds-comparison tbody, .fds-comparison tr, .fds-comparison td { display: block; width: 100%; }
    .fds-comparison tbody tr {
      border: var(--hair) solid var(--line);
      border-radius: var(--radius-sm);
      padding: var(--space-2) var(--space-4);
      margin-top: var(--space-3);
    }
    .fds-comparison tbody tr.is-rec { background: var(--signal-soft); }
    .fds-comparison td {
      display: flex; align-items: baseline; justify-content: space-between;
      gap: var(--space-4); text-align: right;
      padding: var(--space-2) 0; border-top: var(--hair) solid var(--line-fine);
    }
    .fds-comparison td::before {
      content: attr(data-label); text-align: left; flex: none;
      font-size: var(--text-2xs); font-weight: var(--weight-strong);
      letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint);
    }
    /* first cell is the option name — a full-width heading, no key label */
    .fds-comparison td:first-child {
      border-top: 0; justify-content: flex-start; text-align: left;
      font-size: var(--text-md); color: var(--ink-2);
    }
    .fds-comparison td:first-child::before { content: none; }

    /* --- Data table: same stacked-card reflow as the comparison table, minus
       the decision band. Each row becomes a labelled key/value card so every
       column stays visible on a phone with no horizontal scroll; the header row
       is hidden from view but kept for assistive tech, and each cell self-labels
       via its data-label. Numeric cells lose their right-align (the value sits
       to the right of its label in the stacked row already). --- */
    .fds-data { display: block; width: 100%; }
    .fds-data thead { position: absolute; width: var(--hair); height: var(--hair); overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
    .fds-data thead th { width: var(--hair); max-width: var(--hair); padding: 0; overflow: hidden; }
    .fds-data tbody, .fds-data tr, .fds-data td { display: block; width: 100%; }
    .fds-data tbody tr {
      border: var(--hair) solid var(--line);
      border-radius: var(--radius-sm);
      padding: var(--space-2) var(--space-4);
      margin-top: var(--space-3);
    }
    .fds-data td {
      display: flex; align-items: baseline; justify-content: space-between;
      gap: var(--space-4); text-align: right;
      padding: var(--space-2) 0; border-top: var(--hair) solid var(--line-fine);
    }
    .fds-data td.fds-data__num { text-align: right; }
    .fds-data td::before {
      content: attr(data-label); text-align: left; flex: none;
      font-size: var(--text-2xs); font-weight: var(--weight-strong);
      letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint);
    }
    /* first cell is the row name — a full-width heading, no key label */
    .fds-data td:first-child {
      border-top: 0; justify-content: flex-start; text-align: left;
      padding-left: 0;
      font-size: var(--text-md); color: var(--ink-2);
    }
    .fds-data td:last-child { padding-right: 0; }
    .fds-data td:first-child::before { content: none; }

    /* --- Milestone timeline: the desktop track positions nodes by left:% which
       collide on a phone (the last two sit ~44px apart and overprint into
       illegible glyphs, the last clipping the card edge). Reflow to a vertical
       list — each node a full-width row of dot · label · date; the horizontal
       progress fill is dropped since the node states already carry progress.
       Navy --signal stays on the live node exactly as on desktop. --- */
    .fds-timeline { padding: var(--space-2) 0; }
    .fds-timeline__track { position: static; height: auto; background: none; display: flex; flex-direction: column; }
    .fds-timeline__done { display: none; }
    .fds-tl-node {
      position: static; transform: none;
      width: 100%; display: flex; align-items: center; gap: var(--space-3);
      padding: var(--space-3) 0; border-top: var(--hair) solid var(--line-fine);
    }
    .fds-tl-node:first-child { border-top: 0; }
    .fds-tl-node__dot { order: 1; }
    .fds-tl-node__lbl { order: 2; flex: 1; position: static; top: auto; }
    .fds-tl-node__date { order: 3; position: static; bottom: auto; white-space: nowrap; color: var(--text-faint); }

    /* --- Gate stepper: turn the horizontal pipeline into a vertical timeline.
       Each gate becomes a full-width row; the connector line rotates to a
       short vertical stem on the left so the sequence still reads top-to-bottom
       with no node pushed past the card edge. Navy --signal stays on the
       done/now stems exactly as on desktop. --- */
    .fds-gates { flex-direction: column; align-items: stretch; gap: var(--space-4); }
    .fds-gate, .fds-gate:last-child { flex: 1 1 auto; padding-right: 0; padding-left: var(--space-5); }
    .fds-gate__top {
      position: absolute; left: 0; top: 0; bottom: 0;
      flex-direction: column; align-items: center; gap: var(--space-2);
    }
    .fds-gate__line { flex: 1; width: var(--hair); height: auto; }
    /* vertical "done" / "now" fills mirror the horizontal desktop fills */
    .fds-gate.is-now .fds-gate__line { background: linear-gradient(to bottom, var(--signal) 0 55%, var(--line-2) 55% 100%); }
  }

/* ===== parts/layout.css ===== */
/* Foundational — the layout tier (the system's second rhythm).
   A document is not only a grid of cards. These primitives arrange things on
   PAPER: they own all the space BETWEEN things and own nothing inside a thing's
   border (surfaces own that). Content picks its LANE, never its surface. The
   mosaic and the lead flag are print-safe (parts/print.css). Loaded after
   parts/composition.css so the grid and card modifiers here layer over their bases.

   TOKENS, honestly. Every colour, space, radius and reading MEASURE is a token
   (the lane widths and rail width are --measure* / --rail-aside in tokens/
   spacing.css; the flag's line-height is --leading-snug). Two kinds of value stay
   literal on purpose: a media-query breakpoint (a CSS media condition cannot read a
   custom property, so raw px in @media is the house idiom used across parts/), and
   a display figure's line-height of 1 (the canonical "cap the line box to the
   glyph" for a number-first opener, which no leading token expresses and which the
   type-token freeze does not add). The shared 2px focus ring (outline width and
   offset) is the system-wide idiom, identical in every interactive part, left as
   the literal it is everywhere. Both light and dark resolve either way. */

/* ─────────────────────────  River  ─────────────────────────
   The document spine. A centred reading column with three named lanes: content
   sits in the MEASURE lane (a comfortable ~66-character line) by default; a
   figure or wide table opts into the WIDE lane, and a full-bleed band into the
   FULL lane, WITHOUT leaving the flow ("the chart above" disappears because the
   figure is right here). Capped by measure, so it scales down to a phone with no
   reflow — the lanes just narrow. */
.fds-river { display: flex; flex-direction: column; align-items: center; row-gap: var(--space-6); width: 100%; }
.fds-river > * { width: 100%; max-width: min(var(--measure), 100%); }        /* measure lane (default) */
.fds-river > .fds-river--wide { max-width: min(var(--measure-wide), 100%); } /* wide lane: figures, tables */
.fds-river > .fds-river--full { max-width: 100%; }                           /* full lane: a band edge to edge */
/* A card, figure or callout riding the river sits in its own STRATUM: it gets
   more breath than the paragraph rhythm (ratified 2026-07-06: 32px total, the
   24px river gap + this margin), so furniture reads as its own layer without
   leaving the column. The frames stay on the column edges; the inset feel is the
   card's own internal padding, never a narrower frame. */
.fds-river > .fds-river--wide, .fds-river > .fds-river--full, .fds-river > .fds-card { margin-block: var(--space-2); }

/* ─────────────────────────  Flush mosaic  ─────────────────────────
   A modifier of the .fds-cat grid: the tiles share ONE hairline frame, one
   radius and one shadow, seamed by hairline gutters, so the set reads as a single
   quiet instrument (a KPI strip) rather than a scatter of separate cards. The
   gap becomes the seam: the group's own surface shows through the 1px gutters as
   the divider, and each tile drops its own border/radius/shadow. */
.fds-cat--flush {
  gap: var(--hair);
  background: var(--line);
  border: var(--hair) solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.fds-cat--flush > .fds-card { border: 0; border-radius: 0; box-shadow: none; }

/* Quiet tiles share measure, figure and note tracks through both card layers.
   Each tile spans three rows, so wrapped strips keep the same contract per row
   of tiles. The outer gap remains a hairline seam; body gaps own the rhythm. */
.fds-cat--flush > .fds-card--quiet {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  grid-template-columns: minmax(0, 1fr);
}
.fds-cat--flush > .fds-card--quiet > .fds-card__body {
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
  grid-template-columns: minmax(0, 1fr);
  min-width: 0;
}
.fds-cat--flush > .fds-card--quiet > .fds-card__body > .fds-measure {
  grid-row: 1;
  align-self: start;
}
.fds-cat--flush > .fds-card--quiet > .fds-card__body > :is(.fds-fig, .fds-fig__row) {
  grid-row: 2;
  align-self: first baseline;
}
/* A caption or dot-plus-word starts at the body inset in the same note slot.
   One caption line sets the minimum and leading for either note vocabulary. */
.fds-cat--flush > .fds-card--quiet > .fds-card__body > :is(.fds-sub, .fds-stat) {
  grid-row: 3;
  align-self: start;
  min-height: calc(var(--text-xs) * var(--leading-snug));
  line-height: calc(var(--text-xs) * var(--leading-snug));
}

/* ─────────────────────────  Stack  ─────────────────────────
   Vertical rhythm. Owns the space between its children; the children own nothing
   outside their box. One gap, set once (tight / loose steps for a denser or airier
   run). */
.fds-stack { display: flex; flex-direction: column; gap: var(--space-5); }
.fds-stack--tight { gap: var(--space-3); }
.fds-stack--loose { gap: var(--space-8); }

/* ─────────────────────────  Cluster  ─────────────────────────
   An inline group that wraps: tags, metadata, a row of actions. Owns the gap in
   both axes; wraps in place on a phone (scale-to-fit, never a structural reflow). */
.fds-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.fds-cluster--between { justify-content: space-between; }

/* ─────────────────────────  Duo  ─────────────────────────
   Two equal columns that scale together and drop to one only at the phone
   breakpoint. No divider (the divided two-column is the older .fds-split); a duo
   is a plain pair of equal lanes. */
.fds-duo { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-6); }

/* ─────────────────────────  Pair  ─────────────────────────
   Side-by-side that SCALES rather than stacks: the two children keep their
   side-by-side relationship at every width and shrink together (scale-to-fit,
   never reflow). Reach for it when the pairing itself is the meaning (a
   before/after, a label beside its value) and stacking would lose it. */
.fds-pair { display: flex; gap: var(--space-5); align-items: flex-start; }
.fds-pair > * { flex: 1 1 0; min-width: 0; }

/* ─────────────────────────  Rail  ─────────────────────────
   A main reading column beside a companion that stays in view: a sticky aside for
   a summary, a table of contents, or the one decision. Asymmetric main + aside
   (the symmetric divided two-column is the older .fds-split). Drops the rail below
   the main at the phone breakpoint. */
.fds-rail { display: grid; grid-template-columns: 1fr minmax(0, var(--rail-aside)); gap: var(--space-8); align-items: start; }
.fds-rail__aside { position: sticky; top: var(--appbar-clearance); align-self: start; }

/* Lead-aside rail: the same instrument with the companion on the LEFT. The aside
   leads (first column, first in the DOM), the reading column follows on the
   right. Reach for it when the companion is a section navigation the reader
   moves through before reading, so it wants to sit where the eye starts. Author
   the children aside-first in the markup; the aside keeps its sticky behaviour
   and the gap is unchanged. Because the aside is first in document order, the
   phone stack (below) puts the navigation ABOVE the reading, which matches the
   reading order for a nav you consult first. */
.fds-rail--lead-aside { grid-template-columns: minmax(0, var(--rail-aside)) 1fr; }

/* ─────────────────────────  Statement  ─────────────────────────
   A display-scale, number-first opener on PAPER (never a card). The one figure
   that frames the whole page ("Checkout was down 38 minutes."). Reuses the display
   type; its surface is paper, so it belongs to the reading, not to a panel. */
.fds-statement { display: flex; flex-direction: column; gap: var(--space-3); }
.fds-statement__fig {
  font-size: var(--text-display); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-tighter); line-height: var(--leading-none);
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.fds-statement__unit { font-size: var(--text-xl); font-weight: var(--weight-strong); color: var(--mut); margin-left: var(--space-1); letter-spacing: var(--tracking-tight); }
.fds-statement__lede { font-size: var(--text-md); line-height: var(--leading-snug); color: var(--body); max-width: var(--measure-lede); text-wrap: pretty; }

/* ─────────────────────────  Lead flag + act band  ─────────────────────────
   The lead and the act band are ONE instrument: at most one lead per page, and it
   is where the reader's actions are collected. The band is the lead's canonical,
   full-width form; the escalation card (block 21) is its card-shaped form. The
   flag is FILLED (a dark navy band, not coloured text) so the "act on this" mark
   survives greyscale and print, never riding on colour alone. */
.fds-lead {
  display: inline-flex; align-items: center; gap: var(--space-2); align-self: flex-start;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--signal); color: var(--on-accent);
  font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase; line-height: var(--leading-snug);
}

.fds-act {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: var(--space-5);
  padding: var(--space-5) var(--space-6);
  background: var(--signal-soft);
  border: var(--hair) solid var(--signal-line);
  border-radius: var(--radius-md);
}
.fds-act__main { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.fds-act__ask { font-size: var(--text-md); font-weight: var(--weight-strong); color: var(--ink); letter-spacing: var(--tracking-tight); line-height: var(--leading-snug); }
.fds-act__sub { font-size: var(--text-sm); color: var(--body); line-height: var(--leading-snug); }
.fds-act__cta {
  appearance: none; border: 0; flex: none; cursor: pointer; font: inherit;
  background: var(--signal); color: var(--on-accent);
  font-size: var(--text-sm); font-weight: var(--weight-strong);
  padding: var(--space-3) var(--space-5); border-radius: var(--radius-pill); white-space: nowrap;
}
.fds-act__cta:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

/* ─────────────────────────  Scale-to-fit breakpoints  ─────────────────────────
   The layout tier honours scale-to-fit-never-reflow: only where a side-by-side
   would truly crowd on a phone does it drop to a single column. Duo and rail
   stack; pair deliberately does NOT (its whole point is to stay side-by-side). */
@media (max-width: 720px) {
  .fds-rail, .fds-rail--lead-aside { grid-template-columns: 1fr; }
  .fds-rail__aside { position: static; }
}
@media (max-width: 620px) {
  .fds-duo { grid-template-columns: 1fr; }
}

/* ===== parts/controls.css ===== */
/* parts/controls.css
   Shared interactive controls used across the new web-UI blocks (forms, overlays,
   feedback). Tokens only. Extracted so button, close, and scrim are defined once. */

/* Button: one primary, one secondary. Used by form-section and the overlays. */
.fds-btn { appearance: none; -webkit-appearance: none; font: inherit; font-size: var(--text-sm); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); line-height: var(--leading-none); cursor: pointer; white-space: nowrap; border-radius: var(--radius-pill); padding: var(--space-3) var(--space-5); border: var(--hair) solid transparent; transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out); }
.fds-btn:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }
.fds-btn--primary { background: var(--signal); color: var(--on-accent); }
.fds-btn--secondary { color: var(--ink-2); border-color: var(--line-2); }

/* Close: a CSS-drawn cross in a square hit area. Used by modal, drawer, toast. */
.fds-x { flex: none; width: var(--space-6); height: var(--space-6); padding: 0; border: 0; background: transparent; border-radius: var(--radius-sm); position: relative; cursor: pointer; color: var(--mut); transition: color var(--dur-snap) var(--ease-out), background var(--dur-snap) var(--ease-out); }
.fds-x::before, .fds-x::after { content: ""; position: absolute; top: 50%; left: 50%; width: var(--space-3); height: calc(var(--space-1) / 2); border-radius: var(--radius-mark); background: currentColor; }
.fds-x::before { transform: translate(-50%, -50%) rotate(45deg); }
.fds-x::after { transform: translate(-50%, -50%) rotate(-45deg); }
.fds-x:hover { color: var(--ink-2); background: var(--line-fine); }
.fds-x:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

/* Contained scrim: the dimmed wash behind an overlay shown inside a specimen.
   In a live page the scrim would be position:fixed; here it is contained so it
   renders in the gallery. --end pins the panel to the right edge (drawer). */
.fds-scrim { position: relative; isolation: isolate; display: flex; justify-content: center; align-items: flex-start; padding: var(--space-6); min-width: 0; border-radius: var(--radius-md); background: var(--scrim); }
.fds-scrim--end { justify-content: flex-end; align-items: stretch; padding: 0; overflow: hidden; min-height: var(--overlay-min-height); }

/* ===== parts/forms.css ===== */
/* parts/forms.css. Shared component CSS for the Forms & input category.
   Promoted out of the individual block specimens so the gallery (which inlines
   styles.css and strips each block's local <style>) renders them fully.
   Tokens only; light and dark both render cleanly. Shared primitives (button,
   close cross, scrim) live in controls.css and are reused, not redefined. */

/* The field shell, label, and helper line are shared across text-field and
   select so a text input and a dropdown sit level beside each other. */
.fds-field { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.fds-field__label { font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); line-height: var(--leading-snug); }
.fds-help { font-size: var(--text-2xs); color: var(--mut); line-height: var(--leading-snug); }

/* ── 29-text-field ─────────────────────────────────────────────────────────
   The input control: same fill, hairline, and radius as the select control. */
.fds-input {
  display: block; width: 100%; box-sizing: border-box;
  padding: var(--space-3) var(--space-4);
  border: var(--hair) solid var(--line-2);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--text-sm); font-weight: var(--weight-strong);
  line-height: var(--leading-snug);
  transition: border-color var(--dur-snap) var(--ease-out), box-shadow var(--dur-snap) var(--ease-out);
}
.fds-input::placeholder { color: var(--mut); font-weight: var(--weight-body); }
.fds-input:hover { border-color: var(--signal-line); }
/* Keyboard focus uses the system focus ring (keyboard users only). */
.fds-input:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }
/* Invalid control: clay edge with a soft clay ring, so the field reads as
   wrong before any word is read. The word "Error" still rides below. */
.fds-input.is-invalid { border-color: var(--blk-line); box-shadow: 0 0 0 var(--space-1) var(--blk-bg); }
.fds-input.is-invalid:hover { border-color: var(--blk-line); }
/* Error line: a clay dot plus the word "Error" (the shared fds-stat--blk
   dot+word), then the plain message. Colour never carries the meaning alone. */
.fds-error { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; }
.fds-error .fds-stat { flex: none; align-self: center; }
.fds-error__msg { min-width: 0; font-size: var(--text-2xs); color: var(--blk-ink); line-height: var(--leading-snug); }

/* ── 30-select ─────────────────────────────────────────────────────────────
   The closed control: a chosen value on the left, a caret on the right. */
.fds-select {
  display: flex; align-items: center; gap: var(--space-3); min-width: 0;
  width: 100%; box-sizing: border-box;
  padding: var(--space-3) var(--space-4);
  border: var(--hair) solid var(--line-2);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-size: var(--text-sm); font-weight: var(--weight-strong);
  line-height: var(--leading-snug);
  cursor: pointer;
  transition: border-color var(--dur-snap) var(--ease-out), box-shadow var(--dur-snap) var(--ease-out);
}
.fds-select:hover { border-color: var(--signal-line); }
/* Keyboard focus uses the system focus ring (keyboard users only). */
.fds-select:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }
.fds-select__value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fds-select__value--placeholder { color: var(--mut); font-weight: var(--weight-body); }
/* Caret drawn from a border, no glyph (matches the no-glyph house style). */
.fds-caret { flex: none; width: var(--space-2); height: var(--space-2); margin-top: calc(var(--space-1) * -1);
  border-right: var(--stroke-2) solid var(--mut); border-bottom: var(--stroke-2) solid var(--mut);
  transform: rotate(45deg); transition: transform var(--dur-fast) var(--ease-out); }
/* Open / active state: one honest container. The open select becomes a single
   bordered surface that holds an inner trigger row and the menu as children, so
   there is only one border, one radius, one shadow, and no shared edge between
   two surfaces. Overflow clips the inner rows to the radius. */
.fds-select.is-open { display: block; padding: 0; border-color: var(--signal); border-radius: var(--radius-sm); box-shadow: var(--shadow-card); overflow: hidden; }
/* The inner trigger row: value on the left, caret on the right. Its bottom
   hairline IS the seam, painted once, between the value row and the options. */
.fds-select.is-open .fds-select__trigger { display: flex; align-items: center; gap: var(--space-3); min-width: 0; padding: var(--space-3) var(--space-4); border-bottom: var(--hair) solid var(--signal-line); }
.fds-select.is-open .fds-caret { transform: rotate(-135deg); margin-top: var(--hair); border-color: var(--signal); }
/* The nested menu drops all of its own chrome; the container owns the border,
   radius, shadow, and fill. */
.fds-select.is-open .fds-menu { margin: 0; border: 0; border-radius: 0; box-shadow: none; background: transparent; }
/* Disabled control reads as not-now: stone text, faint fill, word says so. */
.fds-select.is-disabled { cursor: default; background: var(--na-bg); border-color: var(--na-line); color: var(--na-ink); }
.fds-select.is-disabled .fds-caret { border-color: var(--faint); }
/* The open list, shown beneath the control. Each option pairs a CSS dot
   with its word so selection never rides on colour alone. */
.fds-menu { margin-top: calc(var(--space-2) * -1 + var(--space-1));
  border: var(--hair) solid var(--line-2); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card); overflow: hidden; }
.fds-opt { display: flex; align-items: center; gap: var(--space-3); min-width: 0;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm); color: var(--ink-2); line-height: var(--leading-snug);
  border-top: var(--hair) solid var(--line-fine); cursor: pointer; }
.fds-opt:first-child { border-top: 0; }
.fds-opt:hover { background: var(--signal-soft); }
.fds-opt__t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fds-opt__mark { flex: none; font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--signal); white-space: nowrap; }
/* Selected option: signal-tinted, bold, dot + the word "Selected". */
.fds-opt.is-selected { background: var(--signal-soft); color: var(--ink); font-weight: var(--weight-strong); }
.fds-opt__dot { flex: none; width: var(--dot); height: var(--dot); border-radius: var(--radius-pill);
  background: var(--line-2); }
.fds-opt.is-selected .fds-opt__dot { background: var(--signal); }

/* ── 31-toggle ─────────────────────────────────────────────────────────────
   The switch: a track with a knob. Position carries the state; the word beside
   it (in the markup) spells it out so colour never stands alone. Promoted from
   the block's inline styles into a reusable primitive. */
.fds-toggle { position: relative; flex: none; width: var(--space-10); height: var(--space-6);
  border-radius: var(--radius-pill);
  border: var(--hair) solid var(--line-2); box-shadow: var(--shadow-flat);
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out); }
.fds-toggle__knob { position: absolute; top: calc(var(--space-1) - var(--hair)); left: calc(var(--space-1) - var(--hair)); width: var(--space-4); height: var(--space-4);
  border-radius: var(--radius-pill); background: var(--mut);
  transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out); }
/* On: signal track, knob slides to the end and takes the signal fill. */
.fds-toggle--on { background: var(--signal-soft); border-color: var(--signal-line); }
.fds-toggle--on .fds-toggle__knob { background: var(--signal); transform: translateX(var(--space-4)); }
/* Disabled: faint, not-now; the row also carries the word "Disabled". */
.fds-toggle--disabled { background: var(--paper); border-color: var(--line); box-shadow: none; cursor: not-allowed; }
.fds-toggle--disabled .fds-toggle__knob { background: var(--faint); }
/* Keyboard focus: the switch is reachable (tabindex in the markup) and shows the
   system focus ring; the disabled switch stays out of the tab order. */
.fds-toggle:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

/* ── 32-choice-group ───────────────────────────────────────────────────────
   The choice card groups a radio set and a checkbox set. Each set lays out as
   shared rows (.fds-rows / .fds-row) with shared marks (.fds-radio / .fds-chk);
   this wrapper just keeps the groups from overflowing their column. */
.fds-choice { min-width: 0; }
.fds-choice .fds-rows { min-width: 0; }

/* ── 33-form-section ───────────────────────────────────────────────────────
   The fieldset: stacked fields and one action row. Buttons reuse the shared
   .fds-btn primitive from controls.css. */
.fds-form { display: flex; flex-direction: column; gap: var(--space-5); border: 0; margin: 0; padding: 0; min-width: 0; }
/* A <legend> does not receive the fieldset's flex gap (browser quirk), so it
   needs an explicit margin to read as a balanced section heading above the
   first field, neither cramped nor excessive. */
.fds-form__legend { padding: 0; margin: 0 0 var(--space-3); font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); letter-spacing: var(--tracking-tight); }
.fds-form__fields { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
.fds-field__hint { font-size: var(--text-2xs); color: var(--mut); line-height: var(--leading-snug); }
/* Control surface: flat panel, hairline, signal focus ring. The active field
   shows the focused state in a static render. This is the native input/select
   control of the form section, distinct from the custom .fds-select dropdown
   above. Its native <select> uses .fds-form__select (not .fds-select) for the
   chevron so the two never collide. */
.fds-control {
  appearance: none; -webkit-appearance: none;
  width: 100%; box-sizing: border-box; min-width: 0;
  font: inherit; font-size: var(--text-sm); color: var(--ink-2);
  border: var(--hair) solid var(--line-2); border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4); line-height: var(--leading-snug);
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.fds-control::placeholder { color: var(--faint); }
.fds-control:focus, .fds-control:focus-visible,
.fds-control.is-active {
  outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2);
  border-color: var(--signal);
}
/* Native select gets a CSS-drawn chevron so no glyph font is required. */
.fds-form__select { padding-right: var(--space-8); cursor: pointer; background-image: linear-gradient(45deg, transparent 50%, var(--mut) 50%),
    linear-gradient(135deg, var(--mut) 50%, transparent 50%);
  background-position: right var(--space-4) center, calc(100% - var(--space-4) + var(--space-1)) center;
  background-size: var(--space-1) var(--space-1), var(--space-1) var(--space-1); background-repeat: no-repeat; }

/* ── native-control accent ───────────────────────────────────────────────────
   accent-color paints the parts of a native control the engine draws itself —
   the checkbox tick, the radio dot, the range fill, the <progress> bar, and, on
   engines that honour it, the <select> highlight — in the FDS signal family
   instead of the OS default blue. --signal already flips per theme, so this one
   declaration serves light and dark. It inherits, so a native <input> a builder
   composes into an FDS form inherits the calm accent with no extra class. The
   design system owns the base layer, so this sits on the bare controls. */
input, select, textarea, progress, .fds-control { accent-color: var(--signal); }

/* ── native <select> open popup ──────────────────────────────────────────────
   The open <select> menu is drawn by the browser and, on macOS, by the OS. This
   stylesheet cannot repaint an OS-owned surface, so it reaches for the levers the
   platform does offer, weakest first, each degrading silently where unsupported.
   1: color-scheme. The popup follows the active theme by INHERITANCE from the
   theme roots in tokens/colors.css, the single owner of the selection contract
   (an explicit data-theme pins the theme and ignores the OS preference; no
   attribute follows the OS). The control declares NO color-scheme of its own.
   A per-control copy here once broke the contract: a bare prefers-color-scheme
   query with no :not([data-theme]) guard turned a theme-pinned cool page's
   popups dark on a dark-OS machine, and its opt-out targeted a "light" theme
   name nothing sets (the light theme attribute is "cool"). Deleted rather than
   repaired, so the contract has exactly one home. */
/* 2 — <option> colours: Chromium honours background/color on options on some
   platforms and ignores them where the menu is OS-drawn, so they land in the FDS
   panel and ink where they can and cost nothing where they cannot. */
.fds-form__select option { background: var(--panel); color: var(--ink-2); }
.fds-form__select option:checked { color: var(--ink); font-weight: var(--weight-strong); }
/* 3 — the customizable-select API (Chromium, progressive enhancement): where the
   engine supports appearance: base-select it hands the whole popup to CSS, and we
   paint it in full FDS vocabulary, mirroring the custom .fds-select dropdown — a
   --panel picker on a hairline with the card radius and shadow, hairline-separated
   rows, a quiet --signal-soft hover wash (never the OS blue), and the selected row
   marked by a --signal check beside its word, so selection never rides on colour
   alone. Engines without the API keep the native popup improved by 1 and 2. */
@supports (appearance: base-select) {
  .fds-form__select, .fds-form__select::picker(select) { appearance: base-select; }
  .fds-form__select::picker(select) {
    border: var(--hair) solid var(--line-2); border-radius: var(--radius-sm);
    background: var(--panel); box-shadow: var(--shadow-card); overflow: hidden;
  }
  .fds-form__select option {
    display: flex; align-items: center; gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    color: var(--ink-2); background: var(--panel);
    font-size: var(--text-sm); line-height: var(--leading-snug);
    border-top: var(--hair) solid var(--line-fine);
  }
  .fds-form__select option:first-child { border-top: 0; }
  .fds-form__select option:hover,
  .fds-form__select option:focus { background: var(--signal-soft); color: var(--ink); }
  .fds-form__select option:checked { background: var(--signal-soft); color: var(--ink); font-weight: var(--weight-strong); }
  .fds-form__select option::checkmark { color: var(--signal); order: 1; margin-left: auto; }
  /* base-select supplies its own ::picker-icon; the closed control keeps the
     existing CSS-drawn chevron above, so the native one is hidden to avoid a
     double caret and leave the closed control's paint byte-for-byte unchanged. */
  .fds-form__select::picker-icon { display: none; }
}

/* The honest limit: on every engine WITHOUT the customizable-select API — Safari,
   Firefox, and Chromium where the menu is handed to the OS — the open <select>
   popup's surface, highlight row, and checkmark stay OS-owned. color-scheme and
   the <option> colours above nudge it toward the theme; they cannot repaint it.
   We enhance the popup where the platform allows and never fake it where it does
   not. The custom .fds-select dropdown above is the fully-FDS alternative for a
   surface that must read as ours on every engine. */

/* Action row: one primary, one secondary. Primary leads, sits at the end. */
.fds-form__actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-3); padding-top: var(--space-4); border-top: var(--hair) solid var(--line); }

/* ── 34-validation-summary ─────────────────────────────────────────────────
   Collects every field error at the top of a form in one place, with a jump to
   each. Built on shared rows (.fds-rows / .fds-row / .fds-sev). The field links
   and the "Go to field" jump are the only block-specific pieces. */
.fds-validation .fds-row__t a { color: var(--ink-2); text-decoration: none; }
.fds-validation .fds-row__t a:hover { text-decoration: underline; text-underline-offset: var(--stroke-2); }
.fds-validation .fds-jump { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--signal); text-decoration: none; white-space: nowrap; }
.fds-validation .fds-jump:hover { color: var(--accent-text); }

/* B2 still mode / reduced motion — collapse every motion transition in this file to
   instant, so a reader who asked for stillness gets the rest state with identical meaning:
   the focus-ring box-shadows (.fds-input / .fds-select / .fds-control) and the transforms
   the caret rotate and the toggle knob slide are motion. Colour crossfades on the same
   controls stay; these do not. Held byte-for-byte in lockstep with the origins above by
   build/lint-still-mode.mjs (positive coverage); the two twins may not drift or vanish. */
@media (prefers-reduced-motion: reduce) {
  .fds-input,
  .fds-select,
  .fds-caret,
  .fds-toggle__knob,
  .fds-control { transition: none; }
}
:root[data-still] .fds-input,
:root[data-still] .fds-select,
:root[data-still] .fds-caret,
:root[data-still] .fds-toggle__knob,
:root[data-still] .fds-control { transition: none; }

/* ===== parts/nav.css ===== */
/* parts/nav.css — component CSS for the Navigation category.
   Tokens only. Shared so the gallery (which inlines styles.css) renders these
   blocks fully and the component CSS is defined once. */

/* ── 35-tabs ────────────────────────────────────────────────────────────── */
/* Tabs — a horizontal tab bar with an underline indicator on the active tab.
   The active tab is marked three ways, never colour alone: selected state
   (aria-selected), the underline indicator, and the signal text. Inactive
   tabs are muted with no indicator. On a narrow screen the bar wraps to a
   second line rather than overflowing or hiding tabs behind a scroll. */
.fds-tabs { display: flex; flex-direction: column; min-width: 0; }

.fds-tabs__bar {
  display: flex; flex-wrap: wrap; gap: var(--space-1);
  border-bottom: var(--hair) solid var(--line);
  min-width: 0;
}
.fds-tabs__tab {
  appearance: none; border: 0; background: none; font: inherit; cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  margin-bottom: calc(-1 * var(--hair)); /* sit the underline on the bar hairline */
  border-bottom: var(--stroke-2) solid transparent;
  font-size: var(--text-sm); font-weight: var(--weight-strong); letter-spacing: var(--tracking-open);
  color: var(--text-muted); white-space: nowrap; min-width: 0;
  transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.fds-tabs__tab:hover { color: var(--ink-2); }
.fds-tabs__tab[aria-selected="true"] {
  color: var(--accent-text);
  border-bottom-color: var(--signal);
}
.fds-tabs__tab:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); border-radius: var(--radius-sm); }

/* a small count chip riding alongside a tab label, neutral */
.fds-tabs__count {
  font-size: var(--text-2xs); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums;
  color: var(--text-faint); line-height: var(--leading-none);
  padding: calc(var(--space-1) / 2) var(--space-2); border-radius: var(--radius-pill);
  border: var(--hair) solid var(--line-2);
}
.fds-tabs__tab[aria-selected="true"] .fds-tabs__count {
  color: var(--accent-text); border-color: var(--signal-line); background: var(--signal-soft);
}

.fds-tabs__panel { padding-top: var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.fds-tabs__panel-title { margin: 0; font-size: var(--text-sm); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
.fds-tabs__panel p { margin: 0; }

/* ── 36-breadcrumbs ───────────────────────────────────────────────────────── */
/* Breadcrumbs — the trail of where this page sits, from the top level down to
   the page in view. Each level except the last is a link back up the tree.
   The last item is the current page: it is not a link, it carries
   aria-current, and it is the only item in heading ink, so the current
   location reads three ways and never by colour alone. A small chevron sits
   between levels, marked aria-hidden so a screen reader hears only the names.
   The trail wraps to the next line on a narrow screen rather than overflowing
   or hiding levels behind a sideways scroll. */
.fds-crumbs {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-1) var(--space-2);
  min-width: 0; margin: 0; padding: 0; list-style: none;
}
.fds-crumbs__item { display: inline-flex; align-items: center; min-width: 0; }

.fds-crumbs__link {
  display: inline-flex; align-items: center; min-width: 0;
  max-width: 100%;
  font-size: var(--text-sm); font-weight: var(--weight-strong); letter-spacing: var(--tracking-open);
  color: var(--text-muted); text-decoration: none; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  border-radius: var(--radius-sm);
  transition: color var(--dur-fast) var(--ease-out);
}
.fds-crumbs__link:hover { color: var(--ink-2); text-decoration: underline; text-underline-offset: var(--space-1); }
.fds-crumbs__link:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

/* the current page: heading ink, heavier, and not a link */
.fds-crumbs__current {
  display: inline-flex; align-items: center; min-width: 0; max-width: 100%;
  font-size: var(--text-sm); font-weight: var(--weight-strong); letter-spacing: var(--tracking-open);
  color: var(--ink-2); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* a small leading marker on the top level, so the start of the trail reads at a glance */
.fds-crumbs__home { flex: none; width: calc(var(--space-3) + var(--space-1) / 2); height: calc(var(--space-3) + var(--space-1) / 2); margin-right: var(--space-2); color: var(--text-faint); }

/* the chevron between levels, decorative only */
.fds-crumbs__sep { flex: none; width: var(--space-3); height: var(--space-3); color: var(--text-faint); }

/* ── 37-pagination ────────────────────────────────────────────────────────── */
/* Pagination — a row of numbered pages between a previous and a next control.
   The current page is marked three ways, never colour alone: it carries
   aria-current, it is the only filled item (signal wash), and it reads as the
   current page to a screen reader. Skipped ranges collapse to an ellipsis
   marked aria-hidden, so the reader sees the shape of the set without every
   number. Previous and next are real controls; at the ends one is disabled and
   drops out of the tab order. On a narrow screen the row wraps to a second line
   rather than overflowing or hiding pages behind a sideways scroll. */
.fds-pager {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-1) var(--space-2);
  min-width: 0; margin: 0; padding: 0; list-style: none;
}
.fds-pager__item { display: inline-flex; min-width: 0; }

/* shared base for every page number and the two ends: quiet and boxless. Only
   the current page is a filled chip; every other control is plain text that
   shifts ink on hover, nothing more. The row stays calm and light, and the
   state line beside it ("Page 4 of 12") carries the story. */
.fds-pager__page,
.fds-pager__step {
  appearance: none; box-sizing: border-box; font: inherit; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-2);
  min-width: calc(var(--space-8) + var(--space-1)); height: calc(var(--space-8) + var(--space-1)); padding: 0 var(--space-2);
  border: 0; background: none; border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: var(--text-sm); font-weight: var(--weight-strong);
  font-variant-numeric: tabular-nums; letter-spacing: var(--tracking-open);
  text-decoration: none; white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out);
}
/* quiet hover: the ink shifts, no box grows back in */
.fds-pager__page:hover,
.fds-pager__step:hover {
  color: var(--ink-2);
}
.fds-pager__page:focus-visible,
.fds-pager__step:focus-visible {
  outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2);
}

/* the current page: the ONE filled element, in the single accent */
.fds-pager__page[aria-current="page"] {
  color: var(--on-accent); background: var(--signal);
  cursor: default;
}
.fds-pager__page[aria-current="page"]:hover {
  color: var(--on-accent);
}

/* previous / next: a small chevron beside a word, so direction never reads by
   glyph alone */
.fds-pager__step { padding: 0 var(--space-3); }
.fds-pager__chev { flex: none; width: var(--space-3); height: var(--space-3); }
.fds-pager__steplabel { min-width: 0; }

/* an end control with nowhere to go: faint, not a target, out of tab order */
.fds-pager__step[aria-disabled="true"] {
  color: var(--text-faint); cursor: default;
}
.fds-pager__step[aria-disabled="true"]:hover {
  color: var(--text-faint);
}

/* the gap standing in for skipped pages, decorative */
.fds-pager__gap {
  display: inline-flex; align-items: flex-end; justify-content: center;
  min-width: var(--space-6); height: calc(var(--space-8) + var(--space-1)); padding-bottom: var(--space-2);
  color: var(--text-faint); font-size: var(--text-sm); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label-loose); line-height: var(--leading-none); user-select: none;
}

/* on very narrow screens, let the word on previous/next fall away so the
   chevrons still wrap to one tidy line with the numbers */
@media (max-width: 360px) {
  .fds-pager__steplabel { display: none; }
  .fds-pager__step { padding: 0 var(--space-2); }
}

/* Glued into a card foot, the pager sits in a between-cluster beside the
   page-state text. That cluster wraps: on a wide foot the state and the pager
   share one line (state at the left, pager at the right); as the foot narrows
   the state wraps to its own line ABOVE the pager, and only the pager itself
   must still hold a single row. A foot that broke the PAGER into extra rows
   would be a structural reflow, not the house scale-to-fit. So at the phone
   width a foot-bound pager compacts EARLY (before the standalone 360 step): the
   previous/next words fall to their chevrons and the pager row stops wrapping,
   so its numbers stay on one tidy line. The standalone pager (not in a foot)
   keeps its later 360 breakpoint and its wrap. */
@media (max-width: 480px) {
  .fds-card__foot .fds-pager { flex-wrap: nowrap; }
  .fds-card__foot .fds-pager .fds-pager__steplabel { display: none; }
  .fds-card__foot .fds-pager .fds-pager__step { padding: 0 var(--space-2); }
}

/* In the same nowrap band a long foot pager (many numbered pages, an ellipsis
   on each side) cannot keep its single row inside the card: measured, its full
   numbers only fit down to ~456px, so the shed must fire wherever the nowrap
   rule does — one band, no gap where the fixed row overflows a still-narrowing
   card. The current page stays marked on the control itself (aria-current, the
   filled step), so the interior page numbers are redundant weight here. Shed
   them to the essentials the reader still needs (previous, next, and the
   current page) so the row shrinks to fit the narrowest card without overflow.
   A short foot pager sheds its interior numbers the same way, landing on the
   same tidy prev / current / next. */
@media (max-width: 480px) {
  .fds-card__foot .fds-pager__item:has(.fds-pager__page:not([aria-current="page"])),
  .fds-card__foot .fds-pager__item:has(.fds-pager__gap) {
    display: none;
  }
}

/* ── 38-side-nav ──────────────────────────────────────────────────────────── */
/* Side nav — a vertical list of links grouped into labelled sections. Each
   group carries a quiet uppercase label so the reader sees the shape of the
   navigation before reading every link. One link is the page in view: it is
   marked three ways and never by colour alone. It carries aria-current, a
   filled indicator bar runs down its leading edge, and it shows a small
   "Current" tag in words, so the location survives a greyscale print or a
   colourblind reader. The other links stay muted until chosen. Every link is
   a full-width target that wraps to a second line on a narrow column rather
   than overflowing or clipping its label. */
.fds-sidenav {
  display: flex; flex-direction: column; gap: var(--space-5);
  min-width: 0; margin: 0; padding: 0;
}

.fds-sidenav__group { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }

/* the group label: a quiet uppercase eyebrow above its links */
.fds-sidenav__label {
  margin: 0 0 var(--space-1); padding: 0 var(--space-3);
  font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--text-faint);
}

.fds-sidenav__list { display: flex; flex-direction: column; gap: calc(var(--space-1) / 2); min-width: 0; margin: 0; padding: 0; list-style: none; }
.fds-sidenav__item { display: flex; min-width: 0; }

/* a link: a full-width target. A leading indicator rail sits at the start,
   transparent until the link is current. */
.fds-sidenav__link {
  position: relative; display: flex; align-items: center;
  gap: var(--space-2); width: 100%; min-width: 0; box-sizing: border-box;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-muted); text-decoration: none;
  font-size: var(--text-sm); font-weight: var(--weight-strong); letter-spacing: var(--tracking-open);
  transition: color var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out);
}
/* the indicator rail down the leading edge, drawn for every link but only
   inked on the current one */
.fds-sidenav__link::before {
  content: ""; flex: none; align-self: stretch;
  width: var(--space-1); margin: calc(var(--space-1) / 2) 0; border-radius: var(--radius-pill);
  background: transparent;
}
.fds-sidenav__link:hover { color: var(--ink-2); }
.fds-sidenav__link:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

/* the page in view: filled rail, faint accent wash, accent text */
.fds-sidenav__link[aria-current="page"] {
  color: var(--accent-text); background: var(--signal-soft); cursor: default;
}
.fds-sidenav__link[aria-current="page"]::before { background: var(--signal); }
.fds-sidenav__link[aria-current="page"]:hover { color: var(--accent-text); background: var(--signal-soft); }

/* the link label: wraps rather than clipping on a narrow column */
.fds-sidenav__text { min-width: 0; flex: 1 1 auto; }

/* the word that names the current location, so it reads without colour */
.fds-sidenav__tag {
  flex: none; font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--accent-text); line-height: var(--leading-none);
  padding: calc(var(--space-1) / 2) var(--space-2); border-radius: var(--radius-pill);
  border: var(--hair) solid var(--signal-line);
}

/* ===== parts/feedback.css ===== */
/* parts/feedback.css — component CSS for the feedback category.
   Tokens only. Shared primitives (button, close cross, scrim) live in
   controls.css and are reused, not redefined here. */

/* ── alert (39-alert) ─────────────────────────────────────────────────────
   Inline alert / banner primitive. The kind is always named in words and
   carries a distinct icon SHAPE, so meaning survives a colourblind reader or
   a greyscale print: colour never stands alone. */
.fds-alerts { display: flex; flex-direction: column; gap: var(--space-3); }

.fds-alert {
  display: flex; align-items: flex-start; gap: var(--space-3); min-width: 0;
  padding: var(--space-3) var(--space-4);
  border: var(--hair) solid var(--line);
  border-radius: var(--radius-sm);
}
.fds-alert__main { min-width: 0; display: flex; flex-direction: column; gap: calc(var(--space-1) / 2); }
.fds-alert__kind { font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); line-height: var(--leading-snug); }
.fds-alert__msg { font-size: var(--text-xs); color: var(--body); line-height: var(--leading-snug); text-wrap: pretty; }

/* Icon chip: a token-tinted square holding a CSS-drawn mark, one shape per kind.
   The shape is the redundant cue; no glyph font, no colour-only meaning. */
.fds-alert__icon {
  flex: none; width: var(--space-6); height: var(--space-6); border-radius: var(--radius-sm);
  display: grid; place-items: center; position: relative;
}
.fds-alert__icon::before, .fds-alert__icon::after { content: ""; position: absolute; }

/* Info — signal navy. Mark: a lower-case "i" (dot over a stem). */
.fds-alert--info .fds-alert__icon { background: var(--signal-soft); }
.fds-alert--info .fds-alert__icon::before { width: var(--space-1); height: var(--space-1); border-radius: var(--radius-pill); background: var(--signal); transform: translateY(calc(var(--space-1) * -1)); }
.fds-alert--info .fds-alert__icon::after { width: var(--space-1); height: var(--space-2); border-radius: var(--radius-mark); background: var(--signal); transform: translateY(calc(var(--space-1) / 2)); }

/* Success — sage. Mark: a check tick. */
.fds-alert--success .fds-alert__icon { background: var(--ok-bg); }
.fds-alert--success .fds-alert__icon::after {
  width: var(--space-2); height: var(--space-1); margin-top: calc(calc(var(--space-1) / 2) * -1);
  border-left: var(--stroke-2) solid var(--ok-dot); border-bottom: var(--stroke-2) solid var(--ok-dot);
  transform: rotate(-45deg);
}

/* Warning — muted ochre. Mark: an exclamation (stem over a dot). */
.fds-alert--warning .fds-alert__icon { background: var(--warn-bg); }
.fds-alert--warning .fds-alert__icon::before { width: var(--space-1); height: var(--space-2); border-radius: var(--radius-mark); background: var(--warn-ink); transform: translateY(calc(var(--space-1) * -1)); }
.fds-alert--warning .fds-alert__icon::after { width: var(--space-1); height: var(--space-1); border-radius: var(--radius-pill); background: var(--warn-ink); transform: translateY(var(--space-1)); }

/* Danger — muted clay. Mark: a cross. */
.fds-alert--danger .fds-alert__icon { background: var(--blk-bg); }
.fds-alert--danger .fds-alert__icon::before,
.fds-alert--danger .fds-alert__icon::after { width: var(--space-3); height: calc(var(--space-1) / 2); border-radius: var(--radius-mark); background: var(--blk-ink); }
.fds-alert--danger .fds-alert__icon::before { transform: rotate(45deg); }
.fds-alert--danger .fds-alert__icon::after { transform: rotate(-45deg); }

/* ── toast (40-toast) ─────────────────────────────────────────────────────
   Transient toast primitive. It rides the floating layer (--shadow-float),
   the same depth the system reserves for things that hover above the page.
   The kind is always a coloured dot PLUS a word, and the success mark is a
   drawn CHECK SHAPE, so meaning survives a colourblind reader or a greyscale
   print: colour never stands alone. The dismiss control reuses the shared
   .fds-x close cross from controls.css. */
.fds-toasts { display: flex; flex-direction: column; gap: var(--space-3); }

.fds-toast {
  display: flex; align-items: flex-start; gap: var(--space-3); min-width: 0;
  padding: var(--space-3) var(--space-4);
  border: var(--hair) solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-float);
}

/* Icon chip: a token-tinted disc holding a CSS-drawn mark. The shape is the
   redundant cue; no glyph font, no colour-only meaning. */
.fds-toast__icon {
  flex: none; width: var(--space-5); height: var(--space-5); border-radius: var(--radius-pill);
  display: grid; place-items: center; position: relative; margin-top: var(--hair);
}
.fds-toast__icon::after { content: ""; position: absolute; }

/* Success — sage. Mark: a check tick. */
.fds-toast--success .fds-toast__icon { background: var(--ok-bg); }
.fds-toast--success .fds-toast__icon::after {
  width: var(--space-2); height: var(--space-1); margin-top: calc(var(--hair) * -1);
  border-left: var(--stroke-2) solid var(--ok-dot); border-bottom: var(--stroke-2) solid var(--ok-dot);
  transform: rotate(-45deg);
}

/* Neutral — stone. Mark: a small solid dot, the system's plain status dot. */
.fds-toast--neutral .fds-toast__icon { background: var(--na-bg); }
.fds-toast--neutral .fds-toast__icon::after {
  width: var(--dot); height: var(--dot); border-radius: var(--radius-pill);
  background: var(--na-dot);
}

.fds-toast__main { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; gap: calc(var(--space-1) / 2); }
.fds-toast__kind {
  font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--mut); line-height: var(--leading-snug);
}
.fds-toast__msg {
  font-size: var(--text-sm); color: var(--body);
  line-height: var(--leading-snug); text-wrap: pretty;
}

/* ── empty-state (41-empty-state) ─────────────────────────────────────────
   A calm placeholder for an empty list, with one plain action to add the
   first item. Neutral surface ink: an empty list is neither good nor bad, so
   colour carries no meaning. The "Nothing here yet" line says the state in
   words, so it reads without colour. */
.fds-empty {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--space-4); padding: var(--space-8) var(--space-3) var(--space-6);
}
.fds-empty__mark {
  display: grid; place-items: center; flex: none;
  width: calc(var(--space-12) + var(--space-2)); height: calc(var(--space-12) + var(--space-2)); border-radius: var(--radius-md);
  border: var(--hair) solid var(--line-2); background: var(--paper);
  color: var(--text-faint);
}
.fds-empty__mark svg { max-width: 100%; }
.fds-empty__copy { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; max-width: 34ch; }
.fds-empty__title {
  margin: 0; font-size: var(--text-md); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-tight); line-height: var(--leading-tight);
  color: var(--ink-2);
}

/* ── skeleton (42-skeleton) ───────────────────────────────────────────────
   Loading skeleton primitive. The skeleton carries NO colour meaning. It is
   plain surface ink, not a status, because waiting is neither good nor bad.
   The fact that this is a loading state is always said in WORDS (the "Loading"
   line, plus role="status"), so it reads for a colourblind reader, a greyscale
   print, or a reader who has turned animation off. */
.fds-skeleton { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }

/* The "Loading" line: the meaning in words, with the system's resting state dot
   so the placeholder is never colour or motion alone. */
.fds-skeleton__status {
  display: flex; align-items: center; gap: var(--space-2); min-width: 0;
  font-size: var(--text-2xs); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--mut); line-height: var(--leading-snug);
}
.fds-skeleton__status::before {
  content: ""; flex: none; width: var(--dot); height: var(--dot);
  border-radius: var(--radius-pill); background: var(--na-dot);
}

/* A single placeholder bar. Neutral surface tint on the panel, a soft shimmer
   sweeping across it to read as "still arriving". Every bar is the same token
   surface; size is the only difference between a title, a line, and a figure. */
.fds-skeleton__bar {
  position: relative; overflow: hidden; min-width: 0;
  background: var(--line);
  border-radius: var(--radius-sm);
}
.fds-skeleton__bar::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--line-fine) 50%,
    transparent 100%
  );
  transform: translateX(-100%);
  animation: fds-skeleton-shimmer var(--dur-loading) var(--ease-inout) infinite;
}
@keyframes fds-skeleton-shimmer {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

/* The placeholder shapes. Heights ride the type and spacing scale so the
   skeleton keeps the same rhythm as the real card it stands in for. */
.fds-skeleton__title { height: var(--text-lg); width: 62%; border-radius: var(--radius-sm); }
.fds-skeleton__lines { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.fds-skeleton__line  { height: var(--text-sm); }
.fds-skeleton__line--short { width: 78%; }
.fds-skeleton__figure {
  height: var(--space-20); width: 100%; max-width: 100%;
  border-radius: var(--radius-md);
}

/* Calm by default: if the reader prefers reduced motion, the shimmer holds
   still and the resting surface plus the "Loading" word still carry the meaning. */
@media (prefers-reduced-motion: reduce) {
  .fds-skeleton__bar::after { animation: none; transform: translateX(0); opacity: var(--opacity-disabled); }
}
/* B2 still mode twin (kept identical to the reduced-motion rule by lint-still-mode.mjs) */
:root[data-still] .fds-skeleton__bar::after { animation: none; transform: translateX(0); opacity: var(--opacity-disabled); }

/* ── progress (43-progress) ───────────────────────────────────────────────
   Progress primitive. The determinate bar reuses the shared .fds-meter track
   and fill (so it inherits the runtime "Now NN%" hover read-out) but drops the
   plan target: progress is its own meaning, not a number against a plan. The
   plain consequence ("3 of 5 steps done") always sits beside the bar, so the
   reading never rides on the fill length alone, and survives a greyscale print.
   Progress is shown in NEUTRAL ink, not a status colour: being part-way through
   is not good or bad, so colour carries no meaning here. */
.fds-progress { display: flex; flex-direction: column; gap: var(--space-5); min-width: 0; }
.fds-progress__item { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.fds-progress__row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-3); min-width: 0;
}
.fds-progress__label { font-size: var(--text-sm); font-weight: var(--weight-strong); color: var(--ink-2); min-width: 0; }
.fds-progress__count {
  flex: none; font-size: var(--text-xs); font-weight: var(--weight-strong);
  color: var(--body); font-variant-numeric: tabular-nums;
}

/* Indeterminate variant: amount of work is unknown, so there is no fill width
   and no percent. A short segment travels the track to mean "working", and the
   word "Working" names that meaning so it reads without motion or colour. */
.fds-progress__track--wait { position: relative; overflow: hidden; }
.fds-progress__wait {
  position: absolute; top: 0; bottom: 0; left: 0; width: 38%;
  border-radius: var(--radius-pill); background: var(--ink-2);
  animation: fds-progress-slide var(--dur-wait) var(--ease-inout) infinite alternate;
}
@keyframes fds-progress-slide {
  from { left: 0; }
  to   { left: 62%; }
}
/* Calm by default: if the reader prefers reduced motion, the segment holds a
   resting position rather than travelling, and the word still carries meaning. */
@media (prefers-reduced-motion: reduce) {
  .fds-progress__wait { animation: none; left: 31%; }
}
/* B2 still mode twin (kept identical to the reduced-motion rule by lint-still-mode.mjs) */
:root[data-still] .fds-progress__wait { animation: none; left: 31%; }

/* ===== parts/content.css ===== */
/* parts/content.css. Component CSS for the content & media category.
   Promoted verbatim from the block specimens so the gallery (which inlines
   styles.css) renders each block fully. Tokens only; light and dark both clean. */

/* ── prose (44-prose) ───────────────────────────────────────────────────────
   Long-form prose primitive, a comfortable reading column on the type scale.
   Body copy sits at --text-base with relaxed leading; the measure is capped so
   lines stay readable. Headings derive from --ink-2, links carry the one signal
   accent AND an underline so colour never carries meaning alone.

   SCOPE CONTRACT. .fds-prose styles the full markdown element set (heading,
   paragraph, list, quote, table, code, figure, rule) by matching elements, so a
   renderer's raw HTML drops in and renders house-styled. It wraps MARKDOWN
   CONTENT: in a document a figure, log, chart, or card sits as a SIBLING of the
   prose in the river (the archetypes), never nested inside it. So that a
   composed block nested inside prose (against that contract) is not corrupted,
   Prose wraps a MARKDOWN document. Composed fds- blocks are its SIBLINGS in the
   river (the archetypes compose them side by side), never its children. That
   sibling contract is the real isolation boundary, because no prose primitive
   can fully wall itself off from a composed block nested INSIDE it: CSS can stop
   prose from OVERRIDING a property the block declares, but not from FILLING IN a
   property the block leaves at its default (a nested code viewer that never sets
   white-space, a nested nav list that never resets its list marker). To make the
   override half airtight, every prose rule is written with :where(.fds-prose), so
   its specificity is a bare element (0,0,x) and any composed block class (0,1,x)
   always wins for the properties it sets; the rhythm and heading-spacing rules
   use :where(.fds-prose) > (direct child) so they only add outer margin to a
   direct child, and the figure image rule matches only a direct-child <img> (a
   markdown figure). The whole prose cascade keeps its own relative order because
   every rule shifts down by the same amount; block 44 (the only prose consumer)
   renders identically. The fill-in half is closed by the sibling contract, not
   by CSS: do not nest a composed block inside prose (see ADOPT.md / the river
   archetypes). Reader text on a well stays strong / body / code weight; muted
   text sits on paper or a panel (--mut is at the AA floor on paper, so a recessed
   well cannot hold it). */
/* In a river, the LANE owns the width (one-width doctrine): prose fills it like
   every other element, so text and cards share both edges. Outside a river (a
   prose well inside a card, the gallery specimen) the 64ch cap still guards the
   line length. */
.fds-river .fds-prose { max-width: 100%; }
/* One reading width. 64ch was a second, narrower column and left tables and
   the review canvas looking half-empty. --measure is the ratified page geometry
   (pixels, not ch) so prose, cards, and tables share both edges. */
.fds-prose { max-width: var(--measure); color: var(--text-body); font-size: var(--text-base); line-height: var(--leading-relaxed); }
:where(.fds-prose) > * { margin: 0; }
:where(.fds-prose) > * + * { margin-top: var(--space-4); }

:where(.fds-prose) h2 { font-size: var(--text-lg); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); color: var(--ink-2); text-wrap: balance; }
:where(.fds-prose) > h2 + p { margin-top: var(--space-3); }
:where(.fds-prose) p { text-wrap: pretty; }
:where(.fds-prose) strong { font-weight: var(--weight-strong); color: var(--ink-2); }

/* inline link: signal accent plus a persistent underline (the redundant cue) */
:where(.fds-prose) a { color: var(--accent); text-decoration: underline; text-decoration-color: var(--accent-line); text-underline-offset: var(--stroke-2); text-decoration-thickness: var(--hair); border-radius: var(--radius-sm); }
:where(.fds-prose) a:where(:hover) { text-decoration-color: var(--accent); }
:where(.fds-prose) a:where(:focus-visible) { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

/* bulleted list: a small signal marker plus the words; comfortable row rhythm.
   Scoped to a DIRECT child of a ul so a nested ordered list keeps its number
   marker instead of also getting a dot, and so the marker never leaks onto a
   list that belongs to a composed block dropped inside the prose. */
:where(.fds-prose) ul { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
:where(.fds-prose) ul > li { position: relative; padding-left: var(--space-5); text-wrap: pretty; }
:where(.fds-prose) ul > li::before { content: ""; position: absolute; left: var(--space-1); top: calc(var(--leading-relaxed) * 0.5em); width: var(--space-1); height: var(--space-1); border-radius: var(--radius-pill); background: var(--accent); transform: translateY(-50%); }

/* ordered list: a signal-accent number plus the words. Styles the NATIVE
   ::marker on a real decimal list, so a markdown renderer's <ol start>, <ol
   reversed>, and per-item <li value> all number correctly — the marker follows
   the list's true ordinal, never a reset-to-1 (a private CSS counter cannot read
   those attributes). The marker sits outside in the list padding, right-aligned,
   so single- and multi-digit numbers line up on one edge; tabular figures hold
   the alignment. ::marker only takes colour/font, which is all the accent needs. */
:where(.fds-prose) ol { padding-left: var(--space-8); }
:where(.fds-prose) ol > li { text-wrap: pretty; }
:where(.fds-prose) ol > li + li { margin-top: var(--space-2); }
:where(.fds-prose) ol > li::marker { color: var(--accent-text); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums; }

/* nested list: give an inner list a little air below its parent line */
:where(.fds-prose) li > ul, :where(.fds-prose) li > ol { margin-top: var(--space-2); }

/* subheadings: h3 and h4 carry the ink-2 heading voice one and two steps down
   from h2, sized by the scale, never picked for size. A heading binds to what
   follows it: more space above, less below. Direct-child combinators keep the
   rhythm from reaching a nested block's own headings. */
:where(.fds-prose) h3 { font-size: var(--text-md); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); line-height: var(--leading-snug); color: var(--ink-2); text-wrap: balance; }
:where(.fds-prose) h4 { font-size: var(--text-base); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); line-height: var(--leading-snug); color: var(--ink-2); text-wrap: balance; }
:where(.fds-prose) > * + h3, :where(.fds-prose) > * + h4 { margin-top: var(--space-6); }
:where(.fds-prose) > h3 + *, :where(.fds-prose) > h4 + * { margin-top: var(--space-3); }

/* inline code: a monospace run set into a subtle well so it reads as a literal
   without shouting. Strong ink on the well clears AA in both themes. Mono is
   sanctioned for code only (see docs/USAGE.md). Excludes the <code> inside a
   <pre> (the block below owns that). */
:where(.fds-prose) :not(pre) > code { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--ink-2); background: var(--well); border-radius: var(--radius-sm); padding: var(--stroke-2) var(--space-1); overflow-wrap: anywhere; }

/* code block: a monospace surface on the well. In a reading document a code
   block WRAPS to the measure rather than opening a horizontal scroll: it keeps
   the page from ever scrolling sideways AND avoids a scroll region a keyboard
   user cannot reach. The dedicated code viewer (block 46, .fds-code__pre) wraps
   the same way, so both surfaces keep every character in the frame. A long
   unbreakable token still breaks (overflow-wrap) so nothing spills past the
   frame. No shadow: a well is a recessed island, not a raised panel. :where()
   keeps it below a nested composed .fds-code__pre (on --panel), which always
   wins. */
:where(.fds-prose) pre { margin: 0; min-width: 0; max-width: 100%; white-space: pre-wrap; overflow-wrap: anywhere; background: var(--well); border: var(--hair) solid var(--line); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5); font-size: var(--text-xs); line-height: var(--leading-relaxed); color: var(--ink-2); }
:where(.fds-prose) pre code { font-family: var(--font-mono); font-size: inherit; color: inherit; background: none; padding: 0; border-radius: 0; }

/* Hanging indent on the wrap (progressive). Where the engine understands each-line
   indents, a folded continuation hangs 2ch past its own line's start instead of
   restarting flush-left and reading as a new statement: the padding carries every
   line 2ch in, the negative each-line indent pulls only the AUTHORED line starts
   back out. The reachability trade above (wrap, never a sideways scroll region) is
   unchanged; an engine without each-line keeps today's flush fold, byte for byte. */
@supports (text-indent: 2ch each-line) {
  :where(.fds-prose) pre { padding-left: calc(var(--space-5) + 2ch); text-indent: -2ch each-line; }
}

/* table: the .fds-data reporting treatment for a plain markdown <table> —
   uppercase faint column heads, hairline row rules, first/last cells flush to
   the measure. A real width:100% table (like .fds-data), so the cells WRAP to
   fit the reading column at any width instead of the table becoming its own
   horizontal scroller: a scrolled-off column in an overflow box is unreachable
   for a keyboard-only user, and the page must never scroll sideways either.
   Wrapping serves both. Long unbreakable tokens break rather than force
   overflow. The real <table> semantics (a thead of column headers) are
   preserved for assistive tech. A genuinely wide dataset belongs in the
   composition .fds-data block (which reflows each row to a labelled card on a
   phone), not raw in prose. Wrapped in :where() so its specificity is a bare
   element: a real .fds-data / .fds-comparison table nested inside prose keeps its own
   classed rules (including the phone stacked-card reflow), which would otherwise
   tie on specificity and lose to these later-loaded prose rules. */
:where(.fds-prose) table { width: 100%; border-collapse: collapse; color: var(--body); font-size: var(--text-sm); }
:where(.fds-prose) th, :where(.fds-prose) td { padding: var(--space-3) var(--space-3); border-top: var(--hair) solid var(--line-fine); text-align: left; vertical-align: top; text-wrap: pretty; overflow-wrap: anywhere; }
:where(.fds-prose) thead th { border-top: 0; font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
/* the :first-child / :last-child are themselves wrapped in :where so the
   pseudo-class adds no specificity; otherwise a bare :first-child (0,1,0) would
   lift these to 0,1,1 and tie (then beat, on load order) a nested .fds-comparison /
   .fds-data cell rule. They still win over the base cell rule above by source
   order at equal 0,0,1 specificity. */
:where(.fds-prose) th:where(:first-child), :where(.fds-prose) td:where(:first-child) { padding-left: 0; }
:where(.fds-prose) th:where(:last-child), :where(.fds-prose) td:where(:last-child) { padding-right: 0; }

/* figure: captioned media. The media sits on the well (a subordinate island);
   the caption stays on paper in the quiet measure voice, below the frame, never
   on the well (muted text belongs on paper/panel). :where() keeps every rule
   below a nested composed .fds-figure (whose .fds-figure__caption wins); the
   image rule matches only an <img> that is a DIRECT child of the figure (a
   markdown figure), never a composed .fds-figure's <img> nested in its
   .fds-figure__media wrapper. */
:where(.fds-prose) figure { margin: 0; display: flex; flex-direction: column; gap: var(--space-3); }
:where(.fds-prose) figure > :is(img, svg) { display: block; width: 100%; max-width: 100%; height: auto; border: var(--hair) solid var(--line); border-radius: var(--radius-sm); background: var(--well); }
:where(.fds-prose) figure > figcaption { font-size: var(--text-sm); color: var(--mut); line-height: var(--leading-snug); text-wrap: pretty; }

/* thematic break: a hairline rule with breathing room on both sides. :where()
   keeps it below a nested composed divider (.fds-rule / .fds-card__rule), which
   owns its own filled treatment and always wins. */
:where(.fds-prose) hr { border: 0; border-top: var(--hair) solid var(--line-2); margin: var(--space-6) 0; }

/* blockquote: set off by the one signal accent on a left rule, ink-2 voice */
:where(.fds-prose) blockquote { padding-left: var(--space-5); border-left: var(--stroke-2) solid var(--accent); color: var(--ink-2); font-size: var(--text-md); line-height: var(--leading-snug); letter-spacing: var(--tracking-tight); text-wrap: pretty; }

/* ── accordion (45-accordion) ────────────────────────────────────────────────
   Accordion, a vertical stack of disclosure rows. Each header is a real
   button that carries its own expanded or collapsed state, so a screen
   reader and the keyboard both know what is open. The chevron is a second,
   redundant cue: it points down when the row is folded and rotates up when
   the row is open, so the state never rests on colour alone. One answer is
   shown at a time; the rest stay folded to keep the page calm.
   Built only from tokens so it sits beside the other blocks and renders
   cleanly in light and dark. */
.fds-accordion { display: flex; flex-direction: column; min-width: 0; }

.fds-accordion__item {
  border-top: var(--hair) solid var(--line);
  min-width: 0;
}
.fds-accordion__item:first-child { border-top: 0; }

/* The header is the disclosure control: full-width button, label left,
   chevron right. No fill until it is open or hovered, so the stack reads
   as quiet rows rather than buttons. */
.fds-accordion__header {
  appearance: none; border: 0; background: none; font: inherit; cursor: pointer;
  width: 100%; min-width: 0;
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4) var(--space-1);
  text-align: left;
  color: var(--ink-2);
  transition: color var(--dur-fast) var(--ease-out);
}
.fds-accordion__header:hover { color: var(--ink); }
.fds-accordion__header:focus-visible {
  outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); border-radius: var(--radius-sm);
}

.fds-accordion__label {
  flex: 1; min-width: 0;
  font-size: var(--text-base); font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-tight); line-height: var(--leading-snug);
  text-wrap: pretty;
}

/* Chevron: two short strokes drawn with borders, pointing down when folded.
   It rotates a half turn when the header is open. Token motion, no glyph. */
.fds-accordion__chevron {
  flex: none; width: var(--space-5); height: var(--space-5); position: relative;
  display: grid; place-items: center;
  color: var(--text-muted);
  transition: transform var(--dur-base) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.fds-accordion__chevron::before {
  content: ""; width: var(--space-2); height: var(--space-2);
  border-right: var(--stroke-2) solid currentColor; border-bottom: var(--stroke-2) solid currentColor;
  border-radius: var(--radius-mark);
  transform: translateY(calc(calc(var(--space-1) / 2) * -1)) rotate(45deg);
}
.fds-accordion__header:hover .fds-accordion__chevron { color: var(--ink-2); }

/* Open state, marked three ways, never colour alone: the button reports
   aria-expanded="true", the chevron rotates to point up, and the open label
   lifts to the signal accent for live wayfinding. */
.fds-accordion__header[aria-expanded="true"] .fds-accordion__chevron {
  transform: rotate(180deg);
  color: var(--signal);
}
.fds-accordion__header[aria-expanded="true"] .fds-accordion__label {
  color: var(--accent-text);
}

/* Panel: the answer. Hidden entirely when collapsed (the [hidden] attribute),
   so only the open answer takes space. */
.fds-accordion__panel { padding: 0 var(--space-1) var(--space-5); min-width: 0; }
.fds-accordion__panel[hidden] { display: none; }
.fds-accordion__panel p {
  margin: 0; font-size: var(--text-sm); color: var(--body);
  line-height: var(--leading-relaxed); text-wrap: pretty;
}
.fds-accordion__panel p + p { margin-top: var(--space-3); }

/* ── code-block (46-code-block) ──────────────────────────────────────────────
   Code-block primitive. The system has no shared code surface yet, so this block
   defines its own from tokens. Two parts a plain card does not have: a head row
   carrying the language label and a copy control, and the code surface itself.
   A long line WRAPS onto the next line inside the pre (white-space: pre-wrap,
   capped at 100% width) rather than widening the page or hiding characters behind
   a horizontal scroll, so every character stays in the frame at any width, on
   screen and on paper. */
.fds-code { min-width: 0; }
.fds-code__bar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-3); }
.fds-code__lang { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-tight); color: var(--mut); }
.fds-code__copy {
  appearance: none; -webkit-appearance: none; font: inherit; font-size: var(--text-2xs); font-weight: var(--weight-strong);
  display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer;
  color: var(--ink-2); border: var(--hair) solid var(--line-2); border-radius: var(--radius-pill);
  padding: var(--space-2) var(--space-3);
  transition: color var(--dur-snap) var(--ease-out), background var(--dur-snap) var(--ease-out);
}
.fds-code__copy::before { content: ""; width: var(--space-3); height: var(--space-3); border: var(--hair) solid currentColor; border-radius: var(--radius-mark); box-shadow: var(--space-1) var(--space-1) 0 calc(var(--hair) * -1) var(--panel), var(--space-1) var(--space-1) 0 calc(var(--hair) * -1) currentColor; }
.fds-code__copy:hover { color: var(--ink); background: var(--line-fine); }
.fds-code__copy:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }
.fds-code__pre {
  /* This viewer WRAPS a long line onto the next line rather than opening a
     horizontal scroll, so every character stays inside the frame at any width
     and nothing is ever clipped at the right edge (on screen or on paper). It
     declares its line-breaking explicitly rather than leaning on the bare <pre>
     default: pre-wrap keeps the author's own newlines and indentation while
     letting an over-long line fold, and overflow-wrap: anywhere breaks a single
     unbreakable token (a long path or URL) so it too stays in the frame. This
     also means placing the component inside .fds-prose changes nothing: both
     surfaces now wrap, and .fds-code__pre owns its own breaking.
     Where the engine understands each-line indents, a folded continuation
     hangs 2ch under its own line's start (the @supports rule below), so a wrap
     never reads as the author's own next statement; an engine without each-line
     keeps the flush fold, and the honest limit there stays what it was: a
     wrapped line is not visually distinct from the next authored line. It is
     not a scrollable region (there is nothing to scroll), so the <pre> takes no
     tabindex. */
  white-space: pre-wrap; overflow-wrap: anywhere;
  margin: 0; min-width: 0; max-width: 100%;
  border: var(--hair) solid var(--line); border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
  font-family: var(--font-mono);
  font-size: var(--text-xs); line-height: var(--leading-relaxed); color: var(--ink-2);
}
/* The same progressive hanging indent the prose <pre> takes (see above): authored
   line starts stay put, only a folded continuation hangs 2ch in. */
@supports (text-indent: 2ch each-line) {
  .fds-code__pre { padding-left: calc(var(--space-5) + 2ch); text-indent: -2ch each-line; }
}

/* ── figure (47-figure) ──────────────────────────────────────────────────────
   Figure primitive, a captioned media area with a credit line. The image area
   is a placeholder surface (token gradient plus a grid texture and an "Image"
   tag) that any real <img> can replace; aspect-ratio holds the frame and
   max-width keeps it inside the column. Caption uses ink-2 voice, credit uses
   the quiet measure label. Tokens only, light and dark both clean. */
.fds-figure { margin: 0; display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.fds-figure__media { position: relative; width: 100%; max-width: 100%; aspect-ratio: 16 / 9; border-radius: var(--radius-sm); border: var(--hair) solid var(--line); overflow: hidden; background: linear-gradient(135deg, var(--signal-soft) 0%, var(--panel) 55%, var(--paper) 100%); }
.fds-figure__grid { position: absolute; inset: 0; background-image: repeating-linear-gradient(to right, transparent 0, transparent calc(12.5% - var(--hair)), var(--line-fine) calc(12.5% - var(--hair)), var(--line-fine) 12.5%), repeating-linear-gradient(to bottom, transparent 0, transparent calc(25% - var(--hair)), var(--line-fine) calc(25% - var(--hair)), var(--line-fine) 25%); }
.fds-figure__tag { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-radius: var(--radius-pill); border: var(--hair) solid var(--line-2); box-shadow: var(--shadow-flat); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--mut); white-space: nowrap; }
.fds-figure__tag-dot { width: var(--dot); height: var(--dot); border-radius: var(--radius-pill); background: var(--na-dot); flex: none; }
.fds-figure__caption { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.fds-figure__cap-text { color: var(--ink-2); }
.fds-figure__credit { white-space: normal; }

/* ── card-grid (48-card-grid) ────────────────────────────────────────────────
   Card grid: equal cards in a row that reflow to one column on a phone. The
   grid rides the shared .fds-cat columns, so the gallery still reflows correctly.
   The active card carries a dot-plus-word tag for meaning; the border here is a
   quiet reinforcement that degrades cleanly if styles are not present. */
.fds-cardgrid .fds-card { gap: var(--space-2); }
.fds-cardgrid .fds-card.is-active { border-color: var(--accent-line); box-shadow: var(--shadow-card); }

/* ── event log (69-event-log) ────────────────────────────────────────────────
   A vertical, timestamped event log: the spine of an incident report or an audit
   trail — the one thing the milestone timeline (a plan-progress device of
   hand-placed dots) could never say. Each row carries a MACHINE-READABLE <time>
   so a person and a machine read the same instant, an optional duration, a marker
   on a hairline spine, and the event in plain words with a link to the fuller
   account. It works two ways from the SAME markup: BARE in the river (events
   interleaved with the reading, on paper) and BOXED in a card (one panel in a
   grid). Tokens only, no motion. The marker is a dot PLUS the time, the words,
   and — on the live row — the word "Now", so nothing rests on colour. Muted time
   sits on paper/panel (above AA there); the spine and dots are structure. */
.fds-log { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; --log-dot-c: calc(var(--space-1) + var(--dot) / 2); }
.fds-log__row { display: grid; grid-template-columns: max-content var(--space-5) minmax(0, 1fr); column-gap: var(--space-4); }
.fds-log__time { font-size: var(--text-xs); font-weight: var(--weight-strong); line-height: var(--leading-snug); color: var(--mut); font-variant-numeric: tabular-nums; letter-spacing: var(--tracking-tight); white-space: nowrap; }
/* the spine: a single hairline down the middle column, trimmed at the ends so it
   starts and stops at the first and last dot rather than overshooting. */
.fds-log__mark { position: relative; display: flex; justify-content: center; }
.fds-log__mark::before { content: ""; position: absolute; top: 0; bottom: 0; left: calc(50% - var(--hair) / 2); width: var(--hair); background: var(--line-2); }
.fds-log__row:first-child .fds-log__mark::before { top: var(--log-dot-c); }
.fds-log__row:last-child  .fds-log__mark::before { bottom: calc(100% - var(--log-dot-c)); }
.fds-log__dot { position: relative; margin-top: var(--space-1); width: var(--dot); height: var(--dot); border-radius: var(--radius-pill); background: var(--mut); }
.fds-log__row--now .fds-log__dot { background: var(--signal); }
.fds-log__body { min-width: 0; padding-bottom: var(--space-5); }
.fds-log__row:last-child .fds-log__body { padding-bottom: 0; }
.fds-log__what { margin: 0; font-size: var(--text-sm); font-weight: var(--weight-strong); line-height: var(--leading-snug); color: var(--ink-2); text-wrap: pretty; }
.fds-log__now { margin-left: var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--accent-text); }
.fds-log__dur { margin-left: var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); white-space: nowrap; }
.fds-log__note { margin: var(--space-1) 0 0; font-size: var(--text-xs); line-height: var(--leading-snug); color: var(--body); text-wrap: pretty; }
.fds-log__link { color: var(--accent); text-decoration: underline; text-decoration-color: var(--accent-line); text-underline-offset: var(--stroke-2); text-decoration-thickness: var(--hair); border-radius: var(--radius-sm); }
.fds-log__link:where(:hover) { text-decoration-color: var(--accent); }
.fds-log__link:where(:focus-visible) { outline: var(--stroke-2) solid var(--focus); outline-offset: var(--stroke-2); }

/* ── aside (70-aside) ─────────────────────────────────────────────────────────
   Marginalia: a secondary note that runs ALONGSIDE the reading without breaking
   it — "what we got lucky on", a definition at first use, a reviewer's remark.
   Quieter than a callout: it stays on PAPER (not pulled onto a well), set off by
   one faint hairline on its leading edge and a labelled eyebrow, so the reader
   can take it or leave it. The eyebrow WORD names the kind of note; colour never
   carries it. Body sits on paper where --body clears AA. */
.fds-aside { border-left: var(--hair) solid var(--line-2); padding-left: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); }
.fds-aside__label { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--mut); }
.fds-aside__body { margin: 0; font-size: var(--text-sm); line-height: var(--leading-snug); color: var(--body); text-wrap: pretty; }
.fds-aside__body strong { color: var(--ink-2); font-weight: var(--weight-strong); }

/* ── editorial callout (71-callout) ──────────────────────────────────────────
   A point pulled OUT of the reading so it lands: a caveat, a key takeaway, a
   definition worth stopping on. Sits on the WELL (a recessed island in the flow,
   no shadow — a well recedes, a panel lifts), with a labelled eyebrow so the KIND
   of note is a WORD, never a colour. Reader text on a well stays body/ink weight:
   --mut is below AA on a well, so the callout never uses it (Wave 1 SCOPE
   CONTRACT). More present than an aside (it has a surface), less than a panel. */
.fds-callout { background: var(--well); border-radius: var(--radius-md); padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); }
.fds-callout__label { font-size: var(--text-2xs); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--accent-text); }
.fds-callout__body { margin: 0; font-size: var(--text-sm); line-height: var(--leading-snug); color: var(--body); text-wrap: pretty; }
.fds-callout__body strong { color: var(--ink-2); font-weight: var(--weight-strong); }

/* B2 still mode / reduced motion — the accordion chevron's half-turn (transform) is the
   one motion transition in this file; collapse it to instant so open/closed reads the same
   at rest, with identical meaning (aria-expanded + label still carry the state). The colour
   crossfade on the same chevron stays. Held byte-for-byte in lockstep by
   build/lint-still-mode.mjs (positive coverage); the twins may not drift or vanish. */
@media (prefers-reduced-motion: reduce) {
  .fds-accordion__chevron { transition: none; }
}
:root[data-still] .fds-accordion__chevron { transition: none; }

/* ===== parts/print.css ===== */
/* Print layout. Palette ownership stays in tokens/colors.css. */

@media print {
  /* The light print ramp is owned by tokens/colors.css. */
  .fds-scroll-edge::after { display: none; }

  body { background: var(--paper); }

  /* 2. Flatten floating readouts on paper. */
  .fds-readout,
  .fds-tip {
    background: var(--paper) !important;
    box-shadow: none !important;
  }

  /* The dimming scrim has no place on paper; it would print as a grey block over
     the very content the overlay is presenting. */
  .fds-scrim,
  .fds-scrim--end { background: transparent !important; }

  /* 4. PRESERVE LOAD-BEARING FILLS. These colour fills ARE the data and are not
     all accompanied by a printed word, so force the browser to print them.
       - chart series fills/strokes (lines, bars, ring, donut segments, caps),
       - the event-marker drop-line (--chart-mark resolves to the --tick-2 ruler
         strength, which the forced light palette restates to greyscale; without
         forcing it the browser drops the stroke and the marker loses the faint line
         that ties its word to a bar),
       - the sparkline highlight and tooltip swatch,
       - meter fill + track (the bar length plus its colour is the reading).
     The LEAD FLAG and the ACT-BAND CTA carry a filled navy fill with light text
     (.fds-lead / .fds-act__cta): drop the fill and the light word vanishes on
     white. They ARE the "act on this" mark the report requires to survive print,
     so force the fill; the dark band then reads in greyscale too.
     Status dots, chip dots, and the beacon are deliberately NOT forced here:
     each is paired with a WORD per the house rule, so the meaning survives in
     greyscale and the ink is better spent elsewhere. The same rule chooses what
     of the pacing/vintage blocks is forced: the pacing bar fills carry the reading
     (bar length plus the actual/forecast/track luminance ladder, a strong/light/pale
     ink step) so they are forced — and, being .fds-meter__fill / .fds-meter__track
     in the markup, they are covered by the meter selectors below; only the pacing
     legend swatches need naming. The vintage EMPTY cell needs no forcing: its cue
     is now a faint en-dash GLYPH plus an off-screen word, and text prints on its
     own; the vintage actual TINT is likewise NOT forced (its bold weight and legend
     word survive print, so the ink is spared). */
  .fds-lead, .fds-act__cta,
  .fds-chart,
  .fds-chart__line, .fds-chart__line--accent,
  .fds-chart__mark-line,
  .fds-chart__bar, .fds-chart__bar-2, .fds-chart__bar--accent,
  .fds-chart__dot, .fds-chart__cap,
  .fds-chart__seg-1, .fds-chart__seg-2, .fds-chart__seg-3,
  .fds-chart__ring, .fds-chart__ring-val,
  .fds-spark__hl, .fds-spark,
  .fds-readout__sw,
  .fds-pace__sw--actual, .fds-pace__sw--fcst,
  .fds-meter__fill, .fds-meter__track {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* 5. PRINT THE MARKER SUMMARY IN FULL. The event-marker word strip caps each
     label at 15ch with an ellipsis; on screen the full text of a long label is
     reachable through the label's title (hover) and the .fds-sr-only summary
     (assistive tech). Paper has NEITHER channel, so a marker like "Regulatory
     migration" would print as a meaningless truncated strip and lose its meaning.
     Un-clip the bar chart's own sr-only summary for print so the FULL label of
     every marker, with its position, prints as one plain sentence with the chart.
     Scoped to .fds-bars-wrap so no unrelated sr-only text is surfaced. Tokens
     only. The truncated visual strip stays as the at-a-glance index; this sentence
     is the complete, greyscale-safe record the reader keeps on paper. */
  .fds-bars-wrap .fds-sr-only {
    position: static;
    width: auto; height: auto;
    margin: var(--space-1) 0 0;
    padding: 0;
    overflow: visible;
    clip: auto;
    clip-path: none;
    white-space: normal;
    font-size: var(--text-micro);
    line-height: var(--leading-snug);
    color: var(--ink-2);
  }

  /* 6. FLUSH-MOSAIC SEAMS SURVIVE A BACKGROUND-DROPPING ENGINE. On screen a flush
     mosaic (.fds-cat--flush) seams its tiles with the container's own fill showing
     through 1px gutters, and each tile drops its border. A print engine that omits
     background colours (the default) erases that fill and the seams together, while
     the borderless tiles collapse into one unbordered blob. Borders print even when
     backgrounds do not, so give each tile a real hairline back for print and close
     the gutter, so adjacent hairlines meet as one crisp seam and every cell is
     divided on paper. The container keeps its own printed frame (its border prints).
     No forced background: forcing the container fill would flood the whole box grey
     behind tiles whose own fill the engine has dropped, so the border is the safe
     mechanism. */
  .fds-cat--flush { gap: 0; }
  .fds-cat--flush > .fds-card { border: var(--hair) solid var(--line); }

  /* 7. EVENT-LOG SPINE SURVIVES A BACKGROUND-DROPPING ENGINE. The time spine
     (.fds-log__mark::before) and its node dots (.fds-log__dot) are token-driven
     colour fills on positioned elements — the SAME connective-line construction as
     the chart event-marker line forced in section 4: the spine ties each dot to the
     next and the dots sit each row on it, so the log reads as a timeline rather than
     a loose list. A print engine that omits background colours (the default) erases
     both and the spine collapses. Borders would distort the hairline spine and the
     round dots, so force these fills instead. They are greyscale-safe (--line-2 and
     --mut restate to greys; the --now dot to navy) and every row still carries its
     own machine-readable time and words, so the forced ink only restores the
     structure and never becomes the sole carrier of meaning. */
  .fds-log__mark::before,
  .fds-log__dot {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  /* 8. WIDE LEDGER. On screen the financial statement scrolls sideways with a
     pinned line-item column; paper has no scroll, so a clipped overflow box would
     drop every period past the fold. Un-pin the sticky cells and open the overflow
     so the whole statement flows and paginates. Tighten cell padding and step the
     figures down one size so more columns fit the sheet; the indent, weight, and
     rule hierarchy (which is what carries the statement, not the dropped tints)
     stays intact. A wide statement prints best in landscape. */
  .fds-ledger__scroll { overflow: visible; }
  .fds-ledger th[scope="row"],
  .fds-ledger thead th:first-child,
  .fds-ledger__band-label { position: static; }
  /* white-space:normal: on screen the cells are nowrap so the columns
     line up under a sideways scroll. Paper has no scroll and a fixed sheet width, so
     15 nowrap columns overflow and CLIP the last periods off a portrait A4. Allow
     the cells to wrap on paper so every period survives the sheet, in portrait or
     landscape; the rule/weight hierarchy still carries the statement. */
  .fds-ledger th, .fds-ledger td { padding: var(--space-1) var(--space-2); font-size: var(--text-2xs); white-space: normal; }
  /* Reset the on-screen tints explicitly: the current-period wash and
     the variance green/red washes are reinforcement only. The current column keeps
     its 2px accent top rule (a border, not a background, so it survives) plus the
     caption word; the variance sign and word, and the rule/weight hierarchy, carry
     every other meaning without the tints. Reset here rather than trust the browser's
     default background suppression, which print-color-adjust:exact elsewhere could
     otherwise override, so a background-free statement is enforced, not accidental
     (D-FS2-7). */
  .fds-ledger__cell-current,
  .fds-ledger__colhead--current,
  .fds-ledger__var--ahead,
  .fds-ledger__var--behind { background: transparent; }
}
