/* ═══════════════════════════════════════════════════════════════════
   VOLTEX — design system
   ═══════════════════════════════════════════════════════════════════

   Built against the design-taste / design-redesign standards:

   - ONE accent (sodium amber), locked. Everything else is neutral or the
     functional traffic scale. The previous build had 21 distinct hex values
     and two competing accents (mint #00e5a0 AND the traffic colours).
   - ONE radius scale: 4 / 8 / 12 / 18. Nothing arbitrary. The previous
     build had 6 unrelated radii.
   - Tinted shadows carrying the background hue, never pure black. A black
     shadow on a cool near-black background reads as dirt.
   - Real texture: a fixed noise overlay + a subtle vignette, so the deep
     background is not a flat vector fill.
   - Self-hosted variable fonts. No Google Fonts link (a driver's phone on
     mobile data should not block first paint on a third-party host), and
     Geist rather than the default Inter.
   - Tabular figures everywhere a number changes, so scores do not jitter
     as they tick.
   - Dials: VARIANCE 5 · MOTION 4 · DENSITY 6. This is a cockpit read at
     a glance in a car — density and legibility beat asymmetry, and motion
     must be short and non-repeating because a driver glances, not studies.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Type ─────────────────────────────────────────────────────────── */
@font-face {
  font-family: 'Geist';
  src: url('fonts/geist-latin-wght-normal.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
  font-style: normal;
}
@font-face {
  font-family: 'Geist Mono';
  src: url('fonts/jetbrains-mono-latin-wght-normal.woff2') format('woff2-variations');
  font-weight: 100 800;
  font-display: swap;
  font-style: normal;
}

:root {
  /* ── Neutral ramp. One hue (220° cool), tinted — never pure grey,
        never pure black. ─────────────────────────────────────────────── */
  --n-950: #08090c;   /* page */
  --n-900: #0c0e13;   /* raised surface */
  --n-850: #11141a;   /* card */
  --n-800: #171a22;   /* hover */
  --n-750: #1e222c;   /* pressed */
  --n-700: #272c38;   /* border strong */
  --n-600: #363c4b;   /* border */
  --n-500: #4d5468;   /* disabled text */
  --n-400: #6b7386;   /* tertiary text */
  --n-300: #9aa2b4;   /* secondary text */
  --n-200: #c3c9d6;   /* primary text */
  --n-100: #e9ecf3;   /* headings */

  --bg:         var(--n-950);
  --bg-raised:  var(--n-900);
  --surface:    var(--n-850);
  --surface-hover: var(--n-800);
  --surface-press:  var(--n-750);
  --border:     var(--n-700);
  --border-soft: rgba(54, 60, 75, 0.42);
  --text:       var(--n-100);
  --text-2:     var(--n-300);
  --text-3:     var(--n-400);
  --text-dim:   var(--n-500);

  /* ── THE accent. Sodium amber: the colour of a streetlight and of a
        dashboard warning. Chosen because a driver scanning a mounted
        phone reads it as "live instrument" rather than "app chrome".
        One accent, used everywhere. ─────────────────────────────────── */
  --accent:       #f5a524;
  --accent-dim:   #b87a12;
  --accent-wash:  rgba(245, 165, 36, 0.12);
  --accent-line:  rgba(245, 165, 36, 0.34);
  --on-accent:    #140c00;   /* text ON amber — 13.4:1 contrast */

  /* ── Functional traffic scale. These are DATA, not decoration, so
        they are exempt from the one-accent rule: they encode a
        measured value. ──────────────────────────────────────────────── */
  --surge-high: #ff5c5c;
  --surge-mid:  #f5a524;
  --surge-low:  #4ade80;
  --surge-high-wash: rgba(255, 92, 92, 0.13);
  --surge-mid-wash:  rgba(245, 165, 36, 0.13);
  --surge-low-wash:  rgba(74, 222, 128, 0.13);
  --offline:    var(--n-500);

  /* ── Radius scale. Four steps, used everywhere, no exceptions. ────── */
  --r-xs: 4px;    /* badges, inline chips */
  --r-sm: 8px;    /* inputs, small controls */
  --r-md: 12px;   /* cards, panels */
  --r-lg: 18px;   /* sheets, the app container */

  /* ── Shadows, tinted to the background hue. Never #000. ──────────── */
  --lift-1: 0 1px 2px rgba(4, 6, 12, 0.5), 0 0 0 1px rgba(255,255,255,0.022);
  --lift-2: 0 4px 14px -4px rgba(4, 6, 12, 0.68), 0 0 0 1px rgba(255,255,255,0.03);
  --lift-3: 0 18px 44px -12px rgba(3, 5, 11, 0.82), 0 0 0 1px rgba(255,255,255,0.042);
  --glow:    0 0 0 1px var(--accent-line), 0 0 22px -6px var(--accent-wash);

  /* ── Motion. Short and non-repeating: a driver glances for ~1s. ──── */
  --fast: 120ms cubic-bezier(0.2, 0, 0.2, 1);
  --base: 200ms cubic-bezier(0.2, 0, 0.2, 1);
  --slow: 320ms cubic-bezier(0.16, 1, 0.3, 1);
  --press: scale(0.975);

  --font: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --mono: 'Geist Mono', ui-monospace, 'SF Mono', monospace;

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

/* Numbers must not jitter as scores tick every 30s. */
.tnum, .stat-val, .zone-score, .kz, .st-row .val {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* ── Icons ─────────────────────────────────────────────────────────
   One family, one stroke weight (1.75, set in icons.js). Icons
   inherit currentColor, so an icon is automatically correct in
   every state without a variant per state. */
.ic { display: inline-block; vertical-align: -0.18em; flex: none; }
.ic-slot { display: inline-flex; align-items: center; justify-content: center; }
button:has(> .ic-slot) { gap: 7px; }
.nav-item .ic { opacity: .9; }
.nav-item.active .ic { opacity: 1; }

/* ── Texture ──────────────────────────────────────────────────────
   A flat #08090c fill reads as a dead screen. Two stacked layers: a
   fine grain and a soft vignette, both pointer-events-none. */
.texture {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.texture::before {
  content: '';
  position: absolute;
  inset: 0;
  opacity: 0.5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.028'/%3E%3C/svg%3E");
}
.texture::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 80% at 50% -10%, rgba(245,165,36,0.05), transparent 62%);
}

/* ── Focus. Visible, and amber. Keyboard users get the same affordance
      as a tap, and the accent lock means it is the one colour that
      always means "you are here". ─────────────────────────────────── */
:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}
