/* ============================================
   DDD Design Tokens & Base Styles
   Single source of truth for the design system
   ============================================ */

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

/* ================================================================================================
   THE COLOUR SYSTEM HAS THREE LAYERS. Read them in order.

     LAYER 1  --palette-*   Primitives. Deliberate source colours for each theme. Named by colour
                            family and intensity. NEVER consumed by a component or a page.
     LAYER 2  --theme-*     Semantic roles. Named by job, not by colour or theme. Every role is
                            defined in all three mappings below. THIS is what components migrate to.
     LAYER 3  --st-* and
              unprefixed    Legacy compatibility aliases. Existing public names, now routed into
                            the active semantic mapping. Consumed today by page CSS and by
                            --dt-*, --tape-* and --momentum-*.

   Phase 1.1 introduced layers 1 and 2 without changing production rendering. Phase 1.3 makes the
   approved light mapping the default and routes layer 3 into it. The intended dark mapping remains
   available through data-theme="dark"; system-preference resolution and the visible control are
   later Phase 1 batches. See docs/design-implementation-roadmap.md.
   ================================================================================================ */

/* ================================================================================================
   LAYER 1 — PALETTE PRIMITIVES
   Steps are perceptual, not arithmetic: a higher number is further from that family's base surface.
   ================================================================================================ */
:root {
  /* -- Light family: warm cream paper -------------------------------------------------------- */
  /* Paper surfaces. The approved page colour is --palette-paper-100; raised sits nearer white and
     inset sits slightly deeper, so elevation reads as paper stock rather than as a drop shadow. */
  --palette-paper-000: #FDFCFA;  /* overlay: menus, tooltips, dialogs */
  --palette-paper-050: #FAF8F3;  /* raised: cards, panels */
  --palette-paper-100: #F3F0E9;  /* page: the approved cream anchor */
  --palette-paper-150: #EBE7DE;  /* interactive hover */
  --palette-paper-200: #E8E4DA;  /* inset / recessed */
  --palette-paper-250: #E1DCD1;  /* interactive active */
  --palette-sand-100: #ECE8DF;   /* mono / code surface */
  --palette-sand-200: #E9E5DC;   /* neutral status surface */

  /* Ink ramp. Cool near-black through to a disabled grey. */
  --palette-ink-900: #080A0F;    /* primary ink: the approved anchor */
  --palette-ink-800: #23282F;    /* mono / code text */
  --palette-ink-700: #3B424C;    /* secondary ink */
  --palette-ink-600: #4C535C;    /* neutral status ink */
  --palette-ink-550: #535B65;    /* metadata ink */
  --palette-ink-500: #5A626D;    /* muted ink, provenance ink */
  --palette-ink-300: #8C939C;    /* disabled ink */
  --palette-ink-950: #12141A;    /* inverse surface, chart tooltip surface */
  --palette-ink-on: #F7F5F0;     /* ink placed on an inverse surface */

  /* Rules. Derived from the paper, not from the ink ramp, so hairlines stay warm and restrained. */
  --palette-rule-100: #DFDACE;   /* subtle hairline, chart grid */
  --palette-rule-200: #CAC4B5;   /* standard rule, provenance rule */
  --palette-rule-400: #847C6A;   /* interactive border, chart axis */
  --palette-rule-500: #6F6759;   /* strong border */

  /* Mint. --palette-mint-500 is the approved brand anchor. It is a fill and a mark colour, not a
     text colour on paper: the readable forms are the deepened -700 and -800 steps. */
  --palette-mint-200: #CFEFE0;   /* selection surface */
  --palette-mint-300: #DCF5E9;   /* accent surface */
  --palette-mint-350: #DDF3E7;   /* positive status surface */
  --palette-mint-500: #53E7AC;   /* brand anchor */
  --palette-mint-700: #17714E;   /* expansion ink */
  --palette-mint-800: #0F6B47;   /* link, focus ring, primary chart series */
  --palette-mint-900: #0A5537;   /* link hover */
  --palette-mint-950: #062A1C;   /* ink placed on mint */

  /* Clay: contraction and negative status. Calmer than a pure error red on purpose, because
     contraction is a normal market state and not a failure. */
  --palette-clay-100: #FBE6E3;
  --palette-clay-700: #B42318;

  /* Ochre: caution, research beta and source-coverage notes only. Never a live canonical metric. */
  --palette-ochre-100: #F7EBD2;
  --palette-ochre-600: #8E6B2F;  /* secondary chart series */
  --palette-ochre-700: #7A5200;

  /* -- Dark family: the intended translation ------------------------------------------------- */
  /* Not the current production dark. Warmer and less deep, so the same hierarchy reads without the
     terminal character the constitution's anti-patterns rule out. */
  --palette-night-900: #0F1115;  /* inset / recessed */
  --palette-night-850: #0C0E12;  /* focus outer ring */
  --palette-night-800: #14161A;  /* page */
  --palette-night-700: #1A1D22;  /* mono / code surface */
  --palette-night-600: #1C1F25;  /* raised */
  --palette-night-500: #22262D;  /* interactive hover */
  --palette-night-450: #242830;  /* overlay, subtle hairline */
  --palette-night-400: #2A2F37;  /* interactive active */
  --palette-night-350: #262A31;  /* chart grid */
  --palette-night-300: #23272E;  /* neutral status surface */

  /* Bone: the dark theme's ink. Warm off-white rather than clinical white, so both themes share a
     paper character. */
  --palette-bone-100: #ECEAE4;   /* primary ink */
  --palette-bone-200: #DCD9D2;   /* mono / code text */
  --palette-bone-300: #B6B3AB;   /* secondary ink */
  --palette-bone-400: #9A988F;   /* metadata ink */
  --palette-bone-450: #A0A49C;   /* neutral status ink */
  --palette-bone-500: #8F8D86;   /* muted ink, provenance ink */
  --palette-bone-600: #6A6862;   /* disabled ink */

  /* Steel: dark-theme rules. Visible without boxing every element. */
  --palette-steel-200: #31363F;  /* standard rule, provenance rule */
  --palette-steel-400: #626A76;  /* interactive border */
  --palette-steel-500: #6E7683;  /* strong border */
  --palette-steel-600: #7E8189;  /* chart axis */

  /* Dark-side accent and status. Mint keeps the same brand role in both themes. */
  --palette-mint-400: #7FEFC2;   /* link hover on dark */
  --palette-mint-450: #5FDCA6;   /* expansion ink on dark */
  --palette-mint-surface-dark: #133025;
  --palette-mint-status-dark: #122E24;
  --palette-mint-selection-dark: #1E4638;
  --palette-clay-400: #F0897C;
  --palette-clay-surface-dark: #331D1B;
  --palette-ochre-300: #D9B27A;  /* secondary chart series on dark */
  --palette-ochre-400: #E8B662;
  --palette-ochre-surface-dark: #2F2617;
}

/* ================================================================================================
   LAYER 2 — SEMANTIC THEME ROLES

   Three mappings, all defining the same role set:

     :root                    The approved cream-paper light theme. Active by default.
     :root[data-theme=light]  The same approved mapping, retained for explicit selection.
     :root[data-theme=dark]   The intended dark theme. Defined but not selected automatically yet.

   The attribute name matches the one widget.html already uses on its root element for the same
   light/dark meaning, so the site keeps one theme vocabulary. widget.html does not load this file,
   so the selectors below cannot affect it today.
   ================================================================================================ */

