/* ─────────────────────────────────────────────────────────────────────
   robertz.co — shared simulator design language ("Rams")

   Linked from every sim as <link rel="stylesheet" href="../_rams.css">.
   The path is RELATIVE on purpose: every sim lives at
   public/sim/<key>/index.html, so this resolves both over HTTP and when
   the file is opened straight off disk with file://. The sims stay
   standalone — they just stop duplicating the same 200 lines.

   After Dieter Rams: as little design as possible. Three rules govern
   every colour decision here:

     1. Data is blue.   Traces, bars, particles, series — anything that is
                        a *quantity* — draw from the blue ramp. Series are
                        separated by weight and tone, never by hue.
     2. Colour is state. Exactly three state colours exist (run/ok/warn).
                        Coloured means "in a state"; decoration is grey.
     3. Lowercase, one mono. Labels are lowercase ui-monospace with
                        tabular numerals. No webfonts inside a sim.

   Sims may override any token in their own inline <style> (which loads
   after this file), but should not redefine the whole palette.
   ───────────────────────────────────────────────────────────────────── */

:root {
  /* ── dark instrument window ─────────────────────────────────────── */
  --bg:      #0c1320;   /* window ground — navy, not black */
  --panel:   #101725;   /* module plate */
  --panel2:  #0c121c;   /* recessed well */
  --line:    #223047;   /* hairline */
  --faint:   #182234;   /* faintest divider */
  --fg:      #cdd7e4;   /* primary text */
  --dim:     #74869b;   /* secondary text — lifted from #5d6b80, which
                           measured 3.3:1 on the window grounds (below AA) */
  --hdr:     #8496ad;   /* panel headings */

  /* ── the blue ramp — ALL quantity draws from here ───────────────── */
  --blue1:   #9fc2eb;   /* bright trace / foreground series */
  --blue2:   #6f9fd8;   /* mid trace */
  --blue3:   #2b4a75;   /* quiet fill / background series */
  --blue4:   #1a2d47;   /* trough, grid emphasis */
  --steel:   #a9b9d6;   /* pale neutral series */

  /* ── the only three state colours ───────────────────────────────── */
  --run:     #c57327;   /* engaged · write · hot · blocked — the signal lamp */
  --ok:      #4da184;   /* pass · settled · complete */
  --warn:    #cfa050;   /* back-off · caution · retry */

  /* Legacy aliases so existing draw code keeps resolving while sims are
     migrated one at a time. They deliberately collapse the old rainbow
     onto the ramp above — violet/cyan/magenta no longer exist. */
  --accent:  var(--ok);
  --accent2: var(--blue2);
  --hot:     var(--run);
  --violet:  var(--blue3);
  --cyan:    var(--blue1);
  --magenta: var(--steel);

  /* ── cabin chrome (the dash around the window) — charcoal, warm
        engraving, cognac on everything you touch ─────────────────── */
  --paper:            #141c2a;
  --paper-light:      #1a2434;
  --paper-card:       #202c3e;
  --paper-deep:       #101724;
  --rule-paper:       #2b3a52;
  --ink-warm:         #e4e9f2;
  --ink-warm-soft:    #b6c0d0;
  --ink-warm-faint:   #93a0b6;
  --navy:             #14294d;
  --accent-brick:        #a35f36;   /* cognac — engaged, touchable */
  --accent-brick-strong: #c98f5f;
  --accent-brick-soft:   rgba(163, 95, 54, 0.16);
  --paper-shadow:     rgba(0, 0, 0, 0.35);

  --mono: ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
  --radius: 6px;   /* modern key rounding; the lamp alone is round */

  /* ── cabinet elements — flat colours, no textures ───────────────────
     The instrument stack, top to bottom: navy cabinet rail → cool
     enamel control face → navy glass window → enamel status → navy
     base rail. Hardware (window bezel, slider thumbs, lamp collar) is
     light blue. Everything FLAT — shape and colour carry the cabinet,
     never grain or gloss. Modern and simple: two hues, navy and light
     blue, and nothing else outside canvas state colours. */
  --cab:       #0a1120;
  --cab-lo:    #070d18;
  --cab-text:  #e4e9f2;
  --cab-link:  #c98f5f;
  --hw-hi:     #d29a6b;
  --hw:        #a35f36;
  --hw-lo:     #6f4225;
}

