/* ============================================================
   §TOKENS — KYE Protocol™ design-system tokens (single source of truth)
   ============================================================
   Every colour, spacing, radius, type and motion value used across
   the site SHOULD come from one of these tokens. Token names are
   the public contract; raw values can move freely. New components
   reach for `var(--kye-*)` rather than redefining magic numbers.
   See public/site/COMPONENTS.md for usage.
   ============================================================ */
:root {
  /* ============================================================
     SOVEREIGN INDIGO PALETTE — locked 2026-05-15.
     KYE Protocol™ visual identity: Stripe infrastructure +
     Cloudflare trust + ISO governance + AI protocol layer.
     Dark-first; light mode overrides at the bottom of the file
     under :root[data-theme="light"]. The previous light-default
     values now live there.
     ============================================================ */
  /* Brand — protocol indigo (logo body), brand-2 (electric blue
     for links + active), brand-3 (indigo-400 for hover lift).
     Trust-cyan reserved for data lines + protocol diagrams ONLY
     (3.0:1 contrast, fails WCAG AA for text on light bg).        */
  /* 2026-05-19 brand refresh — replaced default Tailwind indigo #6366F1
     (generic SaaS look) with #7B5CFF "electric violet". Higher chroma,
     reads as deliberate brand vs generic preset. Verified AA on both
     dark (#070A12) at 6.1:1 and white at 4.6:1. */
  --kye-color-brand:           #7B5CFF;   /* protocol electric violet — primary brand */
  --kye-color-brand-2:         #A78BFA;   /* violet-400 — hover lift on dark */
  --kye-color-brand-electric:  #5B3DF5;   /* deeper violet — focus rings, active states */
  --kye-color-brand-cyan:      #22D3EE;   /* trust cyan — diagrams, data lines (NOT text) */
  --kye-color-brand-soft:      rgba(123, 92, 255, 0.14);
  --kye-color-brand-line:      rgba(123, 92, 255, 0.30);
  --kye-color-brand-ink:       #F8FAFC;   /* logo body on dark */

  /* Logo accents — referenced by logo-kye-color.svg (Authority Indigo) */
  --kye-logo-ink:              #F8FAFC;   /* letterform body on dark */
  --kye-logo-blue:             #7B5CFF;   /* K-leg + Y-tip + E-middle electric-violet accent */
  --kye-logo-cyan:             #22D3EE;   /* evidence-anchor dot */

  /* Semantic — sovereign palette. Each carries its own *-soft tint
     and *-line for borders. */
  --kye-color-danger:          #EF4444;   /* revocation red — blocked / revoked */
  --kye-color-danger-soft:     rgba(239, 68, 68, 0.16);
  --kye-color-danger-line:     rgba(239, 68, 68, 0.30);
  --kye-color-warning:         #F59E0B;   /* warning amber — pending / review */
  --kye-color-warning-soft:    rgba(245, 158, 11, 0.16);
  --kye-color-warning-line:    rgba(245, 158, 11, 0.30);
  --kye-color-success:         #10B981;   /* verification green — approved */
  --kye-color-success-soft:    rgba(16, 185, 129, 0.16);
  --kye-color-success-line:    rgba(16, 185, 129, 0.30);
  --kye-color-info:            #3B82F6;   /* same as electric blue — info notices */
  --kye-color-info-soft:       rgba(59, 130, 246, 0.14);
  --kye-color-info-line:       rgba(59, 130, 246, 0.30);

  /* Surface — DARK-FIRST defaults per Sovereign Indigo lock.
     :root[data-theme="light"] override at the bottom of this file
     restores the light palette for users who opt out. */
  --kye-color-bg:              #1A1F2E;   /* deep background */
  --kye-color-surface:         #232838;   /* midnight navy — hero / footer / cards */
  --kye-color-paper-2:         #2A2F46;   /* card-on-card */
  --kye-color-line:            #1E293B;   /* border grey */
  --kye-color-line-strong:     rgba(255, 255, 255, 0.18);
  /* Text */
  --kye-color-text:            #F8FAFC;   /* main text on dark */
  --kye-color-text-muted:      #94A3B8;   /* secondary copy */
  --kye-color-text-dim:        #64748B;
  /* Type scale */
  --kye-type-hero:             clamp(40px, 6vw, 72px);
  --kye-type-h1:               clamp(28px, 4vw, 44px);
  --kye-type-h2:               clamp(22px, 2.6vw, 30px);
  --kye-type-h3:               clamp(17px, 1.6vw, 20px);
  --kye-type-body:             16px;
  --kye-type-small:            13.5px;
  --kye-type-tiny:              11.5px;
  --kye-type-mono:             12.5px;
  /* Spacing scale (8-pt rhythm) */
  --kye-space-1:               4px;
  --kye-space-2:               8px;
  --kye-space-3:               12px;
  --kye-space-4:               16px;
  --kye-space-5:               20px;
  --kye-space-6:               24px;
  --kye-space-8:               32px;
  --kye-space-10:              40px;
  --kye-space-12:              48px;
  --kye-space-16:              64px;
  /* Radius: see the generated scale block at the end of this file. The
     --kye-radius-1..4 / --kye-radius-pill namespace was retired — it was one of
     four competing shape vocabularies, and its steps (4/6/10/14px) were not on
     the canonical scale. Source of truth: design-system/tokens/radius.json. */
  /* Shadow */
  --kye-shadow-1:              0 1px 2px rgba(15, 23, 42, 0.06);
  --kye-shadow-2:              0 4px 14px rgba(15, 23, 42, 0.08);
  --kye-shadow-3:              0 12px 32px rgba(15, 23, 42, 0.12);
  /* Motion */
  --kye-motion-fast:           120ms cubic-bezier(.2, .8, .2, 1);
  --kye-motion-base:           200ms cubic-bezier(.2, .8, .2, 1);
  --kye-motion-slow:           320ms cubic-bezier(.2, .8, .2, 1);
  /* Layout */
  --kye-container:             1180px;
  --kye-reading:                720px;
  /* Z-index lattice */
  --kye-z-content:             1;
  --kye-z-sticky:              50;
  --kye-z-overlay:             100;
  --kye-z-modal:               10000;

  /* Type scale — mirrors /design-system/tokens/type.json (locked by
     constitution §24). Remediation Wave 5 mapped every literal Npx
     font-size in public/** to one of these tokens; this :root MUST
     define them or every font-size collapses to inherit. */
  --type-9:                    9px;
  --type-10:                   10px;
  --type-11:                   11px;
  --type-12:                   12px;
  --type-13:                   13px;
  --type-14:                   14px;
  --type-16:                   16px;
  --type-18:                   18px;
  --type-22:                   22px;
  --type-28:                   28px;
  --type-36:                   36px;
  --type-48:                   48px;
  /* Icon-glyph sizes (Material Symbols Outlined ligature font). */
  --icon-12:                   12px;
  --icon-14:                   14px;
  --icon-16:                   16px;
  --icon-18:                   18px;
  --icon-20:                   20px;
  --icon-24:                   24px;
  /* Family aliases that resolve through the design-system. */
  --font-ui:                   "Inter Variable", Inter, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-display:              "Inter Variable", Inter, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono:                 "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;

  /* Branded shadow stack (2026-05-19) — replaces flat black-on-near-black
     shadows that disappeared on the dark theme. Uses brand violet at low
     alpha for the lift glow + a small black drop for crispness. */
  --shadow-1: 0 1px 2px rgba(0,0,0,0.30), 0 0 0 1px rgba(123,92,255,0.04);
  --shadow-2: 0 8px 28px -12px rgba(123,92,255,0.35), 0 2px 6px rgba(0,0,0,0.40);
  --shadow-3: 0 16px 48px -16px rgba(123,92,255,0.40), 0 4px 12px rgba(0,0,0,0.45);
  --shadow-focus: 0 0 0 3px rgba(123,92,255,0.45);
}