/* -- Approved cream-paper light theme. ACTIVE DEFAULT. ------------------------------------------ */
:root {
  color-scheme: light;

  /* Surfaces */
  --theme-surface-page: var(--palette-paper-100);
  --theme-surface-raised: var(--palette-paper-050);
  --theme-surface-inset: var(--palette-paper-200);
  --theme-surface-overlay: var(--palette-paper-000);
  --theme-surface-inverse: var(--palette-ink-950);
  --theme-surface-hover: var(--palette-paper-150);
  --theme-surface-active: var(--palette-paper-250);

  /* Text */
  --theme-ink-primary: var(--palette-ink-900);
  --theme-ink-secondary: var(--palette-ink-700);
  --theme-ink-muted: var(--palette-ink-500);
  --theme-ink-inverse: var(--palette-ink-on);
  --theme-ink-link: var(--palette-mint-800);
  --theme-ink-link-hover: var(--palette-mint-900);
  --theme-ink-disabled: var(--palette-ink-300);

  /* Rules and borders */
  --theme-rule-subtle: var(--palette-rule-100);
  --theme-rule-standard: var(--palette-rule-200);
  --theme-rule-strong: var(--palette-rule-500);
  --theme-rule-interactive: var(--palette-rule-400);
  --theme-rule-focus: var(--palette-mint-800);

  /* Brand and emphasis */
  --theme-accent: var(--palette-mint-500);
  --theme-accent-hover: var(--palette-mint-700);
  --theme-accent-surface: var(--palette-mint-300);
  --theme-accent-ink: var(--palette-mint-950);

  /* Status */
  --theme-status-positive-ink: var(--palette-mint-700);
  --theme-status-positive-surface: var(--palette-mint-350);
  --theme-status-warning-ink: var(--palette-ochre-700);
  --theme-status-warning-surface: var(--palette-ochre-100);
  --theme-status-negative-ink: var(--palette-clay-700);
  --theme-status-negative-surface: var(--palette-clay-100);
  --theme-status-neutral-ink: var(--palette-ink-600);
  --theme-status-neutral-surface: var(--palette-sand-200);

  /* Charts */
  --theme-chart-surface: var(--palette-paper-100);
  --theme-chart-grid: var(--palette-rule-100);
  --theme-chart-axis: var(--palette-rule-400);
  --theme-chart-series-primary: var(--palette-mint-800);
  --theme-chart-series-secondary: var(--palette-ochre-600);
  --theme-chart-series-positive: var(--palette-mint-700);
  --theme-chart-series-negative: var(--palette-clay-700);
  --theme-chart-annotation: var(--palette-ochre-700);
  --theme-chart-tooltip-surface: var(--palette-ink-950);
  --theme-chart-tooltip-ink: var(--palette-ink-on);

  /* Interaction and accessibility */
  --theme-focus-ring: var(--palette-mint-800);
  --theme-focus-ring-outer: var(--palette-paper-000);
  --theme-selection-surface: var(--palette-mint-200);
  --theme-selection-ink: var(--palette-mint-950);
  --theme-disabled-opacity: 0.45;

  /* Provenance and metadata */
  --theme-provenance-ink: var(--palette-ink-500);
  --theme-provenance-rule: var(--palette-rule-200);
  --theme-metadata-ink: var(--palette-ink-550);
  --theme-mono-surface: var(--palette-sand-100);
  --theme-mono-ink: var(--palette-ink-800);

  /* Transitional compatibility for the frozen route-study footer's inline separators. */
  --theme-legacy-footer-separator: var(--theme-rule-standard);
}

/* -- Approved cream-paper light theme. Explicit selection; identical to the default. ------------ */
:root[data-theme="light"] {
  color-scheme: light;

  /* Surfaces */
  --theme-surface-page: var(--palette-paper-100);
  --theme-surface-raised: var(--palette-paper-050);
  --theme-surface-inset: var(--palette-paper-200);
  --theme-surface-overlay: var(--palette-paper-000);
  --theme-surface-inverse: var(--palette-ink-950);
  --theme-surface-hover: var(--palette-paper-150);
  --theme-surface-active: var(--palette-paper-250);

  /* Text */
  --theme-ink-primary: var(--palette-ink-900);
  --theme-ink-secondary: var(--palette-ink-700);
  --theme-ink-muted: var(--palette-ink-500);
  --theme-ink-inverse: var(--palette-ink-on);
  --theme-ink-link: var(--palette-mint-800);
  --theme-ink-link-hover: var(--palette-mint-900);
  --theme-ink-disabled: var(--palette-ink-300);

  /* Rules and borders */
  --theme-rule-subtle: var(--palette-rule-100);
  --theme-rule-standard: var(--palette-rule-200);
  --theme-rule-strong: var(--palette-rule-500);
  --theme-rule-interactive: var(--palette-rule-400);
  --theme-rule-focus: var(--palette-mint-800);

  /* Brand and emphasis */
  --theme-accent: var(--palette-mint-500);
  --theme-accent-hover: var(--palette-mint-700);
  --theme-accent-surface: var(--palette-mint-300);
  --theme-accent-ink: var(--palette-mint-950);

  /* Status */
  --theme-status-positive-ink: var(--palette-mint-700);
  --theme-status-positive-surface: var(--palette-mint-350);
  --theme-status-warning-ink: var(--palette-ochre-700);
  --theme-status-warning-surface: var(--palette-ochre-100);
  --theme-status-negative-ink: var(--palette-clay-700);
  --theme-status-negative-surface: var(--palette-clay-100);
  --theme-status-neutral-ink: var(--palette-ink-600);
  --theme-status-neutral-surface: var(--palette-sand-200);

  /* Charts */
  --theme-chart-surface: var(--palette-paper-100);
  --theme-chart-grid: var(--palette-rule-100);
  --theme-chart-axis: var(--palette-rule-400);
  --theme-chart-series-primary: var(--palette-mint-800);
  --theme-chart-series-secondary: var(--palette-ochre-600);
  --theme-chart-series-positive: var(--palette-mint-700);
  --theme-chart-series-negative: var(--palette-clay-700);
  --theme-chart-annotation: var(--palette-ochre-700);
  --theme-chart-tooltip-surface: var(--palette-ink-950);
  --theme-chart-tooltip-ink: var(--palette-ink-on);

  /* Interaction and accessibility */
  --theme-focus-ring: var(--palette-mint-800);
  --theme-focus-ring-outer: var(--palette-paper-000);
  --theme-selection-surface: var(--palette-mint-200);
  --theme-selection-ink: var(--palette-mint-950);
  --theme-disabled-opacity: 0.45;

  /* Provenance and metadata */
  --theme-provenance-ink: var(--palette-ink-500);
  --theme-provenance-rule: var(--palette-rule-200);
  --theme-metadata-ink: var(--palette-ink-550);
  --theme-mono-surface: var(--palette-sand-100);
  --theme-mono-ink: var(--palette-ink-800);
  --theme-legacy-footer-separator: var(--theme-rule-standard);
}

/* -- Intended dark theme. INACTIVE. Not the same as the compatibility mapping above. ------------ */
:root[data-theme="dark"] {
  color-scheme: dark;

  /* Surfaces */
  --theme-surface-page: var(--palette-night-800);
  --theme-surface-raised: var(--palette-night-600);
  --theme-surface-inset: var(--palette-night-900);
  --theme-surface-overlay: var(--palette-night-450);
  --theme-surface-inverse: var(--palette-bone-100);
  --theme-surface-hover: var(--palette-night-500);
  --theme-surface-active: var(--palette-night-400);

  /* Text */
  --theme-ink-primary: var(--palette-bone-100);
  --theme-ink-secondary: var(--palette-bone-300);
  --theme-ink-muted: var(--palette-bone-500);
  --theme-ink-inverse: var(--palette-night-800);
  --theme-ink-link: var(--palette-mint-500);
  --theme-ink-link-hover: var(--palette-mint-400);
  --theme-ink-disabled: var(--palette-bone-600);

  /* Rules and borders */
  --theme-rule-subtle: var(--palette-night-450);
  --theme-rule-standard: var(--palette-steel-200);
  --theme-rule-strong: var(--palette-steel-500);
  --theme-rule-interactive: var(--palette-steel-400);
  --theme-rule-focus: var(--palette-mint-500);

  /* Brand and emphasis */
  --theme-accent: var(--palette-mint-500);
  --theme-accent-hover: var(--palette-mint-400);
  --theme-accent-surface: var(--palette-mint-surface-dark);
  --theme-accent-ink: var(--palette-mint-950);

  /* Status */
  --theme-status-positive-ink: var(--palette-mint-450);
  --theme-status-positive-surface: var(--palette-mint-status-dark);
  --theme-status-warning-ink: var(--palette-ochre-400);
  --theme-status-warning-surface: var(--palette-ochre-surface-dark);
  --theme-status-negative-ink: var(--palette-clay-400);
  --theme-status-negative-surface: var(--palette-clay-surface-dark);
  --theme-status-neutral-ink: var(--palette-bone-450);
  --theme-status-neutral-surface: var(--palette-night-300);

  /* Charts */
  --theme-chart-surface: var(--palette-night-800);
  --theme-chart-grid: var(--palette-night-350);
  --theme-chart-axis: var(--palette-steel-600);
  --theme-chart-series-primary: var(--palette-mint-500);
  --theme-chart-series-secondary: var(--palette-ochre-300);
  --theme-chart-series-positive: var(--palette-mint-450);
  --theme-chart-series-negative: var(--palette-clay-400);
  --theme-chart-annotation: var(--palette-ochre-400);
  --theme-chart-tooltip-surface: var(--palette-night-450);
  --theme-chart-tooltip-ink: var(--palette-bone-100);

  /* Interaction and accessibility */
  --theme-focus-ring: var(--palette-mint-500);
  --theme-focus-ring-outer: var(--palette-night-850);
  --theme-selection-surface: var(--palette-mint-selection-dark);
  --theme-selection-ink: var(--palette-mint-300);
  --theme-disabled-opacity: 0.45;

  /* Provenance and metadata */
  --theme-provenance-ink: var(--palette-bone-500);
  --theme-provenance-rule: var(--palette-steel-200);
  --theme-metadata-ink: var(--palette-bone-400);
  --theme-mono-surface: var(--palette-night-700);
  --theme-mono-ink: var(--palette-bone-200);
  --theme-legacy-footer-separator: var(--theme-rule-standard);
}