/* ── token overrides that must beat each sim's own :root ───────────────
   Every sim still declares its inherited dark palette in its own
   `:root { … }`, and that block parses AFTER this sheet, so at :root level
   the sim wins on source order. Custom properties resolve by INHERITANCE
   PROXIMITY though, not source order — so declaring them on `body` (a
   nearer ancestor of every rendered element than `:root`) wins regardless.

   --dim shipped at #5e7186/#5d6b80, which measures 3.3–3.5:1 on the window
   grounds — below AA for the secondary text it carries in every sim. */
body {
  --dim: #74869b;
}

/* ── base ─────────────────────────────────────────────────────────── */
html, body { margin: 0; padding: 0; }
body {
  background: var(--paper);
  color: var(--ink-warm);
  font: 13.5px/1.5 var(--sans);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}
/* Readouts, addresses, counters stay mono by element, not by page. */
code, kbd, samp, time, .mono { font-family: var(--mono); }
* , *::before, *::after { box-sizing: border-box; }

/* ── cabinet frame ────────────────────────────────────────────────────
   Furniture-system logic: a visible structural frame carries the
   modules. Two thin navy posts run down the viewport edges; the navy
   header and footer rails close the frame; the enamel face and the
   glass window mount between them. `body > header` outranks each sim's
   own `header {}` rule by specificity, so this applies to all sims
   from this one file. Paint only — no padding or size changes, so
   every sim stays exactly as compact as before on any screen. */
body {
  border-inline: 2px solid var(--cab);
  min-height: 100vh;
}
body > header {
  background: var(--cab);
  border-bottom: 2px solid var(--hw);
  color: var(--cab-text);
}
body > header, body > footer { font-family: var(--sans); }
body > header h1,
body > header b,
body > header strong { color: var(--cab-text); font-family: var(--sans); }
body > header .sub,
body > header .crumbs,
body > header .sep { color: rgba(228, 233, 242, 0.62); }
body > header a { color: var(--cab-link); }
body > header a:hover { color: var(--hw-hi); }
/* Chips sit on the rail as enamel plates. */
body > header .badge { background: var(--paper-card); color: var(--ink-warm-soft); border-color: var(--hw-lo); }
body > footer {
  background: var(--cab-lo);
  border-top: 1px solid var(--hw-lo);
  color: var(--cab-text);
}
body > footer b, body > footer strong { color: var(--cab-text); }
body > footer a { color: var(--cab-link); }

/* ── bezel around the glass ───────────────────────────────────────────
   The window is set into the face with a 2px light-blue frame. Paint
   only — no layout size change, sims stay as compact as before. */
main canvas,
.stage canvas {
  border: 2px solid var(--hw);
}

/* ── key glyphs: the Rams line-icon register inside sim buttons ─────
   One stroke weight, currentColor, sized to the label. Sims embed the
   svg inline before the label text (see picorv32, the reference). */
.btn svg, button.k svg, .key svg,
body .toolbar button svg {
  width: 13px; height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -2px;
  margin-right: 3px;
}

/* ── controls: flat modern keys; engaged key is filled navy ────────── */
.btn,
button.k,
.key {
  font: 500 12.5px/1 var(--sans);
  letter-spacing: 0.01em;
  color: var(--ink-warm-soft);
  background: var(--paper-card);
  border: 1px solid var(--rule-paper);
  border-radius: var(--radius);
  padding: 8px 14px;
  cursor: pointer;
  transition: color .14s, border-color .14s, background .14s;
}
.btn:hover,
button.k:hover,
.key:hover {
  color: #ffffff;
  border-color: var(--hw);
}
.btn[aria-pressed="true"],
.btn.on,
button.k.on,
.key.on {
  color: #ffffff;
  font-weight: 600;
  background: var(--accent-brick);
  border-color: var(--accent-brick);
}
.btn:focus-visible,
button.k:focus-visible,
.key:focus-visible {
  outline: 2px solid var(--accent-brick);
  outline-offset: 2px;
}

