/* ──────────────────────────────────────────────────────────────
   Tokens (production palette + diorama-only --desk and --bezel).
   ────────────────────────────────────────────────────────────── */
:root {
  --bg:        #0c0e0b;
  --panel:     #131a14;
  --panel-2:   #192019;
  --panel-3:   #1f271f;
  --border:    #2b352c;
  --border-2:  #3a4a3b;
  --text:      #e8e4d8;
  --muted:     #7d8e7e;
  --subtle:    #4a584b;
  --gold:      #c9a227;
  --gold-2:    #e5bc3f;
  --forest:    #4a9e5c;
  --forest-2:  #5cb870;
  --amber:     #d4852a;
  --amber-2:   #e8a040;
  --crimson:   #c43b3b;
  --crimson-2: #e04848;
  --steel:     #5b8fad;
  --steel-2:   #78a8c5;
  /* Agent app accent. Previously the agent used --forest-2, but
     green/red are reserved for diff semantics (memory.edit add/del,
     positive HUD deltas, running status). Violet sits next to steel
     in hue but reads distinct enough to be the agent's own color. */
  --violet:    #8062c5;
  --violet-2:  #a589dc;
  /* Settings app accent. Chromatically neutral (cool slate) so the
     configuration window reads as "system" rather than competing with
     the four colored apps (gold / steel / violet / status colors). */
  --slate:     #6b7785;
  --slate-2:   #97a4b4;

  --screen-bg:     #000;
  --screen-text:   #c8a800;
  --screen-border: #2a2a00;

  --font-display: 'Chakra Petch', 'Courier New', monospace;
  --font-body:    'Plus Jakarta Sans', 'DM Sans', Helvetica, Arial, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'Cascadia Code', Menlo, Consolas, monospace;

  /* 1980s computer cabinet — Commodore 64 "breadbox" tan.
     The yellowed-from-UV warm brown plastic everyone remembers,
     with the breadbox's medium-rounded corners and matte finish.
     No visible screws; no separate stand. */
  --cab:       #b8a578;          /* outer body — warm breadbox tan */
  --cab-hi:    #d2bf90;          /* top edge highlight */
  --cab-lo:    #7a6840;          /* shadow side */
  --cab-bezel: #8d7a52;          /* inner bezel — darker tan ring */
  --cab-bezel-hi: #a08d65;
  --cab-bezel-lo: #5a4828;
  --cab-panel:    #968151;       /* right-side control panel — distinct, slightly darker */
  --cab-panel-hi: #b09a64;
  --cab-panel-lo: #614e2a;
  --cab-deep:  #2e2410;          /* recessed vent slots */
  --cab-ink:   #3e3018;          /* embossed/silkscreen text */
  --screen-glass: #08090a;       /* screen well behind the windows */

  /* Playback knobs */
  --anim-scale: 1;
  --dwell-ms:   0;

  /* Vertical budgets — tuned so every fixed element has a known
     height; the monitor takes the remainder of 100vh. The plate
     and deck rows were removed; metadata moved to a left card,
     transport moved to the cabinet's right panel. */
  --topnav-h:  44px;
  --stage-pad: 12px;
  --gap:       14px;
  --card-w:    220px;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body.is-viewer {
  height: 100vh;
  overflow: hidden;
  line-height: normal;
}
a { color: var(--steel); text-decoration: none; }
a:hover { color: var(--steel-2); }
button { font: inherit; cursor: pointer; }
.hidden { display: none !important; }

/* ── Scrollbars (themed) ────────────────────────────────────────
   Firefox uses scrollbar-color (thumb track); WebKit/Blink need
   ::-webkit-scrollbar pseudo-elements. Both styled to match the
   dark forest panel palette so they read as part of the chassis,
   not an OS overlay. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-2) var(--panel-2);
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track {
  background: var(--panel-2);
  border-left: 1px solid var(--border);
}
::-webkit-scrollbar-thumb {
  background: var(--border-2);
  border-radius: 4px;
  border: 2px solid var(--panel-2);
}
::-webkit-scrollbar-thumb:hover { background: var(--muted); }
::-webkit-scrollbar-corner { background: var(--panel-2); }

/* ── App icons (inline SVG, currentColor) ──────────────────────
   Three glyphs used by Warsim/Journal/Agent windows. They live
   in three sizes: title bars (~1.2em), taskbar tiles (13px in a
   16px well), start menu tiles (18px in a 28px well). Stroke
   2.2 so the lines hold up at the tiny taskbar size. */
.app-icon {
  display: inline-block;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linejoin: round;
  stroke-linecap: round;
  flex-shrink: 0;
}
.win-title .app-icon {
  width: 1.2em;
  height: 1.2em;
  vertical-align: -0.28em;
  margin-right: 0.6em;
}
.task-tile .app-icon  { width: 13px; height: 13px; }
.start-tile .app-icon { width: 18px; height: 18px; }
/* Per-app accent color in title bars — matches taskbar/start tiles
   so each app keeps the same color in every spot it appears. */
.warsim-win   .win-title .app-icon { color: var(--gold-2); }
.notebook-win .win-title .app-icon { color: var(--steel-2); }
.activity-win .win-title .app-icon { color: var(--violet-2); }
.settings-win .win-title .app-icon { color: var(--slate-2); }

/* ── Topnav ─────────────────────────────────────────────────── */
.topnav {
  height: var(--topnav-h);
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 24px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  position: relative;
  z-index: 50;
  flex-shrink: 0;
}
.topnav .brand {
  font-family: var(--font-display);
  font-size: 0.88rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  color: var(--gold-2);
  padding-right: 18px;
  border-right: 1px solid var(--border);
}
.topnav nav { display: flex; gap: 2px; }
.topnav nav a {
  color: var(--muted);
  padding: 5px 11px;
  border-radius: 5px;
  font-size: 0.84rem;
  font-weight: 500;
}
.topnav nav a:hover, .topnav nav a.active { color: var(--text); background: var(--panel-2); }
.topnav .actions { margin-left: auto; display: flex; align-items: center; gap: 12px; }

/* Scenario picker — DEMO-only control in the topnav */
.scenario-picker {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 3px 6px 3px 10px;
  background: var(--panel-2);
  border: 1px dashed var(--amber);
  border-radius: 6px;
}
.scenario-picker label {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--amber-2);
  font-weight: 700;
}
.scenario-picker select {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  font: inherit;
  font-size: 0.78rem;
  padding: 3px 6px;
  outline: none;
  max-width: 280px;
}
.scenario-picker select:focus { border-color: var(--gold); }

/* Recovered tool call badge inside Agent Activity Call section */
.aa-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 7px;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.04em;
  font-weight: 700;
}
.aa-chip.recovered {
  background: rgba(128,98,197,0.18);
  color: var(--violet-2);
  border: 1px solid rgba(128,98,197,0.35);
}
.running-badge {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(74,158,92,0.12);
  border: 1px solid rgba(74,158,92,0.25);
  color: var(--forest-2);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 3px 9px;
  border-radius: 999px;
}
.running-badge::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--forest-2); animation: pulse-dot 2s infinite;
}
@keyframes pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.topnav a.primary {
  background: var(--gold); color: #0c0e0b; font-weight: 600;
  padding: 5px 14px; border-radius: 5px; font-size: 0.82rem;
}

/* ── Stage (the desk surface) ──────────────────────────────────
   Two columns now: a metadata card on the left, the monitor wrap
   on the right. The full-width plate and deck rows are gone —
   metadata moved into the card, transport moved into the cabinet
   right panel. */
.stage {
  height: calc(100vh - var(--topnav-h));
  padding: var(--stage-pad) 24px;
  display: grid;
  grid-template-columns: var(--card-w) 1fr;
  gap: var(--gap);
  background: var(--bg);
}

/* ── Metadata card (left of the cabinet) ──────────────────────
   Stretches the column height, then pulls back 61px from the
   bottom (= monitor-legs 13px + pc-base 48px) so its top + bottom
   align with the cabinet's top + bottom. The pc-base sliver still
   extends below the card on the right side, like a desk surface. */
.metadata-card {
  margin-bottom: 61px;
  background:
    linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 18px 18px 14px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow: hidden;
  box-shadow:
    0 2px 0 rgba(0,0,0,0.35),
    0 14px 22px -14px rgba(0,0,0,0.55);
}
.mc-head {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* Title row hosts the H1 plus the inline rename pencil. The pencil
   stays out of the document flow visually until hover so the title
   reads cleanly at rest, then fades in for the affordance. */
.mc-title-row {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  min-width: 0;
}
.mc-title {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text);
  margin: 0;
  line-height: 1.2;
  word-break: break-word;
  flex: 1 1 auto;
  min-width: 0;
}
.mc-title-edit-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  margin-top: 1px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--muted);
  cursor: pointer;
  opacity: 0;
  transition: opacity 120ms, color 120ms, border-color 120ms, background 120ms;
}
.mc-title-row:hover .mc-title-edit-btn,
.mc-title-edit-btn:focus-visible {
  opacity: 1;
}
.mc-title-edit-btn:hover {
  color: var(--text);
  background: rgba(255,255,255,0.04);
  border-color: var(--border);
}
.mc-title-edit-btn:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}
.mc-title-edit-btn svg {
  width: 12px;
  height: 12px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.mc-title-input {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text);
  line-height: 1.2;
  background: rgba(0,0,0,0.25);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 2px 6px;
  margin: 0;
}
.mc-title-input:focus {
  outline: none;
  border-color: var(--gold);
}
/* Status row: running pill + heartbeat ("4s ago") inline so the
   freshness signal sits next to the status it qualifies. */
.mc-status {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.status-pill {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  padding: 2px 8px;
  border-radius: 999px;
  letter-spacing: 0.04em;
  font-weight: 700;
}
.status-pill.running { background: rgba(74,158,92,0.18); color: var(--forest-2); }
.mc-heartbeat {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--muted);
  letter-spacing: 0.04em;
}
/* Stop-session button. Sits next to the running pill inside
   .mc-status; only shown while the session is actively running
   (verified against /api/active-sessions, not just the DB row).
   Compact danger style — small enough to coexist with the pill
   and heartbeat without dominating the row. */
.mc-stop-btn {
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 3px 9px;
  border-radius: 4px;
  background: rgba(196,59,59,0.12);
  color: var(--crimson-2);
  border: 1px solid rgba(196,59,59,0.55);
  cursor: pointer;
  transition: background 120ms, border-color 120ms;
}
.mc-stop-btn:hover {
  background: rgba(196,59,59,0.25);
  border-color: var(--crimson);
}
.mc-stop-btn:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
.mc-stop-btn[disabled] {
  opacity: 0.5;
  cursor: progress;
}
/* "Stopping…" indicator that replaces the Stop button after a
   successful POST. Stays visible until SSE session_end arrives
   and flips the pill to `stopped`. Amber to read as in-progress
   rather than terminal. */
.mc-stopping {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(212,133,42,0.18);
  color: var(--amber-2);
}
.mc-stopping::before {
  content: ""; display: inline-block;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--amber-2); margin-right: 6px;
  animation: pulse-dot 1.2s infinite;
  vertical-align: middle;
}
.mc-divider {
  height: 1px;
  background: var(--border);
  flex-shrink: 0;
}