/* ================================================================================================
   TEMPORARY INTENTIONAL-DARK ISLANDS

   These legacy surfaces already own an explicit dark page treatment and are replaced in
   later page-family phases. Keeping their former semantic values at the root prevents cream from
   showing around a dark body and, critically, preserves the frozen in-practice route study without
   touching its HTML or weakening its preservation tests.

   - [data-theme-lock=dark]: the early, explicit route lock used by protected dark responses
   - html.in-practice-page: the frozen route study (its source cannot receive the early script)
   - .current-read-shell: the archived, explicitly dark Current Read surface
   - body > .issuers-container: the archived issuer handoff (the live issuer page nests this inside
     main#main-content and therefore does not match)
   - nav .nav-back: the edge-rendered, explicitly dark dated Daily Tape record
   - body > .thanks-kicker: the noindex dark signup-confirmation helper

   The values are the previous production mapping. They remain literals only inside this temporary
   isolation boundary and are removed with those page families. Text contrast remains: primary
   17.91:1, secondary 8.93:1, muted 5.37:1 and link/focus 6.75:1 on #0A0C10.
   ================================================================================================ */
:root[data-theme-lock="dark"],
html.in-practice-page,
:root:has(body > .current-read-shell),
:root:has(body > .issuers-container),
:root:has(body > nav .nav-back),
:root:has(body > .thanks-kicker) {
  color-scheme: dark;

  --theme-surface-page: #0A0C10;
  --theme-surface-raised: #0F1319;
  --theme-surface-inset: #0A0C10;
  --theme-surface-overlay: #1B232C;
  --theme-surface-inverse: #F3F5F7;
  --theme-surface-hover: #141A21;
  --theme-surface-active: #1B232C;

  --theme-ink-primary: #F3F5F7;
  --theme-ink-secondary: #A8B0BA;
  --theme-ink-muted: #7D8794;
  --theme-ink-inverse: #0A0C10;
  --theme-ink-link: #5A96FF;
  --theme-ink-link-hover: #86C0FF;
  --theme-ink-disabled: #4B5563;

  --theme-rule-subtle: #1F242D;
  --theme-rule-standard: #1F242D;
  --theme-rule-strong: #27303B;
  --theme-rule-interactive: #27303B;
  --theme-rule-focus: #5A96FF;

  --theme-accent: #5A96FF;
  --theme-accent-hover: #86C0FF;
  --theme-accent-surface: rgba(90, 150, 255, 0.16);
  --theme-accent-ink: #0A0C10;

  --theme-status-positive-ink: #6FE3B5;
  --theme-status-positive-surface: rgba(111, 227, 181, 0.07);
  --theme-status-warning-ink: #FFC869;
  --theme-status-warning-surface: rgba(255, 200, 105, 0.06);
  --theme-status-negative-ink: #F07B69;
  --theme-status-negative-surface: #3B1F1F;
  --theme-status-neutral-ink: #6C7480;
  --theme-status-neutral-surface: #27303B;

  --theme-chart-surface: #0A0C10;
  --theme-chart-grid: #27303B;
  --theme-chart-axis: #7D8794;
  --theme-chart-series-primary: #6FE3B5;
  --theme-chart-series-secondary: #86C0FF;
  --theme-chart-series-positive: #6FE3B5;
  --theme-chart-series-negative: #F07B69;
  --theme-chart-annotation: #FFC869;
  --theme-chart-tooltip-surface: #1B232C;
  --theme-chart-tooltip-ink: #F3F5F7;

  --theme-focus-ring: #5A96FF;
  --theme-focus-ring-outer: #0A0C10;
  --theme-selection-surface: rgba(90, 150, 255, 0.16);
  --theme-selection-ink: #5A96FF;

  --theme-provenance-ink: #7D8794;
  --theme-provenance-rule: #1F242D;
  --theme-metadata-ink: #7D8794;
  --theme-mono-surface: #141A21;
  --theme-mono-ink: #A8B0BA;
  --theme-legacy-footer-separator: rgba(255, 255, 255, 0.1);
}

/* ================================================================================================
   LAYER 3 — LEGACY COMPATIBILITY

   Existing public token names. Phase 1.3 routes their colour values into the active semantic roles
   so direct --st-* consumers switch with the unprefixed aliases and with explicit dark selection.
   Components that cannot yet move safely receive a scoped compatibility treatment below.
   ================================================================================================ */