/* ── jewel lamp — the only glow permitted anywhere ─────────────────── */
.lamp {
  width: 11px; height: 11px;
  border-radius: 50%;
  display: inline-block;
  background: radial-gradient(circle at 35% 30%, #ecc79f 0%, #a35f36 48%, #45291a 100%);
  border: 1px solid var(--hw-lo);
  box-shadow: 0 0 7px rgba(163, 95, 54, .5), inset 0 0 2px rgba(255, 255, 255, .35);
}
.lamp.off {
  background: radial-gradient(circle at 35% 30%, #b9aeae 0%, #7d7373 48%, #3a3434 100%);
  border-color: #6b6060;
  box-shadow: none;
}

/* ── thin slider ──────────────────────────────────────────────────── */
input[type="range"] {
  -webkit-appearance: none; appearance: none;
  height: 4px;
  background: var(--rule-paper);
  border-radius: 2px;
  outline: none;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--hw);
  border: 1px solid var(--hw-lo);
  cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--hw);
  border: 1px solid var(--hw-lo);
  cursor: pointer;
}

/* ── hover clouds (CLAUDE.md mandates these on every control) ─────── */
[data-cloud] { position: relative; }
[data-cloud]::after {
  content: attr(data-cloud);
  position: absolute;
  left: 50%; bottom: 100%;
  transform: translate(-50%, -8px);
  background: var(--navy);
  border: 1px solid var(--navy);
  border-radius: var(--radius);
  padding: 8px 11px;
  font: 11.5px/1.45 var(--mono);
  color: #eef2f8;
  width: max-content;
  max-width: min(300px, calc(100vw - 32px));
  white-space: normal;
  z-index: 500;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s ease .2s, transform .15s ease .2s;
}
[data-cloud]::before {
  content: ''; position: absolute;
  left: 50%; bottom: 100%;
  transform: translate(-50%, -2px);
  width: 0; height: 0;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 6px solid var(--navy);
  z-index: 501; opacity: 0;
  transition: opacity .15s ease .2s;
  pointer-events: none;
}
[data-cloud]:hover::after,
[data-cloud]:hover::before { opacity: 1; }
[data-cloud]:hover::after  { transform: translate(-50%, -10px); }
[data-cloud-side="below"]::after,
[data-cloud-side="below"]::before { top: 100%; bottom: auto; }
[data-cloud-side="below"]::after  { transform: translate(-50%, 8px); }
[data-cloud-side="below"]:hover::after { transform: translate(-50%, 10px); }
[data-cloud-side="below"]::before {
  transform: translate(-50%, 2px);
  border-top: none; border-bottom: 6px solid var(--navy);
}

/* Hover-cloud edge overflow.
   A centred 300px cloud hangs off the viewport when its control sits near
   an edge — measured -93px at 1440 on the first toolbar key, across every
   sim. Clipping on the LEFT is worse than on the right: you lose the start
   of the sentence and it is unrecoverable, whereas a right-clipped cloud
   still reads from its beginning.

   So: anchor to the control's LEFT edge throughout the left-aligned groups
   (toolbar, view tabs, knobs), and to the RIGHT edge for the right-aligned
   readouts (speed, counters, status) — which are the only controls sitting
   near the right edge. Every cloud then opens away from the nearest edge.

   Each sim also inlines its own [data-cloud] block, and its <style> parses
   AFTER this sheet — so at equal specificity the sim wins on source order.
   These selectors carry a `body` prefix to outrank it. */
body .toolbar > [data-cloud]::after,
body .viewtoggle > [data-cloud]::after,
body .knobs > [data-cloud]::after {
  left: 0;
  transform: translate(0, -8px);
}
body .toolbar > [data-cloud]:hover::after,
body .viewtoggle > [data-cloud]:hover::after,
body .knobs > [data-cloud]:hover::after { transform: translate(0, -10px); }
body .toolbar > [data-cloud]::before,
body .viewtoggle > [data-cloud]::before,
body .knobs > [data-cloud]::before { left: 16px; }

