/* Helix design tokens — the single source of truth for both surfaces.
 *
 * THIS FILE IS COPIED BYTE-IDENTICAL TO apps/desktop/src/tokens.css.
 * The cloud copy is canonical because the web pages must be served a real
 * file with no build step (a deliberate constraint of cloud/api/web); the
 * desktop imports its copy through Vite. A test in cloud/api asserts the
 * two are identical — the same mechanism that keeps the NMS contract from
 * drifting, applied to CSS. Edit here, copy there, or the suite goes red.
 *
 * Consumption: cloud pages get this via `@import url("tokens.css")` at the
 * top of app.css; the desktop imports it in main.tsx before styles.css.
 *
 * Rules that shaped this file:
 * - Colour is SEMANTIC. Components use --status-* and --chart-*, never a
 *   literal. The legacy names (--ok, --warn, --err, --accent) are kept as
 *   aliases so existing rules keep working while they migrate.
 * - Status is never carried by hue alone: every status colour has a paired
 *   glyph (--status-*-glyph) that components render alongside it, because
 *   a red/green quality dashboard is unusable for roughly 1 in 12 men.
 * - The chart palette is ordered for adjacent-series distinguishability
 *   under deuteranopia/protanopia (no green next to red, lightness varies
 *   as well as hue) and is tuned per theme. Series colour is assigned by
 *   index via palette.ts / palette.js — never picked inside a component.
 * - Numerics everywhere use tabular figures (.tnum, or the token) so live
 *   values do not jitter in width as digits change.
 * - Dark is the product default (no OS preference = dark). Light applies
 *   on OS preference, and an explicit [data-theme] override — persisted by
 *   theme.ts / theme.js — beats the OS in both directions.
 */

/* ------------------------------------------------ theme-independent */
:root {
  --font-ui: Inter, "Segoe UI Variable", "Segoe UI", system-ui, sans-serif;
  --font-mono: "Cascadia Code", Consolas, ui-monospace, "SF Mono", monospace;

  --text-xs: 11.5px;
  --text-sm: 12.5px;
  --text-base: 14px;
  --text-lg: 16px;
  --text-xl: 20px;
  --text-2xl: 28px;
  --text-hero: 56px;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 40px;
  --space-8: 48px;

  --radius: 14px;
  --radius-sm: 8px;
  --radius-pill: 999px;

  /* Motion exists to explain a state change, never to decorate. */
  --dur-fast: 120ms;
  --dur: 200ms;
  --dur-slow: 320ms;
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);

  /* Glassmorphism: every .card-like surface pairs --card with
   * backdrop-filter: blur(var(--glass-blur)). The blur amount is a token
   * so the whole product softens or sharpens together — a surface that
   * hardcodes its own blur is one theme change away from looking pasted
   * on. Operator instruction 2026-08-10: the general background across
   * both dashboards is darkest-blue glass. */
  --glass-blur: 14px;

  /* Density: modes set data-density on <html>; these are what it moves. */
  --gap: 14px;
  --pad-card: 14px 16px;

  /* Paired glyphs so status never rides on hue alone. */
  --status-ok-glyph: "●";
  --status-degraded-glyph: "◐";
  --status-down-glyph: "✕";
  --status-unknown-glyph: "◌";
}

/* ------------------------------------------------ dark (default)
 * Darkest-blue glass: the base is a deep navy rather than neutral
 * near-black, and card surfaces are a faint BLUE-tinted translucency —
 * white-tinted glass over neutral grey was the pre-tokens look and it
 * read as charcoal, not glass. The glows are what the blur has to catch
 * for the material to register at all. */
:root {
  color-scheme: dark;

  --bg: #040918;
  --bg-soft: #0a1226;
  --bg-glow-1: rgba(56, 189, 248, 0.1);
  --bg-glow-2: rgba(167, 139, 250, 0.08);
  --card: rgba(158, 190, 255, 0.055);
  --card-border: rgba(158, 190, 255, 0.14);
  --text: #e6e9f0;
  --muted: #8b93a7;
  --accent: #38bdf8;
  --accent-soft: rgba(56, 189, 248, 0.16);
  --focus-ring: #7dd3fc;

  --status-ok: #4ade80;
  --status-ok-soft: rgba(74, 222, 128, 0.12);
  --status-degraded: #fbbf24;
  --status-degraded-soft: rgba(251, 191, 36, 0.12);
  --status-down: #f87171;
  --status-down-soft: rgba(248, 113, 113, 0.12);
  --status-unknown: #8b93a7;
  --status-unknown-soft: rgba(139, 147, 167, 0.12);

  /* Insufficient data (coarse_loss) is its own state, not a softer OK. */
  --insufficient: #8b93a7;
  --insufficient-hatch: repeating-linear-gradient(
    -45deg,
    transparent 0 4px,
    rgba(139, 147, 167, 0.28) 4px 6px
  );

  --chart-1: #38bdf8;
  --chart-2: #e8a33d;
  --chart-3: #a78bfa;
  --chart-4: #2dd4a7;
  --chart-5: #f27ba6;
  --chart-6: #d9cf4a;
  --chart-7: #9aa4b5;
  --chart-8: #f0703a;
}