:root {
  /* ============================================
     Stable Tape color system — single source of truth for every semantic
     color on the site. Mint = live/positive/expansion/primary CTA. Coral
     red = contraction/negative — calmer than a pure error red on purpose,
     since contraction is a normal market state, not a failure. Amber =
     research-beta/warning/source-coverage notes only, never used for a
     live canonical metric. Neutral gray = flat/balanced/unavailable.
     Everything below this block is aliased onto these tokens so existing
     component CSS (--accent, --tape-pos, etc.) picks the new palette up
     automatically without a rename pass.

     They are consumed directly by css/hero-terminal.css (--dt-*), css/tape.css (--tape-*) and
     css/momentum.css (--momentum-*). The status families intentionally resolve to readable ink
     roles: the old "*-soft" names are also used as text, so a pale surface role would fail on
     paper. ================================================================================ */
  --st-bg: var(--theme-surface-page);
  --st-surface-1: var(--theme-surface-raised);
  --st-surface-2: var(--theme-surface-inset);
  --st-surface-3: var(--theme-surface-overlay);
  --st-border: var(--theme-rule-standard);
  --st-grid: var(--theme-chart-grid);

  --st-text: var(--theme-ink-primary);
  --st-text-secondary: var(--theme-ink-secondary);
  --st-text-muted: var(--theme-ink-muted);

  --st-blue: var(--theme-ink-link-hover);
  --st-blue-strong: var(--theme-ink-link);
  --st-blue-mid: var(--theme-ink-link);
  --st-blue-soft: var(--theme-ink-link);
  --st-blue-surface: var(--theme-accent-surface);

  --st-mint: var(--theme-status-positive-ink);
  --st-mint-strong: var(--theme-status-positive-ink);
  --st-mint-mid: var(--theme-status-positive-ink);
  --st-mint-soft: var(--theme-status-positive-ink);

  --st-red: var(--theme-status-negative-ink);
  --st-red-strong: var(--theme-status-negative-ink);
  --st-red-mid: var(--theme-status-negative-ink);
  --st-red-soft: var(--theme-status-negative-ink);
  --st-red-surface: var(--theme-status-negative-surface);

  --st-amber: var(--theme-status-warning-ink);
  --st-neutral: var(--theme-status-neutral-ink);
  --st-neutral-surface: var(--theme-status-neutral-surface);

  /* Colors — unified with the terminal-style home hero. These now resolve through the layer 2
     semantic roles rather than pointing straight at --st-*. Because the compatibility mapping
     resolves back into --st-*, every computed value below is byte-identical to what it was before
     the semantic layer existed; the indirection is what lets a later batch retheme them. The hex
     values are kept as comments only to document how close the old and new palettes are. */
  --bg: var(--theme-surface-page);        /* was #080A0F */
  --bg-deep: var(--theme-surface-page);
  --bg-card: var(--theme-surface-raised); /* was #11151C */
  --bg-ui: var(--theme-surface-raised);
  --border: var(--theme-rule-standard);   /* was #1E2630 */
  --border-hairline: var(--theme-rule-subtle);
  /* Opaque panel edges — avoids moiré / double-line from border + shadow rings.
     DEFERRED: these are component-specific opacities chosen for a stacking artefact, not a global
     rule role. Promoting them to --theme-rule-* would misrepresent them, so they stay literal until
     .ddd-card is rebuilt. */
  --border-card: #2a3342;
  --border-card-hover: #3d4d62;
  --border-card-nested: #242c38;
  --text: var(--theme-ink-primary);            /* was #F3F0E9 */
  --text-secondary: var(--theme-ink-secondary); /* was #A8ABAE */
  /* NOT A TYPO. --text-muted has always resolved to the SECONDARY ink, not the muted ink, and many
     pages depend on that value. It is routed to the secondary role to preserve its exact computed
     value. Correcting the name/role mismatch is a deliberate later change with a visual diff. */
  --text-muted: var(--theme-ink-secondary);
  --text-faint: var(--theme-ink-disabled); /* legacy: retained for decorative/low-priority/unavailable non-label uses only */
  /* Canonical accessible token for genuine labels, eyebrows, metadata and table
     headings. WCAG AA on the site's dark backgrounds (~4.8-5.4:1) vs --text-faint's
     ~2.3-2.6:1. Momentum's --momentum-label resolves through this. */
  --label-muted: var(--theme-ink-muted);
  /* Legacy --accent is widely consumed as text. Use the readable brand-toned link form; components
     needing the #53E7AC brand fill consume --theme-accent directly. */
  --accent: var(--theme-ink-link);
  --accent-light: var(--theme-ink-link-hover);
  --accent-dim: var(--theme-accent-surface);
  /* DEFERRED: a glow wash. Constitution section N rules out glow, so this gets no semantic role and
     is removed with its consumers rather than retheme. */
  --accent-glow: rgba(90, 150, 255, 0.09);

    /* Typography — sitewide system limited to Fraunces, IBM Plex Sans, and IBM Plex Mono. */
    --sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --serif: 'Fraunces', Georgia, 'Times New Roman', serif;
    --serif-display: 'Fraunces', Georgia, 'Times New Roman', serif;
    --mono: 'IBM Plex Mono', 'SF Mono', 'Fira Code', 'Courier New', monospace;

  /* Layout — legacy names, now routed into the LAYER 5 layout roles at the end of this file.
     --max-w and --max-w-wide have always been consumed as OUTER boxes (each consumer adds its own
     side padding), so they alias the box forms rather than the measures. --gap is consumed as a
     one-sided `section { padding: var(--gap) 0 }`, so it is half a section separation: two adjacent
     sections then sit exactly --rhythm-section apart. */
  --max-w: var(--layout-box-reading);   /* narrative / reading column (index, faq, learn, methodology) */
  --max-w-wide: var(--layout-box-page); /* data-heavy pages (issuers, chains, history) */
  --gap: calc(var(--rhythm-section) / 2);
  --gap-sm: calc(var(--rhythm-section-compact) / 2);
  --gap-lg: var(--rhythm-section);
}

/* Deferred components with deliberately opaque dark surfaces. Their layouts and surface literals
   remain untouched; only their inherited colour aliases are held to the former dark mapping so
   paper ink never lands on a dark panel. This is temporary legibility treatment, not a redesign.
   The pairs below retain at least 5.37:1 for muted ink and 6.75:1 for links/focus on #0A0C10. */
:is(
  .ddd-card,
  .mx-card,
  .alerts-panel,
  .alerts-legend,
  .filters-shell,
  .history-event-card,
  .issuer-structure-summary,
  .share-panel,
  .term-live,
  .code-block,
  .ew-code-block,
  .report-card,
  .report-figure,
  .report-pill,
  .partners-founding-block,
  .partners-contact
) {
  --theme-ink-primary: #F3F5F7;
  --theme-ink-secondary: #A8B0BA;
  --theme-ink-muted: #7D8794;
  --theme-ink-link: #5A96FF;
  --theme-ink-link-hover: #86C0FF;
  --theme-rule-subtle: #1F242D;
  --theme-rule-standard: #1F242D;
  --theme-rule-focus: #5A96FF;
  --theme-focus-ring: #5A96FF;

  --st-bg: #0A0C10;
  --st-surface-1: #0F1319;
  --st-surface-2: #141A21;
  --st-surface-3: #1B232C;
  --st-border: #1F242D;
  --st-grid: #27303B;
  --st-text: #F3F5F7;
  --st-text-secondary: #A8B0BA;
  --st-text-muted: #7D8794;
  --st-blue: #86C0FF;
  --st-blue-strong: #5A96FF;
  --st-blue-mid: #2F70FF;
  --st-blue-soft: #D8E9FF;
  --st-blue-surface: #10203A;
  --st-mint: #A8F2D2;
  --st-mint-strong: #6FE3B5;
  --st-mint-mid: #35C79A;
  --st-mint-soft: #CFF8EA;
  --st-red: #E56A59;
  --st-red-strong: #F07B69;
  --st-red-mid: #D4574A;
  --st-red-soft: #F3B3AD;
  --st-red-surface: #3B1F1F;
  --st-amber: #FFC869;
  --st-neutral: #6C7480;
  --st-neutral-surface: #27303B;

  --bg: #0A0C10;
  --bg-deep: #0A0C10;
  --bg-card: #0F1319;
  --bg-ui: #0F1319;
  --border: #1F242D;
  --border-hairline: #1F242D;
  --text: #F3F5F7;
  --text-secondary: #A8B0BA;
  --text-muted: #A8B0BA;
  --text-faint: #7D8794;
  --label-muted: #7D8794;
  --accent: #5A96FF;
  --accent-light: #86C0FF;
  --accent-dim: rgba(90, 150, 255, 0.16);
}

/* These retained panels use translucent dark gradients that previously composited over the page
   background. The extra element in each selector gives the base precedence over those later
   one-class background shorthands without changing their gradients, borders, or layout. */
body .issuer-structure-summary,
body .share-panel,
body .history-event-card,
body .partners-founding-block {
  background-color: #0A0C10;
}

/* Light-page compatibility repairs for retained selectors that encoded white-alpha text and rules
   directly. Each rule changes colour only; the owning page retains its component structure. */
body .chain-jump-chip {
  color: var(--theme-ink-link);
  border-color: var(--theme-rule-standard);
  background: var(--theme-surface-raised);
}
body .chain-jump-chip:hover {
  color: var(--theme-ink-link-hover);
  border-color: var(--theme-rule-focus);
  background: var(--theme-accent-surface);
}
body :is(.tm-window, .tm-empty, .gw-live-badge) {
  color: var(--theme-ink-muted);
}
body .gw-live-badge {
  border-color: var(--theme-rule-standard);
  background: var(--theme-surface-raised);
}
body .filters-shell {
  color: #F3F5F7;
}
body .partners-hero .partners-action--primary {
  color: var(--theme-ink-link);
}
body .partners-hero .partners-action--primary:hover {
  color: var(--theme-ink-link-hover);
}
body .partners-hero .partners-action--secondary {
  color: var(--theme-ink-secondary);
  border-color: var(--theme-rule-standard);
  background: var(--theme-surface-raised);
}
body .partners-hero .partners-action--secondary:hover {
  color: var(--theme-ink-link-hover);
  border-color: var(--theme-rule-focus);
}
body :is(.mon-state--error, .mon-status-badge--error) {
  color: var(--theme-status-negative-ink);
}
body :is(.api-badge--stable) {
  color: var(--theme-status-positive-ink);
}
body :is(.api-badge--daily) {
  color: var(--theme-ink-link);
}
body :is(.api-badge--research, .field-type) {
  color: var(--theme-status-warning-ink);
}
body :is(.mx-layer-table, .mx-lens) .mx-badge--live,
body :is(.mx-layer-table, .mx-lens) .mx-badge--bootstrap {
  color: var(--theme-status-positive-ink);
}
body :is(.mx-layer-table, .mx-lens) .mx-badge--beta {
  color: var(--theme-ink-link);
}
body :is(.mx-layer-table, .mx-lens) .mx-badge--research {
  color: var(--theme-status-warning-ink);
}
body :is(.mx-layer-table, .mx-lens) .mx-badge--planned {
  color: var(--theme-status-neutral-ink);
}
body :is(.mx-layer-table, .mx-lens) .mx-badge--context {
  color: var(--theme-ink-muted);
}