body .speed[data-cloud]::after,
body .cycle[data-cloud]::after,
body .tb-right [data-cloud]::after,
body .status [data-cloud]::after {
  left: auto; right: 0;
  transform: translate(0, -8px);
}
body .speed[data-cloud]:hover::after,
body .cycle[data-cloud]:hover::after,
body .tb-right [data-cloud]:hover::after,
body .status [data-cloud]:hover::after { transform: translate(0, -10px); }
body .speed[data-cloud]::before,
body .cycle[data-cloud]::before,
body .tb-right [data-cloud]::before,
body .status [data-cloud]::before { left: auto; right: 16px; }

/* Trailing control of a left-aligned group sits near the right edge too —
   mirror the rule so it opens leftward. */
body .toolbar > [data-cloud]:last-child::after,
body .viewtoggle > [data-cloud]:last-child::after,
body .knobs > [data-cloud]:last-child::after {
  left: auto; right: 0;
  transform: translate(0, -8px);
}
body .toolbar > [data-cloud]:last-child:hover::after,
body .viewtoggle > [data-cloud]:last-child:hover::after,
body .knobs > [data-cloud]:last-child:hover::after { transform: translate(0, -10px); }
body .toolbar > [data-cloud]:last-child::before,
body .viewtoggle > [data-cloud]:last-child::before,
body .knobs > [data-cloud]:last-child::before { left: auto; right: 16px; }

/* Phones: a ~300px cloud cannot sit beside a control inside a 390px
   viewport without clipping on one side or the other, whatever it is
   anchored to — measured, not assumed. So stop anchoring it to the control
   and dock it to the viewport as a full-width bar at the bottom, which is
   the usual mobile pattern and is always fully readable. (Touch devices do
   not hover at all; this is for a narrow desktop window.) */
@media (max-width: 560px) {
  body [data-cloud]::after {
    position: fixed;
    left: 10px; right: 10px; bottom: 10px; top: auto;
    width: auto; max-width: none;
    transform: none;
  }
  body [data-cloud]:hover::after { transform: none; }
  body [data-cloud]::before { display: none; }
}

/* ── legibility guard for the floating cards ───────────────────────────
   The sims were written against a light paper theme and each hardcodes a
   cream `rgba(251,246,231,…)` surface (with !important) on the narration
   strip and the canvas hover-tooltip. Their TEXT resolves through
   --ink-warm, which is now near-white for the dark cabin — leaving those
   cards at ~1.06:1 contrast, i.e. unreadable, including the hover
   explanations CLAUDE.md makes mandatory.

   Fixed centrally rather than in 16 files. This sheet loads BEFORE each
   sim's inline <style>, so at equal importance the sim would win on
   source order. These rules therefore carry !important AND a `body`
   prefix, so they outrank the sims' own `.notif { … !important }` on
   specificity (0,1,1 vs 0,1,0) regardless of order. */
body .notif,
body .insp {
  background: var(--paper-card) !important;
  border-color: var(--rule-paper) !important;
  color: var(--ink-warm) !important;
  backdrop-filter: none;
}
body .notif-title,
body .notif-title b { color: var(--ink-warm) !important; }
body .notif-text  { color: var(--ink-warm-soft) !important; }
body .notif-time  { color: var(--ink-warm-faint) !important; }
body .insp b,
body #notif-state,
body .notif-state { color: var(--accent-brick-strong) !important; }

/* ── canvas inspector tooltip ─────────────────────────────────────── */
.insp {
  position: absolute;
  display: none;
  background: var(--navy);
  border: 1px solid var(--navy);
  border-radius: var(--radius);
  padding: 7px 10px;
  font: 11.5px/1.45 var(--mono);
  color: #eef2f8;
  max-width: 320px;
  pointer-events: none;
  z-index: 600;
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}
