/* ============================================================
   PRODECK — Inventor's Codex, instrumented.

   Design system inherited wholesale from cadens_portfolio: chalkboard
   blueprint ground, electric blue + neon red signal colours, mono
   eyebrows, hairline grids, handwritten marginalia. What's new here is
   the panel grid, the renderers, and a second surface (Mission Control)
   that scales the whole thing up for a wall display.

   One stylesheet serves both surfaces. Mission Control differs by a
   --scale multiplier and a handful of overrides under [data-surface].
   ============================================================ */

:root {
  --bg:        #06080F;
  --bg-2:      #090D18;

  --surface-1: rgba(16, 23, 41, 0.94);
  --surface-2: rgba(21, 30, 54, 0.94);
  /* The portfolio can afford translucent panels because its sections are
     mostly whitespace. A dashboard is dense, so panels here are nearly
     opaque — the chalkboard reads in the gutters and margins instead of
     behind the numbers. */
  --panel:     rgba(9, 13, 24, 0.90);

  --line:      rgba(96, 128, 188, 0.16);
  --line-2:    rgba(96, 128, 188, 0.30);

  --ink:       #EAF1FF;
  --ink-2:     #B4C1DA;
  --muted:     #7C8AA8;
  --faint:     #55617C;

  --hot:       #3E7DFF;
  --hot-soft:  rgba(62, 125, 255, 0.14);
  --hot-line:  rgba(62, 125, 255, 0.48);
  --hot-glow:  rgba(62, 125, 255, 0.65);

  --red:       #FF2E43;
  --red-soft:  rgba(255, 46, 67, 0.14);
  --red-line:  rgba(255, 46, 67, 0.52);
  --red-glow:  rgba(255, 46, 67, 0.62);

  --steel:     #6E88B8;
  --good:      #35D6A4;
  --good-glow: rgba(53, 214, 164, 0.55);

  --sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", "Roboto Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --hand: "Chalkboard SE", "Bradley Hand", "Segoe Print", "Comic Sans MS", cursive;

  --scale: 1;
  --gutter: clamp(0.9rem, 2.5vw, 1.6rem);
}

* { box-sizing: border-box; }

html {
  /* the single knob Mission Control turns to become legible across a room */
  font-size: calc(16px * var(--scale));
}