/* Phase 1.6 light-theme legibility containment. The homepage terminal and its top bar retain
   white-alpha type that was authored for an atmospheric dark canvas, so the default/no-attribute
   state and explicit light mode keep only that bounded hero surface dark. The frozen
   .in-practice-page and every explicit/locked dark route remain outside this boundary. The lower
   transparent sections use the active paper-theme roles. Metrics and Partners each retain direct
   white-alpha body text on paper; the semantic repairs below apply in every active theme. */
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body :is(.dt-topbar, .dt) {
  --theme-surface-raised: #0F1319;
  --theme-surface-hover: #141A21;
  --theme-ink-primary: #F3F5F7;
  --theme-ink-secondary: #A8B0BA;
  --theme-ink-muted: #7D8794;
  --theme-status-positive-ink: #6FE3B5;
  --theme-status-warning-ink: #FFC869;
  --theme-rule-standard: #1F242D;
  --theme-rule-interactive: #27303B;

  --st-bg: #0A0C10;
  --st-surface-1: #0F1319;
  --st-text: #F3F5F7;
  --st-text-secondary: #A8B0BA;
  --st-text-muted: #7D8794;
  --st-border: #1F242D;
  --st-amber: var(--theme-status-warning-ink);

  /* These aliases are declared on html.dt-page in hero-terminal.css. Re-resolve the three consumed
     top-bar aliases inside the dark island; descendant --theme-* / --st-* overrides cannot
     retroactively change a custom property that already resolved at the root. */
  --dt-fg-dim: var(--theme-ink-secondary);
  --dt-fg-faint: var(--theme-ink-muted);
  --dt-teal: var(--theme-status-positive-ink);
}
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .dt {
  background-color: #0A0C10;
}
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body :is(.home-supporting, .home-audit, .home-faq-compact) .home-card-kicker,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-explore-line-link,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-audit-links a {
  color: var(--theme-ink-link);
}
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body :is(.home-supporting, .home-audit, .home-faq-compact) .home-section-head h2,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-supporting-links strong,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-faq-q,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-audit .ddd-formula-value {
  color: var(--theme-ink-primary);
}
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body :is(.home-supporting, .home-audit) .home-section-head p:last-child,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-faq-a {
  color: var(--theme-ink-secondary);
}
html.dt-page:not(.in-practice-page) body .home-supporting-links span {
  color: var(--theme-ink-secondary);
}
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body :is(.home-supporting, .home-audit),
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-supporting-links,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-supporting-links a,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-faq-row,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-audit .ddd-formula--compact,
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-audit-links {
  border-color: var(--theme-rule-standard);
}
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-audit :is(.ddd-formula-op, .ddd-formula-label, .ddd-strip-note),
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body :is(.home-explore-line-kicker, .home-explore-line-sep) {
  color: var(--theme-ink-muted);
}
html.dt-page:not(.in-practice-page):not([data-theme-lock="dark"]):not([data-theme="dark"]) body .home-audit .ddd-formula-value--result {
  color: var(--theme-status-positive-ink);
}
body .mx-lens .mx-lens-formula,
body .partners-why-item p {
  color: var(--theme-ink-secondary);
}
/* The three comparison details carry inline opacity:.55. Muted ink at full opacity preserves their
   subordinate hierarchy while avoiding a second alpha blend that fails in both themes. */
body .mx-lens .mx-lens-formula > span {
  color: var(--theme-ink-muted);
  opacity: 1 !important;
}

/* The three step-up overrides that used to live here (--max-w 680 -> 720 at 1024px, --max-w-wide
   1120 -> 1200 at 1280px -> 1280 at 1600px) are gone. They were the mechanism that produced four
   different page widths at four viewports and no shared left edge with the navigation, which is
   fixed at one measure. Both roles are now continuous: the LAYER 5 gutter interpolates and the
   measures are constant, so the spine is the same object at every width. */

html {
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  scrollbar-color: var(--theme-rule-standard) transparent;
  scrollbar-width: thin;
}
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--theme-rule-standard); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--theme-rule-interactive); }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.65;
  overflow-x: hidden;
  max-width: 100vw;
}

::selection { background: var(--theme-selection-surface); color: var(--theme-selection-ink); }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-light); }
button:focus-visible, input:focus-visible, a:focus-visible, select:focus-visible {
  outline: 2px solid var(--theme-focus-ring);
  outline-offset: 2px;
}

.container { max-width: var(--max-w); margin: 0 auto; padding: 0 var(--layout-gutter); }
section { padding: var(--gap) 0; }

/* The former @media (max-width: 600px) step-down of --gap / --gap-sm / --gap-lg is gone: all three
   now derive from the LAYER 5 rhythm roles, which already carry their own mobile values. */

/* ============================================
   Terminal primitives — shared across subpages.
   Mirrors the home hero's eyebrow/headline recipe so every page reads as
   one surface. Pages can override layout (width, padding) while keeping
   the typographic language consistent.
   ============================================ */
.page-header {
  padding: var(--rhythm-page-top-clear) 0 var(--rhythm-title-content);
  border-bottom: 1px solid var(--border-hairline);
  margin-bottom: var(--rhythm-title-content);
}
.hero-eyebrow,
.section-eyebrow {
  font-family: var(--mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-lh);
  color: var(--label-muted);
  letter-spacing: var(--type-label-ls);
  text-transform: uppercase;
  margin-bottom: 0.9rem;
}
.hero-headline,
.page-title {
  font-family: var(--serif-display);
  font-weight: var(--type-page-title-weight);
  font-size: var(--type-page-title-size);
  line-height: var(--type-page-title-lh);
  letter-spacing: var(--type-page-title-ls);
  color: var(--text);
  margin-bottom: var(--rhythm-title-lead);
  font-variant-numeric: tabular-nums lining-nums;
}
.hero-headline .hero-pct,
.hero-headline .accent,
.page-title .accent {
  color: var(--accent);
}
.hero-meta {
  font-family: var(--mono);
  font-size: var(--type-metadata-size);
  font-weight: var(--type-metadata-weight);
  line-height: var(--type-metadata-lh);
  color: var(--text-muted);
  letter-spacing: var(--type-metadata-ls);
  font-variant-numeric: tabular-nums;
  margin: 0;
}
.page-intro {
  font-family: var(--sans);
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  color: var(--text-secondary);
  line-height: var(--type-body-lh);
  max-width: 58ch;
}

/* The @media (max-width: 600px) step-down of .page-header padding is no longer needed: both values
   now come from rhythm roles that carry their own mobile values. */

/* ============================================
   Shared card system
   ============================================ */
/* DEFERRED as a group. .ddd-card implements a gradient-and-radius grammar that constitution
   sections C, I and N prohibit, and the roadmap replaces the component rather than rethemes it.
   Mapping --card-bg onto --theme-surface-raised would turn a component decision into a global
   surface role and change its rendering, so these stay literal until that rebuild. */
:root {
  --card-radius: 14px;
  --card-padding: 1.25rem;
  --card-bg: linear-gradient(180deg, rgba(15,19,27,0.97), rgba(10,13,18,0.94));
  --card-border: rgba(255,255,255,0.07);
  --card-border-accent: rgba(90,150,255,0.22);
}

