/* Perimeter — design tokens.
 *
 * The single source of truth for both surfaces: the three public sites and the
 * admin panel. Neither defines its own palette; both link this file first.
 *
 * Dark-first, because the reading ground is dark by intent. Light is a designed
 * second theme, not an inversion — the accent darkens to hold contrast on paper
 * rather than simply flipping.
 *
 * Contrast: every foreground/background pair used for text meets WCAG AA (4.5:1
 * for body, 3:1 for large text) in BOTH themes. Verified by tools/check_contrast.py
 * — run it after touching any colour here.
 */

:root {
  /* ── Ground ─────────────────────────────────────────────────────────────
     Neutrals are tinted toward the accent hue rather than pure grey, so the
     surfaces feel like part of one system instead of a default stylesheet. */
  --bg:         #05070c;
  --bg-grid:    #ffffff05;
  --surface:    #0b0f18;
  --raised:     #10161f;
  --rule:       #1c2534;
  --rule-soft:  #121a26;

  /* ── Ink ────────────────────────────────────────────────────────────────
     --muted is the workhorse: it colours every piece of machine-derived
     metadata on the site, so it must clear 4.5:1 rather than sit just under. */
  --ink:        #dfe6f0;   /* 16.0:1 on --bg */
  --ink-soft:   #a9b8cc;   /* 10.0:1 */
  --muted:      #8494ad;   /*  5.7:1 — was #61708a at 4.0:1, failing AA */

  /* ── Colour system ──────────────────────────────────────────────────────
     Three tiers, separated by CHROMA rather than hue. Saturation is the
     hierarchy, which is what lets a KEV badge shout without anything competing:

       neutral (chroma 0)      structure — carries no meaning
       quiet   (chroma 0.055)  which section a story belongs to
       accent  (chroma 0.135)  interactive, live, editorially flagged
       loud    (chroma 0.185)  exploitation evidence

     Generated by tools/palette.py in OKLCH, so the six section hues are
     perceptually equal in weight rather than merely equal on paper. Regenerate
     there rather than editing these by hand. */

  /* Interactive: links, focus, live state, must-read. Sits in the hue gap
     between the azure and violet section tints, and clear of the warm band
     that severity owns. */
  --accent:     #7fb3ff;
  --accent-dim: #7fb3ff1f;

  /* Severity — exploitation evidence, nothing else. Used decoratively it stops
     carrying information. */
  --sev-crit:    #fc6661;   /* on CISA KEV — confirmed exploited in the wild */
  --sev-crit-bg: #fc666116;
  --sev-high:    #f7ad30;   /* high EPSS, or CVSS >= 9 */
  --sev-high-bg: #f7ad3016;
  --sev-mid:     #93a6c0;
  --focus:       #7fb3ff;

  /* Section identity — the wayfinding layer. Low chroma on purpose: in a
     forty-item edition these should orient you as you scroll past, not compete
     with the severity rail beside them. */
  --sec-vulns:   #d0aac4;
  --sec-threat:  #c5add0;
  --sec-offense: #b5b2d9;
  --sec-aisec:   #8fc1cc;
  --sec-defense: #91c3b9;
  --sec-grc:     #a2c1a2;

  /* ── Type ───────────────────────────────────────────────────────────────
     Mono for machine-derived data, sans for prose a person reads. */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, "JetBrains Mono", "IBM Plex Mono", Menlo, Consolas, monospace;

  /* A ~1.14 scale. Dense on purpose: this is a scanning surface, not an essay.
     Consolidated from 27 ad-hoc sizes that differed by hundredths of a rem. */
  --text-3xs:  0.625rem;   /* 10px — micro labels, item numbers */
  --text-2xs:  0.6875rem;  /* 11px — metadata, badges, chips */
  --text-xs:   0.75rem;    /* 12px — nav, pager, stats */
  --text-sm:   0.8125rem;  /* 13px — secondary UI, footer */
  --text-base: 0.9375rem;  /* 15px — summaries, prose */
  --text-md:   1rem;       /* 16px — lede, intro */
  --text-lg:   1.0625rem;  /* 17px — item titles */
  --display-sm: clamp(1.55rem, 1.1rem + 2vw,   2.4rem);
  --display-md: clamp(1.8rem,  1.2rem + 2.6vw, 2.9rem);

  --lh-tight: 1.15;
  --lh-snug:  1.38;
  --lh-body:  1.6;
  --lh-loose: 1.68;

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-bold:   600;

  /* Tracking for uppercase mono labels — consolidated from five near-identical
     values. Uppercase mono needs air or it reads as a solid block. */
  --track-tight: -0.02em;
  --track-flat:   0;
  --track-wide:   0.09em;
  --track-wider:  0.15em;

  /* ── Space ──────────────────────────────────────────────────────────────
     A 4px base scale, replacing 70 ad-hoc rem values. Rhythm comes from
     choosing different steps, not from inventing new numbers. */
  --sp-0:  0;
  --sp-1:  0.25rem;
  --sp-2:  0.5rem;
  --sp-3:  0.75rem;
  --sp-4:  1rem;
  --sp-5:  1.25rem;
  --sp-6:  1.5rem;
  --sp-8:  2rem;
  --sp-10: 2.5rem;
  --sp-12: 3rem;
  --sp-16: 4rem;
  /* Fluid page gutter — breathes on wide screens, stays usable on a phone. */
  --gutter: clamp(0.9rem, 0.6rem + 0.5vw, 1.5rem);

  /* ── Shape ──────────────────────────────────────────────────────────────
     Near-square. Rounded rectangles with soft shadows are the generic default;
     this surface is an instrument panel, so corners stay tight. */
  --radius-sm:   2px;
  --radius-md:   3px;
  --radius-pill: 999px;
  --border:      1px;
  --rail:        2px;

  /* ── Motion ─────────────────────────────────────────────────────────────
     Exponential ease-out: things decelerate the way real objects do. No bounce. */
  --ease:      cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur-fast:  0.12s;
  --dur:       0.2s;

  /* ── Layout ─────────────────────────────────────────────────────────────*/
  --measure:      48rem;   /* reading column */
  --measure-wide: 74rem;   /* admin tables */
  --measure-prose: 66ch;   /* paragraph width */
  --tap-min:      2.75rem; /* 44px — WCAG 2.5.5 enhanced target */
  --tap-floor:    1.5rem;  /* 24px — WCAG 2.5.8 minimum */
}