body {
  margin: 0;
  min-height: 100vh;
  background-color: var(--bg);
  background-image:
    radial-gradient(1100px 640px at 80% -6%, rgba(62,125,255,0.12), transparent 60%),
    radial-gradient(940px 560px at 4% 100%, rgba(255,46,67,0.10), transparent 58%),
    radial-gradient(700px 700px at 50% 40%, rgba(10,14,26,0), rgba(4,6,12,0.65) 90%);
  color: var(--ink-2);
  font-family: var(--sans);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

::selection { background: var(--red); color: #06080F; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--hot); outline-offset: 3px; border-radius: 2px; }
h1, h2, h3, h4 { color: var(--ink); margin: 0; text-wrap: balance; }

/* ============================================================
   CODEX — the fixed chalkboard backdrop
   ============================================================ */
.codex { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.codex::before {
  content: ""; position: absolute; inset: -20%;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.45'/%3E%3C/svg%3E");
  opacity: 0.04; mix-blend-mode: screen;
}
.note {
  position: absolute; font-family: var(--hand); white-space: nowrap;
  font-size: clamp(0.78rem, 1.3vw, 1.02rem);
  color: rgba(180, 200, 235, 0.17); letter-spacing: 0.01em;
}
.note.blue { color: rgba(62, 125, 255, 0.24); }
.note.red  { color: rgba(255, 46, 67, 0.22); }
.schem { position: absolute; color: var(--hot); opacity: 0.11; transform-origin: center; }
.schem.red { color: var(--red); }
.s-astro { animation: spin 200s linear infinite; }
.s-gear  { animation: spin 150s linear infinite reverse; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (max-width: 820px) { .codex .hide-sm { display: none; } .note { font-size: 0.8rem; } }

/* everything sits above the codex */
.shell { position: relative; z-index: 1; }

/* ============================================================
   shared type
   ============================================================ */
.eyebrow {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--hot);
  display: inline-flex; align-items: center; gap: 0.6em;
}
.eyebrow::before { content: ""; width: 20px; height: 1px; background: var(--hot-line); }
.eyebrow.red { color: var(--red); }
.eyebrow.red::before { background: var(--red-line); }

.mono { font-family: var(--mono); }
.dim  { color: var(--muted); }
.faint { color: var(--faint); }

.live-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--red);
  box-shadow: 0 0 9px var(--red-glow); animation: blip 2.6s ease-in-out infinite;
  display: inline-block; flex: none;
}
.live-dot.good { background: var(--good); box-shadow: 0 0 9px var(--good-glow); }
.live-dot.idle { background: var(--faint); box-shadow: none; animation: none; }
@keyframes blip { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

/* ============================================================
   TOPBAR
   ============================================================ */
.topbar {
  position: sticky; top: 0; z-index: 50;
  backdrop-filter: blur(11px); background: rgba(6, 8, 15, 0.78);
  border-bottom: 1px solid var(--line);
}
.topbar-inner {
  display: flex; align-items: center; gap: 1rem;
  padding: 0 var(--gutter); height: calc(3.6rem);
}
.brand {
  display: inline-flex; align-items: center; gap: 0.7rem;
  font-family: var(--mono); font-weight: 600; letter-spacing: 0.03em; color: var(--ink);
  font-size: 0.95rem;
}
.brand .mark {
  display: inline-grid; place-items: center; width: 30px; height: 32px;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  background: var(--hot-soft); color: var(--hot);
  font-size: 0.8rem; font-weight: 700;
  filter: drop-shadow(0 0 6px var(--hot-glow));
}
.brand .sub { color: var(--muted); font-weight: 400; font-size: 0.78rem; }
.topbar-spacer { flex: 1; }
.topbar-stats {
  display: flex; gap: 1.1rem; font-family: var(--mono);
  font-size: 0.7rem; letter-spacing: 0.08em; color: var(--muted);
  text-transform: uppercase; align-items: center;
}
.topbar-stats .stat { display: inline-flex; align-items: center; gap: 0.45em; white-space: nowrap; }
.topbar-stats b { color: var(--ink); font-weight: 600; }
@media (max-width: 700px) { .topbar-stats .opt { display: none; } }

.kbd-hint {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.08em;
  color: var(--muted); border: 1px solid var(--line-2);
  padding: 0.35rem 0.6rem; cursor: pointer;
  transition: border-color .18s ease, color .18s ease, background .18s ease;
}
.kbd-hint:hover { border-color: var(--hot-line); color: var(--hot); background: var(--hot-soft); }

/* ============================================================
   PANEL GRID
   The portfolio's signature: 1px gaps over a hairline background, so
   the seams read as blueprint rules rather than as card shadows.
   ============================================================ */
.deck-body { padding: var(--gutter); }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.panel {
  position: relative;
  background: var(--panel);
  padding: 1.15rem 1.15rem 1.25rem;
  display: flex; flex-direction: column; gap: 0.85rem;
  min-height: 9.5rem;
  transition: background .2s ease;
  overflow: hidden;
}
.panel:hover { background: var(--surface-1); }
.panel[data-span="2"] { grid-column: span 2; }
.panel[data-span="3"] { grid-column: span 3; }
@media (max-width: 780px) {
  .panel[data-span="2"], .panel[data-span="3"] { grid-column: span 1; }
}

/* corner bracket, lifted from .xp-featured — marks the accent colour */
.panel::before {
  content: ""; position: absolute; top: -1px; left: -1px;
  width: 13px; height: 13px;
  border: 2px solid var(--hot); border-right: none; border-bottom: none;
  filter: drop-shadow(0 0 6px var(--hot-glow));
  opacity: 0; transition: opacity .2s ease;
}
.panel[data-accent="hot"]::before   { border-color: var(--hot); filter: drop-shadow(0 0 6px var(--hot-glow)); opacity: 1; }
.panel[data-accent="red"]::before   { border-color: var(--red); filter: drop-shadow(0 0 6px var(--red-glow)); opacity: 1; }
.panel[data-accent="steel"]::before { border-color: var(--steel); filter: none; opacity: 0.8; }

.panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.8rem; }
.panel-title { font-size: 0.95rem; font-weight: 650; color: var(--ink); letter-spacing: -0.01em; }
.panel-sub { font-family: var(--mono); font-size: 0.65rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); white-space: nowrap; }
.panel-body { flex: 1; display: flex; flex-direction: column; justify-content: center; min-height: 0; }

.panel.is-stale { opacity: 0.55; }
.panel.is-fault { background: rgba(255, 46, 67, 0.05); }
.panel.is-fault::before { border-color: var(--red); opacity: 1; }
.fault {
  font-family: var(--mono); font-size: 0.72rem; color: var(--red);
  line-height: 1.5; word-break: break-word;
}
.disabled-note {
  font-family: var(--mono); font-size: 0.72rem; color: var(--faint);
  border: 1px dashed var(--line-2); padding: 0.6rem 0.7rem; line-height: 1.5;
}

/* ============================================================
   RENDERERS
   ============================================================ */