/* Legacy aliases — do not use in new code; migrate old rules as touched. */
:root {
  --ok: var(--status-ok);
  --warn: var(--status-degraded);
  --err: var(--status-down);
}

/* ------------------------------------------------ light
 * Two blocks carry the SAME values: the media query serves an OS
 * preference with no stored override, the attribute serves an explicit
 * choice. CSS has no way to share a declaration block without a build
 * step, which the cloud pages are not allowed — keep the blocks
 * identical when editing. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;

    --bg: #eef2fb;
    --bg-soft: #ffffff;
    --bg-glow-1: rgba(2, 132, 199, 0.07);
    --bg-glow-2: rgba(124, 58, 237, 0.05);
    --card: rgba(255, 255, 255, 0.66);
    --card-border: rgba(15, 23, 42, 0.1);
    --text: #1a2233;
    --muted: #5b6474;
    --accent: #0284c7;
    --accent-soft: rgba(2, 132, 199, 0.1);
    --focus-ring: #0369a1;

    --status-ok: #15803d;
    --status-ok-soft: rgba(21, 128, 61, 0.1);
    --status-degraded: #b45309;
    --status-degraded-soft: rgba(180, 83, 9, 0.1);
    --status-down: #b91c1c;
    --status-down-soft: rgba(185, 28, 28, 0.08);
    --status-unknown: #64748b;
    --status-unknown-soft: rgba(100, 116, 139, 0.1);

    --insufficient: #64748b;
    --insufficient-hatch: repeating-linear-gradient(
      -45deg,
      transparent 0 4px,
      rgba(100, 116, 139, 0.25) 4px 6px
    );

    --chart-1: #0284c7;
    --chart-2: #b8770b;
    --chart-3: #7c3aed;
    --chart-4: #0f9d75;
    --chart-5: #be5b8a;
    --chart-6: #8f8618;
    --chart-7: #64748b;
    --chart-8: #c2410c;
  }
}

:root[data-theme="light"] {
  color-scheme: light;

  --bg: #eef2fb;
  --bg-soft: #ffffff;
  --bg-glow-1: rgba(2, 132, 199, 0.07);
  --bg-glow-2: rgba(124, 58, 237, 0.05);
  --card: rgba(255, 255, 255, 0.66);
  --card-border: rgba(15, 23, 42, 0.1);
  --text: #1a2233;
  --muted: #5b6474;
  --accent: #0284c7;
  --accent-soft: rgba(2, 132, 199, 0.1);
  --focus-ring: #0369a1;

  --status-ok: #15803d;
  --status-ok-soft: rgba(21, 128, 61, 0.1);
  --status-degraded: #b45309;
  --status-degraded-soft: rgba(180, 83, 9, 0.1);
  --status-down: #b91c1c;
  --status-down-soft: rgba(185, 28, 28, 0.08);
  --status-unknown: #64748b;
  --status-unknown-soft: rgba(100, 116, 139, 0.1);

  --insufficient: #64748b;
  --insufficient-hatch: repeating-linear-gradient(
    -45deg,
    transparent 0 4px,
    rgba(100, 116, 139, 0.25) 4px 6px
  );

  --chart-1: #0284c7;
  --chart-2: #b8770b;
  --chart-3: #7c3aed;
  --chart-4: #0f9d75;
  --chart-5: #be5b8a;
  --chart-6: #8f8618;
  --chart-7: #64748b;
  --chart-8: #c2410c;
}

/* ------------------------------------------------ density
 * Set by mode: operator=compact, enterprise=medium (the default values
 * above), home=comfortable, gamer=medium. Only spacing moves — type size
 * shifts are done by the components that opt in, so a density change
 * cannot silently shrink body text below readable. */
:root[data-density="compact"] {
  --gap: 10px;
  --pad-card: 10px 12px;
}

:root[data-density="comfortable"] {
  --gap: 18px;
  --pad-card: 18px 20px;
}

/* ------------------------------------------------ motion opt-out */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0ms;
    --dur: 0ms;
    --dur-slow: 0ms;
  }
}

/* ------------------------------------------------ shared utilities
 * The three rules small enough that duplicating them per surface would
 * only invite drift. Everything else lives in the surface's own CSS. */
.tnum {
  font-variant-numeric: tabular-nums;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