.ddd-card {
  border-radius: var(--card-radius);
  border: 1px solid var(--card-border);
  background: var(--card-bg);
  padding: var(--card-padding);
}
.ddd-card--accent { border-color: var(--card-border-accent); }
.ddd-card-title {
  font-family: var(--serif-display);
  font-size: var(--type-subsection-title-size);
  font-weight: var(--type-subsection-title-weight);
  letter-spacing: var(--type-subsection-title-ls);
  color: var(--text);
  line-height: var(--type-subsection-title-lh);
}
.ddd-card-body {
  font-family: var(--sans);
  font-size: var(--type-body-supporting-size);
  font-weight: var(--type-body-supporting-weight);
  line-height: var(--type-body-supporting-lh);
  color: var(--text-secondary);
}
.ddd-card-meta {
  font-family: var(--mono);
  font-size: var(--type-metadata-size);
  font-weight: var(--type-metadata-weight);
  line-height: var(--type-metadata-lh);
  color: var(--label-muted);
  letter-spacing: var(--type-metadata-ls);
}

/* ============================================
   Shared badge system
   ============================================ */
.ddd-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-family: var(--mono);
  font-size: var(--type-label-compact-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-compact-ls);
  text-transform: uppercase;
  white-space: nowrap;
}
.ddd-badge-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  flex-shrink: 0;
}
.ddd-badge--live      { color: var(--st-mint-strong); border-color: rgba(111,227,181,0.3);  background: rgba(111,227,181,0.07); }
.ddd-badge--live .ddd-badge-dot      { background: var(--st-mint-strong); box-shadow: 0 0 6px rgba(111,227,181,0.6); }
.ddd-badge--bootstrap { color: var(--st-mint-strong); border-color: rgba(111,227,181,0.22); background: rgba(111,227,181,0.05); }
.ddd-badge--bootstrap .ddd-badge-dot { background: var(--st-mint-strong); }
.ddd-badge--planned   { color: #a78bfa; border-color: rgba(167,139,250,0.25); background: rgba(167,139,250,0.06); }
.ddd-badge--planned .ddd-badge-dot   { background: #a78bfa; opacity: 0.6; }
.ddd-badge--research  { color: var(--st-amber); border-color: rgba(255,200,105,0.25);  background: rgba(255,200,105,0.06); }
.ddd-badge--research .ddd-badge-dot  { background: var(--st-amber); opacity: 0.6; }
.ddd-badge--delayed   { color: var(--st-amber); border-color: rgba(255,200,105,0.3);   background: rgba(255,200,105,0.06); }
.ddd-badge--delayed .ddd-badge-dot   { background: var(--st-amber); }
.ddd-badge--error     { color: var(--st-red-strong); border-color: rgba(240,123,105,0.25); background: rgba(240,123,105,0.06); }
.ddd-badge--error .ddd-badge-dot     { background: var(--st-red-strong); }
.ddd-badge--context   { color: rgba(232,234,237,0.45); border-color: rgba(255,255,255,0.09); background: rgba(255,255,255,0.03); }
.ddd-badge--context .ddd-badge-dot   { background: rgba(232,234,237,0.3); }

/* ============================================
   Shared button / CTA system
   ============================================ */
.ddd-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  border-radius: 8px;
  font-family: var(--sans);
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease, opacity 0.18s ease;
  white-space: nowrap;
  padding: 0.55rem 1.1rem;
  min-height: 40px;
}
/* Primary — teal fill */
.ddd-btn--primary {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
}
.ddd-btn--primary:hover { opacity: 0.88; color: var(--bg); }
/* Secondary — outlined */
.ddd-btn--secondary {
  background: transparent;
  color: var(--accent);
  border-color: rgba(90,150,255,0.34);
}
.ddd-btn--secondary:hover { border-color: var(--accent); color: var(--accent-light); }
/* Subtle — text link style */
.ddd-btn--subtle {
  background: transparent;
  color: var(--text-secondary);
  border-color: var(--border);
  font-family: var(--mono);
  font-size: var(--type-label-compact-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-compact-ls);
  text-transform: uppercase;
  padding: 0.45rem 0.9rem;
}
.ddd-btn--subtle:hover { color: var(--accent); border-color: rgba(90,150,255,0.28); }

/* ================================================================================================
   LAYER 4 — EDITORIAL TYPE ROLES

   Eight roles, named by editorial job rather than by size. Every shared surface consumes a role;
   nothing below display level declares a raw font-size any more. Two things follow from that:

     1. Hierarchy becomes a property of the system rather than of each page. Before this layer the
        thirteen public routes rendered their H1 at nine different sizes between 42px and 69px, and
        their H2 at sizes between 14.7px and 64px. Sequence and scale could not carry hierarchy
        because no two pages agreed on the scale.
     2. The approved Cormorant Garamond / Inter / JetBrains Mono migration becomes a family swap
        plus a per-role metric adjustment in this one block, instead of an audit of every selector
        in the repository.

   FAMILIES ARE DEFERRED. This batch keeps Fraunces / IBM Plex Sans / IBM Plex Mono. The roles are
   sized for those faces; Cormorant runs optically smaller and lighter and will need its own values.

   WEIGHTS ARE CAPPED BY THE LOADED AXIS. Every public route loads Fraunces 300/400/500, IBM Plex
   Mono 300/400/500 and IBM Plex Sans 300/400/500/600/700. No role asks for a weight outside those,
   because a weight the axis cannot supply is synthesised — a smeared faux-bold, not a heavier face.

   MOBILE STEPS UP RATHER THAN DOWN. The approved reference enlarges every non-display role at
   390px (body 13.5px -> 15px, labels 11px -> 12px) while the display drops by half. That is what
   "recomposed, not reduced" means numerically, and it is the opposite of a proportional shrink.
   Sizes here are absolute so they survive the 15px mobile root in css/index.css.
   ================================================================================================ */
:root {
  /* PAGE TITLE — route H1s, major report titles. Below the DDD display, above everything else. */
  --type-page-title-size: clamp(32px, 4.2vw, 46px);
  --type-page-title-weight: 400;
  --type-page-title-lh: 1.08;
  --type-page-title-ls: -0.018em;

  /* SECTION TITLE — H2-level editorial sections, major table and methodology divisions. */
  --type-section-title-size: 28px;
  --type-section-title-weight: 400;
  --type-section-title-lh: 1.2;
  --type-section-title-ls: -0.012em;

  /* SUBSECTION TITLE — H3-level groupings and compact secondary headings inside a section. */
  --type-subsection-title-size: 19px;
  --type-subsection-title-weight: 400;
  --type-subsection-title-lh: 1.3;
  --type-subsection-title-ls: -0.005em;

  /* BODY — ordinary explanatory prose, methodology paragraphs, narrative descriptions. */
  --type-body-size: 15.5px;
  --type-body-weight: 400;
  --type-body-lh: 1.62;

  /* SUPPORTING BODY — captions, subordinate descriptions, secondary explanatory copy. */
  --type-body-supporting-size: 14px;
  --type-body-supporting-weight: 400;
  --type-body-supporting-lh: 1.6;

  /* LABEL — section labels, eyebrows, kickers, standalone data labels. Carries meaning, so it is
     held to 12px desktop / 13px mobile. */
  --type-label-size: 12px;
  --type-label-weight: 500;
  --type-label-lh: 1.35;
  --type-label-ls: 0.13em;

  /* LABEL, COMPACT — the documented exception. Table column headings, badges and in-row marks sit
     inside a fixed column or a 44px control and would overflow at label size. 11px desktop / 12px
     mobile is the constitution's section J floor for essential text, and it is also what the
     approved reference uses for its own table headings (10-11px desktop, 11-12px mobile). */
  --type-label-compact-size: 11px;
  --type-label-compact-ls: 0.11em;

  /* METADATA — dates, statuses, record identifiers, compact measurements, source timestamps. */
  --type-metadata-size: 12px;
  --type-metadata-weight: 400;
  --type-metadata-lh: 1.45;
  --type-metadata-ls: 0.045em;

  /* PROVENANCE — the compact source and signature lines closing a block. Quieter than metadata. */
  --type-provenance-size: 11.5px;
  --type-provenance-lh: 1.5;
  --type-provenance-ls: 0.02em;
}

@media (max-width: 600px) {
  :root {
    --type-page-title-size: 30px;
    --type-section-title-size: 23px;
    --type-subsection-title-size: 18px;
    --type-body-supporting-size: 14.5px;
    --type-label-size: 13px;
    --type-label-compact-size: 12px;
    --type-metadata-size: 13px;
    --type-provenance-size: 12.5px;
  }
}

/* A weight the loaded axis cannot supply must fall back to the nearest real face rather than be
   algorithmically smeared. Before this declaration the site rendered 112 faux-bold instances, all
   of them mono at 600/650/700/800 against an axis that stops at 500. */
body {
  font-synthesis-weight: none;
}

/* ------------------------------------------------------------------------------------------------
   ROLE REGISTRY

   Which existing selectors carry which role. Selectors are grouped by role so the later family
   migration reads as one list per role.

   The `:root body` prefix is a specificity device, not decoration. Two things defeat a plain
   selector here: four of the thirteen routes keep their page CSS in an inline <style> block that
   follows this file in document order, and the homepage stylesheets scope almost every rule as
   `html.dt-page .thing`, which is (0,2,1). `:root body :is(...)` is (0,2,3) and therefore wins,
   while still losing to any page rule that genuinely needs to be more specific than a role —
   `html.dt-page .home-product-journey .signup-block h3` at (0,3,2), for instance, still applies.
   ------------------------------------------------------------------------------------------------ */

/* PAGE TITLE. `.hero-headline` and `.page-title` are already handled by the shared primitive above,
   which covers /issuers, /chains, /crossings and /reports. The rest declare their own H1 class.
   Deliberately excluded: `h1.dt-what-is` and `h1.history-big-number`, which are display-role
   readings rather than page titles and are governed by their own pages. */
:root body :is(
  h1.hero-headline,
  h1.page-title,
  h1.tape-title,
  h1.mx-hero-title,
  h1.dev-hero-title,
  h1.partners-title,
  h1.support-title
) {
  font-family: var(--serif-display);
  font-size: var(--type-page-title-size);
  font-weight: var(--type-page-title-weight);
  line-height: var(--type-page-title-lh);
  letter-spacing: var(--type-page-title-ls);
}

/* SECTION TITLE. */
:root body :is(
  h2.mx-card-title,
  h2.tape-mintburn-title,
  h2.isg-title,
  h2.issuer-structure-title,
  h2.structure-summary-title,
  h2.market-structure-title,
  h2.chains-main-title,
  h2.cx-section-title,
  h2.history-event-title,
  h2.report-title,
  h2.support-section-heading,
  .home-section-head h2,
  .home-card-copy h2,
  .section > h2,
  .directory-title > h2,
  .partners-section > h2
) {
  font-family: var(--serif-display);
  font-size: var(--type-section-title-size);
  font-weight: var(--type-section-title-weight);
  line-height: var(--type-section-title-lh);
  letter-spacing: var(--type-section-title-ls);
}

/* SUBSECTION TITLE. */
:root body :is(
  h2.tm-title,
  h2.share-panel-title,
  h3.signal-method-ladder-title,
  h3.market-structure-title,
  h3.mx-card-title,
  h3.report-title,
  .partners-why-item > h3,
  .signup-block h3
) {
  font-family: var(--serif-display);
  font-size: var(--type-subsection-title-size);
  font-weight: var(--type-subsection-title-weight);
  line-height: var(--type-subsection-title-lh);
  letter-spacing: var(--type-subsection-title-ls);
}

/* BODY. Route introductions and lead paragraphs. */
:root body :is(
  p.mx-hero-lead,
  p.dev-hero-lead,
  p.partners-lead,
  p.support-lead,
  p.tape-lead,
  p.dt-subhead,
  p.home-signal-evidence
) {
  font-family: var(--sans);
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-lh);
}