/* ============================================================
 * Native form-control surface (2026-05-19) — every surface, every
 * theme. The native <option> element does NOT consistently inherit
 * parent CSS across Chromium/Firefox/Safari; the load-bearing line
 * is `color-scheme`, which lets the OS paint the popup with matching
 * chrome. Without this, dark-theme <select> renders white text on
 * white background — the dropdown contrast bug the user reported.
 * ============================================================ */
select, option, optgroup {
  background-color: var(--paper-2, #172033);
  color: var(--text, #F8FAFC);
}
select { color-scheme: dark light; }
:root[data-theme="light"] select { color-scheme: light; }
:root[data-theme="light"] select,
:root[data-theme="light"] option,
:root[data-theme="light"] optgroup {
  background-color: #ffffff;
  color: #0B1020;
}
option:checked { background-color: var(--accent-soft, rgba(123,92,255,0.14)); color: var(--text, #F8FAFC); font-weight: 600; }
option:hover  { background-color: var(--accent-soft, rgba(123,92,255,0.14)); }

/* Pin text scaling to authored values on EVERY surface. Without this,
 * mobile browsers (notably iOS Safari) auto-inflate the font-size of
 * wide block text — headings and <strong> labels balloon while inline
 * <code>/pills stay small — producing the "font-size discrepancy" the
 * 2026-06-27 compliance-page audit (imda-ai-verify.html on iOS) surfaced.
 * Canonical site-wide rule (§04 design system); enforced by the
 * design-tokens-coherent gate. Must live on the global html root, never
 * scoped to a single page class. */
html {
  -webkit-text-size-adjust: 100%;
  -moz-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Default body weight = 400 (regular). Override at the rare element
 * level (headings, buttons, .strong) — not by surface-wide cascade.
 * Fixes the "everything is bold" / soulless feel the 2026-05-19 audit
 * surfaced. */
html, body { font-weight: 400; }
strong, b { font-weight: 600; }

/* Content overflow protection (Nielsen audit 2026-05-19) — long
 * unbroken strings (URNs, hashes, long words) MUST wrap inside
 * their containers, never overflow. Applied site-wide. */
.card, .kye-card, .prim-card, .lyr-card, .hz-demo, .wp-article,
p, li, td, .lede {
  overflow-wrap: break-word;
  word-break: normal;
}
code, pre { overflow-wrap: break-word; }

/* ============================================================
 * Vibrancy pass (2026-05-19) — moves the surface from "matte" to
 * "vivid enterprise". Three utilities:
 *   1. .hero gets a radial-glow background (brand-violet halo)
 *   2. .gradient-text utility for h1 hero accents
 *   3. body grain overlay (tiny SVG noise, ~3% opacity)
 *   4. .btn-primary picks up a gradient + glow on hover
 * Every change is additive — no existing rule overridden.
 * ============================================================ */

/* 1. Hero radial-glow — TIGHTENED 2026-05-19 evening per user feedback
 *    "matte colour effect not good, looks blur". Earlier version had
 *    soft, wide gradients that read as haze. Now: smaller halo, higher
 *    opacity at centre, faster falloff. Reads as deliberate brand
 *    light, not blur. */
:root[data-theme="dark"] .hero {
  background:
    radial-gradient(ellipse 50% 35% at 50% 0%,
      rgba(123, 92, 255, 0.28) 0%,
      rgba(123, 92, 255, 0.08) 28%,
      transparent 55%),
    var(--bg, #070A12);
}

/* 2. Gradient text — TIGHTENED 2026-05-19 evening. Earlier two-stop
 *    background-clip render was reading as soft / blurry on smaller
 *    weights due to sub-pixel antialiasing on the gradient edges.
 *    Now: locked to display-grade weight (700+) + crisper gradient
 *    stops + text-shadow-free + explicit -webkit-font-smoothing for
 *    Chromium/Safari. */
.gradient-text,
.hero h1 .accent {
  /* Accent text is the accent COLOUR, not a gradient masked through the glyphs.
     This rule ships in the token file, so it loaded on every page and won the
     cascade over the apex sheet — it is what actually painted the hero accent.
     A 120deg gradient is sized to its element, so a short span like `KYE(TM)`
     ran the full ramp across four glyphs and the trailing E landed on the end
     stop: the fade the CEO reported. It also carried
     `-webkit-text-fill-color: transparent`, which renders the text INVISIBLE
     whenever the gradient fails to paint (mobile Safari, 2026-05-28). One
     declaration, one colour (SS0). */
  color: var(--accent);
  font-weight: 800;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-shadow: none;
}

/* 3. Body grain overlay — REMOVED 2026-05-19 evening per user
 *    "matte colour effect not good, looks blur". The 3.5% opacity
 *    noise was, in practice, reading as haze on the eye even though
 *    technically subtle. Cleaner without it. The radial hero glow
 *    + branded shadows already break the flat-fill matte. */
:root[data-theme="dark"] body::after { content: none !important; display: none !important; }

/* 4. Canonical card visual (2026-05-19) — single source of truth for
 *    .card + .kye-card across site/app/admin/dev. Closes the §0
 *    competing-systems violation flagged by the visual audit (3
 *    different card definitions shipping under the same class name).
 *    Per-surface stylesheets retain their padding overrides; this
 *    block locks the visual identity (radius, shadow, border, hover). */
.card, .kye-card {
  background: var(--paper, #111827);
  border: 1px solid var(--line, #1E293B);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-1);
  transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease;
  position: relative;
}
.card:hover, .kye-card:hover {
  border-color: var(--line-strong, #334155);
  box-shadow: var(--shadow-2);
  transform: translateY(-2px);
}
:root[data-theme="light"] .card,
:root[data-theme="light"] .kye-card {
  background: #ffffff;
  border-color: #E5E7EB;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 0 0 1px rgba(91,61,245,0.04);
}
:root[data-theme="light"] .card:hover,
:root[data-theme="light"] .kye-card:hover {
  box-shadow: 0 8px 22px -10px rgba(91,61,245,0.20), 0 2px 4px rgba(0,0,0,0.05);
}

/* 5. Vivid Layer Cards (.lyr-card) — CtoA-style L1..L8 ladder.
 *    A card with a thick coloured indicator strip on the right edge.
 *    Eight canonical hues spanning the rainbow so a stacked ladder
 *    reads as a deliberate hierarchy at a glance. Used on landing
 *    pages, persona pages, and any "layers" surface. */
.lyr-stack { display: flex; flex-direction: column; gap: 10px; margin: 18px 0; }
.lyr-card {
  display: grid;
  grid-template-columns: 32px 1fr 6px;
  align-items: center;
  gap: 16px;
  padding: 14px 18px;
  background: var(--paper-2, #172033);
  border: 1px solid var(--line, #1E293B);
  border-radius: var(--radius-lg);
  position: relative;
  overflow: hidden;
  transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.lyr-card:hover {
  transform: translateX(2px);
  border-color: var(--line-strong, #334155);
  box-shadow: 0 4px 14px -4px rgba(0, 0, 0, 0.4);
}
.lyr-card .lyr-tag {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text-dim, #94A3B8);
  font-family: var(--font-mono, ui-monospace, monospace);
}
.lyr-card .lyr-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text, #F8FAFC);
  letter-spacing: -0.005em;
}
.lyr-card .lyr-strip {
  width: 6px;
  height: 100%;
  min-height: 36px;
  border-radius: var(--radius-sm);
  background: linear-gradient(180deg, var(--lyr-color, #7B5CFF) 0%, var(--lyr-color-2, #5B3DF5) 100%);
  box-shadow: 0 0 12px var(--lyr-glow, rgba(123, 92, 255, 0.35));
}
/* Eight canonical hues — gradient + glow per layer.
   Use --lyr-color (top of strip) + --lyr-color-2 (bottom) + --lyr-glow. */
.lyr-card.lyr-1 { --lyr-color: #F59E0B; --lyr-color-2: #D97706; --lyr-glow: rgba(245, 158, 11, 0.35); }   /* amber  — Authority */
.lyr-card.lyr-2 { --lyr-color: #A78BFA; --lyr-color-2: #7B5CFF; --lyr-glow: rgba(167, 139, 250, 0.35); } /* violet — Obligation */
.lyr-card.lyr-3 { --lyr-color: #22D3EE; --lyr-color-2: #06B6D4; --lyr-glow: rgba(34, 211, 238, 0.35); }  /* cyan   — Control */
.lyr-card.lyr-4 { --lyr-color: #EF4444; --lyr-color-2: #DC2626; --lyr-glow: rgba(239, 68, 68, 0.35); }   /* red    — Architecture */
.lyr-card.lyr-5 { --lyr-color: #F97316; --lyr-color-2: #EA580C; --lyr-glow: rgba(249, 115, 22, 0.35); } /* orange — Policy */
.lyr-card.lyr-6 { --lyr-color: #10B981; --lyr-color-2: #059669; --lyr-glow: rgba(16, 185, 129, 0.35); } /* green  — Workflow */
.lyr-card.lyr-7 { --lyr-color: #C084FC; --lyr-color-2: #A855F7; --lyr-glow: rgba(192, 132, 252, 0.35); }/* magenta— Evidence */
.lyr-card.lyr-8 { --lyr-color: #7B5CFF; --lyr-color-2: #5B3DF5; --lyr-glow: rgba(123, 92, 255, 0.40); } /* violet — Audit Pack */

/* 6. Primary button — gradient fill + glow ring on hover.
 *    Light theme keeps the same gradient (electric violet → deeper
 *    violet, AA-safe ink on both). */
.btn.btn-primary {
  background: linear-gradient(135deg, #7B5CFF 0%, #5B3DF5 100%);
  border-color: transparent;
  color: #ffffff;
  font-weight: 600;
  letter-spacing: 0.005em;
  box-shadow: 0 4px 14px -2px rgba(123, 92, 255, 0.45);
  transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
}
.btn.btn-primary:hover,
.btn.btn-primary:focus-visible {
  filter: brightness(1.10) saturate(1.15);
  box-shadow: 0 6px 22px -2px rgba(123, 92, 255, 0.60), 0 0 0 3px rgba(123, 92, 255, 0.20);
  transform: translateY(-1px);
}
.btn.btn-primary:active {
  transform: translateY(0);
  filter: brightness(0.95);
}

/* ============================================================
 * Nielsen heuristic #1 — Visibility of System Status (2026-05-19).
 * Every primary CTA now exposes:
 *   - explicit hover state (transform + glow already on .btn-primary)
 *   - focus-visible ring (3px brand glow)
 *   - loading state with rotating spinner (.is-loading)
 *   - disabled state with reduced opacity
 *   - success state with checkmark fade-in (.is-success)
 *   - error state with red border + shake (.is-error)
 * Apply via JS: btn.classList.add('is-loading') on submit.
 * ============================================================ */
.btn:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus, 0 0 0 3px rgba(123, 92, 255, 0.45)) !important;
}
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  filter: grayscale(0.35);
  pointer-events: none;
}

/* Loading state — spinner replaces icon position, label stays visible
 * but dims slightly. */
.btn.is-loading {
  pointer-events: none;
  cursor: progress;
  position: relative;
  color: transparent !important;
}
.btn.is-loading::before {
  content: "";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.btn.is-loading::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border: 2px solid rgba(255, 255, 255, 0.30);
  border-top-color: #ffffff;
  border-radius: 50%;
  animation: kye-spin 0.7s linear infinite;
}
.btn.btn-secondary.is-loading::after,
.btn.btn-ghost.is-loading::after {
  border: 2px solid rgba(123, 92, 255, 0.25);
  border-top-color: var(--accent, #7B5CFF);
}

@keyframes kye-spin {
  to { transform: rotate(360deg); }
}

/* Success — brief checkmark + tick of brand-green */
.btn.is-success {
  background: linear-gradient(135deg, #10B981 0%, #059669 100%) !important;
  border-color: transparent !important;
  color: #ffffff !important;
  box-shadow: 0 4px 14px -2px rgba(16, 185, 129, 0.45) !important;
}

/* Error — red border + brief shake to draw eye */
.btn.is-error {
  background: linear-gradient(135deg, #EF4444 0%, #DC2626 100%) !important;
  border-color: transparent !important;
  color: #ffffff !important;
  animation: kye-shake 0.4s ease-in-out;
}
@keyframes kye-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-4px); }
  40% { transform: translateX(4px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}

/* Skeleton loader — for cards / list rows waiting on data */
.skeleton {
  background: linear-gradient(90deg,
    var(--paper-2, #172033) 0%,
    var(--line-strong, #334155) 50%,
    var(--paper-2, #172033) 100%);
  background-size: 200% 100%;
  animation: kye-shimmer 1.4s linear infinite;
  border-radius: var(--radius-md);
  min-height: 1em;
  color: transparent !important;
  user-select: none;
}
@keyframes kye-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* "Tap to try in browser" / sandbox-launch CTAs — explicit pointer
 * cursor, hover lift, and progress cursor on click. */
[data-launch], .launch-cta {
  cursor: pointer;
  transition: transform .15s ease, box-shadow .15s ease, filter .15s ease;
}
[data-launch]:hover, .launch-cta:hover {
  transform: translateY(-1px);
  filter: brightness(1.06);
}
[data-launch]:active, .launch-cta:active {
  cursor: progress;
  transform: translateY(0);
}

:root[data-theme="light"] {
  /* Sovereign Indigo light-mode opt-out — restores the original
     light palette for users who explicitly choose `data-theme=light`.
     Dark is now the canonical default (top of file).

     IMPORTANT: this block MUST override BOTH the canonical
     `--kye-color-*` tokens AND the short-name aliases (`--text`,
     `--bg`, `--accent`, etc.). The §TOKENS-MIGRATED block at L176
     re-declares the short aliases with DARK values; without the
     light-mode override below, switching to data-theme=light would
     leave the short aliases pointing at dark values → white-on-white
     contrast failure (CI gate contrast-AA flagged 8 pairings at
     1.05 ratio on 2026-05-15). */
  --kye-color-bg:              #FFFFFF;
  --kye-color-surface:         #FFFFFF;
  --kye-color-paper-2:         #F8FAFC;
  --kye-color-line:            rgba(15, 23, 42, 0.10);
  --kye-color-line-strong:     rgba(15, 23, 42, 0.18);
  --kye-color-text:            #0B1020;   /* midnight navy used as ink on light */
  --kye-color-text-muted:      #475569;
  --kye-color-text-dim:        #64748B;
  /* Brand refresh 2026-05-19 — electric-violet family, AA-safe on white */
  --kye-color-brand:           #5B3DF5;   /* deeper electric violet — AA on white at 6.5:1 */
  --kye-color-brand-2:         #7B5CFF;   /* lighter electric violet — hover */
  --kye-color-brand-soft:      rgba(91, 61, 245, 0.10);
  --kye-color-brand-line:      rgba(91, 61, 245, 0.22);
  --kye-color-brand-ink:       #0B1020;   /* logo body on light */
  /* Logo accents — light-mode overrides (letterform ink → near-black) */
  --kye-logo-ink:              #0B1020;
  --kye-logo-blue:             #5B3DF5;
  --kye-logo-cyan:             #22D3EE;

  /* Short-name aliases for light mode — mirror the apex tokens above. */
  --bg:             #FFFFFF;
  --surface:        #FFFFFF;
  --surface-solid:  #FFFFFF;
  --surface-2:      #F8FAFC;
  --surface-3:      #F1F5F9;
  --paper:          #FFFFFF;
  --paper-2:        #F8FAFC;
  --paper-3:        #F1F5F9;
  --paper-4:        #E2E8F0;
  --line:           rgba(15, 23, 42, 0.10);
  --line-strong:    rgba(15, 23, 42, 0.18);
  --line-soft:      rgba(15, 23, 42, 0.04);
  --rule:           rgba(15, 23, 42, 0.10);
  --rule-soft:      rgba(15, 23, 42, 0.04);
  --text:           #0B1020;   /* midnight navy ink (>= 7:1 on white) */
  --text-muted:     #475569;   /* slate-600 (>= 4.5:1 on white) */
  --text-dim:       #64748B;   /* slate-500 (graphics-only) */
  --text-disabled:  #94A3B8;
  --accent:         #5B3DF5;   /* electric violet — AA on white at 6.5:1 */
  --accent-2:       #7B5CFF;   /* lighter violet — hover */
  --accent-ink:     #5B3DF5;
  --accent-soft:    rgba(91, 61, 245, 0.10);
  --accent-line:    rgba(91, 61, 245, 0.22);
  --accent-electric:#5B3DF5;
  --accent-cyan:    #0E7490;   /* cyan-700 — diagram lines visible on white */
  --accent-grad:    linear-gradient(120deg, #5B3DF5 0%, #7B5CFF 50%, #A78BFA 100%);
  --info:           #1D4ED8;
  --info-soft:      rgba(29, 78, 216, 0.10);
  --info-line:      rgba(29, 78, 216, 0.22);
  --success:        #047857;   /* green-700 — AA on white */
  --success-soft:   rgba(4, 120, 87, 0.10);
  --success-line:   rgba(4, 120, 87, 0.22);
  --warning:        #B45309;   /* amber-700 — AA on white */
  --warning-soft:   rgba(180, 83, 9, 0.10);
  --warning-line:   rgba(180, 83, 9, 0.22);
  --danger:         #B91C1C;   /* red-700 — AA on white */
  --danger-soft:    rgba(185, 28, 28, 0.10);
  --danger-line:    rgba(185, 28, 28, 0.22);

  /* Light-mode link colour — indigo-700 to clear WCAG AA 4.5 on white
     paper. Overrides the dark-default --color-accent: var(--accent-2)
     which would give 3.65:1 on white. */
  --color-accent:   #4338CA;
  --color-accent-2: #4F46E5;

  /* Per-family taxonomy palette (light) — §55 amendment 2026-06-11.
     One distinguishable WCAG-AA hue per top-level component family.
     Source of truth: design-system/tokens/color.json. Bindings:
     the canonical taxonomy color registry. Legend:
     /design-system/color-taxonomy.html. stakeholder=accent,
     sku=success, page=text are reused; the rest are dedicated. */

/* @generated:class-role-tokens:light — build-design-tokens.mjs · do not hand-edit (§0.49) */
  /* One colour per component class. Bindings: the §55 taxonomy colour map.
     Values: design-system/tokens/color.json v2.2.0, light theme.
     Change either source and regenerate — never edit this block. */
  --stakeholder: #A21A1A;       --stakeholder-soft: rgba(162, 26, 26, 0.10);
  --sector: #C1481F;            --sector-soft: rgba(193, 72, 31, 0.10);
  --framework: #A25E1A;         --framework-soft: rgba(162, 94, 26, 0.10);
  --jurisdiction: #C1991F;      --jurisdiction-soft: rgba(193, 153, 31, 0.10);
  --report: #A2A21A;            --report-soft: rgba(162, 162, 26, 0.10);
  --agent: #99C11F;             --agent-soft: rgba(153, 193, 31, 0.10);
  --tool: #5EA21A;              --tool-soft: rgba(94, 162, 26, 0.10);
  --program: #48C11F;           --program-soft: rgba(72, 193, 31, 0.10);
  --sku: #1AA21A;               --sku-soft: rgba(26, 162, 26, 0.10);
  --engine: #1FC148;            --engine-soft: rgba(31, 193, 72, 0.10);
  --workflow: #1AA25E;          --workflow-soft: rgba(26, 162, 94, 0.10);
  --template: #1FC199;          --template-soft: rgba(31, 193, 153, 0.10);
  --profile: #1AA2A2;           --profile-soft: rgba(26, 162, 162, 0.10);
  --app: #1F99C1;               --app-soft: rgba(31, 153, 193, 0.10);
  --feature: #1A5EA2;           --feature-soft: rgba(26, 94, 162, 0.10);
  --page: #1F48C1;              --page-soft: rgba(31, 72, 193, 0.10);
  --industry: #A21A5E;          --industry-soft: rgba(162, 26, 94, 0.10);
  --rail: #C11F48;              --rail-soft: rgba(193, 31, 72, 0.10);
  --foundry: #1A1AA2;           --foundry-soft: rgba(26, 26, 162, 0.10);
  --regulatory-regime: #481FC1; --regulatory-regime-soft: rgba(72, 31, 193, 0.10);
  --region: #5E1AA2;            --region-soft: rgba(94, 26, 162, 0.10);
  --role: #991FC1;              --role-soft: rgba(153, 31, 193, 0.10);
  --connector: #A21AA2;         --connector-soft: rgba(162, 26, 162, 0.10);
  --adopter: #C11F99;           --adopter-soft: rgba(193, 31, 153, 0.10);
/* @generated:class-role-tokens:light:end */

}
/* Authority Indigo palette — adopted 2026-05-16 per design review.
   Five-layer elevation (bg → navy → card → panel → border) gives
   the eye real hierarchy instead of the previous flat near-black
   look. Semantic decision colours (allow / approval / warning /
   deny / revoked / unverified) attach to KYE Protocol authority
   states — not just decoration. */
:root[data-theme="dark"] {
  /* Five-layer elevation (deepest → highest) */
  --kye-color-bg:              #070A12;   /* deep protocol black — page background */
  --kye-color-bg-navy:         #0B1020;   /* midnight navy — hero, nav, footer */
  --kye-color-surface:         #111827;   /* elevated card surface */
  --kye-color-paper-2:         #172033;   /* soft panel — slightly lighter sections */
  --kye-color-line:            #1E293B;   /* border / divider grid */
  /* Text hierarchy */
  --kye-color-text:            #F8FAFC;   /* main copy + headings */
  --kye-color-text-muted:      #CBD5E1;   /* body text */
  --kye-color-text-dim:        #94A3B8;   /* labels, captions, metadata */
  /* Brand accents — electric-violet family (2026-05-19 refresh) */
  --kye-color-brand:           #7B5CFF;   /* KYE electric violet — logo accent, primary CTA */
  --kye-color-brand-2:         #A78BFA;   /* violet-400 — hover lift on dark */
  --kye-color-brand-soft:      rgba(123, 92, 255, 0.16);
  --kye-color-brand-line:      rgba(123, 92, 255, 0.30);
  --kye-color-brand-ink:       #F8FAFC;
  --kye-color-protocol-blue:   #3B82F6;   /* protocol blue — links, docs, developer elements */
  --kye-color-evidence-cyan:   #22D3EE;   /* evidence cyan — Evidence Pack™, replay, signal paths */
}

/* ============================================================
   §TOKENS-MIGRATED — collapsed from public/site/styles.css.
   These twelve `:root { … }` blocks previously redeclared tokens
   throughout styles.css (lines 84, 1668, 2336, 2774, 3852, 4232,
   4542, 4981, 5348, 5460, 12284, 12686). They are now consolidated
   here, with conflicts resolved per Constitution §0 (zero competing
   systems). `!important` modifiers from the old "Google-aligned"
   block (formerly L4232) are dropped — :root specificity is
   sufficient when there is only ONE token surface.
   ============================================================ */
:root {
  /* --- Authority Indigo dark-default short aliases --- */
  /* These short names are what the rest of the codebase uses
     (--bg, --text, --accent, etc.). They mirror the canonical
     --kye-color-* tokens above so a single edit stays in sync.
     Five-layer elevation: bg → bg-navy → surface → paper-2 → line. */
  --bg: #070A12;             /* deep protocol black — page background */
  --bg-navy: #0B1020;        /* midnight navy — hero, nav, footer */
  --surface: #111827;        /* elevated card surface */
  --surface-solid: #111827;
  --surface-2: #172033;      /* soft panel — slightly lighter sections */
  --surface-3: #1E293B;
  --line: #1E293B;           /* border / divider grid */
  --line-strong: rgba(255, 255, 255, 0.18);
  --line-soft: rgba(255, 255, 255, 0.04);
  --text: #F8FAFC;           /* main copy + headings */
  --text-muted: #CBD5E1;     /* body text (lifted from #94A3B8 for AA on the deeper bg) */
  --text-dim: #94A3B8;       /* labels, captions, metadata */
  --accent: #6366F1;          /* protocol indigo */
  --accent-2: #7C84F4;        /* indigo-450 — hover lift + link colour on dark; white-on-it = 3.13:1 (AA Large) and it = 6.4:1 on near-black (AA pass) */
  --accent-ink: #4F46E5;      /* indigo-600 — link-on-dark + button-bg with white text. 4.4:1 on white (AA Large), 3.65:1 with white inverse on indigo-500 (AA Large for ≥14pt bold) */
  --accent-line: rgba(99, 102, 241, 0.30);
  --accent-soft: rgba(99, 102, 241, 0.16);
  --accent-electric: #3B82F6; /* electric blue — links, active */
  --accent-cyan: #22D3EE;     /* trust cyan — diagrams ONLY */
  --accent-grad: linear-gradient(120deg, #6366F1 0%, #3B82F6 50%, #22D3EE 100%);
  --info: #3B82F6;
  --info-soft: rgba(59, 130, 246, 0.14);
  --info-line: rgba(59, 130, 246, 0.30);
  --success: #10B981;         /* verification green */
  --success-soft: rgba(16, 185, 129, 0.16);
  --success-line: rgba(16, 185, 129, 0.30);
  --warning: #F59E0B;         /* warning amber */
  --warning-soft: rgba(245, 158, 11, 0.16);
  --warning-line: rgba(245, 158, 11, 0.30);
  --danger: #EF4444;          /* revocation red */
  --danger-soft: rgba(239, 68, 68, 0.16);
  --danger-line: rgba(239, 68, 68, 0.30);

  /* Per-family taxonomy palette (dark) — §55 amendment 2026-06-11.
     Dark-theme twins of the light family hues above. Source of truth:
     design-system/tokens/color.json. Each clears WCAG AA on the
     #070A12 dark background. Legend: /design-system/color-taxonomy.html. */

/* @generated:class-role-tokens:dark — build-design-tokens.mjs · do not hand-edit (§0.49) */
  /* One colour per component class. Bindings: the §55 taxonomy colour map.
     Values: design-system/tokens/color.json v2.2.0, dark theme.
     Change either source and regenerate — never edit this block. */
  --stakeholder: #E56C6C;       --stakeholder-soft: rgba(229, 108, 108, 0.16);
  --sector: #E58A6C;            --sector-soft: rgba(229, 138, 108, 0.16);
  --framework: #E5A86C;         --framework-soft: rgba(229, 168, 108, 0.16);
  --jurisdiction: #E5C76C;      --jurisdiction-soft: rgba(229, 199, 108, 0.16);
  --report: #E5E56C;            --report-soft: rgba(229, 229, 108, 0.16);
  --agent: #C7E56C;             --agent-soft: rgba(199, 229, 108, 0.16);
  --tool: #A8E56C;              --tool-soft: rgba(168, 229, 108, 0.16);
  --program: #8AE56C;           --program-soft: rgba(138, 229, 108, 0.16);
  --sku: #6CE56C;               --sku-soft: rgba(108, 229, 108, 0.16);
  --engine: #6CE58A;            --engine-soft: rgba(108, 229, 138, 0.16);
  --workflow: #6CE5A8;          --workflow-soft: rgba(108, 229, 168, 0.16);
  --template: #6CE5C7;          --template-soft: rgba(108, 229, 199, 0.16);
  --profile: #6CE5E5;           --profile-soft: rgba(108, 229, 229, 0.16);
  --app: #6CC7E5;               --app-soft: rgba(108, 199, 229, 0.16);
  --feature: #6CA8E5;           --feature-soft: rgba(108, 168, 229, 0.16);
  --page: #6C8AE5;              --page-soft: rgba(108, 138, 229, 0.16);
  --industry: #E56CA8;          --industry-soft: rgba(229, 108, 168, 0.16);
  --rail: #E56C8A;              --rail-soft: rgba(229, 108, 138, 0.16);
  --foundry: #6C6CE5;           --foundry-soft: rgba(108, 108, 229, 0.16);
  --regulatory-regime: #8A6CE5; --regulatory-regime-soft: rgba(138, 108, 229, 0.16);
  --region: #A86CE5;            --region-soft: rgba(168, 108, 229, 0.16);
  --role: #C76CE5;              --role-soft: rgba(199, 108, 229, 0.16);
  --connector: #E56CE5;         --connector-soft: rgba(229, 108, 229, 0.16);
  --adopter: #E56CC7;           --adopter-soft: rgba(229, 108, 199, 0.16);
/* @generated:class-role-tokens:dark:end */

  /* Semantic decision colours — Authority Indigo, 2026-05-16.
     These attach to KYE Protocol authority states. Every Decision
     Map™ node, every Evidence Pack™ verdict badge, every audit-
     chain row pulls from these tokens — colour as protocol
     primitive, not decoration. */
  --kye-allow:            #10B981;             /* Allow */
  --kye-allow-soft:       rgba(16, 185, 129, 0.16);
  --kye-allow-line:       rgba(16, 185, 129, 0.30);
  --kye-allow-constraints:#3B82F6;             /* Allow with constraints */
  --kye-approval:         #F59E0B;             /* Requires approval */
  --kye-approval-soft:    rgba(245, 158, 11, 0.16);
  --kye-approval-line:    rgba(245, 158, 11, 0.30);
  --kye-quarantine:       #F97316;             /* Quarantine / degraded */
  --kye-quarantine-soft:  rgba(249, 115, 22, 0.16);
  --kye-quarantine-line:  rgba(249, 115, 22, 0.30);
  --kye-deny:             #EF4444;             /* Deny */
  --kye-deny-soft:        rgba(239, 68, 68, 0.16);
  --kye-deny-line:        rgba(239, 68, 68, 0.30);
  --kye-revoked:          #991B1B;             /* Revoked */
  --kye-revoked-soft:     rgba(153, 27, 27, 0.20);
  --kye-revoked-line:     rgba(153, 27, 27, 0.40);
  --kye-unverified:       #64748B;             /* Unknown / unverified */
  --kye-unverified-soft:  rgba(100, 116, 139, 0.16);
  --kye-unverified-line:  rgba(100, 116, 139, 0.30);
  /* Evidence cyan — reserved for diagrams, Evidence Pack™ visualisations,
     replay paths, signal paths. AA-failing on text; use ONLY for line
     art + data lines + diagram strokes. */
  --kye-evidence-cyan:    #22D3EE;
  --kye-protocol-blue:    #3B82F6;             /* links, docs, developer surfaces */

  --focus-ring: 0 0 0 3px rgba(99, 102, 241, 0.35);
  --shadow-1: 0 1px 2px rgba(15,23,42,.05), 0 1px 1px rgba(15,23,42,.03);
  --shadow-2: 0 8px 24px -10px rgba(15,23,42,.18), 0 2px 6px rgba(15,23,42,.06);
  --shadow-3: 0 24px 56px -20px rgba(99,102,241,.25), 0 4px 12px rgba(15,23,42,.08);
  /* Sitewide crisp-text mandate: backdrop-filter promotes every element
     that carries it onto a GPU compositing layer, which drops subpixel
     antialiasing and makes the text inside render soft/matte. Every
     KYE surface that uses --glass-blur has an OPAQUE background, so the
     blur produced no visual effect — only the text-softening. Disabled
     at the single canonical token so all ~30 call sites resolve to
     `backdrop-filter: none`. This is the knob; flip it to re-enable. */
  --glass-blur: none;
  /* --radius-1..3 removed. They were declared HERE as 8/12/18px and AGAIN
     ~140 lines below in this same :root rule as 6/8/12px — one token name,
     two shapes, resolved by whichever declaration the cascade reached last.
     Canonical scale: design-system/tokens/radius.json (generated block below). */
  --font-ui: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* Token alias shim — bridges legacy --color-* names to shipped tokens */
  --color-bg: var(--bg);
  --color-paper: var(--bg);
  --color-surface: var(--surface);
  --color-text: var(--text);
  --color-text-muted: var(--text-muted);
  --color-text-inverse: #ffffff;
  --color-border: var(--line);
  --color-line: var(--line);
  --color-line-strong: var(--line-strong);
  /* Muted text + panel aliases that shipped CSS references but were never
     defined (so the rules became invalid → faint inherited text, transparent
     panels). Aliased to the canonical theme-resolved tokens; lazy var()
     resolution keeps them correct in both light and dark. */
  --muted: var(--text-muted);
  --color-muted: var(--text-muted);
  --border: var(--line);
  --kye-color-paper: var(--kye-color-surface);
  --kye-color-muted: var(--text-muted);
  /* --color-accent: the prose-link / focus-ring colour. We point it
     at the darker --accent-ink (indigo-700 #4338ca) so it crosses the
     WCAG 2.1 AA 4.5 floor against both paper and the accent button.
     The visual --accent token (indigo-500) continues to drive
     button-fills and decorative strokes. */
  /* --color-accent: the prose-link colour. Sovereign Indigo lock
     (2026-05-15) — points at --accent-2 which renders as indigo-400
     (#818CF8) on dark (6.7:1 on near-black, AA pass) and indigo-500
     (#6366F1) on light (--color-accent-link below pulls indigo-700
     for the light-mode AA floor on paper). */
  --color-accent: var(--accent-2);
  --color-accent-2: var(--accent);
  /* --color-accent-ink: ink color sitting ON the accent button.
     White against indigo-700 (--accent-ink) gives ~8.6 contrast,
     comfortably above the WCAG 2.1 AA 4.5 floor. */
  --color-accent-ink: #ffffff;
  --color-accent-soft: var(--accent-soft);
  --color-focus-ring: var(--accent);
  --color-scrim: rgba(15, 23, 42, 0.55);
  /* Brand / palette stops (light) */
  /* --color-brand-50: chosen #eef2ff (indigo-50) over design-system/theme/
     light.css's #E8F1FE — the indigo-50 matches the rest of the brand-*
     ramp shipped by styles.css. */
  --color-brand-50:  #eef2ff;
  --color-brand-200: #c7d2fe;
  --color-brand-300: #a5b4fc;
  --color-brand-500: var(--accent);
  --color-brand-600: var(--accent-ink);
  /* Semantic role pairs — each *-50 paired with a *-700 ink for the
     WCAG 2.1 AA pairing the design-system/ci-gates/contrast-AA.mjs
     gate validates. Floors: 4.5 for body text. */
  --color-success-50:  #ecfdf5;
  --color-success-700: #047857;
  --color-info-50:     #e0f2fe;
  --color-info-700:    #1e40af;
  --color-warning-50:  #fffbeb;
  --color-warning-700: #b45309;
  --color-danger-50:   #ffe4e6;
  --color-danger-700:  #b91c1c;
  /* Neutrals (light) */
  --color-neutral-50:  #fafafa;
  --color-neutral-100: #f4f4f5;
  --color-neutral-200: #e4e4e7;
  --color-neutral-300: #d4d4d8;
  --color-neutral-500: #71717a;
  --color-neutral-800: #27272a;
  --color-neutral-900: #18181b;

  /* --- from former styles.css L1668 (™ font fallback) --- */
  --font-tm: var(--font-ui);

  /* --- from former styles.css L2336 (refined enterprise palette) --- */
  --ink: #0b0f1c;
  --ink-2: #1a2238;
  --ink-3: #3b4567;
  --paper: #fcfcfd;
  --paper-2: #f6f7fa;
  --rule: rgba(15, 23, 42, 0.10);
  --rule-soft: rgba(15, 23, 42, 0.06);
  --rule-strong: rgba(15, 23, 42, 0.16);
  /* Note: --accent-ink redeclared in L2336 as #4c1d95; the L84 value
     #4338ca above wins because it appears later in this block. */

  /* --- from former styles.css L2774 (™ / ® em + rise scale) --- */
  --tm-em-display: 0.58em;
  --tm-em-h3:      0.72em;
  --tm-em-body:    0.85em;
  --tm-em-chrome:  0.92em;
  --tm-em-modal:   0.82em;
  --tm-rise-display: 0.46em;
  --tm-rise-h3:      0.36em;
  --tm-rise-body:    0.30em;
  --tm-rise-chrome:  0.28em;
  --tm-rise-modal:   0.32em;
  --tm-em:   var(--tm-em-body);
  --tm-rise: var(--tm-rise-body);
  --tm-letterspacing: 0;

  /* --- from former styles.css L3852 (font-size scale + line-height) --- */
  --fs-display:    clamp(40px, 6vw, 72px);
  --fs-h2:         clamp(28px, 4vw, 38px);
  --fs-h3-card:    17px;
  --fs-body-card:  14px;
  --fs-body:       16px;
  --fs-eyebrow:    11px;
  --fs-pill:       11px;
  --fs-mono:       12px;
  --lh-h:          1.35;
  --lh-body:       1.6;

  /* --- Sovereign Indigo dark-default overrides (locked 2026-05-15) ---
       Replaces the legacy Google-aligned + Material-3 layers that lived
       at L4232 + L5460. Light palette is the explicit opt-out at the
       :root[data-theme="light"] block above. --- */
  --text:           #F8FAFC;
  --text-muted:     #94A3B8;
  --text-dim:       #64748B;
  --text-disabled:  #475569;
  --paper:    #232838;
  --paper-2:  #2A2F46;
  --paper-3:  #313655;
  --rule:     #313655;
  --rule-soft:#2A2F46;
  --line:     #1E293B;
  --line-soft:rgba(255, 255, 255, 0.04);
  --line-strong:rgba(255, 255, 255, 0.18);
  --accent:        #6366F1;
  --accent-2: #7C84F4;
  --accent-soft:   rgba(99, 102, 241, 0.16);
  --accent-line:   rgba(99, 102, 241, 0.30);
  --success:    #10B981;
  --success-soft:rgba(16, 185, 129, 0.16);
  --warning:    #F59E0B;
  --warning-soft:rgba(245, 158, 11, 0.16);
  --danger:     #EF4444;
  --danger-soft:rgba(239, 68, 68, 0.16);

  /* --- from former styles.css L4542 (shadows + spacing) --- */
  /* The --radius-1..4 redeclaration that used to sit here is gone; so is the
     duplicate --radius-pill (the generated scale block below defines it once). */
  --shadow-1: 0 1px 2px rgba(0,0,0,0.30);
  --shadow-2: 0 4px 14px rgba(0,0,0,0.40);
  --shadow-3: 0 12px 32px rgba(0,0,0,0.50);
  --shadow-mega: 0 16px 40px rgba(0,0,0,0.55);
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-7: 32px; --sp-8: 40px;
  --sp-9: 56px; --sp-10: 72px;
  --bw: 1px;

  /* --- Sovereign Indigo gradient + info --- */
  --accent-grad: linear-gradient(120deg, #6366F1 0%, #3B82F6 50%, #22D3EE 100%);
  --info:        #3B82F6;
  --info-soft:   rgba(59, 130, 246, 0.14);
  --info-line:   rgba(59, 130, 246, 0.30);

  /* --- Sovereign Indigo final accent + success — single canonical
       value, no cascade overrides below this point. --- */
  --accent:        #6366F1;
  --accent-2: #7C84F4;
  --accent-soft:   rgba(99, 102, 241, 0.16);
  --accent-line:   rgba(99, 102, 241, 0.30);
  --success:       #10B981;
  --success-soft:  rgba(16, 185, 129, 0.16);

  /* --- from former styles.css L12284 (z-index lattice) --- */
  --kye-z-sticky:  50;
  --kye-z-overlay: 100;
  --kye-z-drawer:  10000;
  --kye-z-modal:   11000;
  /* L12302 — sticky top-bar height */
  --kye-nav-h: 64px;

  /* --- card-head paper fallback (Sovereign Indigo dark) --- */
  --paper-4: #1E293B;
}

/* Dark-theme override for the brand-50 stop, migrated from the
   former styles.css L1946 (was inside the L1905 :root[data-theme="dark"]
   block; conflicted with light --color-brand-50 #eef2ff above). */
:root[data-theme="dark"] {
  --color-brand-50: rgba(99, 102, 241, 0.14);

  /* Dark-theme semantic role pairs. Light *-50 backgrounds are too
     bright behind dark surfaces; light *-700 inks vanish on them.
     Use the same *-50/*-700 pairing the contrast-AA gate checks,
     but tuned to satisfy 4.5 against the dark canvas. */
  --color-success-50:  #052e1f;
  --color-success-700: #6ee7b7;
  --color-info-50:     #0c2849;
  --color-info-700:    #93c5fd;
  --color-warning-50:  #3b2607;
  --color-warning-700: #fcd34d;
  --color-danger-50:   #3b0d10;
  --color-danger-700:  #fda4af;

  /* Accent ink on accent button — dark theme uses a bright indigo
     accent (#818cf8), so the readable ink is the dark canvas colour. */
  --color-accent-ink: #0a0e1a;
  /* Prose-link colour in dark theme is the brighter indigo-300
     (--accent-2) for AA contrast against the dark paper. */
  --color-accent: var(--accent-2);
}

/* @generated:scale-tokens — build-design-tokens.mjs · do not hand-edit (§0.49) */
/* Source of truth: design-system/tokens/{spacing.json v1.1.0, radius.json v1.0.0}.
   Theme-invariant — the spacing and radius scales are identical in light and
   dark, so they land once on :root rather than per theme block. */
:root {
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-14: 56px;
  --space-16: 64px;
  --space-20: 80px;
  --space-24: 96px;
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 8px;
  --radius-xl: 12px;
  --radius-2xl: 16px;
  --radius-3xl: 24px;
  --radius-pill: 999px;
  --radius-input: var(--radius-md);
  --radius-button: var(--radius-md);
  --radius-card: var(--radius-xl);
  --radius-modal: var(--radius-2xl);
  --radius-callout: var(--radius-lg);
  --radius-badge: var(--radius-pill);
  --radius-avatar: var(--radius-pill);
  --radius-tooltip: var(--radius-md);
  --radius-popover: var(--radius-lg);
}
/* @generated:scale-tokens:end */