/* — stat: one number that matters — */
.r-stat { display: flex; flex-direction: column; gap: 0.2rem; }
.r-stat .value {
  font-family: var(--mono); font-size: 2.5rem; font-weight: 600;
  color: var(--ink); letter-spacing: -0.03em; line-height: 1;
}
.r-stat .value .unit { font-size: 0.42em; color: var(--muted); margin-left: 0.25em; letter-spacing: 0.06em; }
.r-stat .label { font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.r-stat .trend { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.04em; margin-top: 0.3rem; }
.r-stat .trend.up   { color: var(--good); }
.r-stat .trend.down { color: var(--red); }
.r-stat .trend.flat { color: var(--faint); }
.r-stat[data-tone="hot"] .value { color: var(--hot); text-shadow: 0 0 24px var(--hot-soft); }
.r-stat[data-tone="red"] .value { color: var(--red); text-shadow: 0 0 24px var(--red-soft); }
.r-stat[data-tone="good"] .value { color: var(--good); }

/* — gauge: the astrolabe, reused as a dial — */
.r-gauge { display: flex; align-items: center; gap: 1.1rem; }
.dial-wrap { display: flex; flex-direction: column; align-items: center; gap: 0.45rem; flex: none; }
.dial-cap {
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--faint); white-space: nowrap;
}
.dial { position: relative; width: 6.4rem; aspect-ratio: 1; flex: none; }
.dial-layer { position: absolute; inset: 0; border-radius: 50%; }
.dial-ticks {
  background: repeating-conic-gradient(from 0deg, var(--hot-line) 0deg 0.5deg, transparent 0.5deg 6deg);
  -webkit-mask: radial-gradient(closest-side, #0000 76%, #000 78%, #000 88%, #0000 90%);
          mask: radial-gradient(closest-side, #0000 76%, #000 78%, #000 88%, #0000 90%);
  animation: spin 120s linear infinite;
}
.dial-track { inset: 8%; border: 1px solid var(--line-2); }
.dial-arc {
  inset: 4%;
  /* --pct is written by the renderer; 0–100 */
  background: conic-gradient(from 180deg, var(--dial-color, var(--hot)) 0deg calc(var(--pct, 0) * 3.6deg), transparent 0deg);
  -webkit-mask: radial-gradient(closest-side, #0000 82%, #000 84%, #000 96%, #0000 98%);
          mask: radial-gradient(closest-side, #0000 82%, #000 84%, #000 96%, #0000 98%);
  filter: drop-shadow(0 0 6px var(--dial-glow, var(--hot-glow)));
  transition: background .5s ease;
}
.dial-core {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--mono); font-size: 1.15rem; font-weight: 600; color: var(--ink);
  letter-spacing: -0.02em;
}
.r-gauge .legs { display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }
.r-gauge .leg { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.04em; color: var(--muted); display: flex; gap: 0.5em; justify-content: space-between; }
.r-gauge .leg b { color: var(--ink-2); font-weight: 500; }

/* — list: rows of label / value — */
.r-list { display: flex; flex-direction: column; }
.r-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.9rem;
  padding: 0.5rem 0; border-bottom: 1px solid var(--line);
}
.r-row:last-child { border-bottom: none; }
.r-row .k { color: var(--ink-2); font-size: 0.9rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.r-row .k small { display: block; color: var(--faint); font-size: 0.76em; font-family: var(--mono); letter-spacing: 0.04em; }
.r-row .v { font-family: var(--mono); font-size: 0.78rem; color: var(--muted); letter-spacing: 0.04em; white-space: nowrap; }
.r-row .v.hot { color: var(--hot); }
.r-row .v.red { color: var(--red); }
.r-row .v.good { color: var(--good); }

/* — log: the live event stream — */
.r-log { display: flex; flex-direction: column; gap: 0.1rem; font-family: var(--mono); font-size: 0.72rem; overflow: hidden; }
.log-line { display: flex; gap: 0.7em; align-items: baseline; padding: 0.22rem 0; line-height: 1.45; }
.log-line .t { color: var(--faint); flex: none; letter-spacing: 0.02em; }
.log-line .m { color: var(--steel); flex: none; text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.9em; }
.log-line .x { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.log-line[data-level="warn"]   .x { color: #FFC65C; }
.log-line[data-level="alert"]  .x { color: var(--red); }
.log-line[data-level="notice"] .x { color: var(--ink); }
.log-line[data-level="debug"]  .x { color: var(--faint); }
.log-line.fresh { animation: flashin .9s ease-out; }
@keyframes flashin { from { background: var(--hot-soft); } to { background: transparent; } }

/* — text / grid / frame — */
.r-text { color: var(--ink-2); font-size: 0.92rem; line-height: 1.6; }
.r-text .hand { font-family: var(--hand); color: var(--steel); font-size: 1.05em; }
.r-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr)); gap: 0.9rem 1.1rem; }
.r-cell .cv { font-family: var(--mono); font-size: 1.3rem; color: var(--ink); font-weight: 600; letter-spacing: -0.02em; }
.r-cell .cl { font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); }
.r-frame { border: 1px solid var(--line); background: #000; }
.r-frame iframe { display: block; width: 100%; height: 100%; border: 0; }

/* chips, reused everywhere */
.chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.chip {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.04em;
  color: var(--ink-2); background: var(--panel);
  border: 1px solid var(--line-2); padding: 0.26rem 0.55rem;
}
.chip.off { color: var(--faint); border-style: dashed; }

/* ============================================================
   GUEST MODE
   ============================================================ */
.guest-toggle.on {
  color: var(--red); border-color: var(--red-line); background: var(--red-soft);
}
.guest-badge {
  color: var(--red) !important; border: 1px solid var(--red-line);
  padding: 0.28rem 0.5rem; letter-spacing: 0.14em;
}

.panel.is-withheld { background: rgba(21, 30, 54, 0.55); }
.panel.is-withheld::before { border-color: var(--faint); filter: none; opacity: 0.7; }
.withheld {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.5rem; text-align: center; color: var(--faint);
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.1em;
  text-transform: uppercase; min-height: 5rem;
}
.withheld-mark { font-size: 1.5rem; color: var(--steel); opacity: 0.6; }

/* ============================================================
   QR CORNER  (Mission Control)
   ============================================================ */
.qr-corner {
  position: fixed; right: 1.1rem; bottom: 1.1rem; z-index: 40;
  display: flex; align-items: flex-end; gap: 0.6rem;
  padding: 0.7rem; background: rgba(6, 8, 15, 0.92);
  border: 1px solid var(--line-2);
}
.qr-corner::before {
  content: ""; position: absolute; bottom: -1px; right: -1px;
  width: 13px; height: 13px;
  border: 2px solid var(--hot); border-left: none; border-top: none;
  filter: drop-shadow(0 0 6px var(--hot-glow));
}
.qr-code { width: 5.2rem; height: 5.2rem; color: var(--ink); }
.qr-code svg { display: block; width: 100%; height: 100%; }
.qr-label {
  font-family: var(--mono); font-size: 0.54rem; line-height: 1.5;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted);
  writing-mode: vertical-rl; text-orientation: mixed; transform: rotate(180deg);
}
@media (max-height: 700px) { .qr-corner { display: none; } }

/* ============================================================
   OPS — the public showcase page
   Wider measure, more air, bigger type than the deck. This is the
   page you send someone, so it is allowed to be slower and prettier.
   ============================================================ */
[data-surface="ops"] body { font-size: 17px; }
.ops { max-width: 68rem; margin-inline: auto; padding-inline: var(--gutter); }

.ops-hero {
  padding-block: clamp(3rem, 9vw, 6rem) clamp(2rem, 5vw, 3rem);
  display: grid; grid-template-columns: 1.15fr 0.85fr;
  align-items: center; gap: clamp(1.5rem, 5vw, 4rem);
}
@media (max-width: 900px) {
  .ops-hero { grid-template-columns: 1fr; }
  .ops-hud { display: none; }   /* decorative; don't cost a phone the bandwidth */
}

/* ---------- the live astrolabe ----------
   Lifted from the portfolio's hero HUD, but the two arcs are driven by
   --mem and --cpu rather than being fixed decoration. */
.ops-hud { position: relative; width: min(30vw, 320px); aspect-ratio: 1; justify-self: center; }
.ops-hud .hud-layer { position: absolute; inset: 0; border-radius: 50%; }
.ops-hud .hud-ticks {
  background: repeating-conic-gradient(from 0deg, var(--hot-line) 0deg 0.4deg, transparent 0.4deg 5deg);
  -webkit-mask: radial-gradient(closest-side, #0000 78%, #000 79%, #000 87%, #0000 88%);
          mask: radial-gradient(closest-side, #0000 78%, #000 79%, #000 87%, #0000 88%);
  animation: spin 90s linear infinite;
}
.ops-hud .hud-ticks-2 {
  inset: 19%;
  background: repeating-conic-gradient(from 0deg, var(--red-line) 0deg 0.3deg, transparent 0.3deg 3deg);
  -webkit-mask: radial-gradient(closest-side, #0000 74%, #000 75%, #000 82%, #0000 83%);
          mask: radial-gradient(closest-side, #0000 74%, #000 75%, #000 82%, #0000 83%);
  animation: spin 60s linear infinite reverse;
}
.ops-hud .hud-arc {
  inset: 5%;
  background: conic-gradient(from 202deg, var(--red) 0deg calc(var(--mem, 0) * 3.6deg), transparent 0deg);
  -webkit-mask: radial-gradient(closest-side, #0000 90%, #000 91%, #000 95%, #0000 96%);
          mask: radial-gradient(closest-side, #0000 90%, #000 91%, #000 95%, #0000 96%);
  filter: drop-shadow(0 0 5px var(--red-glow));
  transition: background .8s ease;
  animation: spin 45s linear infinite reverse;
}
.ops-hud .hud-arc-2 {
  inset: 5%;
  background: conic-gradient(from 30deg, var(--hot) 0deg calc(var(--cpu, 0) * 3.6deg), transparent 0deg);
  -webkit-mask: radial-gradient(closest-side, #0000 84%, #000 85%, #000 89%, #0000 90%);
          mask: radial-gradient(closest-side, #0000 84%, #000 85%, #000 89%, #0000 90%);
  filter: drop-shadow(0 0 5px var(--hot-glow));
  transition: background .8s ease;
  animation: spin 70s linear infinite;
}
.ops-hud .hud-ring-dashed { inset: 14%; border: 1px dashed var(--hot-line); }
.ops-hud .hud-ring-solid  { inset: 21%; border: 1px solid var(--line-2); }
.ops-hud .hud-hex {
  position: absolute; inset: 30%;
  clip-path: polygon(50% 1%, 94% 25%, 94% 75%, 50% 99%, 6% 75%, 6% 25%);
  /* The portfolio fills this hex with a headshot. With nothing inside it, a
     flat --hot-soft fill reads as a dark blob, so it gets a gradient and a
     brighter glyph to hold the centre of the composition. */
  background:
    radial-gradient(circle at 50% 35%, rgba(62,125,255,0.30), rgba(62,125,255,0.08) 70%),
    rgba(9, 13, 24, 0.9);
  display: grid; place-items: center;
  animation: hudbreathe 4.6s ease-in-out infinite;
}
.ops-hud .hud-hex span {
  font-family: var(--mono); font-size: 3.2rem; line-height: 1;
  color: var(--hot); text-shadow: 0 0 22px var(--hot-glow);
}
@keyframes hudbreathe {
  0%, 100% { filter: drop-shadow(0 0 13px var(--hot-glow)); }
  50%      { filter: drop-shadow(0 0 28px var(--hot-glow)); }
}
.ops-hud .hud-tag {
  position: absolute; font-family: var(--mono); font-size: 0.6rem;
  letter-spacing: 0.12em; color: var(--muted);
  text-transform: uppercase; white-space: nowrap;
}
.ops-hud .hud-tag b { color: var(--hot); font-weight: 500; }
.ops-hud .t-tl { top: 2%;  left: 0; }
.ops-hud .t-tr { top: 7%;  right: 0; text-align: right; }
.ops-hud .t-bl { bottom: 7%; left: 0; }
.ops-hud .t-br { bottom: 2%; right: 0; text-align: right; color: var(--red); }
.ops-title {
  font-size: clamp(3rem, 11vw, 6.5rem); font-weight: 800;
  letter-spacing: -0.045em; line-height: 0.92; margin: 1.1rem 0 1.4rem;
}
.ops-title .a-blue { color: var(--hot); text-shadow: 0 0 40px var(--hot-glow); }
.ops-lede {
  max-width: 54ch; font-size: clamp(1rem, 2vw, 1.2rem);
  color: var(--ink-2); line-height: 1.65;
}
.ops-lede .a-red { color: var(--red); }

.ops-cta { display: flex; gap: 0.8rem; flex-wrap: wrap; margin-top: 2rem; }
.ops-cta .btn {
  font-family: var(--mono); font-size: 0.78rem; letter-spacing: 0.08em;
  text-transform: uppercase; padding: 0.8rem 1.3rem;
  border: 1px solid var(--line-2); color: var(--ink);
  display: inline-flex; align-items: center;
  transition: border-color .18s ease, background .18s ease, transform .18s ease, box-shadow .18s ease;
}
.ops-cta .btn:hover { transform: translateY(-2px); }
.ops-cta .btn-primary { background: var(--hot); color: #060810; border-color: var(--hot); font-weight: 700; }
.ops-cta .btn-primary:hover { background: #5b90ff; box-shadow: 0 0 24px var(--hot-soft); }
.ops-cta .btn-ghost:hover { border-color: var(--red-line); background: var(--red-soft); color: var(--red); }

.ops-uptime { margin-top: clamp(2.2rem, 5vw, 3.4rem); }
.ops-uptime-val {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: clamp(2.6rem, 9vw, 5rem); font-weight: 600;
  letter-spacing: -0.04em; line-height: 1; color: var(--ink);
}
.ops-uptime-val b { font-weight: 600; }
.ops-uptime-val i {
  font-style: normal; font-size: 0.4em; color: var(--muted);
  margin: 0 0.45em 0 0.1em; letter-spacing: 0.04em;
}
.ops-uptime-label {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--faint); margin-top: 0.7rem;
}
.ops-live {
  display: inline-flex; align-items: center; gap: 0.55em; margin-top: 1.1rem;
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--good);
}

/* the counters band */
.ops-band { border-block: 1px solid var(--line); background: var(--surface-1); }
.ops-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: 1px; background: var(--line);
}
.ops-cell { background: var(--panel); padding: 1.5rem 1.2rem; }
.ops-cell-v {
  font-family: var(--mono); font-size: clamp(1.6rem, 4vw, 2.3rem);
  font-weight: 600; letter-spacing: -0.03em; color: var(--hot);
  text-shadow: 0 0 24px var(--hot-soft); line-height: 1;
}
.ops-cell-l {
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--faint); margin-top: 0.55rem;
}

.ops-main { padding-block: clamp(2.5rem, 6vw, 4rem); }
.ops-section { padding-block: clamp(1.8rem, 4vw, 3rem); }
.ops-section .section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  border-bottom: 1px solid var(--line); padding-bottom: 1rem; margin-bottom: 2rem;
}
.ops-section h2 {
  font-size: clamp(1.3rem, 3vw, 1.8rem); font-weight: 700; letter-spacing: -0.015em;
}
.ops-section .section-index {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.16em;
  color: var(--faint); display: inline-flex; align-items: center; gap: 0.6em;
}
.ops-section .section-index::before {
  content: ""; width: 6px; height: 6px; background: var(--red);
  box-shadow: 0 0 6px var(--red-glow);
}

.ops-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
}
.ops-stat { background: var(--panel); padding: 1.5rem 1.3rem; }
.ops-stat-v {
  font-family: var(--mono); font-size: clamp(1.5rem, 3.6vw, 2.1rem);
  font-weight: 600; letter-spacing: -0.03em; color: var(--ink); line-height: 1;
}
.ops-stat-v .u { font-size: 0.44em; color: var(--muted); margin-left: 0.22em; }
.ops-stat-l {
  font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--faint); margin-top: 0.6rem;
}
.ops-stat[data-tone="good"] .ops-stat-v { color: var(--good); }
.ops-stat[data-tone="red"]  .ops-stat-v { color: var(--red); }
.ops-stat[data-tone="hot"]  .ops-stat-v { color: var(--hot); }
.ops-note-line {
  font-family: var(--mono); font-size: 0.74rem; color: var(--muted);
  letter-spacing: 0.03em; margin: 1rem 0 0;
}

/* activity ticker */
.ops-ticker {
  display: flex; flex-direction: column;
  border: 1px solid var(--line); background: var(--panel);
}
.ops-tick {
  display: grid; grid-template-columns: 5.5rem 7rem 1fr auto;
  gap: 0.9rem; align-items: baseline;
  font-family: var(--mono); font-size: 0.76rem;
  padding: 0.6rem 1rem; border-bottom: 1px solid var(--line);
}
.ops-tick:last-child { border-bottom: none; }
.ops-tick .tk-t { color: var(--faint); }
.ops-tick .tk-m { color: var(--hot); text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.9em; }
.ops-tick .tk-k { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ops-tick .tk-a { color: var(--faint); font-size: 0.9em; }
.ops-tick[data-level="warn"]  .tk-k { color: #FFC65C; }
.ops-tick[data-level="alert"] .tk-k { color: var(--red); }
@media (max-width: 640px) {
  .ops-tick { grid-template-columns: 4.5rem 1fr; }
  .ops-tick .tk-a { display: none; }
}

.ops-fine {
  font-family: var(--mono); font-size: 0.7rem; line-height: 1.7;
  color: var(--faint); max-width: 68ch; margin: 1.2rem 0 0;
}

.ops-notes {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
}
.ops-note { background: var(--panel); padding: 1.6rem 1.4rem; }
.ops-note h3 {
  font-size: 1rem; font-weight: 650; letter-spacing: -0.01em; margin-bottom: 0.6rem;
}
.ops-note p { margin: 0; color: var(--muted); font-size: 0.9rem; line-height: 1.6; }

.ops-foot {
  border-top: 1px solid var(--line); padding-block: 2.2rem;
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem; flex-wrap: wrap; font-size: 0.85rem;
}
.ops-owner {
  color: var(--ink); font-weight: 600; margin-right: 0.7rem;
  border-bottom: 1px solid var(--hot-line);
}
.ops-owner:hover { color: var(--hot); }
.ops-foot .faint { font-size: 0.82rem; }

/* ============================================================
   COMMAND PALETTE  (⌘K)
   ============================================================ */
.palette-scrim {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(3, 5, 10, 0.72); backdrop-filter: blur(6px);
  display: none; padding: 8vh var(--gutter) 2rem; justify-content: center;
}
.palette-scrim.open { display: flex; }
.palette {
  width: min(40rem, 100%); align-self: flex-start;
  background: var(--surface-2); border: 1px solid var(--line-2);
  box-shadow: 0 24px 80px rgba(0,0,0,0.6);
  display: flex; flex-direction: column; max-height: 70vh;
}
.palette::before, .palette::after {
  content: ""; position: absolute; width: 15px; height: 15px;
  border: 2px solid var(--hot); filter: drop-shadow(0 0 6px var(--hot-glow));
}
.palette { position: relative; }
.palette::before { top: -1px; left: -1px; border-right: none; border-bottom: none; }
.palette::after { bottom: -1px; right: -1px; border-left: none; border-top: none; }

.palette input {
  appearance: none; width: 100%; background: transparent; border: 0;
  border-bottom: 1px solid var(--line); color: var(--ink);
  font-family: var(--mono); font-size: 1rem; letter-spacing: 0.02em;
  padding: 1.1rem 1.2rem; outline: none;
}
.palette input::placeholder { color: var(--faint); }
.palette-list { overflow-y: auto; padding: 0.4rem 0; }
.palette-item {
  display: flex; align-items: baseline; gap: 0.8rem;
  padding: 0.65rem 1.2rem; cursor: pointer;
  border-left: 2px solid transparent;
}
.palette-item .pi-icon { font-family: var(--mono); color: var(--steel); flex: none; }
.palette-item .pi-title { color: var(--ink-2); font-size: 0.92rem; }
.palette-item .pi-sub { font-family: var(--mono); font-size: 0.68rem; color: var(--faint); letter-spacing: 0.06em; margin-left: auto; text-transform: uppercase; white-space: nowrap; }
.palette-item[aria-selected="true"] {
  background: var(--hot-soft); border-left-color: var(--hot);
}
.palette-item[aria-selected="true"] .pi-title { color: var(--ink); }
.palette-empty { padding: 1.4rem 1.2rem; font-family: var(--mono); font-size: 0.78rem; color: var(--faint); }
.palette-foot {
  border-top: 1px solid var(--line); padding: 0.6rem 1.2rem;
  font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.1em;
  color: var(--faint); text-transform: uppercase;
  display: flex; gap: 1.2rem; flex-wrap: wrap;
}

/* toast */
.toast-rail { position: fixed; bottom: 1.2rem; right: 1.2rem; z-index: 95; display: flex; flex-direction: column; gap: 0.5rem; align-items: flex-end; }
.toast {
  font-family: var(--mono); font-size: 0.74rem; letter-spacing: 0.04em;
  background: var(--surface-2); border: 1px solid var(--line-2);
  border-left: 2px solid var(--hot); color: var(--ink-2);
  padding: 0.7rem 0.95rem; max-width: 22rem;
  animation: toastin .25s ease-out;
}
.toast.bad { border-left-color: var(--red); color: #FFD3D8; }
@keyframes toastin { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ============================================================
   MISSION CONTROL  — HDMI, ten-foot, no cursor
   ============================================================ */
[data-surface="mission"] { cursor: none; overflow: hidden; }
[data-surface="mission"] body { overflow: hidden; }

/* A wall display must fit exactly. Nobody is going to walk over and scroll
   the TV, so the grid is pinned to the viewport and rows share the height
   evenly — whatever lands on a page fills the screen and nothing is ever
   cut off. Pagination in mission.js keeps the panel count per page low
   enough that this stays legible. */
/* The shell owns the viewport and the body takes what's left. Previously
   this was calc(100vh - 3.2rem), which hardcoded an assumed topbar height —
   and any deviation pushed content past the bottom of a screen nobody can
   scroll. Measuring beats guessing. */
[data-surface="mission"] .shell {
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
[data-surface="mission"] .topbar { flex: none; }
[data-surface="mission"] .deck-body {
  padding: 0.9rem 1.1rem 1.1rem;
  flex: 1;
  overflow: hidden;
  /* Pinned grid takes whatever's left; the rail is a fixed slice. */
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
[data-surface="mission"] .grid {
  border-inline: none;
  flex: 1;
  min-height: 0;
  grid-auto-rows: 1fr;
}

/* ---------- the rotating rail ----------
   Less important panels, smaller, cycling. The point of separating them is
   that a dice roll and a memory gauge are not equally worth a third of a
   television, and pagination alone can't express that. */
.mission-rail {
  flex: none;
  display: flex;
  align-items: stretch;
  gap: 0.9rem;
  /* Tall enough that a three-row list fits without clipping. The pinned grid
     still keeps ~three quarters of the screen, which is plenty for five
     panels in two rows. */
  height: clamp(7.5rem, 23vh, 13rem);
}
.mission-rail[hidden] { display: none; }
.rail-label {
  flex: none; width: 2.4rem;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.5rem;
  font-family: var(--mono); font-size: 0.58rem; letter-spacing: 0.16em;
  color: var(--faint); text-transform: uppercase;
  border-left: 2px solid var(--red-line);
}
.rail-label #rail-count { writing-mode: vertical-rl; text-orientation: mixed; }
.rail-mark { color: var(--red); animation: railpulse 3s ease-in-out infinite; }
@keyframes railpulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }

.rail-grid {
  flex: 1; min-width: 0;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: 1px; background: var(--line); border: 1px solid var(--line);
  animation: pagein .55s cubic-bezier(.2,.7,.2,1);
}
/* The QR sits fixed in the bottom-right corner, so the rail has to stop short
   of it rather than slide underneath. --qr-w is measured from the real element
   after it renders — hardcoding a rem value guesses wrong, because the code's
   size depends on the URL length and the label on the type scale. */
html[data-qr="on"] .mission-rail { margin-right: calc(var(--qr-w, 8rem) + 1.6rem); }

.rail-grid .panel { min-height: 0; padding: 0.85rem 0.95rem; gap: 0.5rem; }
.rail-grid .panel-title {
  font-size: 0.82rem;
  /* min-width:0 is what lets a flex child actually shrink and ellipsis
     rather than being squeezed to nothing by its nowrap sibling. */
  min-width: 0; flex: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* In a tile this small "Storage" earns its space and "SD CARD" doesn't. */
.rail-grid .panel-sub { display: none; }
.rail-grid .r-stat .value { font-size: 1.5rem; }
.rail-grid .dial { width: 3.4rem; }
.rail-grid .dial-cap { display: none; }
.rail-grid .r-gauge { gap: 0.7rem; }
.rail-grid .leg, .rail-grid .r-row .k, .rail-grid .r-row .v { font-size: 0.68rem; }
.rail-grid .r-row { padding: 0.26rem 0; }
.rail-grid .r-cell .cv { font-size: 1rem; }
.rail-grid .r-log { font-size: 0.62rem; }

/* The sub-line under each row ("820G free of 926G", "this panel only reports
   on a Raspberry Pi") is what was overflowing these tiles. It's the least
   important text on screen and the first thing to go at this size — the row
   label and its value carry the meaning. */
.rail-grid .r-row .k small { display: none; }
.rail-grid .r-row .k { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Content starts at the top rather than centring, so a list that is one row
   too long loses its last row instead of half a row at each end. */
.rail-grid .panel-body { justify-content: flex-start; }

/* Lists and logs no longer need a fade — fitRows() in mission.js hides any
   row that can't be shown whole, so there is never a partial row to
   disguise. The mask stays off deliberately: a fade over a complete row
   just makes readable text look broken. */
.rail-grid .r-list,
.rail-grid .r-log,
.rail-grid .r-grid { overflow: hidden; }
.rail-grid .r-text {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 0.78rem; line-height: 1.45;
}
.rail-grid .r-text .hand { display: none; }
.rail-grid .disabled-note { font-size: 0.62rem; padding: 0.4rem 0.5rem; }
@media (max-height: 700px) { .mission-rail { display: none; } }
[data-surface="mission"] .panel { min-height: 0; padding: 1.3rem; }
[data-surface="mission"] .panel:hover { background: var(--panel); }
[data-surface="mission"] .panel-title { font-size: 1.1rem; }
/* Sized against viewport *height*, not a fixed rem: a 720p display or a
   portrait panel gives each row far less vertical space, and a fixed 3.2rem
   overflows and clips mid-glyph. */
[data-surface="mission"] .r-stat .value {
  font-size: clamp(1.5rem, 4.6vh, 3.2rem);
  white-space: nowrap;
}
[data-surface="mission"] .r-stat .label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The trend line is an annotation ("booted Jul 13, 20:22"). Unreadable from a
   couch, and it's what pushes a stat panel past its row height. A wall display
   shows the number; the Deck keeps the footnote. */
[data-surface="mission"] .r-stat .trend { display: none; }

/* The topbar must never wrap — it's a single line of instruments. */
[data-surface="mission"] .topbar-inner { flex-wrap: nowrap; }
[data-surface="mission"] .brand span,
[data-surface="mission"] .mission-clock { white-space: nowrap; }
[data-surface="mission"] .topbar-stats { flex-wrap: nowrap; overflow: hidden; }
@media (max-width: 1200px) {
  [data-surface="mission"] .brand span:not(.mark) { font-size: 0.8rem; }
  [data-surface="mission"] .mission-clock { font-size: 1.1rem; }
  [data-surface="mission"] .mission-clock small { display: none; }
}
[data-surface="mission"] .panel-body { overflow: hidden; min-height: 0; }
[data-surface="mission"] .r-gauge { min-height: 0; }

/* Overflow is handled by fitRows() dropping whole rows, not by fading a
   half-visible one. */
[data-surface="mission"] .r-list,
[data-surface="mission"] .r-log { overflow: hidden; }
[data-surface="mission"] .panel-body:has(.r-list),
[data-surface="mission"] .panel-body:has(.r-log) { justify-content: flex-start; }
/* Sized off viewport height for the same reason as the stat value: the row
   height available to a gauge is a fraction of the screen, not a fixed
   number of rems. A 1080p TV gets a big dial; a short window gets a small
   one; neither clips its legs. */
[data-surface="mission"] .dial { width: clamp(2.6rem, 8vh, 7rem); }
@media (max-height: 980px) {
  [data-surface="mission"] .panel { padding: 0.9rem 1rem; }
  [data-surface="mission"] .r-gauge { gap: 0.8rem; }
  [data-surface="mission"] .leg { font-size: 0.66rem; }
  [data-surface="mission"] .panel-body { gap: 0.4rem; }
  [data-surface="mission"] .dial-wrap { gap: 0.2rem; }
  [data-surface="mission"] .dial-cap { font-size: 0.55rem; line-height: 1.2; }
  /* A short viewport starves the pinned grid first — it's carrying more
     panels — so the strip gives height back rather than taking it. */
  [data-surface="mission"] .mission-rail { height: clamp(6rem, 18vh, 9rem); }
}
[data-surface="mission"] .topbar { position: static; background: transparent; backdrop-filter: none; }
[data-surface="mission"] .topbar-inner { height: 3.2rem; }

.mission-clock {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 1.5rem; font-weight: 600; color: var(--ink); letter-spacing: -0.01em;
}
.mission-clock small { font-size: 0.5em; color: var(--muted); letter-spacing: 0.12em; margin-left: 0.5em; text-transform: uppercase; }

.page-dots { display: flex; gap: 0.4rem; align-items: center; }
.page-dot { width: 6px; height: 6px; background: var(--faint); transition: background .3s ease, box-shadow .3s ease; }
.page-dot.on { background: var(--hot); box-shadow: 0 0 8px var(--hot-glow); }

.mission-page { animation: pagein .55s cubic-bezier(.2,.7,.2,1); }
@keyframes pagein { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ============================================================
   BOOT SEQUENCE
   ============================================================ */
/* The boot screen is bare text with no panels to sit on, so the chalk
   marginalia would collide with the diagnostic lines. Schematics stay. */
html[data-boot] .note { display: none; }

.boot {
  min-height: 100vh; display: flex; flex-direction: column; justify-content: center;
  padding: 6vh clamp(1.5rem, 6vw, 6rem);
  font-family: var(--mono);
}
.boot-mark {
  display: flex; align-items: center; gap: 1rem; margin-bottom: 2rem;
  font-size: 1.4rem; font-weight: 700; color: var(--ink); letter-spacing: 0.04em;
}
.boot-mark .hex {
  display: inline-grid; place-items: center; width: 42px; height: 46px;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  background: var(--hot-soft); color: var(--hot); font-size: 1rem;
  filter: drop-shadow(0 0 10px var(--hot-glow)); animation: breathe 3.4s ease-in-out infinite;
}
@keyframes breathe {
  0%, 100% { filter: drop-shadow(0 0 8px var(--hot-glow)); }
  50%      { filter: drop-shadow(0 0 24px var(--hot-glow)); }
}
.boot-lines { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.92rem; }
.boot-line { display: flex; gap: 1rem; opacity: 0; animation: bootin .3s ease-out forwards; }
.boot-line .ok   { color: var(--good); }
.boot-line .wait { color: var(--hot); }
.boot-line .bad  { color: var(--red); }
.boot-line .txt  { color: var(--ink-2); }
.boot-line .tag  { color: var(--faint); margin-left: auto; }
@keyframes bootin { to { opacity: 1; } }
.boot-rule { height: 1px; background: var(--line); margin: 1.6rem 0; }
.boot-final { font-size: 1.05rem; color: var(--hot); letter-spacing: 0.16em; text-transform: uppercase; }
.boot-cursor::after {
  content: "▊"; color: var(--hot); animation: caret 1.05s step-end infinite; margin-left: 0.2em;
}
@keyframes caret { 50% { opacity: 0; } }

/* ============================================================
   reduced motion — honour it everywhere
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