/* Light theme. Redefines tokens only — never component styles, so nothing can
   be defined solely inside a theme block and vanish in the other state. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg:         #f5f7f8;
    --bg-grid:    #0000000a;
    --surface:    #fcfdfd;   /* tinted, not pure white */
    --raised:     #eef1f3;
    --rule:       #d8dee4;
    --rule-soft:  #e8ecef;

    --ink:        #0d1420;
    --ink-soft:   #36435a;
    --muted:      #5a6880;   /* 5.1:1 on --bg */

    --accent:     #1657af;
    --accent-dim: #1657af1a;

    --sev-crit:    #b71824;
    --sev-crit-bg: #b7182412;
    --sev-high:    #965802;
    --sev-high-bg: #96580212;
    --sev-mid:     #55637a;
    --focus:       #1657af;

    --sec-vulns:   #734767;
    --sec-threat:  #684b74;
    --sec-offense: #565180;
    --sec-aisec:   #126371;
    --sec-defense: #18665a;
    --sec-grc:     #3c633d;
  }
}

:root[data-theme="light"] {
  --bg:         #f5f7f8;
  --bg-grid:    #0000000a;
  --surface:    #fcfdfd;
  --raised:     #eef1f3;
  --rule:       #d8dee4;
  --rule-soft:  #e8ecef;

  --ink:        #0d1420;
  --ink-soft:   #36435a;
  --muted:      #5a6880;

  --accent:     #1657af;
  --accent-dim: #1657af1a;

  --sev-crit:    #b71824;
  --sev-crit-bg: #b7182412;
  --sev-high:    #965802;
  --sev-high-bg: #96580212;
  --sev-mid:     #55637a;
  --focus:       #1657af;

  --sec-vulns:   #734767;
  --sec-threat:  #684b74;
  --sec-offense: #565180;
  --sec-aisec:   #126371;
  --sec-defense: #18665a;
  --sec-grc:     #3c633d;
}
