/* GENERATED FILE - DO NOT EDIT.
 * Source: web/src/styles/tokens.css and its imports.
 * Run npm run docs:tokens after editing the authored styles.
 */
/* ---- src/styles/tokens/fonts.css ---- */
/* Vaultspec webfonts — self-hosted (SIL OFL 1.1). Archivo carries every text
   role, display and body alike; JetBrains Mono carries code, paths, and hashes,
   where monospace is doing real work rather than wearing a technical costume.

   Archivo is variable across BOTH weight (100-900) and width (62%-125%). The
   width axis is why it was chosen: one family draws the display headline and
   the condensed ruler labels the mat language needs, so no second family has
   to be loaded for them.

   Latin, latin-ext and vietnamese subsets with unicode-range, so a reader only
   downloads what their text needs; font-display: swap; no third-party origin
   and no render-blocking CDN import. WOFF2 live in /public/fonts. Regenerate by
   downloading the Google Fonts css2 output for the same axes and rewriting the
   gstatic URLs to /fonts/. */
/* ---------- Archivo — display and text ---------- */
/* vietnamese */
@font-face {
  font-family: 'Archivo';
  font-style: italic;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url(../../fonts/k3kSo8UDI-1M0wlSfdzYI2HEEaM.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Archivo';
  font-style: italic;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url(../../fonts/k3kSo8UDI-1M0wlSfdzYImHEEaM.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Archivo';
  font-style: italic;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url(../../fonts/k3kSo8UDI-1M0wlSfdzYLGHE.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url(../../fonts/k3kQo8UDI-1M0wlSfdboLnnA.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url(../../fonts/k3kQo8UDI-1M0wlSfdfoLnnA.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url(../../fonts/k3kQo8UDI-1M0wlSfdnoLg.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* ---------- JetBrains Mono — code ---------- */
/* cyrillic-ext */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../../fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx3cwhsk.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../../fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxTcwhsk.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../../fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxPcwhsk.woff2) format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../../fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx_cwhsk.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../../fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx7cwhsk.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../../fonts/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwg.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* ---- src/styles/tokens.css ---- */
/* Vaultspec Design System — shared values. Each surface owns font loading. */
/* ---- src/styles/tokens/colors.css ---- */
/* ============================================================================
   COLORS — Vaultspec OKLCH generative core.

   Three layers, exactly as the product ships (vaultspec-dashboard
   frontend/src/styles.css, generated from the DTCG token source):

     1. PRIMITIVES  (--primitive-*)  — intent-free stops. The cutting-board
        materials (measured hex: two grounds, their stock, ink, rules and
        accent), plus the OKLCH ramps the product still shares — a legacy warm
        neutral ramp, an earthy-green accent ramp (hue 150°), four
        grayscale-safe tier hues, and the sacred diff hues. Never read
        directly by chrome or scene.
     2. SEMANTIC TIER   (--semantic-*)    — Radix-style role model (surface /
        ink / border / accent / focus) aliasing primitives. The layer a
        [data-theme] remaps.
     3. PUBLIC SURFACE  (--color-*)       — the names components consume.
        'chrome' tokens are var() aliases onto the semantic tier; the 'scene'
        subset (--color-canvas-bg, --color-tier-*, --color-state-*, --color-ink,
        --color-rule, category colors) is literal #rrggbb because the canvas
        readers parse hex directly.

   The default :root carries the LIGHT theme. dark / light / high-contrast are
   peer [data-theme] remaps — no component knows which theme is active. Light
   and dark are authored as two materials rather than one inverted: a pale mat
   carrying white stock, and a dark mat carrying graphite stock. The neutral is
   a cool green-grey at very low chroma. Character lives in the material and in
   exactly three signal hues: green for primary action, burnt ochre for work in
   hand, blue for a measured reference. Never gradients, never textures, never
   a fourth signal. The per-document category hues keep their names because the
   file's lineage is shared with the product, but on this surface they resolve
   onto those three — eight hues with no legend communicate nothing.
   ========================================================================== */
:root {
  /* 1. PRIMITIVE RAMPS ---------------------------------------------------- */
  /* Warm neutral — the ground and the ink (hue 75°). */
  --primitive-neutral-0: oklch(1 0 75);
  --primitive-neutral-50: oklch(0.985 0.006 75);
  --primitive-neutral-100: oklch(0.968 0.008 75);
  --primitive-neutral-150: oklch(0.955 0.009 75);
  --primitive-neutral-200: oklch(0.928 0.01 75);
  --primitive-neutral-300: oklch(0.86 0.011 75);
  --primitive-neutral-400: oklch(0.72 0.012 75);
  --primitive-neutral-500: oklch(0.62 0.012 75);
  --primitive-neutral-600: oklch(0.53 0.012 75);
  --primitive-neutral-700: oklch(0.47 0.013 75);
  --primitive-neutral-800: oklch(0.38 0.012 75);
  --primitive-neutral-850: oklch(0.3 0.011 75);
  --primitive-neutral-900: oklch(0.235 0.01 75);
  --primitive-neutral-920: oklch(0.205 0.009 75);
  --primitive-neutral-940: oklch(0.185 0.008 75);
  --primitive-neutral-950: oklch(0.165 0.008 75);
  --primitive-neutral-980: oklch(0.13 0.006 75);
  /* Earthy green accent — the single spent hue (150°). */
  --primitive-accent-300: oklch(0.945 0.03 150);
  --primitive-accent-500: oklch(0.52 0.08 150);
  --primitive-accent-600: oklch(0.38 0.09 150);
  --primitive-accent-700: oklch(0.7 0.09 150);
  --primitive-accent-800: oklch(0.8 0.08 150);
  --primitive-accent-dark-subtle: oklch(0.3 0.045 150);
  /* Cutting-board materials. Two grounds authored independently, not one
     inverted: light is a pale mat carrying white stock, dark is a dark mat
     carrying graphite stock. Literal hex because these are measured values —
     every ink token clears 4.5:1 on both grounds in its own mode, most clear
     7:1 — and a value re-derived through a ramp would no longer be the value
     that was measured. The neutral reads cool green-grey at very low chroma,
     which is the single move that turns editorial paper into workshop mat. */
  --primitive-mat-l: #e7eae5;
  --primitive-stock-l: #fbfcfa;
  --primitive-stock-sunk-l: #dce0da;
  --primitive-bench-l: #efece3;
  --primitive-ink-l: #141a16;
  --primitive-ink-muted-l: #343d37;
  --primitive-ink-faint-l: #606864;
  --primitive-edge-l: #79817b;
  --primitive-rule-strong-l: #afb6ae;
  --primitive-rule-l: #ccd2cb;
  --primitive-accent-l: #2e6b45;
  --primitive-accent-ink-l: #245638;
  --primitive-mat-d: #141816;
  --primitive-stock-d: #1e2321;
  --primitive-stock-sunk-d: #0f1211;
  --primitive-bench-d: #1a1813;
  --primitive-ink-d: #f1f4f1;
  --primitive-ink-muted-d: #d8dfda;
  --primitive-ink-faint-d: #aeb8b1;
  --primitive-edge-d: #8d9991;
  --primitive-rule-strong-d: #59645f;
  --primitive-rule-d: #3c4541;
  --primitive-accent-d: #6fbe8b;
  --primitive-accent-ink-d: #8acfa2;
  /* The other two of the three signal hues. Green is primary action; the
     burnt ochre means work in hand; the blue means a measured reference.
     Three is the whole vocabulary — the per-document hues below collapse onto
     it, because eight hues with no legend on a marketing page say nothing. */
  --primitive-mark-l: #8c5312;
  --primitive-chalk-l: #356788;
  --primitive-mark-d: #dca05a;
  --primitive-chalk-d: #84b6d6;
  /* Four tier hues at fixed distinct lightness (grayscale-safe). */
  --primitive-tier-declared-l: oklch(0.3 0.012 75);
  --primitive-tier-structural-l: oklch(0.52 0.09 150);
  --primitive-tier-temporal-l: oklch(0.44 0.03 75);
  --primitive-tier-semantic-l: oklch(0.6 0.07 290);
  --primitive-tier-declared-d: oklch(0.85 0.01 75);
  --primitive-tier-structural-d: oklch(0.72 0.095 150);
  --primitive-tier-temporal-d: oklch(0.78 0.03 75);
  --primitive-tier-semantic-d: oklch(0.7 0.08 290);
  /* Sacred diff hues — high-contrast in every theme. */
  --primitive-diff-add-l: oklch(0.5 0.13 150);
  --primitive-diff-remove-l: oklch(0.52 0.16 28);
  --primitive-diff-add-d: oklch(0.72 0.13 150);
  --primitive-diff-remove-d: oklch(0.68 0.15 28);

  /* 2. SEMANTIC TIER (light default) -------------------------------------
     The mat is the page; stock is what is laid on it. --semantic-edge is the
     only line token permitted to carry meaning (control boundaries, the scored
     inlay border, focus rings) and clears 3:1 against both mat and stock in
     both modes; the rule tokens are decorative seams and must never encode
     state on their own. */
  --semantic-mat: var(--primitive-mat-l);
  --semantic-bench: var(--primitive-bench-l);
  --semantic-surface-base: var(--primitive-mat-l);
  --semantic-surface-raised: var(--primitive-stock-l);
  --semantic-surface-sunken: var(--primitive-stock-sunk-l);
  --semantic-edge: var(--primitive-edge-l);
  --semantic-border-subtle: var(--primitive-rule-l);
  --semantic-border-strong: var(--primitive-rule-strong-l);
  --semantic-accent-base: var(--primitive-accent-l);
  --semantic-accent-hover: var(--primitive-accent-ink-l);
  --semantic-accent-pressed: var(--primitive-accent-ink-l);
  --semantic-accent-subtle: color-mix(in srgb, var(--primitive-accent-l) 12%, var(--primitive-stock-l));
  --semantic-accent-on-subtle: var(--primitive-accent-ink-l);
  --semantic-mark: var(--primitive-mark-l);
  --semantic-chalk: var(--primitive-chalk-l);
  --semantic-focus-ring: var(--primitive-edge-l);
  --semantic-ink-faint: var(--primitive-ink-faint-l);
  --semantic-ink-muted: var(--primitive-ink-muted-l);
  --semantic-ink-body: var(--primitive-ink-l);

  /* 3a. PUBLIC CHROME SURFACE (var() aliases) ---------------------------- */
  --color-mat: var(--semantic-mat);
  --color-bench: var(--semantic-bench);
  --color-edge: var(--semantic-edge);
  --color-paper: var(--semantic-surface-base);
  --color-paper-raised: var(--semantic-surface-raised);
  --color-paper-sunken: var(--semantic-surface-sunken);
  --color-paper-aged: var(--primitive-bench-l);
  --color-ink-faint: var(--semantic-ink-faint);
  --color-rule-strong: var(--semantic-border-strong);
  --color-accent: var(--semantic-accent-base);
  --color-accent-hover: var(--semantic-accent-hover);
  --color-accent-pressed: var(--semantic-accent-pressed);
  --color-accent-subtle: var(--semantic-accent-subtle);
  --color-accent-text: var(--semantic-accent-on-subtle);
  --color-focus: var(--semantic-focus-ring);
  --color-state-live: oklch(0.55 0.11 160);
  --color-diff-add: var(--primitive-diff-add-l);
  --color-diff-remove: var(--primitive-diff-remove-l);

  /* 3b. PUBLIC SCENE SURFACE (literal hex, read by the canvas) ----------- */
  --color-canvas-bg: #e7eae5;
  --color-mark: #8c5312;
  --color-chalk: #356788;
  --color-ink: #141a16;
  --color-ink-muted: #343d37;
  --color-rule: #ccd2cb;
  --color-scene-rule: #afb6ae;
  --color-tier-declared: #1a1e1c;
  --color-tier-structural: #2e6b45;
  --color-tier-temporal: #8c5312;
  --color-tier-semantic: #356788;
  --color-state-active: #8c5312;
  --color-state-complete: #2e6b45;
  --color-state-archived: #606864;
  --color-state-stale: #9f7100;
  --color-state-broken: #ae4024;
  --color-status-provisional: #806a44;
  --color-status-graded: #9f7100;
  --color-status-tiered: #5c5040;
  /* Document category accents (doc-type marks, graph node legend). */
  --color-category-feature: #8c5312;
  --color-category-research: #356788;
  --color-category-adr: #356788;
  --color-category-plan: #2e6b45;
  --color-category-exec: #8c5312;
  --color-category-audit: #356788;
  --color-category-code: #8c5312;
  --color-category-reference: #356788;
}
/* ===========================================================================
   THEME REMAPS — peer [data-theme] surfaces. Set data-theme on <html> or any
   container; the var() chains resolve to the active theme.
   =========================================================================== */
[data-theme="light"] {
  --semantic-mat: var(--primitive-mat-l);
  --semantic-bench: var(--primitive-bench-l);
  --semantic-surface-base: var(--primitive-mat-l);
  --semantic-surface-raised: var(--primitive-stock-l);
  --semantic-surface-sunken: var(--primitive-stock-sunk-l);
  --semantic-edge: var(--primitive-edge-l);
  --semantic-border-subtle: var(--primitive-rule-l);
  --semantic-border-strong: var(--primitive-rule-strong-l);
  --semantic-accent-base: var(--primitive-accent-l);
  --semantic-accent-hover: var(--primitive-accent-ink-l);
  --semantic-accent-pressed: var(--primitive-accent-ink-l);
  --semantic-accent-subtle: color-mix(in srgb, var(--primitive-accent-l) 12%, var(--primitive-stock-l));
  --semantic-accent-on-subtle: var(--primitive-accent-ink-l);
  --semantic-mark: var(--primitive-mark-l);
  --semantic-chalk: var(--primitive-chalk-l);
  --semantic-focus-ring: var(--primitive-edge-l);
  --semantic-ink-faint: var(--primitive-ink-faint-l);
  --semantic-ink-muted: var(--primitive-ink-muted-l);
  --semantic-ink-body: var(--primitive-ink-l);
  --color-paper-aged: var(--primitive-bench-l);
  --color-state-live: oklch(0.55 0.11 160);
  --color-diff-add: var(--primitive-diff-add-l);
  --color-diff-remove: var(--primitive-diff-remove-l);
  --color-canvas-bg: #e7eae5;
  --color-mark: #8c5312;
  --color-chalk: #356788;
  --color-ink: #141a16;
  --color-ink-muted: #343d37;
  --color-rule: #ccd2cb;
  --color-scene-rule: #afb6ae;
  --color-tier-declared: #1a1e1c;
  --color-tier-structural: #2e6b45;
  --color-tier-temporal: #8c5312;
  --color-tier-semantic: #356788;
  --color-state-active: #8c5312;
  --color-state-complete: #2e6b45;
  --color-state-archived: #606864;
  --color-state-stale: #9f7100;
  --color-state-broken: #ae4024;
  --color-status-provisional: #806a44;
  --color-status-graded: #9f7100;
  --color-status-tiered: #5c5040;
  --color-category-feature: #8c5312;
  --color-category-research: #356788;
  --color-category-adr: #356788;
  --color-category-plan: #2e6b45;
  --color-category-exec: #8c5312;
  --color-category-audit: #356788;
  --color-category-code: #8c5312;
  --color-category-reference: #356788;
}
[data-theme="dark"] {
  --semantic-mat: var(--primitive-mat-d);
  --semantic-bench: var(--primitive-bench-d);
  --semantic-surface-base: var(--primitive-mat-d);
  --semantic-surface-raised: var(--primitive-stock-d);
  --semantic-surface-sunken: var(--primitive-stock-sunk-d);
  --semantic-edge: var(--primitive-edge-d);
  --semantic-border-subtle: var(--primitive-rule-d);
  --semantic-border-strong: var(--primitive-rule-strong-d);
  --semantic-accent-base: var(--primitive-accent-d);
  --semantic-accent-hover: var(--primitive-accent-ink-d);
  --semantic-accent-pressed: var(--primitive-accent-ink-d);
  --semantic-accent-subtle: color-mix(in srgb, var(--primitive-accent-d) 18%, var(--primitive-stock-d));
  --semantic-accent-on-subtle: var(--primitive-accent-ink-d);
  --semantic-mark: var(--primitive-mark-d);
  --semantic-chalk: var(--primitive-chalk-d);
  --semantic-focus-ring: var(--primitive-edge-d);
  --semantic-ink-faint: var(--primitive-ink-faint-d);
  --semantic-ink-muted: var(--primitive-ink-muted-d);
  --semantic-ink-body: var(--primitive-ink-d);
  --color-paper-aged: var(--primitive-bench-d);
  --color-state-live: oklch(0.75 0.11 160);
  --color-diff-add: var(--primitive-diff-add-d);
  --color-diff-remove: var(--primitive-diff-remove-d);
  --color-canvas-bg: #141816;
  --color-mark: #dca05a;
  --color-chalk: #84b6d6;
  --color-ink: #f1f4f1;
  --color-ink-muted: #d8dfda;
  --color-rule: #3c4541;
  --color-scene-rule: #59645f;
  --color-tier-declared: #e9edea;
  --color-tier-structural: #6fbe8b;
  --color-tier-temporal: #dca05a;
  --color-tier-semantic: #84b6d6;
  --color-state-active: #dca05a;
  --color-state-complete: #6fbe8b;
  --color-state-archived: #88918b;
  --color-state-stale: #dcaf61;
  --color-state-broken: #e37f65;
  --color-status-provisional: #c0a877;
  --color-status-graded: #dcaf61;
  --color-status-tiered: #bdaf9d;
  --color-category-feature: #dca05a;
  --color-category-research: #84b6d6;
  --color-category-adr: #84b6d6;
  --color-category-plan: #6fbe8b;
  --color-category-exec: #dca05a;
  --color-category-audit: #84b6d6;
  --color-category-code: #dca05a;
  --color-category-reference: #84b6d6;
}
[data-theme="high-contrast"] {
  --semantic-surface-base: oklch(0.12 0.004 75);
  --semantic-surface-raised: oklch(0.18 0.006 75);
  --semantic-surface-sunken: oklch(0.07 0.003 75);
  --semantic-border-subtle: oklch(0.55 0.01 75);
  --semantic-border-strong: oklch(0.7 0.01 75);
  --semantic-accent-base: oklch(0.78 0.1 150);
  --semantic-accent-hover: oklch(0.85 0.1 150);
  --semantic-accent-pressed: oklch(0.7 0.1 150);
  --semantic-accent-subtle: oklch(0.2 0.05 150);
  --semantic-accent-on-subtle: oklch(0.92 0.08 150);
  --semantic-focus-ring: oklch(0.85 0.05 150);
  --semantic-ink-faint: oklch(0.72 0.008 75);
  --semantic-ink-muted: oklch(0.86 0.006 75);
  --semantic-ink-body: oklch(0.99 0 75);
  --color-paper-aged: oklch(0.16 0.01 75);
  --color-state-live: oklch(0.8 0.12 160);
  --color-diff-add: oklch(0.8 0.15 150);
  --color-diff-remove: oklch(0.7 0.17 28);
  --color-canvas-bg: #050403;
  --color-ink: #fefcf9;
  --color-ink-muted: #ddd8d2;
  --color-rule: #767069;
  --color-scene-rule: #8a847c;
  --color-tier-declared: #f7f5f1;
  --color-tier-structural: #63b376;
  --color-tier-temporal: #dacbb9;
  --color-tier-semantic: #7a6fb1;
  --color-state-active: #e89752;
  --color-state-complete: #63b376;
  --color-state-archived: #82807c;
  --color-state-stale: #e6bb5e;
  --color-state-broken: #ec8166;
  --color-status-provisional: #d2bd91;
  --color-status-graded: #e6bb5e;
  --color-status-tiered: #dacbb9;
  --color-category-feature: #e8c074;
  --color-category-research: #92c0e0;
  --color-category-adr: #c3b0e6;
  --color-category-plan: #79c596;
  --color-category-exec: #ecab7e;
  --color-category-audit: #8fd8e6;
  --color-category-code: #e69aa8;
  --color-category-reference: #d0a3c0;
}
/* ===========================================================================
   CHROME ALIAS RE-RESOLUTION — the var()-alias chrome tokens are declared on
   :root, so they resolve ONCE against :root's semantics and inherit that value.
   That makes container-scoped theming (data-theme on a card/section, not <html>)
   fall back to the root theme. Re-declaring the aliases inside each theme scope
   forces them to re-resolve against that scope's --semantic-* values, so a dark
   card on a light page themes correctly.

   The list has to be complete to make that true, and for a while it was not:
   mat, bench and edge are aliases on :root like the rest and were missing here,
   so those three - and only those three - kept the root theme's value inside a
   scoped container. Measured before the fix, a dark card on a light page
   resolved --color-edge to its light value, 3.30:1 against the mat, where the
   root-level dark theme gives 3.75:1. Edge is the one line token this system
   lets carry meaning, so it was the worst of the three to leave behind. Add
   any new chrome alias here as well as on :root.
   =========================================================================== */
[data-theme="light"],
[data-theme="dark"],
[data-theme="high-contrast"] {
  --color-mat: var(--semantic-mat);
  --color-bench: var(--semantic-bench);
  --color-edge: var(--semantic-edge);
  --color-paper: var(--semantic-surface-base);
  --color-paper-raised: var(--semantic-surface-raised);
  --color-paper-sunken: var(--semantic-surface-sunken);
  --color-ink-faint: var(--semantic-ink-faint);
  --color-rule-strong: var(--semantic-border-strong);
  --color-accent: var(--semantic-accent-base);
  --color-accent-hover: var(--semantic-accent-hover);
  --color-accent-pressed: var(--semantic-accent-pressed);
  --color-accent-subtle: var(--semantic-accent-subtle);
  --color-accent-text: var(--semantic-accent-on-subtle);
  --color-focus: var(--semantic-focus-ring);
}

/* ---- src/styles/tokens/shader-palette.generated.css ---- */
/* GENERATED by scripts/generate-shader-palette.mjs — do not edit by hand.
   Run `node scripts/generate-shader-palette.mjs` to regenerate.

   Hue is inherited from the brand anchors; chroma deliberately is not. Every
   swatch below was solved for a target WCAG ratio against its own theme's mat,
   so the animated fill in the hero word cannot drop below the large-text floor
   on any frame. Measured minimum across the family: 3.7:1.
   Mean chroma is 1.11x the shipped token layer's. */
:root {
  --shader-field-0: #2a8751;
  --shader-field-1: #0f7d59;
  --shader-field-2: #006852;
  --shader-field-3: #558250;
  --shader-field-4: #17564a;
  --shader-field-5: #516d3e;
  --shader-field-6: #004233;
  --shader-field-7: #4d8351;
  --shader-objects-0: #18884d;
  --shader-objects-1: #237553;
  --shader-objects-2: #2c5d4d;
  --shader-objects-3: #558154;
  --shader-objects-4: #526748;
  --shader-objects-5: #3b433e;
  --shader-objects-6: #00885c;
  --shader-objects-7: #3f5242;
  --shader-grayscale-0: #747875;
  --shader-grayscale-1: #686c69;
  --shader-grayscale-2: #545755;
  --shader-grayscale-3: #414342;
  --shader-grayscale-4: #737874;
  --shader-grayscale-5: #313331;
  --shader-grayscale-6: #5d615e;
  --shader-grayscale-7: #242624;
  --shader-register-0: #2a8751;
  --shader-register-1: #297251;
  --shader-register-2: #2b5b4b;
  --shader-register-3: #4b8352;
  --shader-register-4: #47643f;
  --shader-register-5: #5c7970;
  --shader-register-6: #0b3f2f;
  --shader-register-7: #3b4b3e;
}
[data-theme="light"] {
  --shader-field-0: #2a8751;
  --shader-field-1: #0f7d59;
  --shader-field-2: #006852;
  --shader-field-3: #558250;
  --shader-field-4: #17564a;
  --shader-field-5: #516d3e;
  --shader-field-6: #004233;
  --shader-field-7: #4d8351;
  --shader-objects-0: #18884d;
  --shader-objects-1: #237553;
  --shader-objects-2: #2c5d4d;
  --shader-objects-3: #558154;
  --shader-objects-4: #526748;
  --shader-objects-5: #3b433e;
  --shader-objects-6: #00885c;
  --shader-objects-7: #3f5242;
  --shader-grayscale-0: #747875;
  --shader-grayscale-1: #686c69;
  --shader-grayscale-2: #545755;
  --shader-grayscale-3: #414342;
  --shader-grayscale-4: #737874;
  --shader-grayscale-5: #313331;
  --shader-grayscale-6: #5d615e;
  --shader-grayscale-7: #242624;
  --shader-register-0: #2a8751;
  --shader-register-1: #297251;
  --shader-register-2: #2b5b4b;
  --shader-register-3: #4b8352;
  --shader-register-4: #47643f;
  --shader-register-5: #5c7970;
  --shader-register-6: #0b3f2f;
  --shader-register-7: #3b4b3e;
}
[data-theme="dark"] {
  --shader-field-0: #21814d;
  --shader-field-1: #248a66;
  --shader-field-2: #439f86;
  --shader-field-3: #4f7c4b;
  --shader-field-4: #71ada0;
  --shader-field-5: #6e8d5d;
  --shader-field-6: #89c9b5;
  --shader-field-7: #477e4c;
  --shader-objects-0: #068349;
  --shader-objects-1: #408f6d;
  --shader-objects-2: #70a290;
  --shader-objects-3: #4f7c50;
  --shader-objects-4: #798f6f;
  --shader-objects-5: #aab4ae;
  --shader-objects-6: #008259;
  --shader-objects-7: #90a694;
  --shader-grayscale-0: #6e736f;
  --shader-grayscale-1: #7b7f7c;
  --shader-grayscale-2: #939694;
  --shader-grayscale-3: #aeb0ae;
  --shader-grayscale-4: #6e736f;
  --shader-grayscale-5: #c4c7c5;
  --shader-grayscale-6: #878b88;
  --shader-grayscale-7: #d6d9d7;
  --shader-register-0: #21814d;
  --shader-register-1: #4a9270;
  --shader-register-2: #73a592;
  --shader-register-3: #457e4d;
  --shader-register-4: #789770;
  --shader-register-5: #5e7b73;
  --shader-register-6: #98cab6;
  --shader-register-7: #9bae9e;
}

/* ---- src/styles/tokens/typography.css ---- */
/* ============================================================================
   TYPOGRAPHY — Figma-binding type system.

   MARKETING ROLE SCALE (--ms-*) — the scale this site sets type on: display /
   h2 / h3 / lead / body / label / mono / rule-label. Each role pins size,
   line-height, weight and, where it matters, tracking. Archivo carries every
   text role; JetBrains Mono carries the mono role, where it is holding real
   code rather than dressing prose up as technical.

   This is a reading scale and it deliberately does NOT inherit the application
   chrome scale, which is tuned for dense panel UI: body copy there is 13px and
   metadata 10px, sizes that are correct beside a file tree and wrong under a
   headline. Body starts at 16px here.

   The 12px floor governs prose and interactive text, which is where a small size
   actually costs a reader something. It does not govern the ruler label: that
   role is uppercase and widely tracked at 11px by design, it carries a word or
   two rather than a sentence, and WCAG sets no minimum size at all, only a
   contrast threshold that it has to clear like everything else. Setting it to
   12px would break the mat language's smallest voice to satisfy a rule the
   guideline does not make.

   Prose starts at 16px. That sentence used to read "anything a visitor has to
   READ", which the file does not honour and should not: 118 tables carrying
   7365 words sit at --text-meta, 13px, as do captions, breadcrumbs, the pager
   labels and the footer. Those are scanned rather than read - a three-column
   `Flag / Type / Default` grid is looked up a row at a time, and 8.5% of the
   words between tables and paragraphs live there.

   The exemption is a decision, not an oversight, and it was measured before it
   was made: an audit set every table on the eight heaviest reference pages to
   16px and re-measured, and the count of tables that overflow their column on a
   phone rose by half again. A reader who has to swipe to reach the third column
   has lost the row, which costs more than the three pixels bought. Tabular data
   and furniture take --text-meta; anything set as sentences takes body.

   The --text-* names survive as aliases onto this scale because landing and documentation
   styles still read them. They are a migration surface, not a second system:
   retire each one with its last consumer.

   Data-bearing numerics (timestamps, counts, ahead/behind, tiers) take tabular
   figures — the `tabular-nums` helper below, or set font-variant-numeric.
   ========================================================================== */
:root {
  /* Font families. Archivo carries display and text alike; its width axis draws
     the condensed ruler labels, so --font-display and --font-sans are the same
     stack differing only in how they are set. */
  --font-sans: Archivo, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: var(--font-sans);
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;

  --weight-action: 560;
  --weight-emphasis: 560;

  /* Marketing role scale — size / line-height / weight / tracking.
     A reading scale, not a chrome scale. Every role a visitor reads as prose
     starts at 16px; only the tracked uppercase ruler label sits below 12px, for
     the reason given in the header. Display and h2 fluidly clamp so the headline
     is a headline on a phone as well as a desktop. */
  /* These are the headline's real values, not a nominal scale it then argued
     with. The role and its one consumer disagreed: the hero restated all four
     in its own stylesheet, so the token said 2.75rem-4.5rem at 0.98/-0.032em
     and nothing on the site ever rendered that. The ladder now reads the way
     the page does.

     The second clamp is the same role below the width where the first strands
     a word; it is a breakpoint of the role, so it lives with the role. */
  --ms-display: clamp(3.7rem, 5vw, 4.25rem);
  --ms-display-tight: clamp(2.65rem, 12vw, 3.7rem);
  --ms-display-line-height: 1.025;
  --ms-display-weight: 640;
  --ms-display-tracking: -0.055em;

  /* The 1.75rem floor is deliberate and load-bearing on small screens. At 2rem it
     sat within 2px of the H1's own mobile floor, so headline and section titles
     rendered at effectively the same size and nothing said which claim was the
     page's main one. Lowering the floor restores the ratio where the viewport is
     tightest; the ceiling is untouched. */
  --ms-h2: clamp(1.75rem, 3.6vw, 3rem);
  --ms-h2-line-height: 1.05;
  --ms-h2-weight: 620;
  --ms-h2-tracking: -0.026em;

  --ms-h3: 1.375rem;                /* 22px */
  --ms-h3-line-height: 1.22;
  --ms-h3-weight: 600;
  --ms-h3-tracking: -0.016em;

  --ms-lead: clamp(1.0625rem, 1.35vw, 1.25rem);
  --ms-lead-line-height: 1.55;
  --ms-lead-weight: 400;

  --ms-body: 1rem;                  /* 16px */
  --ms-body-line-height: 1.6;
  --ms-body-weight: 400;
  --ms-measure: 68ch;               /* the line length body copy is set to */

  /* The same measure, in a unit that survives being applied to something that
     is not body text. `ch` is font-relative, so 68ch on a 28px heading is
     1095px and on a 48px title is 1890px - capping a heading with --ms-measure
     is a silent no-op, which is how section rules came to overhang the
     paragraphs they head. Any element that must align to the width of body
     prose while being set at another size takes this instead. Keep the two in
     step: this is 68ch at the 16px body size.

     The value is measured, not estimated. `ch` is the advance of `0`, and
     Archivo ships here as a variable font whose default instance is wght 600,
     so the number depends on weight as well as size: 0.5730em at the body's
     400, 0.5750em at 600. Body prose is 400, which puts 68ch at 623.42px.

     It read 36.75rem - 588px - for long enough to invert the very defect this
     token exists to fix. Headings cap here while paragraphs cap at --ms-measure,
     so instead of overhanging by a fifth of the column, the rule under every h2
     stopped 35.42px short of the paragraph beneath it. Both halves of the pair
     now resolve to the same width. */
  --ms-measure-block: 38.964rem;

  --ms-label: 0.8125rem;            /* 13px */
  --ms-label-line-height: 1.3;
  --ms-label-weight: var(--weight-action);
  --ms-label-tracking: 0.012em;

  --ms-mono: 0.8125rem;             /* 13px */
  --ms-mono-line-height: 1.5;
  --ms-mono-weight: 400;

  /* The ruler label: the condensed voice the mat language needs, drawn from
     Archivo's width axis rather than from a second family. */
  --ms-rule-label: 0.6875rem;       /* 11px, and uppercase — a label, not prose */
  --ms-rule-label-line-height: 1.4;
  --ms-rule-label-weight: 560;
  --ms-rule-label-tracking: 0.09em;
  --ms-rule-label-width: 78;

  /* --- Documentation role scale (--doc-*) -------------------------------
     A reference page is a different typographic problem from a landing page
     and needs its own ladder, not the marketing ladder read at an offset.
     The landing page has one headline and six section titles; a command
     reference has one title and forty-three sections, nested three deep, with
     no room anywhere for display type.

     Until now that ladder existed only as a set of choices scattered through
     the theme's selectors: the page title borrowed --ms-h2, the section
     heading was a clamp() invented at the point of use, the subsection
     borrowed --ms-lead (a body role), and the label borrowed --ms-body. One
     scale, two ladders, and the documentation's own one written nowhere.

     Naming the four roles here did not change what rendered - the values were
     exactly what the selectors resolved to - but it put the reading ladder in
     the token layer where it can be tuned as a ladder, in one place, instead
     of four selectors that have to be kept in agreement by hand. The
     subsection role has since been tuned here, which is the whole point of
     the move: see its own note below. */
  /* The masthead title, used on the documentation front page and nowhere else.
     Not --ms-display: that role is sized for a landing page whose headline owns
     the full container, and it clamps to 4.5rem. Here the title sits in a reading
     column beside two rails, so the ceiling comes down to keep the line from
     stranding a word - the same correction the landing page makes to its own
     H1, for the same reason, at a different width. */
  --doc-display: clamp(2.5rem, 4.2vw, 3.75rem);
  --doc-display-line-height: 1.02;
  --doc-display-weight: var(--ms-display-weight);
  /* Held at its own value rather than borrowed. The marketing headline's
     tracking is drawn for a line of four words at 68px; a masthead set in a
     reading column beside two rails is a different line, and following the
     other surface's number here would be inheriting a decision nobody made
     about this one. */
  --doc-display-tracking: -0.032em;

  /* The title carries its own clamp rather than borrowing --ms-h2's. On the
     marketing page --ms-h2 is a SECTION role and floors at 1.75rem so it does
     not collide with the H1 above it; used here as a PAGE TITLE that floor put
     the title at 28px against a 22px section heading, a ratio of 1.27 on a
     phone where the same ladder is 1.71 on a desktop. The ladder changed shape
     with the window, which is the defect the section role's own floor exists to
     prevent - inherited here as the thing it was written to avoid. */
  --doc-h1: clamp(2.125rem, 4.6vw, 3rem);
  --doc-h1-line-height: var(--ms-h2-line-height);
  --doc-h1-weight: var(--ms-h2-weight);
  --doc-h1-tracking: var(--ms-h2-tracking);

  /* Fluid, because the title above it is. --ms-h3 is a flat 1.375rem while the
     title clamps from 1.75rem to 3rem, so a fixed section size made the gap
     between them 1.27x on a phone and 2.18x on a wide screen - the ladder
     changed shape with the window while nothing else in the scale did. The
     floor stays on the token so nothing shrinks on a small viewport. */
  --doc-h2: clamp(var(--ms-h3), 2.2vw, 1.75rem);
  --doc-h2-line-height: var(--ms-h3-line-height);
  --doc-h2-weight: var(--ms-h3-weight);
  --doc-h2-tracking: var(--ms-h3-tracking);

  /* The section role above got a floor so the ladder would not change shape
     with the window. This one never did, and it borrowed --ms-lead, which is a
     body role: 1.0625rem at the bottom of its clamp. That put the subsection
     at 17px against a 16px paragraph on a phone - a 1.06 step, where the same
     pair is 1.215 on a wide screen. Three of the five outline levels landed
     inside 1.06x of each other, on the pages that lean hardest on h3 to carve
     up a long reference.

     Its own clamp now, with the floor raised to the point where the phone step
     matches the desktop one. The upper half is unchanged, so nothing moves
     above 1400px or so; only the small viewport lifts. */
  --doc-h3: clamp(1.1875rem, 1.35vw, 1.25rem);
  --doc-h3-line-height: var(--ms-h3-line-height);
  --doc-h3-weight: var(--ms-label-weight);
  --doc-h3-tracking: var(--ms-h3-tracking);

  /* A label, not a slightly larger paragraph. It sits at body size and earns
     its place by weight, tracking and case instead of by size - which is what
     stops a fourth level from competing with the third. */
  --doc-h4: var(--ms-body);
  --doc-h4-line-height: var(--ms-h3-line-height);
  --doc-h4-weight: var(--text-body-strong-weight);
  --doc-h4-tracking: var(--ms-rule-label-tracking);

  /* A fifth level exists in the source and was never in this scale, so it fell
     to the user agent: 13.28px bold, smaller than the 16px body beneath it.
     That was the only inverted step in the ladder - every other level is larger
     than what it heads - and it sat on the harness reference, where all seven of
     them are.

     It cannot earn its place by size, because the level above it is already at
     body size. It takes the same descent h4 uses and spends one channel less:
     h4 is uppercase, tracked and muted, h5 is muted weight alone. Loud label,
     quiet label, prose. */
  --doc-h5: var(--ms-body);
  --doc-h5-line-height: var(--ms-h3-line-height);
  --doc-h5-weight: var(--text-body-strong-weight);

  /* Compatibility aliases. The old names are the dashboard chrome scale and are
     still read across the landing styles; they now resolve onto the marketing
     scale above so no surface renders 13px body copy or 10px interactive text.
     Retire each alias with its last consumer rather than renaming in place. */
  --text-display: var(--ms-h3);
  --text-display-line-height: var(--ms-h3-line-height);
  --text-display-weight: var(--ms-h3-weight);

  --text-title: var(--ms-h3);
  --text-title-line-height: var(--ms-h3-line-height);
  --text-title-weight: var(--ms-h3-weight);

  --text-body: var(--ms-body);
  --text-body-line-height: var(--ms-body-line-height);
  --text-body-weight: var(--ms-body-weight);

  --text-body-strong: var(--ms-body);
  --text-body-strong-line-height: var(--ms-body-line-height);
  --text-body-strong-weight: var(--weight-emphasis);

  --text-label: var(--ms-label);
  --text-label-line-height: var(--ms-label-line-height);
  --text-label-weight: var(--ms-label-weight);

  --text-meta: var(--ms-label);
  --text-meta-line-height: var(--ms-label-line-height);
  --text-meta-weight: var(--ms-body-weight);

  --text-caption: 0.75rem;          /* 12px: the floor for anything read as prose */
  --text-caption-line-height: 1.35;
  --text-caption-weight: var(--ms-body-weight);

  --text-mono: var(--ms-mono);
  --text-mono-line-height: var(--ms-mono-line-height);
  --text-mono-weight: var(--ms-mono-weight);
}

/* ---- src/styles/tokens/spacing.css ---- */
/* ============================================================================
   SPACING — 4-base scale. The name is the step in quarter-rems, so --space-6 is
   24px at a 16px root. The dashboard's airy, well-padded rhythm comes from
   sticking to these steps.

   The scale used to stop at --space-8 (32px), which was the right ceiling for
   panel chrome and the wrong one for a reading surface. Every gap a page needed
   above 32px was therefore written as a literal or a calc() at the point of use
   — the documentation theme's section gap was `calc(var(--space-8) +
   var(--space-4))` for exactly this reason — so the largest and most visible
   intervals on the page were the only ones not on the scale. The steps above
   continue the same 4-base progression and end that.

   Below the fixed steps are four fluid ones. Section-scale intervals cannot be
   a single value: the gap that gives a desktop page its air is a gap that wastes
   half a phone screen. These four carry the landing page's measured clamps, so
   both surfaces breathe on the same rhythm rather than each inventing one.
   ========================================================================== */
:root {
  --space-0-5: 0.125rem; /* 2px */
  --space-1: 0.25rem;    /* 4px — base step */
  --space-1-5: 0.375rem; /* 6px */
  --space-2: 0.5rem;     /* 8px */
  --space-3: 0.75rem;    /* 12px */
  --space-4: 1rem;       /* 16px */
  --space-5: 1.25rem;    /* 20px */
  --space-6: 1.5rem;     /* 24px */
  --space-8: 2rem;       /* 32px */
  --space-10: 2.5rem;    /* 40px */
  --space-12: 3rem;      /* 48px */
  --space-16: 4rem;      /* 64px */
  --space-20: 5rem;      /* 80px */
  --space-24: 6rem;      /* 96px */
  --space-32: 8rem;      /* 128px */

  /* Fluid section steps. Each is a floor a phone can afford, a ceiling a wide
     screen earns, and a viewport term between them. */
  --space-fluid-sm: clamp(1.75rem, 3vw, 2.5rem);
  --space-fluid-md: clamp(2.5rem, 5vw, 4rem);
  --space-fluid-lg: clamp(3.5rem, 7vw, 5.5rem);
  --space-fluid-xl: clamp(5rem, 9vw, 10rem);
}

/* ---- src/styles/tokens/radius.css ---- */
/* ============================================================================
   RADIUS — Figma-binding corner scale. Soft, rounded corners are core to the
   warm Vaultspec feel: xs4 (chips, small controls) · sm5 (buttons, inputs) ·
   md7 (panels, cards) · lg10 (dialogs, popovers) · pill18 (fully-rounded pills).
   ========================================================================== */
:root {
  --radius-cut: 0;
  --radius-xs: 0.25rem;     /* 4px */
  --radius-sm: 0.3125rem;   /* 5px */
  --radius-md: 0.4375rem;   /* 7px */
  --radius-lg: 0.625rem;    /* 10px */
  --radius-pill: 1.125rem;  /* 18px */
}

/* ---- src/styles/tokens/border.css ---- */
/* ============================================================================
   BORDER — line weights, and the focus ring drawn from them. The sibling of
   radius.css: that file says how a corner turns, this one says how heavy the
   line making it is.

   Three weights, and they mean different things rather than being a ramp:

     hairline    - the seam. A cut edge where stock abuts stock, and the weight
                   of every decorative rule on both surfaces.
     thick       - a line the reader is meant to notice: the focus ring, and
                   borders that carry a state rather than a boundary.
     accent-edge - the marker down the side of a called-out block. Wide enough
                   to read as a deliberate mark at a glance, which a hairline in
                   the same colour does not.

   The hairline was already uniform at 0.0625rem across both stylesheets - the
   relative-units gate settled that argument - but it was uniform by repetition,
   stated thirty-odd times in the documentation theme alone. A weight repeated
   is a weight that can be changed in thirty places minus one.

   The focus ring is accent, not edge. Both were in use; the edge token measures
   exactly 3.00:1 on the sunken ground in light and 3.30:1 against the mat the
   article sits on, so on its better ground it still meets the non-text minimum
   with little to spare. Accent measures 4.76:1 and 5.23:1 on those same two
   grounds, and 8.03:1 against the mat in dark. A ring that only just qualifies
   is not a ring anyone argued for, it is one nobody re-measured.

   Naming both grounds is the correction: this passage used to quote the two
   light figures as measured "against the page" when they were the sunken
   ground, while the dark figure beside them was the mat. One sentence, two
   grounds, and no way for a reader to tell which.
   ========================================================================== */
:root {
  --border-hairline: 0.0625rem;
  --border-thick: 0.125rem;
  --border-accent-edge: 0.1875rem;

  --focus-ring-width: var(--border-thick);
  --focus-ring-offset: var(--border-thick);
  --focus-ring-color: var(--color-accent);
}

/* ---- src/styles/tokens/elevation.css ---- */
/* ============================================================================
   ELEVATION & MOTION.

   Elevation — the system is FLAT: no drop shadows. Surfaces separate through
   ground color and hairline rules, never through cast shadows. The three
   elevation tokens are kept so components can keep declaring intent (raised /
   overlay / popover), but they resolve to none; the high-contrast theme remaps
   them to a 1px ring, which is a border substitute rather than a shadow.

   Motion — fast, subtle, state-communicating. Keyboard-initiated actions never
   animate (--duration-ui-instant). Easing: settle (entrances), snap (state).
   ========================================================================== */
:root {
  --shadow-raised: none;
  --shadow-overlay: none;
  --shadow-popover: none;

  /* Motion */
  --ease-settle: cubic-bezier(0.22, 1, 0.36, 1); /* @kind other */
  --ease-snap: cubic-bezier(0.4, 0, 0.2, 1); /* @kind other */
  --duration-ui-instant: 0ms; /* @kind other */
  --duration-ui-fast: 150ms; /* @kind other */
  --duration-ui: 200ms; /* @kind other */
  --duration-ui-slow: 250ms; /* @kind other */
}
[data-theme="dark"] {
  --shadow-raised: none;
  --shadow-overlay: none;
  --shadow-popover: none;
}
[data-theme="high-contrast"] {
  --shadow-raised: 0 0 0 0.0625rem oklch(0.7 0.01 75);
  --shadow-overlay: 0 0 0 0.0625rem oklch(0.7 0.01 75);
  --shadow-popover: 0 0 0 0.0625rem oklch(0.7 0.01 75);
}

/* ---- src/styles/tokens/layout.css ---- */
/* ============================================================================
   LAYOUT — the container geometry, as tokens rather than as a number repeated
   in every stylesheet that has to line up with it.

   Two surfaces read these. The landing page sets its content column here; the
   documentation shell overrides --container-width for its own wider reading
   frame. The mat's grid origin is derived from the same two values (see
   mat.css), which is what makes a printed line register with the content edge
   instead of drifting against it — on either surface, without either one
   restating the other's arithmetic.

   The padding narrows on a phone. It is expressed here, once, so the container
   and the grid that has to align to it can never disagree about where the
   content edge is; before this was a token they disagreed below 40rem, the
   container at 1.25rem and the grid still originating at 2rem.
   ========================================================================== */
:root {
  /* Persistent product chrome is one height on the landing and docs surfaces. */
  --chrome-header-height: 3.75rem;
  --container-width: 75rem;
  --container-pad: 2rem;
}
@media (max-width: 40rem) {
  :root {
    --container-pad: 1.25rem;
  }
}

/* ---- src/styles/tokens/mat.css ---- */
/* Shared grid geometry, ink and stock shadows. */
:root {
  --acrylic-blur: var(--space-1);
  --acrylic-opacity: 88%;
  --grid-fine: 0.5rem;
  --grid-coarse: 2.5rem;
  --grid-major: 12.5rem;
  --grid-f-ink: color-mix(in srgb, var(--color-ink) 2%, transparent);
  --grid-c-ink: color-mix(in srgb, var(--color-ink) 4%, transparent);
  --grid-m-ink: color-mix(in srgb, var(--color-ink) 7%, transparent);
}
[data-theme="dark"] {
  /* Keep the grid close to the dark ground so reading ink stays dominant. */
  --grid-f-ink: color-mix(in srgb, var(--color-ink) 2.5%, transparent);
  --grid-c-ink: color-mix(in srgb, var(--color-ink) 5%, transparent);
  --grid-m-ink: color-mix(in srgb, var(--color-ink) 8%, transparent);
}
:root {
  /* Cast shadows keep a dark pigment in every theme. Deriving them from ink
     turns them into pale glows as soon as a dark theme remaps ink to white. */
  --stock-contact: 0 0.0625rem 0.125rem rgb(20 42 33 / 10%);
  --stock-contact-stack: 0 0.125rem 0.3125rem rgb(20 42 33 / 13%);
  /* Stock lifted clear of the surface rather than resting on it: a wide soft
     cast for the height, and a tight one under the edge so the sheet still
     reads as having a thickness. Both carry an offset; a blurred halo at zero
     offset is a glow, not a shadow. */
  --stock-lift: 0 1.375rem 2.75rem -0.75rem rgb(20 42 33 / 34%),
    0 0.25rem 0.625rem -0.25rem rgb(20 42 33 / 20%);
  --stock-contact-plate: 0 0.25rem 0.75rem rgb(20 42 33 / 15%);
}
[data-theme="dark"] {
  /* Deeper and cooler: on a dark mat a shadow reads by depth, not by darkness. */
  --stock-contact: 0 0.0625rem 0.1875rem rgb(0 0 0 / 45%);
  --stock-contact-stack: 0 0.1875rem 0.4375rem rgb(0 0 0 / 50%);
  --stock-lift: 0 1.5rem 3rem -0.75rem rgb(0 0 0 / 66%), 0 0.375rem 0.875rem -0.375rem rgb(0 0 0 / 52%);
  --stock-contact-plate: 0 0.375rem 1rem rgb(0 0 0 / 55%);
}

/* ---- src/styles/tokens/interaction.css ---- */
/* Action roles and interaction states shared by the site and documentation. */
:root {
  --interaction-radius: var(--radius-sm);
  --interaction-edge-width: var(--border-hairline);
  --interaction-ink: var(--color-ink);
  --interaction-ground-hover: var(--color-paper-raised);
  --interaction-ground-pressed: var(--color-paper-sunken);
  --interaction-edge: var(--color-edge);
  --interaction-weight: var(--weight-action);
  --interaction-height: 2.5rem;
  --interaction-pad-y: 0.5rem;
  --interaction-pad-x: 0.875rem;
  --interaction-font-size: 0.875rem;
  --interaction-line-height: 1.25rem;

  --action-primary-ground: var(--color-accent);
  --action-primary-ground-hover: var(--color-accent-hover);
  --action-primary-ground-pressed: var(--color-accent-pressed);
  --action-primary-ink: var(--color-paper-raised);
  --action-secondary-ground: var(--color-paper-raised);
  --action-secondary-ground-hover: var(--color-paper-sunken);
  --action-secondary-ink: var(--color-ink);

  --selection-ground: color-mix(in srgb, var(--color-accent) 18%, var(--color-paper-raised));
  --selection-ground-hover: color-mix(in srgb, var(--color-accent) 22%, var(--color-paper-raised));
  --selection-ground-pressed: color-mix(in srgb, var(--color-accent) 26%, var(--color-paper-raised));
  /* An edge that is the accent without being a selection: it marks a control
     as belonging to the accented family while it is at rest, and leaves the
     full-strength edge below to mean chosen. */
  --interaction-edge-accent: color-mix(in srgb, var(--color-accent) 24%, transparent);
  --selection-edge: var(--color-accent);
  --selection-ink: var(--color-accent-text);

  --interaction-disabled-ground: var(--color-paper-sunken);
  --interaction-disabled-edge: var(--color-rule);
  --interaction-disabled-ink: var(--color-ink-faint);
  --interaction-error-ground: var(--color-paper-raised);
  --interaction-error-ink: var(--color-state-broken);
}
/* Dark controls need their own composed surfaces. A brighter label alone
   leaves secondary and quiet actions floating on the mat; the raised ground
   and stronger edge keep their boundaries readable before hover as well. */
[data-theme="dark"] {
  --interaction-ink: #f7faf7;
  --interaction-ground-hover: #2a312e;
  --interaction-ground-pressed: #333c38;
  --action-primary-ground: #2e6b45;
  --action-primary-ground-hover: #347a4f;
  --action-primary-ground-pressed: #245638;
  --action-primary-ink: #f7faf7;
  --action-secondary-ground: #262d2a;
  --action-secondary-ground-hover: #303936;
  --action-secondary-ink: #f7faf7;
}
/* Coarse pointers trade a little density for thumb tolerance. Desktop keeps
   the compact 40px system; touch-first devices receive the 44px floor without
   each surface inventing its own mobile control size. */
@media (pointer: coarse) {
  :root { --interaction-height: 2.75rem; }
}