/* SUPPORTING BODY, including every explanatory sentence promoted out of the mono family. Mono is
   the voice of provenance; a sentence a reader is meant to read is not provenance. Formulas,
   hashes, timestamps, source identifiers, version strings and code stay in mono by design and are
   not listed here. */
:root body :is(
  p.home-faq-a,
  p.home-signal-method,
  p.ddd-chart-loading,
  p.home-chart-summary,
  p.ddd-decade-note,
  div.mx-card-note,
  div.mx-lenses-note,
  div.mx-unavail,
  div.meth-formula-note,
  span.mx-velocity-fact-value,
  p.tape-day-signal-rules-note,
  div.tape-mintburn-scale-note,
  div.tape-status-sub,
  p.tape-viz-footnote,
  div.tape-row-impact,
  p.gw-tail-footer,
  p.currencies-note,
  p.support-section-body,
  p.support-disclosure-body,
  a.dt-hero-tertiary,
  div.mx-lens-source,
  div.mx-active-label,
  div.mx-provider-list
) {
  font-family: var(--sans);
  font-size: var(--type-body-supporting-size);
  font-weight: var(--type-body-supporting-weight);
  line-height: var(--type-body-supporting-lh);
  letter-spacing: 0;
  text-transform: none;
}

/* LABEL. */
:root body :is(
  p.home-card-kicker,
  span.home-explore-line-kicker,
  div.ddd-formula-label,
  span.dt-hero-eyebrow-full,
  span.dt-hero-eyebrow-short,
  p.dt-hero-plain-label,
  div.dt-hero-asof,
  span.ddd-decade-item-eyebrow,
  p.support-section-label,
  p.support-disclosure-label,
  p.support-eyebrow,
  div.mx-hero-eyebrow,
  div.dev-hero-eyebrow,
  /* The shared primitive above is (0,1,0) and loses to same-specificity page copies of it. */
  .hero-eyebrow,
  .section-eyebrow,
  .partners-section-label
) {
  font-family: var(--mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-lh);
  letter-spacing: var(--type-label-ls);
}

/* METADATA. */
:root body :is(
  time.home-signal-date,
  p.ddd-tape-preview-meta,
  p.tape-hero-meta,
  p.ddd-chart-note,
  div.mx-card-source,
  div.meth-source-meta,
  p.tbl-foot
) {
  font-family: var(--mono);
  font-size: var(--type-metadata-size);
  font-weight: var(--type-metadata-weight);
  line-height: var(--type-metadata-lh);
  letter-spacing: var(--type-metadata-ls);
}

/* LABEL FLOOR — the compact label role applied to the recurring cross-page label vocabularies.

   These are not one-off selectors: `mx-*` runs across /methodology and /metrics, `tape-*` across
   the Tape surfaces, and `structure-*` / `tm-*` / `*-kicker` across /issuers, /chains and
   /currencies. Before this rule they rendered word-carrying labels at 8.5px to 9.9px — below the
   constitution's section J floor of 11px for essential text, and well below the reference's own
   table headings. They take the compact size rather than the full label size because each sits in
   a fixed column, a status chip or a 44px control where the full size overflows. */
:root body :is(
  .mx-badge,
  .mx-cv-label,
  .mx-lens-label,
  .mx-velocity-fact-label,
  .mx-velocity-kicker,
  .mx-boundary-label,
  .tape-source-badge,
  .tape-chip,
  .tape-status-label,
  .tape-mini-stat-label,
  .tape-signal-rule-selected,
  .tape-viz-movers-col-head,
  .structure-stat-label,
  .structure-status,
  .concentration-kicker,
  .pulse-detail-label,
  .chain-pulse-detail-label,
  .gw-rail-rank,
  .group-label,
  .addr-label,
  .api-badge,
  .history-event-chip-meta,
  .cm-surpassed-name,
  .tm-window
) {
  font-size: var(--type-label-compact-size);
  letter-spacing: var(--type-label-compact-ls);
}

/* ================================================================================================
   LAYER 5 — EDITORIAL LAYOUT ROLES

   Three measures, one gutter and seven vertical rhythm roles. Named by editorial job, so a surface
   declares what kind of column it is rather than picking a number.

   THE NUMBERS COME FROM THE APPROVED REFERENCE, RENDERED, NOT COPIED.
   docs/design-reference/stable-tape-homepage-concept.html expresses its entire page geometry in one
   rule, `.wrap{max-width:1360px;margin:0 auto;padding:0 48px}`, relaxed to `padding:0 20px` on
   small screens. Measured in Chromium that resolves to a content column of 88..1352 at 1440
   (1264px wide, 88px outer gutter, 39 elements sharing it) and 20..370 at 390 (350px wide, 110
   elements sharing it). Those two readings are the primary measure and the two gutter endpoints
   below. Rendered vertical rhythm from the same file: page top 44/26, section separation 72/44,
   compact separation 52/34, title to lead 10/14, title to content 18/14, row 9/11, footer 72/44.

   WHAT THIS REPLACES. The homepage rendered five competing widths at 1440: .page at 1320, .dt at
   1224, .dt-topbar at 1200, .home-product-journey at 1120 and the lower sections at 1040, giving
   five different left edges (60, 132, 140, 200, 228) and no shared spine. The supporting routes
   added two more, because --max-w and --max-w-wide each stepped up at their own breakpoints while
   the navigation stayed at one width. One measure now runs from navigation to footer.

   MEASURES ARE CONTENT WIDTHS; BOXES ADD THE GUTTER. Most existing containers were written as
   `max-width: <outer>` plus their own side padding, so both forms are published: consume the box
   form for a container that carries the gutter as padding, and the measure form for something
   nested inside a column that already has one.
   ================================================================================================ */
