/* ROHU design tokens — one source, every page.
 *
 * There were three. index.html, dashboard.html and support.html each carried a near-identical
 * :root block, maintained by hand, and they had already drifted: support.html still had
 * --faint at #5c6561, which is 3.49:1 on black and below the 4.5:1 floor for the small text
 * it was used on. The dashboard had been corrected months earlier. Nobody could see the
 * difference because the two values were never on screen together.
 *
 * That is the whole argument for this file. Not tidiness — a support page quietly less
 * readable than the product it supports, for as long as it takes somebody to notice.
 *
 * Everything here is a decision. Anything that is only a measurement stays in the page that
 * measures it.
 */

:root {
  /* ── surface ────────────────────────────────────────────────────────────────
   * Near-black, not black.
   *
   * The first palette was #000 with a dim emerald on it — the default costume of every VPN
   * and every terminal-themed token page, and it did badly in front of the audience it was
   * aimed at. Pure #000 is also the flattest surface there is: nothing can sit *behind*
   * anything, because there is no darker value left to go to.
   *
   * A hair off black fixes both. #0b0b0b is neutral rather than green-tinted, panels lift
   * to #131313 and #1a1a1a, and the page suddenly has three planes instead of one. It reads
   * as a designed dark, not an unlit one.
   *
   * The tint matters as much as the value: the old surfaces were all slightly green, which
   * made the accent feel like a brighter version of the background rather than a different
   * material. These are pure grey, so the lime lands on them like paint on concrete. */
  --bg: #0b0b0b;
  --panel: #151515;
  --panel2: #1e1e1e;

  /* --line2 is the one that has to separate a control from its surface, so it clears 3:1.
     --line is decorative rhythm only and is allowed to be nearly invisible. */
  --line: rgba(255, 255, 255, .08);
  --line2: rgba(255, 255, 255, .24);

  /* ── text ───────────────────────────────────────────────────────────────────
     Plain white for the things that carry the page, and two greys under it. --faint carries
     region codes, timestamps and units — the small text that has to survive a bad screen —
     so it never goes below 4.5:1.
   *
   * The numbers here are measured in the browser, not estimated. The first draft of this
   * block claimed 4.9:1 for --faint and the real figure was 4.15 — under the floor, in a
   * comment asserting it was over. A contrast note that is guessed is worse than no note:
   * the next person reads it instead of checking. */
  --txt: #ffffff;
  --muted: #9b9b9b;
  --faint: #7d7d7d;

  /* ── semantic state ─────────────────────────────────────────────────────────
   * The lime is the whole identity now.
   *
   * One acid chartreuse, used sparingly and always for the same reason: this is the part
   * that matters. It is 17.4:1 on --bg, so unlike the old emerald it is safe as type at any
   * size — which is the point, because in this palette the accent's main job is words, not
   * borders. A headline where one line is lime and the rest is white is the entire visual
   * idea, and it only works while the lime stays rare.
   *
   * --lime-dim is not a tint of the same colour used carelessly. It exists so that borders
   * and resting edges have somewhere to go that is not the headline value — the fastest way
   * to kill an accent this loud is to put it on everything at 30% opacity. */
  --lime: #d2f34c;           /* the accent: headlines, the number that matters, the answer yes */
  --lime-dim: #93ad2f;       /* borders, rules, resting edges — never type */
  --green: var(--lime);      /* kept as an alias: ~200 call sites still ask for --green */
  --green2: var(--lime-dim);
  --amber: #ffb454;          /* degraded · attention · expiring */
  --red: #ff5c4d;            /* failed · held · revoked · critical */
  --glow: rgba(210, 243, 76, .30);

  /* Ink for text sitting on an accent fill.
   *
   * There was no token for this, so two files invented one each: the dashboard wrote #0a0c0b
   * on its green buttons and the shell wrote #04120a on its own. Both read as black and
   * neither is, which is the quiet kind of inconsistency — nobody spots it, and every new
   * green button starts another coin-flip between two values that were never decided. */
  --on-accent: #0b0b0b;

  /* State pairs, so a component asks for the meaning and not the swatch. Added because
     "degraded" and "held" were being written as amber and red at each call site, which is
     how two screens end up disagreeing about what amber means. */
  --state-active: var(--green);
  --state-verified: var(--green);
  --state-degraded: var(--amber);
  --state-held: var(--red);
  --state-dormant: var(--faint);

  /* ── type ───────────────────────────────────────────────────────────────────
     Three roles, not three fonts. Display for scene headings and key numbers; interface for
     everything a person reads as prose; data for anything the system emitted — route ids,
     latency, hashes, timestamps. The rule that keeps it coherent: mono means "the machine
     said this", never "this looks technical". */
  --fd: 'Chakra Petch', system-ui, sans-serif;
  --fs: 'Space Grotesk', system-ui, sans-serif;
  --fm: 'Space Mono', ui-monospace, monospace;

  /* Scale. clamp() so a heading never needs a breakpoint to stay in its column. */
  --t-display-xl: clamp(38px, 7.2vw, 82px);
  --t-display-l: clamp(30px, 4.6vw, 54px);
  --t-heading-m: clamp(20px, 2.4vw, 27px);
  --t-body-l: 16.5px;
  --t-body: 14.5px;
  --t-label: 12.5px;
  --t-telemetry: 12px;

  --lh-display: 1.02;
  --lh-heading: 1.18;
  --lh-body: 1.6;
  --tr-display: -.03em;      /* tight, because display sizes make default tracking look loose */
  --tr-label: .12em;         /* wide, because uppercase labels need air to stay legible */

  /* ── spacing ────────────────────────────────────────────────────────────────
     A 4px base. Named by size rather than by use, so a component cannot claim a step is
     "the card gap" and then disagree with the next component that thought the same. */
  --s1: 4px;   --s2: 8px;   --s3: 12px;  --s4: 16px;
  --s5: 24px;  --s6: 32px;  --s7: 48px;  --s8: 72px;
  --s9: 96px;  --s10: 144px;

  /* ── layout ─────────────────────────────────────────────────────────────────
     Text measure is capped in ch, not px: the limit is how far an eye tracks back to the
     next line, and that is counted in characters. */
  --w-content: 1180px;
  --w-scene: 1400px;
  --measure: 68ch;
  --gutter: clamp(16px, 4vw, 32px);
  --radius: 12px;
  --radius-s: 8px;

  /* ── motion ─────────────────────────────────────────────────────────────────
     Four speeds, each for a different question. Feedback answers "did it hear me" and has
     to beat the ~150ms at which a response stops feeling caused by the click. Reveal and
     scene are slow enough to be followed, which is the point when the movement is the
     explanation rather than decoration. */
  --d-feedback: 140ms;
  --d-ui: 210ms;
  --d-reveal: 520ms;
  --d-scene: 900ms;
  --stagger: 45ms;

  --e-out: cubic-bezier(.16, .7, .3, 1);      /* arrives fast, settles — for things entering */
  --e-in-out: cubic-bezier(.65, 0, .35, 1);   /* symmetric — for things moving between states */
}

/* Somebody who has asked their machine to stop moving things has asked every page, not the
   ones that remembered. Setting the tokens to zero here means a component written later
   cannot forget: it inherits the answer through the variable it was already using. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --d-feedback: 0ms;
    --d-ui: 0ms;
    --d-reveal: 0ms;
    --d-scene: 0ms;
    --stagger: 0ms;
  }
}

/* One focus ring for the whole product.
 *
 * Not :focus — :focus-visible, so it appears for the keyboard and stays out of the way of
 * the mouse. Two layers because a single green ring vanishes against a green button: the
 * dark inner line guarantees an edge whatever it lands on. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 2px;
  border-radius: var(--radius-s);
}