/* ── Sections (Game + Turn) ──────────────────────────────────
   Two clearly labeled groups: GAME is session-static metadata
   (kingdom, ruler, model, started time); TURN N reflects the
   game state at whatever turn the viewer is currently showing.
   Same row pattern in both so the panel reads as one unit. */
.mc-section {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.mc-section + .mc-section {
  border-top: 1px solid var(--border);
  padding-top: 12px;
}
.mc-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  font-weight: 700;
  margin-bottom: 1px;
}
/* Right-side caption on a section header — labels what the
   right column of values means. Used in TURN to clarify the
   second number on each row is a delta vs. session start. */
.mc-section-cap {
  font-size: 0.55rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--subtle);
  text-transform: none;
}
.mc-kv {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  min-width: 0;
}
.mc-kv .k {
  color: var(--subtle);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  flex-shrink: 0;
}
/* Right side of every kv row — wraps the value (and optional
   delta chip) so they align at the right edge of the card. */
.mc-kv .v-wrap {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  text-align: right;
}
.mc-kv .v {
  color: var(--text);
  font-weight: 600;
  word-break: break-word;
}
.mc-kv .v.empty { color: var(--subtle); font-weight: 400; }
/* Delta chip: signed change vs. session start. Color-coded so
   the direction reads at a glance — green up, crimson down,
   muted when zero. Slightly smaller than the absolute so the
   current value stays the visual anchor. */
.mc-delta {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.mc-delta.pos  { color: var(--forest-2); }
.mc-delta.neg  { color: var(--crimson-2); }
.mc-delta.zero { color: var(--subtle); }

/* Multi-value row variant — for fields like Races where one
   value-on-the-right text line would overflow the 220px card.
   Stacks the label above a wrapping chip set so 5+ entries
   stay readable. */
.mc-kv-stack {
  flex-direction: column;
  align-items: stretch;
  gap: 5px;
}
.mc-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.mc-chip {
  font-family: var(--font-mono);
  font-size: 0.64rem;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--panel-3);
  color: var(--text);
  border: 1px solid var(--border);
  line-height: 1.3;
  white-space: nowrap;
}

/* ── Old-school monitor (IBM 5151 / IBM PC era) ─────────────
   The diorama is a stacked piece: a beige CRT monitor with a
   recessed CRT-shaped inner bezel, IBM badge upper-right, and
   a right-side control column (power LED + brightness knob).
   It rests on top of an IBM PC base unit; only the top sliver
   of the PC (logo plate + two floppy drive bays) is visible. */
.monitor-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  min-height: 0;
  /* Hoisted so the pc-base sliver and the contact shadow can derive
     their widths from the same source the cabinet uses. */
  --cabinet-base: calc((100vh - 129px) * 1.35);
}
.cabinet {
  position: relative;
  background:
    linear-gradient(180deg,
      var(--cab-hi) 0%,
      var(--cab)    6%,
      var(--cab)    92%,
      var(--cab-lo) 100%);
  /* Subtle rectangular cabinet — slight rounding only, era-correct
     for an IBM 5151. Bottom corners squared so it sits flush on
     the PC base. */
  border-radius: 6px 6px 2px 2px;
  /* Reserve a chunky right column for the control panel: turn
     readout (was IBM badge), vertical scrub dial, speed knob,
     play and LIVE buttons. Slightly wider than the original
     cosmetic panel to fit the dial track + buttons. */
  padding: 16px 144px 22px 16px;
  /* Cabinet aspect ratio is locked. Width is the smallest of:
     (a) the parent's width, (b) the width derived from the
     available vertical space at the locked aspect ratio. This way
     the cabinet shrinks proportionally when the viewport is
     shorter and never stretches. The non-cabinet vertical budget
     is the topnav + stage padding + monitor legs + pc-base
     sliver — plate and deck rows are gone. */
  width: min(100%, var(--cabinet-base));
  aspect-ratio: 1.35 / 1;
  height: auto;
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  min-height: 0;
  box-shadow:
    /* matte plastic edge highlights */
    inset 0 1px 0 rgba(255,255,255,0.4),
    inset 1px 0 0 rgba(255,255,255,0.15),
    inset -1px 0 0 rgba(0,0,0,0.35),
    inset 0 -1px 0 rgba(0,0,0,0.3),
    /* outline */
    0 0 0 1px rgba(50,38,16,0.75);
}

/* Right-side control panel — distinct sub-panel, slightly darker
   than the outer shell, with a clear vertical seam on its left
   edge. Holds the diegetic transport controls: a small turn-
   counter screen at the top (where the IBM badge used to live),
   a vertical scrub dial in the middle, then a speed knob and
   PLAY / LIVE buttons. */
.cabinet-right-panel {
  position: absolute;
  top: 16px;
  right: 16px;
  bottom: 22px;
  width: 118px;
  background:
    linear-gradient(180deg,
      var(--cab-panel-hi) 0%,
      var(--cab-panel)    8%,
      var(--cab-panel)    92%,
      var(--cab-panel-lo) 100%);
  border-radius: 3px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 12px 0 14px;
  gap: 12px;
  /* Vertical seam — darker groove on the left, bright highlight
     just to its right, sells the "separate insert" read. */
  box-shadow:
    inset 1px 0 0 rgba(0,0,0,0.55),
    inset 2px 0 0 rgba(255,255,255,0.38),
    inset 0 1px 0 rgba(255,255,255,0.28),
    inset 0 -1px 0 rgba(0,0,0,0.4),
    inset -1px 0 0 rgba(0,0,0,0.3),
    -2px 0 4px -2px rgba(0,0,0,0.35);
}

/* Turn counter "screen" — sits where the IBM badge used to,
   same era-correct dark plate footprint and Chakra Petch font,
   but reads as a tiny phosphor readout: gold-on-black, recessed
   bezel, faint scanlines. Shows current turn / max. */