:root {
  /* PRIMARY PAGE MEASURE — shared navigation, homepage reading, principal page content, major
     section rules and footer content. This is the spine; anything that establishes the page's left
     edge uses it and nothing else. */
  --layout-measure-page: 1264px;

  /* READING MEASURE — long-form methodology prose, explanatory paragraphs, FAQ answers, editorial
     narrative. Never tables, charts, benchmark readings, source ledgers or wide data summaries:
     those stay on the page measure so a column of figures is never squeezed for a prose reason. */
  --layout-measure-reading: 680px;

  /* COMPACT MEASURE — short signup messages, concise callouts, small centred empty states. It is
     deliberately narrow enough to be unusable as a second general-purpose page width. */
  --layout-measure-compact: 460px;

  /* SHARED GUTTER — one responsive value for desktop, tablet and mobile. Continuous rather than
     stepped, so 767px and 768px differ by a fraction of a pixel instead of jumping: 20px at 390,
     30px at 768, 48px at 1440 and above. The 20px floor is the reference's own mobile gutter and
     keeps content clear of the viewport edge. The env() terms carry forward the safe-area guard the
     two footer shells and the issuer/chain containers each used to declare for themselves; both
     sides take the same value, because an asymmetric gutter would break the shared spine. */
  --layout-gutter: max(
    clamp(20px, 2.67vw + 9.6px, 48px),
    env(safe-area-inset-left, 0px),
    env(safe-area-inset-right, 0px)
  );

  /* Outer boxes. A container using these carries the gutter itself as padding-inline. */
  --layout-box-page: calc(var(--layout-measure-page) + 2 * var(--layout-gutter));
  --layout-box-reading: calc(var(--layout-measure-reading) + 2 * var(--layout-gutter));
  --layout-box-compact: calc(var(--layout-measure-compact) + 2 * var(--layout-gutter));

  /* Height of the fixed shared navigation. Page-top spacing on every route that carries it has to
     clear this before the editorial space above the first element begins. */
  --layout-nav-h: 48px;

  /* ---- VERTICAL RHYTHM ------------------------------------------------------------------------
     A small scale with a deliberate hierarchy rather than one uniform gap. Section separation is
     the full step and belongs to independent bands; compact separation belongs to a band bound to
     what precedes it, and to the denser reference-like content lower down the page. Both are
     continuous between 390 and 1440 for the same reason as the gutter. */

  /* PAGE TOP — editorial space above the first element on a page. */
  --rhythm-page-top: clamp(26px, 1.71vw + 19.3px, 44px);
  /* PAGE TOP, CLEARING THE FIXED NAV — for the routes whose header is position: fixed. */
  --rhythm-page-top-clear: calc(var(--layout-nav-h) + var(--rhythm-page-top));

  /* SECTION SEPARATION — between independent major sections. */
  --rhythm-section: clamp(44px, 2.67vw + 33.6px, 72px);

  /* COMPACT SECTION SEPARATION — between a section and the one it belongs to, and throughout the
     denser lower page. This is the role that stops a page reading as one uniform gap. */
  --rhythm-section-compact: clamp(34px, 1.71vw + 27.3px, 52px);

  /* TITLE TO LEAD — a page or section title to the sentence that completes it. */
  --rhythm-title-lead: 12px;

  /* SECTION TITLE TO CONTENT — a section heading to the body, table or chart beneath it. */
  --rhythm-title-content: 18px;

  /* ROW — between ledger, statistic and movement rows. Larger on mobile, not smaller: there they
     are tap targets. PUBLISHED, NOT YET CONSUMED. Every row surface in the repository lives in a
     page stylesheet as component padding (css/tape.css `.tape-row`, the issuer and chain tables,
     the metrics stat rows), and this batch deliberately changes outer rhythm only. The role is
     declared here so the batch that migrates those rows has one value to migrate to rather than
     picking a new number, and so the scale is complete when read. */
  --rhythm-row: 9px;

  /* FOOTER SEPARATION — last content band to the footer rule. */
  --rhythm-footer: clamp(44px, 2.67vw + 33.6px, 72px);
}

@media (max-width: 600px) {
  :root {
    --rhythm-title-lead: 14px;
    --rhythm-title-content: 14px;
    --rhythm-row: 11px;
  }
}

/* ------------------------------------------------------------------------------------------------
   LAYOUT ROLE REGISTRY

   Which containers carry which role. The `:root body :is(...)` prefix is the same specificity
   device the type registry uses, and it is needed for the same reason: nine of the thirteen public
   routes declare their page shell inside an inline <style> block that follows this file in document
   order, so a plain `.mx-page` here would lose to an identical `.mx-page` there. This selector is
   (0,2,1) and wins, while still losing to anything a page makes deliberately more specific.

   Only the outer shell and its gutter are set. Page interiors, grids, tables and component padding
   are untouched.
   ------------------------------------------------------------------------------------------------ */

/* PRIMARY PAGE MEASURE. Every route shell, and both footer inners, on the one spine. The
   max-width on most of these already resolves through --max-w-wide; what the registry adds is the
   shared gutter, which each page previously declared for itself as 1.25rem, 1rem, 24px or a
   clamp() of its own. */
:root body :is(
  .mx-page,
  .partners-shell,
  .partners-hero-inner,
  .issuers-container,
  .chains-container,
  .tape-shell,
  .tape-hero-inner,
  .cx-container,
  .dev-shell,
  .dev-hero-inner,
  .site-footer__inner,
  .page-footer__inner
) {
  width: 100%;
  max-width: var(--layout-box-page);
  margin-inline: auto;
  padding-inline: var(--layout-gutter);
  box-sizing: border-box;
}

/* READING MEASURE. The text-led route shells. .support-body and .support-inner already resolve
   their max-width through --max-w; .container is the shared primitive above. Each keeps its
   rendered 680px measure and gains the shared gutter.

   .dev-hero-inner moved to the PAGE measure above when /developers was converged: the route is now
   a data-heavy reference carrying full-width endpoint and schema ledgers, so a reading-measure
   masthead sat 280px inboard of the content under it. Its shell, .dev-shell, is registered
   alongside it so the two share one measure and one gutter. Both selectors are used by
   developers.html alone, so this moves one route and no other. */
:root body :is(
  .support-body,
  .support-inner
) {
  width: 100%;
  max-width: var(--layout-box-reading);
  margin-inline: auto;
  padding-inline: var(--layout-gutter);
  box-sizing: border-box;
}

/* SHARED GUTTER ONLY. The signup block's own measure is deliberately page-specific: it is compact
   by default, and /issuers, /chains and /history widen it to the page measure so its top rule lands
   on the same edges as the data container above it. Each of those pages declared a private side
   padding to go with that, which is what pulled the rule off the shared edge. Only the gutter is
   taken here; the measure stays with the page. */
:root body .signup-block {
  padding-inline: var(--layout-gutter);
}
/* /currencies is the one route whose signup block sits inside the page shell rather than beside it,
   so there the shell has already spent the gutter. */
:root body .mx-page > .signup-block {
  padding-inline: 0;
}

/* PAGE TOP. The route heroes, each of which cleared the fixed navigation with a hand-picked 5.5rem
   or 6rem. Only the top edge is regularised; the closing padding of each hero is its own. */
:root body :is(
  .mx-hero,
  .dev-hero,
  .support-hero,
  .partners-hero,
  .tape-hero
) {
  padding-top: var(--rhythm-page-top-clear);
}

/* FOOTER SEPARATION. */
:root body :is(.site-footer, .page-footer) {
  margin-top: var(--rhythm-footer);
}