.turn-screen {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 5px 10px 6px;
  border-radius: 2px;
  min-width: 86px;
  background:
    /* faint scanline overlay over the phosphor face */
    repeating-linear-gradient(
      0deg,
      rgba(255,255,255,0.025) 0 1px,
      transparent 1px 2px),
    radial-gradient(ellipse at 50% 50%, #0a0c0a 0%, #050605 100%);
  box-shadow:
    /* recessed inset — the screen sits below the panel surface */
    inset 0 0 0 1px rgba(0,0,0,0.7),
    inset 0 2px 4px rgba(0,0,0,0.85),
    inset 0 -1px 0 rgba(255,255,255,0.06),
    /* glass-meets-bezel highlight on the panel side */
    0 1px 0 rgba(255,255,255,0.45);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  /* Classic CRT phosphor green — bright on the dark recessed
     plate, with a soft green halo so it reads as glowing rather
     than printed. */
  color: #5cf590;
  text-shadow:
    0 0 6px rgba(92,245,144,0.55),
    0 0 2px rgba(92,245,144,0.8);
}
.turn-screen .ts-now { color: #5cf590; }

/* Inner bezel — the slightly recessed darker frame that surrounds
   the CRT glass with rounded corners that read as a CRT face. */
.inner-bezel {
  flex: 1;
  min-height: 0;
  background:
    linear-gradient(180deg,
      var(--cab-bezel-lo) 0%,
      var(--cab-bezel)    10%,
      var(--cab-bezel)    90%,
      var(--cab-bezel-lo) 100%);
  border-radius: 22px;
  padding: 14px;
  display: flex;
  box-shadow:
    inset 0 0 0 1px rgba(0,0,0,0.5),
    inset 0 2px 5px rgba(0,0,0,0.55),
    inset 0 -1px 0 rgba(255,255,255,0.06),
    0 0 0 1px rgba(255,255,255,0.06);
}
/* Screen well — the dark phosphor face inside the bezel; the
   screen itself carries a gentle CRT corner curve. */
.screen-well {
  flex: 1;
  min-height: 0;
  position: relative;
  background:
    radial-gradient(ellipse at 50% 50%, #07080a 0%, #030404 100%);
  border-radius: 16px;
  padding: 10px;
  box-shadow:
    inset 0 0 0 1px #000,
    inset 0 0 0 2px rgba(0,0,0,0.55),
    inset 0 0 30px rgba(0,0,0,0.95),
    inset 0 3px 8px rgba(0,0,0,0.9),
    /* glass-meets-bezel highlight */
    0 0 0 1px rgba(255,255,255,0.18);
  display: flex;
}
/* Soft green phosphor halo bleeding from inside the bezel. */
.screen-well::before {
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: 12px;
  box-shadow:
    inset 0 0 24px rgba(74,158,92,0.05),
    inset 0 0 60px rgba(74,158,92,0.03);
  pointer-events: none;
  z-index: 1;
}
.screen-well .desktop {
  box-shadow:
    0 0 14px rgba(74,158,92,0.06),
    inset 0 0 28px rgba(0,0,0,0.75);
  position: relative;
  z-index: 2;
}

/* ── Vertical scrub dial ─────────────────────────────────────
   Old-timey fader feel: a tall recessed track with faint gold
   tick marks and a horizontal "needle" handle that slides up
   and down. Drag the needle, or click anywhere on the track to
   jump the playback head. The needle position = current turn. */
.scrub-dial {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-height: 0;
  width: 100%;
  padding: 0 4px;
}
.scrub-track-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
  width: 36px;
  display: flex;
  justify-content: center;
}
.scrub-track {
  position: relative;
  width: 22px;
  height: 100%;
  background:
    linear-gradient(180deg, #050605 0%, #0a0c0a 50%, #050605 100%);
  border-radius: 3px;
  box-shadow:
    inset 0 1px 2px rgba(0,0,0,0.85),
    inset 0 -1px 0 rgba(255,255,255,0.06),
    0 0 0 1px rgba(0,0,0,0.55);
  cursor: ns-resize;
}
/* Inner phosphor strip — soft amber backlight glow inside the
   track showing the elapsed portion (0 .. needle position). The
   "lit-up backlight" the user wants to keep. */
.scrub-fill {
  position: absolute;
  left: 2px; right: 2px;
  bottom: 4px;
  height: var(--fill-h, 100%);
  background:
    linear-gradient(180deg,
      rgba(229,188,63,0.55) 0%,
      rgba(201,162,39,0.25) 60%,
      rgba(201,162,39,0.0) 100%);
  border-radius: 2px;
  pointer-events: none;
  transition: height 80ms linear;
}
/* Analog fader cap — chunky cream-colored handle with a beveled
   top edge, a subtle shadow underneath, and a horizontal grip
   groove across the middle (like a real audio mixer fader). */
.scrub-needle {
  position: absolute;
  left: -10px; right: -10px;
  height: 14px;
  top: var(--needle-top, 0%);
  transform: translateY(-50%);
  background:
    linear-gradient(180deg,
      #f0e6d0 0%,
      #d8c8a4 45%,
      #b8a578 80%,
      #6e5d3c 100%);
  border-radius: 2px;
  box-shadow:
    /* top highlight + bottom shadow inside the cap */
    inset 0 1px 0 rgba(255,255,255,0.7),
    inset 0 -1px 0 rgba(0,0,0,0.45),
    /* drop shadow under the cap */
    0 2px 3px rgba(0,0,0,0.6),
    0 0 0 1px rgba(0,0,0,0.35);
  cursor: ns-resize;
  pointer-events: none;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Grip groove across the middle — sells the "you can grab it" read. */
.scrub-grip {
  width: 70%;
  height: 2px;
  background:
    linear-gradient(180deg,
      rgba(0,0,0,0.4) 0%,
      rgba(0,0,0,0.55) 50%,
      rgba(255,255,255,0.25) 100%);
  border-radius: 1px;
}
.scrub-label {
  font-family: var(--font-mono);
  font-size: 0.55rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--cab-ink);
  font-weight: 700;
  text-shadow: 0 1px 0 rgba(255,255,255,0.18);
  flex-shrink: 0;
}

/* ── Speed knob — single interactive rotary dial.
   Click cycles through detents (.5×, .75×, 1×, 1.25×, 1.5×, 2×).
   Labels sit around the perimeter; the pointer notch on the knob
   rotates to indicate the current detent. */
.speed-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}
/* Wrap holds the knob + the 5 top-half labels. Bottom of the wrap
   is tight to the knob since labels only live above; top half has
   extra room for the perimeter text. The knob is centered
   horizontally and pinned to the bottom of the wrap. */
.speed-knob-wrap {
  position: relative;
  width: 100px;
  height: 60px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.speed-knob {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  position: relative;
  background:
    radial-gradient(circle at 35% 28%,
      #1a1a1a 0%,
      #0a0a0a 55%,
      #000 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.14),
    inset 0 -2px 2px rgba(0,0,0,0.7),
    0 0 0 1px rgba(0,0,0,0.7),
    0 0 0 4px rgba(0,0,0,0.18),
    0 2px 4px rgba(0,0,0,0.5);
  cursor: pointer;
  border: none;
  padding: 0;
}
.speed-knob::after {
  content: "";
  position: absolute;
  top: 4px;
  left: 50%;
  transform: translateX(-50%) rotate(var(--knob-rot, 0deg));
  transform-origin: 50% 15px;
  width: 3px;
  height: 8px;
  background: linear-gradient(180deg, #f0e6ce 0%, #b8a578 100%);
  border-radius: 1px;
  box-shadow: 0 1px 0 rgba(0,0,0,0.6);
  transition: transform 180ms cubic-bezier(0.34,1.56,0.64,1);
}
.speed-knob:hover { filter: brightness(1.15); }
.speed-knob:active { filter: brightness(0.95); }
/* Perimeter labels — clickable; placed around the top half of the
   knob via CSS angle vars. Origin is the knob's center (which sits
   at the horizontal-center / vertical-bottom of the wrap). Each
   label rotates around that point, translates outward, then un-
   rotates so the text stays upright. */
.speed-mark {
  position: absolute;
  left: 50%;
  bottom: 19px; /* knob radius — keeps the rotation origin on knob center */
  font-family: var(--font-mono);
  font-size: 0.55rem;
  font-weight: 700;
  color: var(--cab-ink);
  letter-spacing: 0.04em;
  text-shadow: 0 1px 0 rgba(255,255,255,0.22);
  transform:
    translate(-50%, 50%)
    rotate(var(--mark-angle))
    translateY(-34px)
    rotate(calc(-1 * var(--mark-angle)));
  cursor: pointer;
  white-space: nowrap;
  padding: 2px 4px;
  border-radius: 2px;
  transition: color 80ms;
}
.speed-mark:hover { color: var(--text); }
/* Active detent — the label that matches the current rate gets
   a brighter color so the active speed reads at a glance even
   before the knob notch lands. */
.speed-mark.active { color: var(--text); font-weight: 700; }

/* ── Retro chunky play / LIVE buttons (cabinet-front style). */
.rc-buttons {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  flex-shrink: 0;
}
/* Cabinet-front buttons — chunky black plastic with screen-printed
   off-white labels. Labels DON'T change on click (real buttons have
   fixed silkscreen). The press state still gives a tactile depress. */
.rc-btn {
  width: 70px;
  height: 28px;
  background:
    linear-gradient(180deg, #2a2a28 0%, #1c1c1a 60%, #0e0d0c 100%);
  color: var(--text);
  border: none;
  border-radius: 4px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  cursor: pointer;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    inset 0 -2px 2px rgba(0,0,0,0.6),
    0 0 0 1px rgba(0,0,0,0.55),
    0 0 0 4px rgba(0,0,0,0.18),
    0 2px 4px rgba(0,0,0,0.45);
  transition: filter 100ms, transform 80ms;
}
.rc-btn:hover { filter: brightness(1.18); }
.rc-btn:active {
  transform: translateY(1px);
  box-shadow:
    inset 0 1px 2px rgba(0,0,0,0.7),
    0 0 0 1px rgba(0,0,0,0.55),
    0 0 0 4px rgba(0,0,0,0.18);
}
.rc-btn.play .glyph {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1;
}
.rc-btn.live {
  /* shown only for active sessions (toggled via .is-shown). */
  display: none;
}
.rc-btn.live.is-shown { display: inline-flex; }

/* PC base sliver — only the TOP portion of an IBM PC unit is
   visible: enough chassis above the IBM logo plate and floppy
   bays for the texture to read, with everything below clipped.
   Children render at full natural height; overflow: hidden cuts
   the bottom so we just see the tops of the features. */
.pc-base {
  /* Width is locked to a multiple of the cabinet's width so the PC
     chassis stays visibly wider than the monitor at every viewport
     size — the ratio (1.4×) is era-correct for an IBM 5151 sitting
     on an IBM PC 5150 chassis (~13.5" monitor on a ~19.6" chassis).
     Falls back to 100% of the column when the viewport is too narrow. */
  width: min(100%, calc(var(--cabinet-base) * 1.4));
  height: 48px;
  flex-shrink: 0;
  margin-top: 0;                /* legs above bridge to the PC top */
  position: relative;
  overflow: hidden;
  /* Darker tones than the monitor body — keeps the same color
     family but reads as a separate, slightly more saturated
     chassis. Subtle top highlight for the "viewed from above"
     angle without the bright cream. */
  background:
    linear-gradient(180deg,
      var(--cab)    0%,
      var(--cab)    20%,
      var(--cab-lo) 100%);
  border-radius: 6px 6px 0 0;
  padding: 24px 22px 0;         /* reserve top band for chassis-top */
  display: flex;
  align-items: flex-start;
  gap: 22px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.35),
    inset 1px 0 0 rgba(255,255,255,0.12),
    inset -1px 0 0 rgba(0,0,0,0.4),
    0 0 0 1px rgba(50,38,16,0.75);
}
/* A soft contact shadow on the chassis-top where the monitor rests,
   darker right under the cabinet and fading outward. */
.pc-base::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  /* Tracks the cabinet's actual width so the contact shadow stays
     directly under the monitor's footprint at every viewport size.
     Clamped to 100% of the pc-base for safety at narrow widths. */
  width: min(100%, var(--cabinet-base));
  height: 18px;
  background:
    radial-gradient(ellipse at 50% 0%,
      rgba(0,0,0,0.5) 0%,
      rgba(0,0,0,0.22) 55%,
      rgba(0,0,0,0)    100%);
  pointer-events: none;
  z-index: 0;
}
.pc-base > * { position: relative; z-index: 1; }
.pc-base .pc-ibm {
  width: 110px;
  height: 60px;                 /* taller than container; clipped */
  border-radius: 1px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  color: #d6d3c8;
  background-image:
    repeating-linear-gradient(
      0deg,
      rgba(0,0,0,0) 0 3px,
      rgba(0,0,0,0.55) 3px 4px),
    linear-gradient(180deg, #1c1a17 0%, #0d0c0a 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    inset 0 -1px 0 rgba(0,0,0,0.6);
}
.pc-base .pc-floppy-bay {
  flex: 1;
  height: 60px;                 /* taller than container; clipped */
  display: flex;
  gap: 18px;
}
.pc-base .pc-floppy {
  flex: 1;
  height: 100%;
  background:
    linear-gradient(180deg,
      var(--cab)    0%,
      var(--cab-lo) 60%,
      #4f3f1f       100%);
  border-radius: 2px;
  display: flex;
  align-items: center;
  padding: 0 12px;
  gap: 12px;
  box-shadow:
    inset 0 0 0 1px rgba(0,0,0,0.45),
    inset 0 1px 0 rgba(255,255,255,0.22);
}
.pc-base .pc-floppy-slot {
  flex: 1;
  height: 12px;
  background: linear-gradient(180deg, #1a1610 0%, #0a0805 100%);
  border-radius: 1px;
  box-shadow:
    inset 0 1px 2px rgba(0,0,0,0.85),
    inset 0 -1px 0 rgba(255,255,255,0.08);
}
.pc-base .pc-floppy-lever {
  width: 18px;
  height: 18px;
  background:
    linear-gradient(180deg,
      var(--cab-hi) 0%,
      var(--cab)    55%,
      var(--cab-lo) 100%);
  border-radius: 1px;
  box-shadow:
    inset 0 0 0 1px rgba(0,0,0,0.45),
    inset 0 1px 0 rgba(255,255,255,0.4);
}
/* Small dark support feet on the bottom of the monitor cabinet —
   they sit on the PC and lift the monitor slightly so a gap is
   visible between the two pieces. Sized small per the reference
   (era-correct: tiny stub feet, not blocky pedestals). */
.monitor-legs {
  /* matches the cabinet's locked width formula */
  width: min(100%, calc((100vh - 253px) * 1.35));
  flex-shrink: 0;
  display: flex;
  justify-content: space-between;
  padding: 0 80px;
  margin-top: -1px;             /* legs hang from the cabinet bottom */
  pointer-events: none;
  position: relative;
  z-index: 1;
}
.monitor-legs .monitor-leg {
  width: 34px;
  height: 13px;                 /* bridges the full gap to the PC */
  background:
    linear-gradient(180deg, #5b4a32 0%, #2c241a 60%, #14100a 100%);
  border-radius: 0;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.12),
    inset -1px 0 0 rgba(0,0,0,0.5),
    inset 0 -1px 0 rgba(255,255,255,0.06);
}

/* The "screen" inside the monitor — the OS desktop.
   Windows are absolutely positioned (draggable / resizable / can
   be closed and re-opened from the bottom taskbar). Default
   positions are computed by JS to mimic the original 3-window
   layout: Warsim top-left big, Notebook bottom-left, Agent
   Activity full right column. The taskbar pins to the bottom
   edge; windows sit above it. */
.desktop {
  flex: 1;
  background:
    radial-gradient(120% 80% at 50% 30%, #11181440 0%, #0a0d0a 70%, #060807 100%),
    #0a0d0a;
  border-radius: 4px;
  padding: 12px;
  overflow: hidden;
  position: relative;
}
/* Subtle screen scanlines — diegetic monitor texture, very low contrast. */
.desktop::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    0deg, rgba(255,255,255,0.012) 0 1px, transparent 1px 3px);
  pointer-events: none;
  mix-blend-mode: overlay;
  border-radius: 4px;
}

/* ── Desktop wallpaper layer ────────────────────────────────
   `.dw` paints the wallpaper edge-to-edge inside `.desktop`.
   z-index:0 keeps it below the scanlines (::after, auto-z) and
   below windows (z >= 10 from bringToFront). The wallpaper is
   selected via [data-wallpaper="..."] on .desktop so all rules
   hang off a single attribute toggle. Motion wallpapers either
   animate via CSS keyframes or are populated by JS at apply
   time (embers, constellations, bliss). */
.dw {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
  border-radius: 4px;
}

/* ── Wallpaper: AURORA (motion, CSS-only) ───────────────────
   Night sky with two oversized translucent aurora bands that
   pan and rotate independently for an unhurried drift. Pine
   silhouette horizon at the bottom is an SVG mask cutting a
   ragged tooth row out of a dark forest fill. */
.desktop[data-wallpaper="aurora"] .dw {
  background: linear-gradient(180deg, #050912 0%, #0b1325 35%, #131c2a 70%, #0c1612 100%);
}
.desktop[data-wallpaper="aurora"] .dw::before,
.desktop[data-wallpaper="aurora"] .dw::after {
  content: "";
  position: absolute;
  left: -25%; right: -25%;
  height: 70%;
  filter: blur(28px);
  opacity: 0.95;
  pointer-events: none;
}
.desktop[data-wallpaper="aurora"] .dw::before {
  top: 5%;
  background: linear-gradient(100deg,
    transparent 0%, rgba(74,158,92,0.0) 8%,
    rgba(74,158,92,0.95) 28%, rgba(229,188,63,0.85) 46%,
    rgba(91,143,173,0.85) 64%, rgba(74,158,92,0.0) 84%, transparent 100%);
  background-size: 200% 100%;
  animation: dw-aurora-1 28s linear infinite;
}
.desktop[data-wallpaper="aurora"] .dw::after {
  top: 22%;
  background: linear-gradient(80deg,
    transparent 0%, rgba(91,143,173,0.0) 8%,
    rgba(128,98,197,0.85) 30%, rgba(74,158,92,0.80) 52%,
    rgba(229,188,63,0.65) 72%, rgba(91,143,173,0.0) 88%, transparent 100%);
  background-size: 220% 100%;
  animation: dw-aurora-2 41s linear infinite reverse;
}
@keyframes dw-aurora-1 {
  from { background-position: 0% 50%;   transform: skewY(-1deg); }
  50%  { background-position: 50% 50%;  transform: skewY(0.6deg); }
  to   { background-position: 100% 50%; transform: skewY(-1deg); }
}
@keyframes dw-aurora-2 {
  from { background-position: 0% 50%;   transform: skewY(0.5deg); }
  50%  { background-position: 50% 50%;  transform: skewY(-0.8deg); }
  to   { background-position: 100% 50%; transform: skewY(0.5deg); }
}
.dw-aurora-pines {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 22%;
  background: linear-gradient(180deg, #0a1410 0%, #050805 100%);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80' preserveAspectRatio='none'><path fill='black' d='M0 80 L0 60 L8 30 L16 55 L24 25 L32 50 L40 18 L48 48 L56 32 L64 12 L72 38 L80 22 L88 45 L96 18 L104 50 L112 28 L120 8 L128 36 L136 22 L144 50 L152 30 L160 14 L168 42 L176 22 L184 48 L192 30 L200 50 L200 80 Z'/></svg>") center / 100% 100% no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80' preserveAspectRatio='none'><path fill='black' d='M0 80 L0 60 L8 30 L16 55 L24 25 L32 50 L40 18 L48 48 L56 32 L64 12 L72 38 L80 22 L88 45 L96 18 L104 50 L112 28 L120 8 L128 36 L136 22 L144 50 L152 30 L160 14 L168 42 L176 22 L184 48 L192 30 L200 50 L200 80 Z'/></svg>") center / 100% 100% no-repeat;
}

/* ── Wallpaper: EMBERS (motion, CSS+JS) ─────────────────────
   Drifting sparks rising from a banked campfire below the
   visible area. JS injects N spans with random --x / --dur /
   --delay / --size custom properties. Animation lifts each
   particle from below the bottom edge to above the top, with
   a small horizontal sway and an opacity envelope. */
.desktop[data-wallpaper="embers"] .dw {
  background:
    radial-gradient(120% 60% at 50% 110%, rgba(212,133,42,0.28) 0%, transparent 70%),
    radial-gradient(80% 40% at 50% 105%, rgba(228,72,72,0.18) 0%, transparent 70%),
    linear-gradient(180deg, #0a0606 0%, #1a0e08 60%, #2a1810 100%);
}
.desktop[data-wallpaper="embers"] .dw::before {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 8%;
  background: radial-gradient(60% 100% at 50% 100%, rgba(255,170,60,0.45) 0%, transparent 80%);
  filter: blur(6px);
  pointer-events: none;
}
.dw-ember {
  position: absolute;
  left: var(--x, 50%);
  bottom: -12px;
  width: var(--size, 3px);
  height: var(--size, 3px);
  border-radius: 50%;
  background: radial-gradient(circle, #ffd089 0%, #e8a040 50%, rgba(212,133,42,0.0) 80%);
  box-shadow: 0 0 6px rgba(232,160,64,0.6);
  opacity: 0;
  animation: dw-ember-rise var(--dur, 9s) linear var(--delay, 0s) infinite;
  pointer-events: none;
  will-change: transform, opacity;
}
@keyframes dw-ember-rise {
  0%   { transform: translate(0, 0)                                  scale(0.6); opacity: 0; }
  8%   { opacity: 0.95; }
  50%  { transform: translate(var(--sway, 8px), -55vh)               scale(1); }
  90%  { opacity: 0.6; }
  100% { transform: translate(calc(var(--sway, 8px) * -0.5), -110vh) scale(0.4); opacity: 0; }
}

/* ── Wallpaper: CONSTELLATIONS (motion, CSS+JS) ─────────────
   Deep night sky. JS injects ~80 stars at random positions —
   a subset twinkle (opacity oscillation with staggered
   delays). A static SVG of crown constellation lines threads
   a few prominent points to suggest the kingdom's heraldry. */
.desktop[data-wallpaper="constellations"] .dw {
  background:
    radial-gradient(120% 80% at 60% 30%, #0d1830 0%, #050912 60%, #02040a 100%);
}
.dw-star {
  position: absolute;
  left: var(--x, 50%);
  top: var(--y, 50%);
  width: var(--size, 2px);
  height: var(--size, 2px);
  background: var(--color, #e8e4d8);
  border-radius: 50%;
  box-shadow: 0 0 var(--glow, 3px) currentColor;
  color: var(--color, #e8e4d8);
  pointer-events: none;
}
.dw-star.twinkle {
  animation: dw-twinkle var(--dur, 4s) ease-in-out var(--delay, 0s) infinite;
}
@keyframes dw-twinkle {
  0%, 100% { opacity: 0.35; transform: scale(1.0); }
  50%      { opacity: 1.0;  transform: scale(1.6); }
}
.dw-crown {
  position: absolute;
  left: 50%;
  top: 32%;
  transform: translate(-50%, -50%);
  width: clamp(200px, 38%, 460px);
  aspect-ratio: 24 / 14;
  color: var(--gold-2);
  opacity: 0.65;
  pointer-events: none;
}
.dw-crown svg { width: 100%; height: 100%; display: block; overflow: visible; }
.dw-crown circle { fill: var(--gold-2); filter: drop-shadow(0 0 3px rgba(229,188,63,0.7)); }
.dw-crown polyline { fill: none; stroke: var(--gold); stroke-width: 0.18; opacity: 0.7; }

/* ── Wallpaper: CATHEDRAL (static, SVG) ─────────────────────
   Heraldic stained-glass rosette over a deep panel base, with
   faint diagonal mullions. The rosette is one inline SVG with
   gold petals, forest diamonds, and steel tracery; mullions
   are a repeating-linear-gradient overlay. */
.desktop[data-wallpaper="cathedral"] .dw {
  background:
    repeating-linear-gradient(45deg,
      rgba(0,0,0,0.18) 0 1px, transparent 1px 22px),
    repeating-linear-gradient(-45deg,
      rgba(0,0,0,0.18) 0 1px, transparent 1px 22px),
    radial-gradient(80% 80% at 50% 50%, #1a2218 0%, #0a0d0a 70%, #050805 100%);
}
.dw-cathedral {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(72%, 80vh);
  aspect-ratio: 1 / 1;
  pointer-events: none;
  filter: drop-shadow(0 0 14px rgba(229,188,63,0.18));
}
.dw-cathedral svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* ── Wallpaper: BLISS (static, ASCII) ───────────────────────
   Hand-rolled ASCII Bliss — green phosphor rendering of the
   iconic Windows XP rolling hill, generated by JS at apply
   time so the silhouette stays smooth. Two <pre>s stack and
   share dimensions: sky (clouds, soft white) over hill
   (phosphor green). JS sets font-size to fit the .dw. */
.desktop[data-wallpaper="bliss"] .dw {
  /* Pure black canvas — every pixel of color comes from the ASCII
     glyphs themselves. The three stacked pre layers (sky / cloud /
     hill) each fill their own cells; spaces leave the black show
     through, giving the picture its character-grid texture. */
  background: #000;
}
.dw-bliss {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  font-family: var(--font-mono);
  font-weight: 600;
  line-height: 1.0;
  letter-spacing: 0;
  white-space: pre;
  pointer-events: none;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  text-align: left;
}
/* Color via background-clip: text so each layer's gradient runs
   across its glyphs only. Falls back to a solid color if a browser
   lacks the prefix path. */
.dw-bliss-sky {
  background: linear-gradient(180deg, #1f5fad 0%, #3f87cd 35%, #7ab1de 65%, #b2d5ec 90%, #d6e8f4 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.dw-bliss-hill {
  background: linear-gradient(180deg, #7ed490 0%, #5cb870 40%, #3a8c4c 80%, #2d6b3a 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.dw-bliss-cloud { color: #f4f8fc; }
.dw-bliss-tag {
  position: absolute;
  right: 12px; bottom: 10px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: rgba(92,184,112,0.6);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  pointer-events: none;
}

/* ── Window chrome (PostHog-inspired, our palette) ─────────── */
.win {
  position: absolute;
  background: var(--panel);
  border: 1px solid var(--border-2);
  border-radius: 8px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-width: 220px;
  min-height: 120px;
  box-shadow:
    0 1px 0 rgba(255,255,255,0.04) inset,
    0 6px 14px -8px rgba(0,0,0,0.7);
  transition: box-shadow 120ms;
}
/* Active-window framing: each app keeps its own accent so the
   Agent window doesn't pick up a gold border (which read as
   "amber on the agent" — the Agent app is violet-themed). The
   box-shadow color matches each window's accent token; the
   border per-app is set in the per-window blocks below. */
.win.active {
  box-shadow:
    0 1px 0 rgba(255,255,255,0.04) inset,
    0 12px 22px -10px rgba(0,0,0,0.85);
}
.warsim-win.active   { border-color: var(--gold);   box-shadow: 0 0 0 1px rgba(201,162,39,0.25), 0 12px 22px -10px rgba(0,0,0,0.85); }
.notebook-win.active { border-color: var(--steel);  box-shadow: 0 0 0 1px rgba(91,143,173,0.25), 0 12px 22px -10px rgba(0,0,0,0.85); }
.activity-win.active { border-color: var(--violet); box-shadow: 0 0 0 1px rgba(128,98,197,0.25), 0 12px 22px -10px rgba(0,0,0,0.85); }
.settings-win.active { border-color: var(--slate);  box-shadow: 0 0 0 1px rgba(107,119,133,0.30), 0 12px 22px -10px rgba(0,0,0,0.85); }
.win.dragging { transition: none; cursor: move; }
.win-titlebar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 10px;
  background: linear-gradient(180deg, var(--panel-3) 0%, var(--panel) 100%);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  min-height: 28px;
  cursor: move;
  user-select: none;
}
.win-lights { display: inline-flex; gap: 6px; flex-shrink: 0; order: 3; margin-left: auto; }
.win-lights button {
  width: 11px; height: 11px;
  border-radius: 50%;
  border: 1px solid rgba(0,0,0,0.45);
  padding: 0;
  cursor: pointer;
  transition: filter 120ms;
  position: relative;
}
.win-lights button:hover { filter: brightness(1.2); }
.win-lights .l-close { background: var(--crimson); }
.win-lights .l-min   { background: var(--amber); }
.win-lights .l-max   { background: var(--forest); }
/* glyph hints inside lights, only visible on hover */
.win-lights button::after {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  line-height: 1;
  color: rgba(0,0,0,0.6);
  opacity: 0;
  font-family: var(--font-mono);
  font-weight: 700;
  transition: opacity 120ms;
}
.win-lights button:hover::after { opacity: 1; }
.win-lights .l-close::after { content: "×"; font-size: 11px; }
.win-lights .l-min::after   { content: "−"; font-size: 11px; }
.win-lights .l-max::after   { content: "+"; font-size: 11px; }
/* Invisible SE corner resize hit zone (kept for symmetry with the
   other edge/corner handles injected by makeResizable). */
.win-resize-handle {
  position: absolute;
  right: 0; bottom: 0;
  width: 14px; height: 14px;
  cursor: nwse-resize;
  z-index: 5;
}
/* Edge/corner resize handles (injected by makeResizable). Invisible
   hit zones; the SE corner keeps its visible gradient via
   .win-resize-handle. Sized to dodge titlebar lights and title text. */
.win-rh { position: absolute; z-index: 5; }
.win-rh-n  { top: 0;    left: 10px;  right: 10px; height: 5px; cursor: ns-resize; }
.win-rh-s  { bottom: 0; left: 10px;  right: 14px; height: 5px; cursor: ns-resize; }
.win-rh-e  { right: 0;  top: 10px;   bottom: 14px; width: 5px; cursor: ew-resize; }
.win-rh-w  { left: 0;   top: 10px;   bottom: 10px; width: 5px; cursor: ew-resize; }
.win-rh-nw { top: 0;    left: 0;     width: 10px; height: 10px; cursor: nwse-resize; }
.win-rh-ne { top: 0;    right: 0;    width: 10px; height: 10px; cursor: nesw-resize; }
.win-rh-sw { bottom: 0; left: 0;     width: 10px; height: 10px; cursor: nesw-resize; }
.win-title {
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.win-title strong { color: var(--text); font-weight: 700; }
.win-titlebar .right {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--muted);
  flex-shrink: 0;
}
.win-body {
  padding: 10px 12px;
  overflow: auto;
  flex: 1;
  min-height: 0;
}
/* Subtle outline pulse to flag a window when its data mutates. */
.win.flash { animation: win-flash 1100ms ease-out 1; }
@keyframes win-flash {
  0%   { box-shadow: 0 0 0 0 rgba(212,133,42,0.0), 0 6px 14px -8px rgba(0,0,0,0.7); }
  20%  { box-shadow: 0 0 0 3px rgba(212,133,42,0.45), 0 6px 14px -8px rgba(0,0,0,0.7); }
  100% { box-shadow: 0 0 0 0 rgba(212,133,42,0.0), 0 6px 14px -8px rgba(0,0,0,0.7); }
}
.win.flash-steel { animation-name: win-flash-steel; }
@keyframes win-flash-steel {
  0%   { box-shadow: 0 0 0 0 rgba(91,143,173,0.0), 0 6px 14px -8px rgba(0,0,0,0.7); }
  20%  { box-shadow: 0 0 0 3px rgba(91,143,173,0.45), 0 6px 14px -8px rgba(0,0,0,0.7); }
  100% { box-shadow: 0 0 0 0 rgba(91,143,173,0.0), 0 6px 14px -8px rgba(0,0,0,0.7); }
}

/* ── Window: Warsim (top-left, dominant) ───────────────────── */
.warsim-win { /* positioned by JS */ }
.warsim-win .win-titlebar {
  background: linear-gradient(180deg, #1a221a 0%, #131a14 100%);
  border-bottom: 1px solid var(--screen-border);
}
.warsim-win .win-title { color: var(--gold-2); letter-spacing: 0.2em; }
.warsim-hud {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  flex-wrap: nowrap;
  overflow: hidden;
  flex-shrink: 1;
  min-width: 0;
}
.hud-stat { display: inline-flex; gap: 3px; align-items: baseline; white-space: nowrap; }
.hud-stat .k {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.58rem;
}
.hud-stat .v { color: var(--gold-2); font-weight: 600; }
.hud-stat .delta { font-size: 0.58rem; }
.hud-stat .delta.pos { color: var(--forest-2); }
.hud-stat .delta.neg { color: var(--crimson-2); }
.warsim-win .win-body {
  background: var(--screen-bg);
  padding: 0;
  display: flex;
  flex-direction: column;
}
.anchor-screen {
  background: var(--screen-bg);
  border: none;
  padding: 12px 16px;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--screen-text);
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
/* ANSI SGR colors are emitted as inline `style="color: rgb(...)"` by
   ``ansi.js`` directly — the parser resolves codes against the xterm
   16-color palette, the 256-color cube, and 24-bit truecolor escapes
   up front, so any color Warsim emits paints regardless of whether
   this page has a CSS rule for it. Bold/dim are still classes. */
.anchor-screen .ansi-bold { font-weight: 600; }
.anchor-screen .ansi-dim  { opacity: 0.7; }
.anchor-line { display: inline; }
.anchor-line.chosen {
  display: inline-block;
  background: rgba(201,162,39,0.22);
  color: #fff;
  font-weight: 700;
  padding: 0 4px;
  margin-left: -4px;
  border-radius: 2px;
  box-shadow: inset 3px 0 0 var(--gold);
  transition:
    background-color 280ms ease,
    color 280ms ease,
    box-shadow 280ms ease;
}
.anchor-line.chosen.pending {
  background-color: transparent;
  color: inherit;
  box-shadow: inset 3px 0 0 transparent;
  font-weight: inherit;
}
.anchor-typed {
  background: rgba(232,160,64,0.22);
  color: var(--amber-2);
  font-weight: 700;
  padding: 0 2px;
  border-radius: 2px;
}
.anchor-continue { color: var(--gold-2); font-weight: 700; }
.anchor-rejection {
  color: var(--amber-2);
  font-weight: 700;
  transition: opacity 110ms ease-out;
}
.anchor-rejection.pending { opacity: 0; }

/* ── Window: Agent (full right column — meta strip on top, then a
   vertical feed of cards; one card per "block" the model emitted
   that we have a real data field for. See playTurn for source
   mapping per card type. Card types: interact, memory.edit,
   set_goal, prose, error.) ─────────────────────────────────── */
.activity-win { /* positioned by JS */ }
/* Feed scrolls inside the body; meta strip pinned at the bottom
   so the card feed gets the full scrollable area above. Title bar
   and feed top stay clean — no header chrome eating the top. */
.activity-win .win-body {
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* Font sizes in this panel collapse to three tiers:
     0.62rem — uppercase mono labels
     0.78rem — secondary body (mono values, italic subtitles)
     0.92rem — primary prose (rationale, no-tool prose) */

/* Thin meta band — window-wide info for the current turn (one LLM
   response). Pinned at the bottom of the body, divided from the
   feed above by a dashed rule; flex-shrink: 0 keeps it visible. */
.aa-meta {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 5px 10px;
  border-top: 1px dashed var(--border);
  background: var(--panel-2);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  flex-wrap: wrap;
  flex-shrink: 0;
}
.aa-meta-item { display: inline-flex; gap: 6px; align-items: baseline; }
.aa-meta .k { color: var(--subtle); text-transform: uppercase; font-size: 0.62rem; letter-spacing: 0.08em; }
.aa-meta .v { color: var(--text); }
.aa-meta-item.turn .k { color: var(--violet); }
.aa-meta-item.turn .v { color: var(--violet-2); font-weight: 600; }
.aa-meta-item.recovered .k { color: var(--violet); }

/* Feed — vertical stack of cards, scrolls inside the body so the
   pinned meta strip below stays put. */
.aa-feed {
  flex: 1;
  overflow-y: auto;
  padding: 8px 10px 10px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  min-height: 0;
}

/* Base card chrome */
.aa-card {
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: 4px;
  padding: 7px 10px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.aa-card-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--muted);
}
.aa-card-label { color: var(--violet-2); }
/* Right-aligned subtext on the card header — explanatory note
   for cards whose title isn't self-evident (currently only the
   "no tool call" / nudge card). */
.aa-card-subtext {
  margin-left: auto;
  color: var(--muted);
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0.02em;
  font-size: 0.78rem;
  font-family: var(--font-body);
  font-style: italic;
}
/* Per-tool accent on the card label. The agent app is violet-themed,
   so all card labels stay in the agent's own color — the tool name
   in the header is flavor text *about* the agent's emission, not a
   pointer to the destination app. (Per-card body content can still
   borrow destination colors where useful — e.g. memory.edit args
   reuse diff red/green.) Runner-response is an out-of-band runner
   reply (not a model emission) and gets a tinted card border so it
   visually pairs with the prose card it answers. */
.aa-card-interact .aa-card-label { color: var(--violet-2); }
.aa-card-memory   .aa-card-label { color: var(--violet-2); }
.aa-card-set-goal .aa-card-label { color: var(--violet-2); }
.aa-card-prose    .aa-card-label { color: var(--violet-2); }
.aa-card-runner-response .aa-card-label { color: var(--violet-2); }
.aa-card-runner-response {
  border-color: rgba(128,98,197,0.42);
  background: rgba(128,98,197,0.04);
}

/* Field block — used inside the interact card for `rationale` and
   `input`. Each field has a tiny uppercase label above its body so
   viewers can name what they're looking at without inferring from
   position. The label color matches `.aa-meta .k` for visual
   consistency with the window-wide meta strip. */
.aa-field { display: flex; flex-direction: column; gap: 2px; }
.aa-field-label {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--subtle);
}
/* Rationale body — the keystone prose, body font, the largest
   size in the panel so it reads as the model's voice. */
.aa-rationale-text {
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--text);
  margin: 0;
  white-space: pre-wrap;
}
/* Input body — monospace value with the steel arrow + green string
   colors carried over from the prior footer treatment so the
   "this is a literal payload" reading stays consistent. */
.aa-input-text {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--text);
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
}
/* Arrow + input value rendered in plain text — the violet card
   label already announces this is an agent emission, so the payload
   itself doesn't need an accent and reads as cleaner literal text.
   (Was gold to mark "this goes there", then violet to claim the
   agent app's color; both pulled the eye away from the rationale
   above.) */
.aa-input-text .arrow { color: var(--text); }
.aa-input-text .str   { color: var(--text); }

/* Mutation card body — args summary as key/val rows. memory.edit
   uses .del (strike) + .add (green) markers so the args themselves
   read as a mini-diff; the full diff still plays in the Journal. */
.aa-args { display: flex; flex-direction: column; gap: 3px; }
.aa-args .row {
  display: grid;
  grid-template-columns: 44px 1fr;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.4;
}
.aa-args .row .k {
  color: var(--subtle);
  text-transform: uppercase;
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  padding-top: 2px;
}
.aa-args .row .v { color: var(--text); white-space: pre-wrap; word-break: break-word; }
.aa-args .row .v.del {
  color: var(--crimson-2);
  text-decoration: line-through;
  text-decoration-color: rgba(196,59,59,0.5);
  opacity: 0.85;
}
.aa-args .row .v.add { color: var(--forest-2); }

/* set_goal body — quoted content, no diff (slot's prior value is
   in the Journal which animates the strike+type swap). */
.aa-goal-content {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text);
  margin: 0;
  white-space: pre-wrap;
  line-height: 1.4;
}
.aa-goal-content.cleared { color: var(--subtle); font-style: italic; }

/* Prose card — model wrote text, no tool call. Rendered as a raw
   monospace payload (the content is typically machine-shaped, e.g.
   a literal `[TOOL_CALLS]{...}` string). The violet framing matches
   the runner-response block below it, so the "model wrote this →
   runner replied with that" exchange reads as a paired cycle. */
.aa-prose-text {
  margin: 0;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.4;
  white-space: pre-wrap;
  word-break: break-word;
}

/* Error card — appears when a tool call errored. Today the error
   text isn't persisted (see UI_OVERHAUL.md data gaps); this card
   renders only when the future error_text plumbing is in place. */
.aa-error-text {
  margin: 0;
  padding: 5px 8px;
  border-left: 2px solid var(--crimson);
  background: rgba(196,59,59,0.08);
  color: var(--crimson-2);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.4;
  border-radius: 0 4px 4px 0;
  white-space: pre-wrap;
}

/* Empty-state placeholder for a turn with no renderable cards
   (extreme edge case: every call errored AND no error_text yet). */
.aa-empty {
  color: var(--subtle);
  font-style: italic;
  padding: 16px 12px;
  text-align: center;
  font-size: 0.92rem;
}

/* Shared "↪ response" header — used by both the tool-error block
   (crimson) and the runner-response block (violet on the prose
   card). The arrow + label tells the viewer "this is what got
   sent back to the model"; the meta line names the role and
   where in the message stream it lands. */
.aa-tool-response,
.aa-runner-response {
  margin-top: 6px;
  padding-top: 5px;
  border-top: 1px dashed var(--border);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.aa-runner-response { border-top-color: rgba(128,98,197,0.35); }
.aa-tool-response   { border-top-color: rgba(196,59,59,0.35); }
.aa-response-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
}
.aa-runner-response .aa-response-label,
.aa-runner-response .aa-response-arrow { color: var(--violet); }
.aa-tool-response   .aa-response-label,
.aa-tool-response   .aa-response-arrow { color: var(--crimson-2); }
.aa-response-meta {
  color: var(--subtle);
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0.02em;
  font-size: 0.78rem;
  font-family: var(--font-body);
  font-style: italic;
}
/* Runner-response body — same monospace treatment as the tool
   error block, but violet framing instead of crimson because this
   isn't an error, just a coaching message from the agent runner. */
.aa-runner-response-text {
  margin: 0;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.4;
  white-space: pre-wrap;
}

.typing::after {
  content: "▋";
  margin-left: 1px;
  animation: caret 800ms steps(1) infinite;
  color: var(--gold-2);
}
@keyframes caret { 0%, 50% { opacity: 0.85; } 51%, 100% { opacity: 0; } }

/* (tool log surface dropped — history lives on the scrubber) */

/* ── Taskbar (bottom of the desktop) ───────────────────────── */
.taskbar {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 34px;
  display: flex;
  align-items: stretch;
  padding: 0 6px;
  gap: 6px;
  background:
    linear-gradient(180deg, #0e120e 0%, #060906 100%);
  border-top: 1px solid var(--border-2);
  /* warm gold seam at the top edge — the "phosphor pin-stripe" */
  box-shadow:
    inset 0 1px 0 rgba(201,162,39,0.18),
    inset 0 2px 0 rgba(0,0,0,0.8),
    0 -6px 14px -6px rgba(0,0,0,0.7);
  /* Stays above windows even after many bringToFront() bumps. */
  z-index: 1000;
}
/* Start button — small square with a 2×2 dot grid, gold on dark.
   Diegetic stand-in for "all apps"; no emoji, no kitsch. */
.taskbar-start {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 26px;
  margin: 4px 4px 4px 2px;
  background: linear-gradient(180deg, #1d2419 0%, #131914 100%);
  border: 1px solid var(--border-2);
  border-radius: 4px;
  cursor: pointer;
  transition: 100ms;
  flex-shrink: 0;
  position: relative;
}
.taskbar-start::before {
  content: "";
  width: 14px; height: 14px;
  background:
    radial-gradient(circle at 25% 25%, var(--gold-2) 0 2px, transparent 2.5px),
    radial-gradient(circle at 75% 25%, var(--gold-2) 0 2px, transparent 2.5px),
    radial-gradient(circle at 25% 75%, var(--gold-2) 0 2px, transparent 2.5px),
    radial-gradient(circle at 75% 75%, var(--gold-2) 0 2px, transparent 2.5px);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  filter: drop-shadow(0 0 2px rgba(229,188,63,0.4));
}
.taskbar-start:hover {
  background: linear-gradient(180deg, #242c1f 0%, #18201a 100%);
  border-color: var(--gold);
}
.taskbar-start.open {
  background: linear-gradient(180deg, #2a3322 0%, #1a221a 100%);
  border-color: var(--gold);
  box-shadow: inset 0 0 0 1px rgba(201,162,39,0.4);
}
/* Vertical separator after start button */
.taskbar-sep {
  width: 1px;
  margin: 6px 2px;
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(255,255,255,0.06) 30%,
    rgba(255,255,255,0.06) 70%,
    transparent 100%);
  flex-shrink: 0;
}
/* Open windows — task buttons in the middle */
.taskbar-tasks {
  display: flex;
  align-items: stretch;
  gap: 4px;
  flex: 1;
  min-width: 0;
  padding: 4px 0;
  overflow: hidden;
}
.task-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 0 10px 0 7px;
  height: 26px;
  min-width: 0;
  max-width: 200px;
  background: linear-gradient(180deg, #141a14 0%, #0a0d0a 100%);
  border: 1px solid var(--border);
  border-radius: 3px;
  cursor: pointer;
  transition: 100ms;
  flex-shrink: 1;
  position: relative;
}
.task-btn:hover { background: linear-gradient(180deg, #1a221a 0%, #10140d 100%); border-color: var(--border-2); }
.task-btn .task-tile {
  width: 16px; height: 16px;
  border-radius: 3px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 0.74rem;
  font-weight: 700;
  background: var(--panel-3);
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.task-btn[data-target="win-warsim"]   .task-tile { color: var(--gold-2); }
.task-btn[data-target="win-notebook"] .task-tile { color: var(--steel-2); }
.task-btn[data-target="win-activity"] .task-tile { color: var(--violet-2); }
.task-btn .task-label {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
}
/* Active (focused) window — accent matches the window's app
   color so the taskbar tile reads as part of the window's frame
   (gold for Warsim, steel for Journal, violet for Agent). */
.task-btn.active {
  background: linear-gradient(180deg, #1f2818 0%, #121810 100%);
}
.task-btn.active[data-target="win-warsim"] {
  border-color: var(--gold);
  box-shadow: inset 0 0 0 1px rgba(201,162,39,0.25), inset 0 -2px 0 var(--gold);
}
.task-btn.active[data-target="win-notebook"] {
  border-color: var(--steel);
  box-shadow: inset 0 0 0 1px rgba(91,143,173,0.25), inset 0 -2px 0 var(--steel);
}
.task-btn.active[data-target="win-activity"] {
  border-color: var(--violet);
  box-shadow: inset 0 0 0 1px rgba(128,98,197,0.25), inset 0 -2px 0 var(--violet);
}
.task-btn.active .task-label { color: var(--text); }
/* Minimized window — dim, no underline */
.task-btn.minimized { opacity: 0.55; }
.task-btn.minimized .task-label { color: var(--subtle); }
.task-btn.minimized:hover { opacity: 0.85; }
/* ── Start menu (pops up above the start button) ───────────── */
.start-menu {
  position: absolute;
  left: 8px;
  bottom: 40px;
  width: 248px;
  background: linear-gradient(180deg, #131a14 0%, #0d110d 100%);
  border: 1px solid var(--gold);
  border-radius: 5px;
  box-shadow:
    0 0 0 1px rgba(201,162,39,0.12),
    0 14px 28px -10px rgba(0,0,0,0.85),
    inset 0 1px 0 rgba(255,255,255,0.03);
  z-index: 1001;        /* above the taskbar */
  display: none;
  overflow: hidden;
}
.start-menu.show {
  display: block;
  animation: start-pop 140ms ease-out;
}
@keyframes start-pop {
  from { transform: translateY(4px); opacity: 0; }
  to   { transform: translateY(0);   opacity: 1; }
}
.start-menu .start-head {
  padding: 8px 12px 6px;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-weight: 700;
  color: var(--gold-2);
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, #1a2218 0%, #131a14 100%);
}
.start-menu .start-list {
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.start-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 8px;
  border-radius: 4px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: 80ms;
}
.start-item:hover {
  background: var(--panel-2);
  border-color: var(--border-2);
}
.start-item .start-tile {
  width: 28px; height: 28px;
  border-radius: 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 0.92rem;
  font-weight: 700;
  background: linear-gradient(180deg, var(--panel-3) 0%, var(--panel-2) 100%);
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.start-item[data-target="win-warsim"]   .start-tile { color: var(--gold-2); }
.start-item[data-target="win-notebook"] .start-tile { color: var(--steel-2); }
.start-item[data-target="win-activity"] .start-tile { color: var(--violet-2); }
.start-item[data-target="win-settings"] .start-tile { color: var(--slate-2); }
.start-item .start-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.start-item .start-name {
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text);
  line-height: 1.1;
}
.start-item .start-desc {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  color: var(--muted);
  letter-spacing: 0.02em;
  margin-top: 2px;
}
.start-item .start-state {
  font-family: var(--font-mono);
  font-size: 0.56rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--subtle);
  flex-shrink: 0;
}
.start-item.is-open .start-state    { color: var(--forest-2); }
.start-item.is-min  .start-state    { color: var(--amber-2); }

/* ── Window: Notebook (bottom-left — bundles goals + memory) */
.notebook-win { /* positioned by JS */ }
.notebook-win .win-body {
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.nb-section {
  padding: 10px 12px;
  border-bottom: 1px dashed var(--border);
  flex-shrink: 0;
}
.nb-section:last-child { border-bottom: none; }
.nb-section.memory { flex: 1; min-height: 0; display: flex; flex-direction: column; padding-bottom: 0; }
/* Goal block: steel-blue mono label + since-chip on its own line,
   italic body below. Matches the memory.txt header pattern so the
   two kinds of journal entries (goals and memory) read as a series
   of labeled blocks rather than mixed inline rows. */
.nb-goal-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 4px;
}
.nb-goal-head .label {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--steel-2);
}
.nb-goal-text {
  color: var(--text);
  font-size: 0.78rem;
  line-height: 1.4;
}
.nb-goal-text.empty { color: var(--subtle); }
.nb-since {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--subtle);
  flex-shrink: 0;
  white-space: nowrap;
}
/* Pencil = last edit, eye = last read. Stroke 2.2 matches
   .app-icon so the glyph reads at 10px without going muddy. */
.nb-since-icon {
  width: 10px;
  height: 10px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linejoin: round;
  stroke-linecap: round;
  flex-shrink: 0;
}
.nb-mem-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 3px;
}
.nb-mem-head .label {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--steel-2);
}
.nb-mem-head .meta {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--subtle);
}
.nb-mem-head .nb-since { margin-left: 0; }
.nb-mem-head .meta .used { color: var(--text); }
.memory-content {
  margin: 0 0 6px;
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--text);
  white-space: pre-wrap;
  word-break: break-word;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
.memory-diff-add { background: rgba(74,158,92,0.22); color: var(--forest-2); }
.memory-diff-rem { background: rgba(196,59,59,0.18); color: var(--crimson-2); text-decoration: line-through; }

/* Live-edit animation primitives — used for memory.edit and
   set_goal updates in the Journal. The flow is editor-style:
     1. Original text becomes a sequence of .mem-char spans.
     2. Each .mem-char gets .struck (line-through + crimson tint),
        left-to-right, simulating select-and-delete.
     3. The container empties; layout reflows.
     4. New text types into the same container; the .mem-edit-typing
        class wraps it in a forest-tinted highlight band.
     5. .mem-edit-settle fades the highlight back to the neutral
        memory amber so the change settles into the surrounding text.
   Green / red here are diff semantics — the rule "green & red are
   reserved for meaningful content" applies; this IS the diff. */
.mem-char {
  transition: color 90ms ease, background-color 90ms ease;
}
.mem-char.struck {
  color: var(--crimson-2);
  background: rgba(196,59,59,0.18);
  text-decoration: line-through;
  text-decoration-color: rgba(196,59,59,0.7);
}
.mem-edit-typing {
  background: rgba(74,158,92,0.22);
  color: var(--forest-2);
  border-radius: 2px;
  padding: 0 1px;
}
.mem-edit-settle {
  background: transparent;
  color: var(--text);
  transition: background-color 540ms ease, color 540ms ease;
}

/* (Activity is bundled into the Agent Activity window above) */

/* ── Window: Settings (closed by default) ───────────────────
   The only setting today is the desktop wallpaper; the body
   is a 2-column grid of preview tiles. Each tile reuses the
   same wallpaper rendering rules (via [data-wallpaper] on the
   .wp-tile element) so users see the actual paint they'll
   get, in miniature. The active tile gets a slate accent ring
   plus a checkmark badge in the top-right. */
.settings-win .win-body {
  padding: 14px 14px 12px;
  overflow-y: auto;
}
.settings-section-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 10px;
}
.settings-section-head .label {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 700;
  color: var(--slate-2);
}
.settings-section-head .meta {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  color: var(--subtle);
}
.wp-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.wp-tile {
  position: relative;
  border-radius: 6px;
  border: 1px solid var(--border-2);
  overflow: hidden;
  cursor: pointer;
  /* Match the cabinet's screen aspect so previews are literal
     miniatures of what the desktop will paint. The desktop sits
     inside a 1.35:1 cabinet whose bezel + well padding leaves a
     ~7:6 inner screen. */
  aspect-ratio: 7 / 6;
  background: #050805;
  transition: border-color 120ms, transform 120ms, box-shadow 120ms;
}
.wp-tile:hover {
  border-color: var(--slate-2);
  transform: translateY(-1px);
  box-shadow: 0 4px 10px -6px rgba(0,0,0,0.7);
}
.wp-tile.is-active {
  border-color: var(--slate);
  box-shadow: 0 0 0 1px var(--slate-2), 0 4px 10px -6px rgba(0,0,0,0.7);
}
.wp-tile .wp-thumb {
  position: absolute;
  inset: 0;
  border-radius: 5px;
  overflow: hidden;
}
.wp-tile .wp-name {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 4px 8px;
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.78) 100%);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  display: flex;
  align-items: center;
  gap: 6px;
}
.wp-tile .wp-name .wp-motion {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.52rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--forest-2);
  font-weight: 700;
}
.wp-tile .wp-check {
  position: absolute;
  top: 6px; right: 6px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--slate);
  color: #fff;
  display: none;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 0 0 2px rgba(0,0,0,0.4);
}
.wp-tile.is-active .wp-check { display: inline-flex; }

/* Static, lightweight thumbnail variants. These reuse the
   wallpaper backgrounds so each tile reads as itself, but
   skip the JS-injected motion content (particles / stars /
   ASCII) for performance — the heading already labels the
   wallpaper, and any motion-bearing tiles are tagged with the
   "MOTION" pip in the bottom-right. */
.wp-thumb[data-wp="aurora"] {
  background: linear-gradient(180deg, #050912 0%, #0b1325 35%, #131c2a 70%, #0c1612 100%);
}
.wp-thumb[data-wp="aurora"]::before {
  content: "";
  position: absolute;
  left: -10%; right: -10%; top: 5%;
  height: 60%;
  background: linear-gradient(100deg, transparent, rgba(74,158,92,0.55), rgba(229,188,63,0.4), rgba(91,143,173,0.4), transparent);
  filter: blur(14px);
  opacity: 0.7;
}
.wp-thumb[data-wp="aurora"]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 24%;
  background: #050805;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80' preserveAspectRatio='none'><path fill='black' d='M0 80 L0 60 L8 30 L16 55 L24 25 L32 50 L40 18 L48 48 L56 32 L64 12 L72 38 L80 22 L88 45 L96 18 L104 50 L112 28 L120 8 L128 36 L136 22 L144 50 L152 30 L160 14 L168 42 L176 22 L184 48 L192 30 L200 50 L200 80 Z'/></svg>") center / 100% 100% no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80' preserveAspectRatio='none'><path fill='black' d='M0 80 L0 60 L8 30 L16 55 L24 25 L32 50 L40 18 L48 48 L56 32 L64 12 L72 38 L80 22 L88 45 L96 18 L104 50 L112 28 L120 8 L128 36 L136 22 L144 50 L152 30 L160 14 L168 42 L176 22 L184 48 L192 30 L200 50 L200 80 Z'/></svg>") center / 100% 100% no-repeat;
}
.wp-thumb[data-wp="embers"] {
  background:
    radial-gradient(120% 60% at 50% 110%, rgba(212,133,42,0.4) 0%, transparent 70%),
    radial-gradient(80% 40% at 50% 105%, rgba(228,72,72,0.25) 0%, transparent 70%),
    linear-gradient(180deg, #0a0606 0%, #1a0e08 60%, #2a1810 100%);
}
.wp-thumb[data-wp="embers"]::before,
.wp-thumb[data-wp="embers"]::after {
  content: "";
  position: absolute;
  width: 3px; height: 3px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffd089 0%, #e8a040 50%, transparent 80%);
  box-shadow: 0 0 5px rgba(232,160,64,0.7);
}
.wp-thumb[data-wp="embers"]::before { left: 28%; top: 38%; }
.wp-thumb[data-wp="embers"]::after  { left: 64%; top: 22%; }
.wp-thumb[data-wp="constellations"] {
  background: radial-gradient(120% 80% at 60% 30%, #0d1830 0%, #050912 60%, #02040a 100%);
}
.wp-thumb[data-wp="constellations"]::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(1px 1px at 12% 22%, #e8e4d8 50%, transparent 51%),
    radial-gradient(1px 1px at 28% 60%, #e8e4d8 50%, transparent 51%),
    radial-gradient(1px 1px at 44% 18%, #e8e4d8 50%, transparent 51%),
    radial-gradient(1px 1px at 58% 44%, #e8e4d8 50%, transparent 51%),
    radial-gradient(1px 1px at 72% 70%, #e8e4d8 50%, transparent 51%),
    radial-gradient(1px 1px at 86% 28%, #e8e4d8 50%, transparent 51%),
    radial-gradient(1.4px 1.4px at 36% 38%, #e5bc3f 50%, transparent 51%),
    radial-gradient(1.4px 1.4px at 64% 50%, #e5bc3f 50%, transparent 51%),
    radial-gradient(1.4px 1.4px at 50% 24%, #e5bc3f 50%, transparent 51%);
  opacity: 0.95;
}
.wp-thumb[data-wp="cathedral"] {
  background:
    repeating-linear-gradient(45deg, rgba(0,0,0,0.22) 0 1px, transparent 1px 10px),
    repeating-linear-gradient(-45deg, rgba(0,0,0,0.22) 0 1px, transparent 1px 10px),
    radial-gradient(80% 80% at 50% 50%, #1a2218 0%, #0a0d0a 70%, #050805 100%);
}
.wp-thumb[data-wp="cathedral"]::before {
  content: "";
  position: absolute;
  inset: 18% 24%;
  border-radius: 50%;
  background:
    conic-gradient(from 0deg,
      rgba(229,188,63,0.7) 0 40deg,
      rgba(74,158,92,0.55) 40deg 80deg,
      rgba(229,188,63,0.7) 80deg 120deg,
      rgba(91,143,173,0.55) 120deg 160deg,
      rgba(229,188,63,0.7) 160deg 200deg,
      rgba(74,158,92,0.55) 200deg 240deg,
      rgba(229,188,63,0.7) 240deg 280deg,
      rgba(91,143,173,0.55) 280deg 320deg,
      rgba(229,188,63,0.7) 320deg 360deg);
  box-shadow:
    inset 0 0 0 2px rgba(0,0,0,0.5),
    0 0 6px rgba(229,188,63,0.4);
}
.wp-thumb[data-wp="cathedral"]::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 12%; aspect-ratio: 1;
  border-radius: 50%;
  background: var(--gold-2);
  box-shadow: 0 0 6px rgba(229,188,63,0.7);
}
.wp-thumb[data-wp="bliss"] {
  background: #000;
  overflow: hidden;
}
/* Bliss thumb is populated by JS at setup time using the same
   buildBliss() that paints the desktop, so the preview is a
   literal miniature of the live wallpaper rather than a hand-
   drawn approximation. The .dw-bliss <pre>s position absolutely
   inside this thumb. */

/* (Control deck and back-to-live pill removed — transport moved
   into the cabinet's right panel; their styles are gone.) */

/* Drop the metadata card on narrow viewports so the cabinet keeps
   its full real estate. The desk gracefully degrades to monitor-
   only; metadata is still reachable via the topnav. */
@media (max-width: 1100px) {
  .stage { grid-template-columns: 1fr; }
  .metadata-card { display: none; }
}
/* Below ~900px the cabinet itself collapses badly. Show an
   explicit "this view requires more horizontal space" message
   rather than degrade silently. */
.narrow-warning {
  display: none;
  position: fixed;
  inset: 0;
  background: var(--bg);
  color: var(--text);
  z-index: 1000;
  padding: 36px 28px;
  text-align: center;
  font-family: var(--font-display);
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
}
.narrow-warning h2 { color: var(--gold-2); margin: 0; letter-spacing: 0.06em; }
.narrow-warning p  { color: var(--muted); max-width: 440px; line-height: 1.5; }
@media (max-width: 900px) {
  .narrow-warning { display: flex; }
}

/* Empty-state placeholders for Journal goals + memory. These
   replace the hard-coded mock content; the first successful
   set_goal / memory.edit replaces the placeholder via the
   standard strike-then-type animation, which works against any
   starting text since animateEditReplace walks character-by-
   character. */
.nb-goal-text.empty {
  color: var(--subtle);
  font-style: italic;
}
.nb-section[data-goal] .nb-goal-text.empty + * .label,
.nb-section[data-goal] .label.dim { color: var(--muted); }
.memory-content.empty {
  color: var(--subtle);
  font-style: italic;
  text-align: center;
  padding: 18px 14px;
  background: transparent;
  border: 1px dashed var(--border);
}

/* Terminal sessions: status pill on the metadata card carries
   the signal — no overlay banner. (The earlier ribbon over the
   desktop read as a toast covering content; user feedback was
   direct that it had to go.) */

/* Status pill colors for terminal states. */
.status-pill.completed { background: rgba(201,162,39,0.22); color: var(--gold-2); }
.status-pill.crashed   { background: rgba(196,59,59,0.18);  color: var(--crimson-2); }
.status-pill.stopped   { background: rgba(125,142,126,0.18); color: var(--muted); }
.status-pill.queued    { background: rgba(91,143,173,0.18);  color: var(--steel-2); }

/* Confirmation modal (stop-session). Backdrop dims the desk;
   card is a panel-tier surface with a danger-tinted confirm
   button. Authored `display: flex` below beats the UA `[hidden]`
   default, so we have to reassert `display: none` explicitly. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(8, 11, 8, 0.72);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.modal-backdrop[hidden] { display: none; }
.modal-card {
  background: var(--panel);
  border: 1px solid var(--border-2);
  border-radius: 6px;
  padding: 20px 22px 18px;
  width: min(420px, 100%);
  display: flex;
  flex-direction: column;
  gap: 14px;
  box-shadow: 0 24px 48px -16px rgba(0,0,0,0.7);
}
.modal-title {
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text);
  margin: 0;
}
.modal-body {
  font-family: var(--font-body);
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.5;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.modal-btn {
  font-family: var(--font-body);
  font-size: 0.82rem;
  font-weight: 500;
  padding: 6px 14px;
  border-radius: 5px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background 120ms, border-color 120ms, color 120ms;
}
.modal-btn.cancel {
  background: transparent;
  color: var(--muted);
  border-color: var(--border);
}
.modal-btn.cancel:hover {
  color: var(--text);
  border-color: var(--border-2);
}
.modal-btn.confirm {
  background: rgba(196,59,59,0.18);
  color: var(--crimson-2);
  border-color: var(--crimson);
  font-weight: 600;
}
.modal-btn.confirm:hover { background: rgba(196,59,59,0.30); }
.modal-btn:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
.modal-btn[disabled] { opacity: 0.5; cursor: progress; }
.modal-error {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--crimson-2);
  margin-top: -4px;
}

/* `.hidden` utility (already used by aa-recovered + running-badge) */

/* ─────────────────────────────────────────────────────────────────────
   Public-only additions: landing page sessions list, submit form,
   kill-switch banner, footer.
   ───────────────────────────────────────────────────────────────────── */

/* Honour the HTML `hidden` attribute — `display:` rules downstream
   (e.g. .kill-banner sets `display:flex`) otherwise win the cascade
   and bypass it. */
[hidden] { display: none !important; }

main.landing {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px;
}

.landing-intro {
  margin: 0 0 20px;
  color: var(--muted);
  font-size: 0.94rem;
  line-height: 1.55;
  max-width: 680px;
}
.landing-intro em { color: var(--text); font-style: italic; }

.section-title {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text);
  margin: 24px 0 10px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.online-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 3px 10px;
  border-radius: 999px;
  text-transform: lowercase;
}
.online-pill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.online-pill.online {
  background: rgba(74,158,92,0.12);
  border: 1px solid rgba(74,158,92,0.25);
  color: var(--forest-2);
}
.online-pill.online::before { animation: pulse-dot 2s infinite; }
.online-pill.offline {
  background: rgba(125,142,126,0.12);
  border: 1px solid rgba(125,142,126,0.25);
  color: var(--muted);
}

.sessions-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}
.sessions-table th, .sessions-table td {
  padding: 10px 14px;
  text-align: left;
  border-bottom: 1px solid var(--border);
  font-size: 0.88rem;
}
.sessions-table th {
  color: var(--muted);
  font-weight: 600;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: var(--panel-2);
}
.sessions-table tbody tr {
  cursor: pointer;
  transition: background 120ms;
}
.sessions-table tbody tr:hover td { background: rgba(201,162,39,0.05); }
.sessions-table .submitter { color: var(--muted); }
.sessions-table .label-cell { color: var(--text); font-weight: 600; }
.sessions-table .label-cell .label-id {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--subtle);
  font-weight: 400;
  margin-top: 2px;
}
.sessions-table .num { font-family: var(--font-mono); }

.empty-state {
  padding: 40px 24px;
  text-align: center;
  color: var(--muted);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
}

.status-pill.queued    { background: rgba(91,143,173,0.18);  color: var(--steel-2); }
.status-pill.completed { background: rgba(91,143,173,0.18);  color: var(--steel-2); }
.status-pill.crashed   { background: rgba(196,59,59,0.18);   color: var(--crimson-2); }
.status-pill.gave_up   { background: rgba(212,133,42,0.18);  color: var(--amber-2); }
.status-pill.stopped   { background: rgba(125,142,126,0.18); color: var(--muted); }
.status-pill.deleted   { background: rgba(125,142,126,0.18); color: var(--muted); }

.submit-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 20px;
  max-width: 720px;
}
.submit-form .field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.submit-form .field-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 0.7rem;
  color: var(--muted);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.submit-form .char-count {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 500;
  color: var(--subtle);
  letter-spacing: 0.04em;
  text-transform: none;
}
.submit-form .char-count.over { color: var(--crimson-2); }
.submit-form input,
.submit-form textarea,
.submit-form select {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 8px 11px;
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
  outline: none;
  transition: 120ms;
}
.submit-form textarea {
  font-family: var(--font-mono);
  font-size: 0.84rem;
  line-height: 1.5;
  resize: vertical;
  min-height: 200px;
}
.submit-form input::placeholder,
.submit-form textarea::placeholder { color: var(--subtle); }
.submit-form input:focus,
.submit-form textarea:focus,
.submit-form select:focus {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px rgba(201,162,39,0.18);
}
.submit-form .privacy {
  background: rgba(91,143,173,0.07);
  border: 1px solid rgba(91,143,173,0.25);
  border-radius: 5px;
  color: var(--steel-2);
  padding: 8px 12px;
  font-size: 0.82rem;
  line-height: 1.5;
}
.submit-form .submit-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 4px;
  flex-wrap: wrap;
}
.submit-form button[type="submit"] {
  background: var(--gold);
  color: #0c0e0b;
  font-weight: 600;
  padding: 9px 20px;
  border-radius: 5px;
  border: none;
  font-size: 0.92rem;
  letter-spacing: 0.02em;
  transition: 120ms;
}
.submit-form button[type="submit"]:hover:not([disabled]) { background: var(--gold-2); }
.submit-form button[type="submit"]:active { transform: scale(0.98); }
.submit-form button[type="submit"][disabled] {
  background: var(--panel-3);
  color: var(--muted);
  cursor: not-allowed;
}
.submit-form .queue-status {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--muted);
}
.submit-form .submit-result {
  margin-top: 6px;
  padding: 9px 12px;
  border-radius: 5px;
  font-size: 0.88rem;
  line-height: 1.45;
}
.submit-form .submit-result.success {
  background: rgba(74,158,92,0.12);
  border: 1px solid rgba(74,158,92,0.35);
  color: var(--forest-2);
}
.submit-form .submit-result.error {
  background: rgba(196,59,59,0.12);
  border: 1px solid rgba(196,59,59,0.35);
  color: var(--crimson-2);
}
.submit-form .offline-warn {
  background: rgba(212,133,42,0.10);
  border: 1px solid rgba(212,133,42,0.35);
  color: var(--amber-2);
  padding: 8px 12px;
  border-radius: 5px;
  font-size: 0.86rem;
}
.submit-form .turnstile-host { min-height: 65px; }

.kill-banner {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(196,59,59,0.18);
  border-bottom: 1px solid rgba(196,59,59,0.55);
  color: var(--crimson-2);
  padding: 8px 24px;
  font-size: 0.88rem;
  font-weight: 500;
}
.kill-banner strong { color: var(--text); margin-right: 4px; }

.public-footer {
  max-width: 1100px;
  margin: 24px auto 36px;
  padding: 20px 24px 0;
  border-top: 1px solid var(--border);
  color: var(--subtle);
  font-size: 0.78rem;
  line-height: 1.6;
}
.public-footer p { margin: 4px 0; }

/* Hide local-operator-only DOM that the viewer template includes by
   default but the public viewer doesn't need.  Removing the elements
   from the template keeps the underlying viewer JS intact (it
   defensively guards on element absence anyway). */
body.is-viewer .mc-stop-btn,
body.is-viewer .mc-stopping,
body.is-viewer .mc-title-edit-btn,
body.is-viewer .modal-backdrop {
  display: none !important;
}
