/* ============================================================================
 * shell.css — Reactor⚛️Dynamics M8 visual shell (layout + look only).
 *
 * A static, mock-data prototype of the control-room UI for rapid iteration on
 * appearance and layout BEFORE wiring it to the live snapshot (M5). Colors are
 * the M8 §15 palette; regions are the M8 §2 layout. Nothing here is wired to the
 * engine — every value is a placeholder.
 * ========================================================================== */

:root {
  /* QUIET-BOARD palette (concept-scan matched). The board reads near-black and
     near-monochrome when normal; color is spent ONLY on the abnormal. Green =
     equipment energized/armed (a calm, stable accent); amber = caution; red =
     alarm/trip (the only saturated, attention-pulling color). EPRI 1003662 /
     NUREG-0700 / ISA-18.2 "manage by exception". */
  /* Backgrounds (darkest → lightest) */
  --bg-strip: #0C0F12;
  --bg-plant: #0E1216;
  --bg-right: #0F1318;
  --bg-elevated: #161B21;
  --border: #232931;
  /* Text — muted by default so readouts recede until something is wrong
     (nudged a touch brighter across the board for legibility) */
  --text: #E4E9EE;
  --text-2: #98A3AF;
  --muted: #69757F;
  --disabled: #3A434D;
  /* Semantic state (board / chrome)
     green  = running / normal
     amber  = abnormal and/or caution alarms
     red    = problem and/or automatic protection (trip)
     cyan   = available for user input
     grey   = OK but not ideal, no alarm */
  --normal: #5BB3C4;        /* cyan — interactive / selected / editable */
  --caution: #D9A441;       /* amber — caution / abnormal */
  --critical: #E5484D;      /* red — trip / critical */
  --running: #46A35E;       /* green — energized, running, healthy normal */
  --running-muted: #35704A;
  --stopped: #586673;
  --trend-up: #FB923C;
  --trend-down: #67E8F9;
  --core-glow: #00C4FF;

  --radius: 6px;
  --gap: 8px;
  font-size: 14px;
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  background: #070A0C;
  color: var(--text);
  font-family: ui-sans-serif, "Segoe UI", Roboto, system-ui, sans-serif;
  font-size: 14px;
  overflow: hidden;
}
.mono { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; }

/* ===================================================================== app */
.app {
  display: flex;
  gap: var(--gap);
  height: 100vh;
  padding: var(--gap);
}

/* Left: plant-control area (M8 §2.2 — would be fixed aspect ratio; here it
   simply fills available space for easy iteration). */
.plant-area {
  flex: 1 1 auto;
  min-width: 760px;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  background: var(--bg-plant);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--gap);
  overflow: hidden;
  position: relative;   /* anchors the app toast */
}

/* Right column: sim controls + instructor + tools + scanner */
.right-col {
  flex: 1 1 340px;
  min-width: 320px;
  max-width: 380px;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  overflow: hidden;
}
/* Panel order in the right column: sim controls, TOOLS block, then the instructor
   block, then the scanner (the tool block sits above the Shift Supervisor). */
.right-col > .sim-controls { order: 0; }
.right-col > #toolsCard     { order: 1; }
.right-col > #instructorCard { order: 2; }
.right-col > .scanner       { order: 3; }

/* Responsive: the layout must survive any monitor. The 760px plant-area floor
   was what forced horizontal scroll on mid-size displays; relax it first, then
   stack the columns on genuinely narrow windows. */
@media (max-width: 1200px) {
  .plant-area { min-width: 0; }
  .right-col { flex-basis: 320px; min-width: 300px; }
}
@media (max-width: 860px) {
  html, body { overflow: auto; }
  .app { flex-direction: column; height: auto; min-height: 100vh; }
  .plant-area, .right-col {
    flex: 0 0 auto; min-width: 0; max-width: none; width: 100%; overflow: visible;
  }
  .synoptic { min-height: 220px; }
  .bottom-row { flex: 0 0 auto; height: 240px; }
}

/* ============================================ PWR control-room 3-column layout
   The PWR board grids .app into: the diagram + vital gauges (left, kept as large
   as possible), the alarms (top) + strip chart (bottom) stacked into a middle
   column, and the simulator panel — time controls pinned on top — on the right.
   app.js (buildPlantDisplay) moves .bottom-row out from under the diagram into
   the middle column, so the diagram reclaims that vertical room. Gridding .app
   makes the older .app.pwr-synoptic flex rules on these children inert;
   pwr_board.js skips its plant-width lock in this mode so the board fits the
   grid track (its ResizeObserver refits on any relayout).

   The ⛶ button hides the right panel (.sim-hidden): the layout drops to two
   columns and app.js moves the time controls (.sim-controls) atop the middle
   column, enlarging the diagram further. */
.demo-btn.on { color: var(--running); border-color: var(--running); }

/* --simcol-w is the simulator track's MAXIMUM, driven by pwr_board.js fitColumns():
   the diagram keeps the width it needs at full height and the leftover — large on
   short-and-wide windows, where the board would otherwise letterbox — is handed to
   that column instead of sitting dead beside the diagram. The value here is the
   floor used before/without that measurement. */
.app.pwr-synoptic {
  --simcol-w: 360px;
  --bottomrow-h: 230px;
  position: relative;   /* splitter handles are absolutely positioned over the grid */
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, var(--simcol-w));
  grid-template-rows: minmax(0, 1fr);
  grid-template-areas: "diagram simcol";
}
.app.pwr-synoptic > .plant-area { grid-area: diagram; min-width: 0; max-width: none; }
.app.pwr-synoptic > .right-col  { grid-area: simcol; min-width: 0; max-width: none; }

/* PWR-only: hide the legacy 4-view switcher / status bar / control row, and let the
   board own the whole view area. app.js empties those three containers on the PWR
   path, but an empty container still takes its padding/border — so they are hidden,
   not merely cleared. These four rules moved here from the retired V1 stylesheet
   (ui/diagram/pwr_synoptic.css, #246): they were always shell hooks keyed on the
   .app class, not V1 board styling, and the V2 board needs them. RBMK/BWR untouched. */
.app.pwr-synoptic .view-switcher,
.app.pwr-synoptic .status-bar,
.app.pwr-synoptic .pd-controlbar { display: none; }
.app.pwr-synoptic .view-area { padding: 0; overflow: hidden; }

/* The V2 board carries its own vital-parameter tile strip (six Indicator Panel
   components across the top), which is what the shell's .gauge-strip used to provide.
   Two copies of the same six readings is worse than one, and the shell copy is the one
   that is NOT part of the diagram — so it is hidden here rather than deleted, because
   RBMK/BWR still run the legacy plant display and genuinely need it. app.js keeps
   building it; that is a few hidden nodes, and it means nothing breaks if a plant
   without its own tiles is put back on this layout. */
.app.pwr-synoptic > .plant-area > .gauge-strip { display: none; }

/* keep the diagram's flex chain honest so the board fits its column width
   instead of overflowing (the .main-area link lacks min-width:0) */
.app.pwr-synoptic > .plant-area .main-area,
.app.pwr-synoptic > .plant-area .view-area,
.app.pwr-synoptic > .plant-area .pwr-board-wrap { min-width: 0; }

/* Under-the-diagram strip: chart and alarms side by side, and — only when the sim panel
   is hidden (⛶) — the time controls tuck in at the left. Fixed height so the diagram
   keeps the rest; the two panels split the width. */
/* FIXED height, draggable — not `flex: 1 1 auto` (#233). Letting this row grow into the
   leftover height fought the sim column for the same space and the DIAGRAM lost both ways:
   a taller strip shortens the board, a shorter board needs less width, and fitColumns then
   hands that freed width to the sim column, which shortens the board again. Two auto-growers
   either side of a fit-to-height diagram is a feedback loop, not a layout. Pinning this row
   breaks it; --bottomrow-h is the operator's to drag (see the splitters below). */
.app.pwr-synoptic .plant-area > .bottom-row { flex: 0 0 var(--bottomrow-h); min-height: 150px; flex-direction: row; }

/* Draggable panel edges (#233). The auto-fit is a good default, not a policy: drag the sim
   panel's inner edge or the trend strip's top edge to trade space with the diagram. A drag
   PINS that axis (persisted in localStorage) and fitColumns stops touching it. */
.bd-split { position: absolute; z-index: 40; touch-action: none; }
.bd-split::after {
  content: ''; position: absolute; inset: 0; border-radius: 2px;
  background: var(--accent, #4fe3ff); opacity: 0; transition: opacity .12s ease;
}
.bd-split:hover::after, .bd-split.bd-dragging::after { opacity: .55; }
.bd-split-v { top: 0; bottom: 0; width: 9px; cursor: col-resize; }
.bd-split-v::after { left: 3.5px; right: 3.5px; }
.bd-split-h { height: 9px; cursor: row-resize; }
.bd-split-h::after { top: 3.5px; bottom: 3.5px; }
/* ⛶ removes the sim column, so there is no vertical edge left to drag. */
.app.pwr-synoptic.sim-hidden .bd-split-v { display: none; }
/* Stacked (narrow) layouts size themselves; dragging a track that isn't there is nonsense. */
@media (max-width: 1200px) { .bd-split { display: none; } }
.app.pwr-synoptic .plant-area > .bottom-row > .sim-controls { order: 1; flex: 0 0 auto; }
.app.pwr-synoptic .plant-area > .bottom-row > .strip-chart  { order: 2; flex: 1 1 0; min-width: 0; }
.app.pwr-synoptic .plant-area > .bottom-row > .alarm-panel  { order: 3; flex: 1 1 0; min-width: 0; min-height: 0; }

/* ⛶ hides the right sim panel → the diagram column takes the whole width */
.app.pwr-synoptic.sim-hidden {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "diagram";
}
.app.pwr-synoptic.sim-hidden > .right-col { display: none; }

/* narrow screens: stack the columns so nothing overflows. The chart+alarms strip rides
   with the diagram now (it is inside .plant-area), so only the sim panel drops below. */
@media (max-width: 1200px) {
  html, body { overflow: auto; }
  .app.pwr-synoptic {
    height: auto; min-height: 100vh;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 78vh auto;
    grid-template-areas: "diagram" "simcol";
  }
  .app.pwr-synoptic.sim-hidden {
    grid-template-rows: minmax(0, 1fr);
    grid-template-areas: "diagram";
  }
  /* stack chart above alarms rather than squeezing both into a narrow row */
  .app.pwr-synoptic .plant-area > .bottom-row { flex: 0 0 auto; flex-direction: column; }
}

/* generic panel chrome */
.panel {
  background: var(--bg-right);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.panel-title {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-2); padding: 8px 10px 6px; font-weight: 600;
}

/* ===================================================== vital-few gauge strip */
.gauge-strip {
  flex: 0 0 auto;
  display: flex; gap: var(--gap); flex-wrap: wrap;
  background: var(--bg-strip);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px;
  align-items: stretch;
  position: relative;
}
.gauge-strip.alarm-tint { box-shadow: inset 0 0 0 1px rgba(239,68,68,.35); }
.gauge {
  flex: 1 1 0; min-width: 96px;
  background: var(--bg-plant);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 6px 8px 7px;
  display: flex; flex-direction: column; gap: 3px;
}
.gauge.lead { box-shadow: inset 0 2px 0 0 var(--normal); }
/* gauge card background subtly tints with state (reinforces the value color) */
.gauge.warn  { background: var(--gauge-bg-warn);  border-color: var(--gauge-border-warn); }
.gauge.alarm { background: var(--gauge-bg-alarm); border-color: var(--gauge-border-alarm); }
/* Quiet board: a normal reading is the DIM resting state — the value's color is
   its status. Normal = dim blue-white, Caution = amber, Alarm = red + flash. */
.gauge .g-label { font-size: 10px; color: var(--clr-dim-label); letter-spacing: .03em; display:flex; justify-content:space-between; }
/* value + mini strip chart share one row (chart to the RIGHT of the number) so the
   gauge strip stays short — freeing vertical room for the diagram below. */
.g-valrow { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* Colors match the plant diagram's readout scheme: green normal, amber caution, red alarm
   (the diagram uses cyan only for user-editable inputs, so the gauges — pure readouts —
   stay green like every other indication on the board). */
.gauge .g-value { flex: 0 0 auto; font-size: 22px; font-weight: 650; line-height: 1.05; color: #5aad7c; }
.gauge .g-units { font-size: 10px; color: var(--clr-dim-label); }
.gauge.warn  .g-value { color: #ffd166; }
.gauge.alarm .g-value { color: #ff6a4d; animation: gauge-alarm-flash .6s steps(1, end) infinite; }
@keyframes gauge-alarm-flash { 50% { opacity: .4; } }
/* trend arrow: dim at rest; color (not direction) signals deviation */
.gauge .g-trend { font-size: 11px; color: #3a4e60; }
.gauge.warn  .g-trend { color: #c09020; }
.gauge.alarm .g-trend { color: #e05030; }
.trend-up, .trend-down, .trend-flat { /* direction is the glyph; color is state (above) */ }
/* range bar: a single DIM track; a colored fill (set by renderGauges) appears to
   the needle ONLY when the value is in a warn/alarm band — never a rainbow. */
.g-band { height: 5px; border-radius: 3px; position: relative; margin-top: 2px; background: var(--bar-track-normal); }
.g-band .g-fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 3px; }
.g-band .needle { position: absolute; top: -2px; width: 2px; height: 9px; background: var(--text); border-radius: 1px;
  transition: left .12s linear; z-index: 1; }
.g-band .trip { position: absolute; top: -3px; width: 0; height: 11px; border-left: 1px dashed var(--critical); }
/* mini strip chart: sits beside the number (1 min of data), fills the slack width */
.g-spark { flex: 1 1 auto; width: auto; min-width: 32px; height: 20px; opacity: .85; }

/* ===================================================== control sections row */
/* minmax(0,1fr) — NOT plain 1fr — forces genuinely equal columns. Plain 1fr is
   minmax(auto,1fr): a column won't shrink below its content's intrinsic width,
   so the dense Reactor-Core rod cluster used to steal width from the others. */
.control-sections {
  flex: 0 0 auto;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap);
}
.section {
  background: var(--bg-strip);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px;
  display: flex; flex-direction: column; gap: 7px;
  min-height: 150px;
  min-width: 0;          /* allow the grid track to shrink past content */
}
.section h3 {
  margin: 0 0 2px; font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-2); font-weight: 700;
}
/* wrap so a control cluster (rod drive + speed + nudge) reflows instead of
   forcing its column wider than the rest */
.ctl-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ctl-label { font-size: 11px; color: var(--text-2); flex: 1 1 auto; }
.ctl-readout { font-size: 12px; font-weight: 600; }

/* button group (segmented) */
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: 5px; overflow: hidden; }
.seg button {
  background: var(--bg-elevated); color: var(--text-2); border: none;
  padding: 4px 8px; font-size: 11px; cursor: pointer; border-right: 1px solid var(--border);
}
.seg button:last-child { border-right: none; }
.seg button:hover { color: var(--text); }
/* selected control state (quiet board): OUTLINE chips, not filled blocks — a
   thin colored ring + colored text marks the active option, the alternative
   stays muted gray. Exactly one accented chip per control = a calm board.
   .run = energized/armed (green), .warn = caution (amber). */
.seg button.on { background: transparent; color: var(--text); font-weight: 700; box-shadow: inset 0 0 0 1px #38424d; }
.seg button.on.run { color: #6FD089; background: rgba(70,163,94,.08); box-shadow: inset 0 0 0 1px rgba(70,163,94,.65); }
.seg button.on.warn { color: var(--caution); background: rgba(217,164,65,.10); box-shadow: inset 0 0 0 1px rgba(217,164,65,.65); }
/* press-and-hold (rod drive) active state */
.seg button.holding { color: #6FD089; background: rgba(70,163,94,.16); box-shadow: inset 0 0 0 1px rgba(70,163,94,.7); }

.btn {
  background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border);
  border-radius: 5px; padding: 5px 9px; font-size: 11px; cursor: pointer;
}
.btn:hover { border-color: var(--text-2); }
.btn.ghost { background: transparent; }
/* A control that can't act right now must look it (honest affordances) */
button:disabled { opacity: .45; cursor: not-allowed; }
/* Keyboard focus must be visible board-wide (never for mouse clicks) */
button:focus-visible, input:focus-visible, select:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--normal); outline-offset: 1px;
}

/* rod position bar */
.rodbar { height: 10px; border-radius: 5px; background: #11151a; border: 1px solid var(--border); position: relative; overflow: hidden; }
.rodbar > span { position: absolute; left: 0; top: 0; bottom: 0; background: var(--running-muted); transition: width .12s linear, background .2s ease; }
.rodbar.shutdown > span { background: var(--running-muted); }
.rodbar .limit { position: absolute; top: -2px; bottom: -2px; width: 0; border-left: 1px dashed var(--caution); }

/* emergency systems set apart (§5.5) */
.emergency { border: 1px dashed var(--caution); border-radius: 5px; padding: 6px; }
.emergency .ctl-label { color: var(--caution); }

/* SCRAM cover/button (§5.1) — quiet-board states:
 *   not scrammed, cover down  → DULL GREEN striped guard (calm "armed/ready")
 *   cover lifted (armed)      → DULL RED exposed SCRAM button
 *   scrammed (manual or auto) → BRIGHT RED FLASHING indicator (always visible) */
.scram-wrap { position: relative; height: 56px; }
.scram-cover, .scram-btn {
  position: absolute; inset: 0; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  font-weight: 800; letter-spacing: .1em; cursor: pointer; user-select: none; text-align: center;
}
/* guard cover nearly invisible at rest: dark bg, dim green border, dark green text
   (no siren). It only becomes vivid red once the scram has fired. */
.scram-cover {
  background: #10151a; border: 1px solid #2e5a3f; color: #3f7a55; box-shadow: none;
}
/* dull red exposed button when the cover is lifted (armed, not yet fired) */
.scram-btn { background: #7f2a2a; border: 2px solid #9e3b3b; color: #f1d6d6; display: none; }
.scram-wrap.open .scram-cover { display: none; }
.scram-wrap.open .scram-btn { display: flex; }
/* SCRAMMED: force the bright-red flashing indicator regardless of cover state */
.scram-wrap.scrammed .scram-cover { display: none; }
.scram-wrap.scrammed .scram-btn { display: flex; }
/* A4 — fired state: one red palette, 0.5s step-end opacity flash (no color cycling) */
.scram-btn.fired { cursor: default; background: #1a0600; border: 2px solid #b03020; color: #e04020;
  font-weight: 700; letter-spacing: .1em; animation: scram-flash .5s step-end infinite; }
@keyframes scram-flash { 0%, 49% { opacity: 1; } 50%, 100% { opacity: .3; } }
.scram-arc { position: absolute; inset: -2px; border-radius: 8px; border: 2px solid transparent;
  border-top-color: var(--critical); animation: scram-countdown 3s linear forwards; pointer-events: none; }
@keyframes scram-countdown { from { transform: rotate(0deg); opacity: 1; } to { transform: rotate(360deg); opacity: .2; } }

/* ============================================================ synoptic area */
/* Diagram block is FIXED height; the chart/alarm strip below takes the slack. */
.synoptic {
  flex: 0 0 340px;
  background: var(--bg-strip);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
  display: flex; flex-direction: column;
  position: relative;
}
.synoptic-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.synoptic-head .seg { font-size: 10px; }
.placeholder-note { font-size: 10px; color: var(--muted); }
/* rod-bank mini-indicator — sits under the Reactor/Core numeric column */
.rod-mini { margin-top: 9px; padding-top: 9px; border-top: 1px dotted #23272d; display: flex; flex-direction: column; gap: 9px; }
.rm-grp { display: flex; flex-direction: column; gap: 4px; }
.rm-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: 12px; }
.rm-head .nk { color: var(--text-2); }
.rm-head .rm-val { font-weight: 600; }
.rod-mini .rodbar { height: 9px; }
.numeric-grid {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; overflow: auto; min-height: 0;
}
.num-col h4 { margin: 0 0 6px; font-size: 12px; letter-spacing: .05em; color: var(--normal); text-transform: uppercase; }
.num-line { display: flex; justify-content: space-between; gap: 8px; font-size: 13px; padding: 3px 0; border-bottom: 1px dotted #23272d; }
.num-line .nk { color: var(--text-2); }
.num-line .nv { font-weight: 600; color: var(--clr-status-normal); }
/* Quiet board: status words are dim at normal; color is spent only on deviation. */
.num-line .nv.q-normal  { color: var(--clr-status-normal); }
.num-line .nv.q-caution { color: var(--caution); }
.num-line .nv.q-alarm   { color: var(--critical); }
.ff-badge { position: absolute; right: 10px; bottom: 8px; font-size: 11px; color: var(--caution);
  background: rgba(245,158,11,.12); border: 1px solid rgba(245,158,11,.4); border-radius: 4px; padding: 1px 6px; }

/* ====================================================== bottom: chart+alarm */
/* the diagram (main-area) now stretches; the chart/alarm strip is a fixed band */
.bottom-row { flex: 0 0 196px; display: flex; gap: var(--gap); min-height: 150px; }
.strip-chart {
  flex: 1 1 auto; background: var(--bg-strip); border: 1px solid var(--border); border-radius: var(--radius);
  display: flex; flex-direction: column; padding: 6px 8px;
}
.chart-legend { min-height: 14px; font-size: 10px; color: var(--muted); letter-spacing: .02em; }
.chart-legend .chart-meta.muted { font-style: italic; }
/* plot wrapper holds the stretched SVG + the floating value-label overlay */
.chart-plot { position: relative; flex: 1 1 auto; min-height: 0; overflow: visible; }
.chart-canvas { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.chart-floats { position: absolute; inset: 0; pointer-events: none; overflow: visible; }
.chart-trace { transition: opacity .14s ease; }
.chart-trace .chart-line, .chart-trace .chart-dot { transition: opacity .14s ease, stroke-width .14s ease; }
.chart-plot.chart-focus .chart-trace { opacity: .32; }
.chart-plot.chart-focus .chart-trace.hl { opacity: 1; }
.chart-plot.chart-focus .chart-trace.hl .chart-line { stroke-width: 2.2px !important; }
.chart-plot.chart-focus .chart-trace.hl .chart-dot { filter: drop-shadow(0 0 2px rgba(255, 255, 255, .35)); }
.cfloat {
  /* value indication sits in the right gutter, to the RIGHT of the trace ends */
  position: absolute; right: 3px; left: auto; transform: translate(0, -50%);
  display: flex; align-items: center; gap: 3px;
  padding: 1px 5px 1px 3px; border-radius: 2px;
  background: rgba(8, 11, 14, .84);
  border-left: 2px solid var(--cf, var(--text-2));
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .35);
  white-space: nowrap; overflow: hidden;
  pointer-events: auto; cursor: default;
  transition: opacity .14s ease, box-shadow .14s ease, background .14s ease;
  max-width: 42%;
}
.chart-plot.chart-focus .cfloat { opacity: .38; }
.chart-plot.chart-focus .cfloat.hl {
  opacity: 1; z-index: 2;
  background: rgba(10, 14, 18, .94);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .08), 0 0 10px color-mix(in srgb, var(--cf) 28%, transparent);
}
.cfloat.hot { background: rgba(12, 10, 8, .9); }
.chart-plot.chart-focus .cfloat.hl.hot { box-shadow: 0 0 0 1px rgba(255, 200, 120, .15), 0 0 10px rgba(255, 180, 80, .18); }
.cfloat-swatch {
  flex: 0 0 auto; width: 8px; height: 2px; border-radius: 1px;
  background: var(--cf, var(--text-2));
}
.cfloat-name {
  flex: 1 1 auto; min-width: 0;
  font: 500 9px/1.1 var(--font, system-ui, sans-serif);
  color: var(--cf, var(--text-2)); opacity: .92;
  overflow: hidden; text-overflow: ellipsis;
}
.cfloat-val {
  flex: 0 0 auto;
  font: 600 9px/1.1 ui-monospace, "Cascadia Mono", Consolas, monospace;
  color: var(--text-1); opacity: .95;
}
.scrubber { height: 14px; display: flex; align-items: center; gap: 6px; margin-top: 2px; }
.scrubber .track { flex: 1 1 auto; height: 4px; background: #23272d; border-radius: 2px; position: relative; cursor: pointer; }
.scrubber .track:hover { background: #2b3138; }
/* The head marks the present: the chart always ends at LIVE (right edge). */
.scrubber .head { position: absolute; right: 0; top: -3px; width: 3px; height: 10px; background: var(--normal); border-radius: 2px; pointer-events: none; }
.scrubber .lbl { font-size: 10px; color: var(--muted); }

/* App-level feedback toast (save / load / file errors) */
.app-toast {
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%) translateY(-6px);
  background: var(--bg-elevated); border: 1px solid var(--normal); border-radius: 6px;
  color: var(--text); font-size: 12px; padding: 7px 14px; z-index: 120;
  opacity: 0; pointer-events: none; transition: opacity .18s ease, transform .18s ease;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .5);
}
.app-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.app-toast.error { border-color: var(--alarm, #e5484d); color: var(--alarm, #e5484d); }

/* Two-press armed confirm (the SCRAM idiom, for destructive plant actions) */
button.armed { background: #3a1618 !important; color: #ff9d9d !important; border-color: #a13a3a !important; animation: pulse 1s ease-in-out infinite; }

.alarm-panel {
  flex: 0 0 33%; background: var(--bg-strip); border: 1px solid var(--border); border-radius: var(--radius);
  display: flex; flex-direction: column; min-width: 220px;
}
.alarm-head { display: flex; align-items: center; justify-content: space-between; padding: 6px 8px; border-bottom: 1px solid var(--border); }
.alarm-head .t { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--text-2); font-weight: 700; }
.alarm-stack { flex: 1 1 auto; overflow: auto; padding: 6px; display: flex; flex-direction: column; gap: 5px; }
/* Under the diagram the alarm panel is wide and short, so a single column wastes the width
   and buries anything past the first two or three. Two columns, filled top-to-bottom in
   priority order (app.js sorts the stack), so the worst alarm is still the first thing read. */
.app.pwr-synoptic .plant-area > .bottom-row > .alarm-panel > .alarm-stack {
  display: grid; grid-template-columns: 1fr 1fr; gap: 5px; align-content: start;
}
.app.pwr-synoptic .plant-area > .bottom-row > .alarm-panel > .alarm-stack > .alarm-empty {
  grid-column: 1 / -1;
}
.alarm-empty { color: var(--muted); font-size: 11px; padding: 10px; text-align: center; font-style: italic; }
.alarm-tile {
  display: flex; gap: 7px; align-items: flex-start; padding: 6px 8px; border-radius: 5px;
  background: var(--bg-elevated); border: 1px solid var(--border); position: relative;
}
.alarm-tile .bar { width: 4px; align-self: stretch; border-radius: 2px; background: var(--muted); flex: 0 0 auto; }
.alarm-tile { cursor: pointer; }
.alarm-tile .ack-chip {
  flex: 0 0 auto; align-self: center; font-size: 9px; font-weight: 700; letter-spacing: .06em;
  color: var(--text-2); border: 1px solid var(--border); border-radius: 4px; padding: 2px 5px;
}
.alarm-tile:hover .ack-chip { color: var(--text); border-color: var(--normal); }
.alarm-tile .body { flex: 1 1 auto; }
.alarm-tile .label { font-size: 12px; font-weight: 600; line-height: 1.2; }
.alarm-tile .meta { font-size: 10px; color: var(--text-2); margin-top: 2px; }
.alarm-tile .glyph { font-size: 13px; }
.alarm-tile.crit { border-color: rgba(229, 72, 77, 0.55); }
.alarm-tile.crit .glyph { color: var(--critical); }
.alarm-tile.crit .bar { background: var(--critical); }
.alarm-tile.warn .glyph { color: var(--caution); }
.alarm-tile.warn .bar { background: var(--caution); }
/* Only unacked critical tiles flash — warnings stay solid amber so a flood
   does not strobe the whole panel. */
.alarm-tile.unack.crit {
  animation: alarmCritFlash 0.9s steps(1, end) infinite;
}
@keyframes alarmCritFlash {
  0%, 100% { background: transparent; }
  50% { background: rgba(229, 72, 77, 0.18); }
}
@media (prefers-reduced-motion: reduce) {
  .alarm-tile.unack.crit { animation: none; box-shadow: inset 0 0 0 1px var(--critical); }
}

/* ===================================================== right col: sim ctrls */
.sim-controls {
  flex: 0 0 auto; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 8px 10px; display: flex; flex-direction: column; gap: 8px;
}
.sim-top { display: flex; align-items: center; justify-content: space-between; }
.logo { font-weight: 800; letter-spacing: .01em; font-size: 15px; white-space: nowrap;
  color: var(--text); text-decoration: none; cursor: pointer; }
.logo:hover { color: var(--text); opacity: 0.82; text-decoration: none; }
.logo .a { color: var(--normal); }
.brand { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.logo-ver { font-size: 10px; font-weight: 600; color: var(--muted); white-space: nowrap; }
/* TEST-BUILD marker — shown only off the released channel, keyed off the
   html[data-channel] attribute shell.html sets from window.RD_CHANNEL. Hidden by
   DEFAULT and opted into per channel, so a missing or misspelled attribute leaves
   the released simulator unmarked rather than falsely branded. Sits in the header
   beside the version, which is the one piece of chrome always on screen. */
.logo-test { display: none; }
html[data-channel="preview"] .logo-test,
html[data-channel="dev"] .logo-test {
  display: inline-block;
  background: var(--caution); color: #17120A;
  border-radius: 999px; padding: 1px 7px;
  font-size: 9px; font-weight: 700; letter-spacing: 1.2px; white-space: nowrap;
}
.clock { font-size: 15px; font-weight: 600; }
.clock.running { animation: pulse 2s ease-in-out infinite; }
.clock.accel { color: var(--caution); }
@keyframes pulse { 50% { opacity: .6; } }
.sim-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.play {
  width: 40px; height: 30px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--bg-right); color: var(--running); font-size: 15px; cursor: pointer; flex: 0 0 auto;
}
.play.paused { color: var(--caution); }
/* First-run cue: pulse the Play button until the sim is started for the first time. */
.play.attention {
  border-color: var(--running); color: var(--running);
  animation: playPulse 1.4s ease-in-out infinite;
}
@keyframes playPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(64, 209, 122, 0.55); }
  50%      { box-shadow: 0 0 0 6px rgba(64, 209, 122, 0); }
}
@media (prefers-reduced-motion: reduce) { .play.attention { animation: none; box-shadow: 0 0 0 2px rgba(64,209,122,0.5); } }
.speed { display: inline-flex; gap: 0; border: 1px solid var(--border); border-radius: 5px; overflow: hidden; flex: 1 1 auto; }
.speed button { flex: 1 1 0; background: var(--bg-right); color: var(--text-2); border: none; border-right: 1px solid var(--border);
  padding: 4px 0; font-size: 11px; cursor: pointer; }
.speed button:last-child { border-right: none; }
/* selected speed: subtle cyan outline (not a saturated fill — the clock turns
   amber to warn that time is accelerated; the selector itself stays quiet). */
.speed button.on { background: transparent; color: var(--text); font-weight: 700; box-shadow: inset 0 0 0 1px var(--normal); }
.text-btn { flex: 0 0 auto; padding: 4px 10px; font-size: 12px; font-weight: 600; }
.demo-btn { flex: 0 0 auto; min-width: 28px; padding: 4px 8px; }

/* What's running now — the always-visible mission entry point (click → Plant & Mission) */
.sim-status {
  display: flex; align-items: center; gap: 6px; width: 100%; margin-top: 8px;
  padding: 5px 8px; background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: 6px; color: var(--text-2); font-size: 11px; cursor: pointer; text-align: left;
}
.sim-status:hover { color: var(--text); border-color: var(--normal); }
.sim-status .ss-txt { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sim-status .ss-chev { flex: 0 0 auto; color: var(--muted); font-size: 13px; }

/* Help / tour — reuses the mission-modal chrome, narrower and content-sized */
.help-modal { width: min(560px, 96vw); height: auto; max-height: min(84vh, 760px); }
.help-body { padding: 14px 18px; overflow: auto; }

/* About docs (#259) — Disclaimer / License / Changelog. Wider and scrollable so
   the full changelog fits; content is packed HTML from the site pages. */
.mission-modal.doc-modal {
  width: min(720px, 96vw); height: min(84vh, 800px);
}
.doc-body {
  flex: 1; min-height: 0; overflow: auto;
  padding: 14px 18px 22px;
  font-size: 13px; line-height: 1.55; color: var(--text);
}
.doc-body h2 {
  margin: 1.1em 0 0.4em; font-size: 13px; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-2); border: none; padding: 0;
}
.doc-body h2:first-child { margin-top: 0; }
.doc-body p { margin: 0 0 0.75em; }
.doc-body ul { margin: 0 0 0.9em; padding-left: 1.25em; }
.doc-body li { margin-bottom: 0.4em; }
.doc-body a { color: var(--normal); }
.doc-body code {
  font-family: var(--mono, ui-monospace, monospace); font-size: 12px;
  background: var(--bg-elevated); padding: 1px 4px; border-radius: 3px;
}
.doc-body .notice, .doc-body .doc-alpha {
  background: rgba(217, 164, 65, 0.10); border: 1px solid var(--caution);
  border-radius: 6px; padding: 10px 12px; margin: 0 0 14px;
  color: var(--text-2); font-size: 13px;
}
.doc-body .notice strong, .doc-body .doc-alpha { color: var(--caution); font-weight: 600; }
.doc-body .lede { color: var(--text-2); margin-bottom: 1em; }
.doc-body .log-entry {
  border-top: 1px solid var(--border); padding-top: 16px; margin-top: 18px;
}
.doc-body .log-entry:first-of-type { border-top: none; padding-top: 0; margin-top: 0; }
.doc-body .log-head {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.doc-body .log-head h2 {
  margin: 0; font-size: 14px; letter-spacing: 0; text-transform: none; color: var(--text);
}
/* The packed changelog is changelog.html verbatim (tools/pack_site_docs.js), so it
   arrives as <details class="log-entry"><summary class="log-head"> — collapsible in
   the About → Changelog modal exactly as on the site. `display:flex` above kills the
   default disclosure triangle in every engine, so draw one. */
.doc-body summary.log-head { cursor: pointer; list-style: none; flex-wrap: nowrap; }
.doc-body summary.log-head h2 { flex: 1 1 auto; min-width: 0; }
.doc-body summary.log-head .log-ver,
.doc-body summary.log-head .log-date { flex: 0 0 auto; }
.doc-body summary.log-head::-webkit-details-marker { display: none; }
.doc-body summary.log-head::before {
  content: '▸'; flex: 0 0 auto; color: var(--muted); font-size: 13px; line-height: 1;
  transition: transform 0.12s; transform-origin: 50% 45%;
}
.doc-body details[open] > summary.log-head::before { transform: rotate(90deg); }
.doc-body summary.log-head:hover h2 { color: var(--normal); }
.doc-body .log-note { color: var(--muted); font-size: 12px; margin: 0 0 12px; }
.doc-body .log-ver {
  font-size: 11px; font-weight: 700; letter-spacing: 0.4px; color: var(--normal);
  border: 1px solid var(--border); border-radius: 999px; padding: 1px 8px;
}
.doc-body .log-date { color: var(--muted); font-size: 12px; margin-left: auto; }
.doc-body .log-entry ul { margin: 10px 0 0; padding-left: 0; list-style: none; }
.doc-body .log-entry li { margin-bottom: 8px; font-size: 13px; line-height: 1.5; }
.doc-body .log-tag {
  display: inline-block; min-width: 56px; margin-right: 6px;
  font-size: 10px; letter-spacing: 0.5px; text-transform: uppercase;
  text-align: center; padding: 1px 5px; border-radius: 3px;
  border: 1px solid currentColor; vertical-align: 1px;
}
.doc-body .log-tag.added { color: var(--running, #79d297); }
.doc-body .log-tag.changed { color: var(--normal); }
.doc-body .log-tag.fixed { color: var(--caution); }
.set-about-btns { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.help-sec { margin-bottom: 14px; }
.help-sec h4 { margin: 0 0 4px; font-size: 12px; letter-spacing: .05em; text-transform: uppercase; color: var(--text-2); }
/* ---- Coach-mark tour (spotlight + tip beside the target) ---- */
.tour-root {
  position: fixed; inset: 0; z-index: 9500; pointer-events: none;
}
.tour-root:not([hidden]) { display: block; }
.tour-scrim {
  position: fixed; inset: 0; pointer-events: auto;
  /* Dim is carried by the spot's box-shadow so the target stays clear */
  background: transparent;
}
.tour-spot {
  position: fixed; pointer-events: none;
  border: 2px solid var(--normal);
  border-radius: 8px;
  box-shadow:
    0 0 0 2px rgba(91, 179, 196, 0.35),
    0 0 0 9999px rgba(0, 0, 0, 0.58);
  transition: top 0.15s ease, left 0.15s ease, width 0.15s ease, height 0.15s ease;
}
.tour-tip {
  position: fixed; pointer-events: auto;
  width: min(320px, calc(100vw - 24px));
  background: var(--bg-elevated);
  border: 1px solid var(--normal);
  border-radius: var(--radius);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
  padding: 12px 14px 12px;
  color: var(--text-2);
  font-size: 13px; line-height: 1.5;
  z-index: 9501;
}
.tour-tip-title {
  margin: 0 0 6px; font-size: 13px; font-weight: 700;
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--text);
}
.tour-tip-body p { margin: 0 0 0.5em; }
.tour-tip-body p:last-child { margin-bottom: 0; }
.tour-tip-nav {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border);
}
.tour-tip-nav .btn { font-size: 12px; padding: 4px 10px; }
.tour-prog { color: var(--muted); font-size: 11px; margin-right: auto; }
/* Raised above the dim while a tour step points at it */
.tour-target-live {
  position: relative;
  z-index: 9502 !important;
}
.instr-idle { font-size: 12px; line-height: 1.45; color: var(--text-2); }
.instr-idle-lead { margin: 0 0 8px; color: var(--text); }
.instr-idle-list { margin: 0 0 10px; padding-left: 1.2em; }
.instr-idle-list li { margin-bottom: 4px; }
.instr-idle-more { margin: 0; font-size: 11px; color: var(--muted); }
.btn.linkish {
  display: inline; padding: 0; border: none; background: none;
  color: var(--normal); font-size: inherit; font-weight: 600; cursor: pointer;
  text-decoration: underline;
}
.btn.linkish:hover { color: var(--text); }
.persona .icon:empty { display: none; }
.persona .icon:not(:empty) {
  width: 22px; height: 22px; border-radius: 4px; background: var(--bg-elevated);
  border: 1px solid var(--border); font-size: 11px; display: flex;
  align-items: center; justify-content: center; color: var(--text-2);
}
.help-sec p { margin: 0; font-size: 13px; line-height: 1.5; color: var(--text); }

/* Feedback overlay (reuses the help modal chrome). No longer a form — it carries
   the address to write to plus the optional diagnostics download. */
.fb-field { margin-bottom: 12px; }
.fb-field label { display: block; font-size: 12px; letter-spacing: .05em; text-transform: uppercase; color: var(--text-2); margin-bottom: 4px; }
.fb-hint { font-size: 12px; color: var(--muted); margin-top: 3px; line-height: 1.4; }
.fb-msg { font-size: 12px; color: var(--running); }
.fb-msg.err { color: var(--caution); }
.fb-lead { margin: 0 0 10px; font-size: 13px; line-height: 1.5; color: var(--text); }
/* The address is the point of this panel, so it gets the size — and it wraps
   rather than overflowing on a narrow window. */
.fb-addr { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.fb-mail { font-size: 17px; color: var(--running); text-decoration: none; border-bottom: 1px dotted var(--running); word-break: break-all; }
.fb-mail:hover { color: var(--text); border-bottom-color: var(--text); }
.fb-diag { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.fb-ver { margin-top: 14px; }
.help-keys { font-size: 11px; color: var(--text-2); }

/* ===================================================== right col: instructor */
/* Cards focus model (§ quiet-board "management by exception"): exactly one of
   {instructor, tools} is EXPANDED (fills the column), the other COLLAPSED to a
   minimal header. Collapsed instructor shows only its latest message; collapsed
   tools shows only its tab strip. Clicking a collapsed card's header — or any
   tool tab — brings it into focus (and collapses the other). */
.instructor, .tools {
  min-height: 0; display: flex; flex-direction: column;
  transition: flex-grow .15s ease;
}
.instructor.expanded, .tools.expanded { flex: 1 1 0; }
.instructor.collapsed, .tools.collapsed { flex: 0 0 auto; }
/* the whole collapsed instructor is a click target to maximize (persona is hidden in chat-mode) */
.instructor.collapsed { cursor: pointer; }
.instructor .persona { cursor: pointer; }
/* #237 attention cue: unseen-content badge + a brief pulse while collapsed —
   the instructor cues instead of stealing the column. Role takes margin-right:auto
   so badge + minimize sit at the right edge of the header. */
.persona .instr-badge {
  background: var(--caution, #d9a441); color: #14181c;
  font-size: 10px; font-weight: 700; border-radius: 8px; padding: 1px 6px; line-height: 1.4;
}
.persona .instr-badge[hidden] { display: none; }
.persona .role { margin-right: auto; }   /* pushes badge + minimize to the right edge */
/* Explicit minimize — the old CSS ▸ chevron was easy to miss; this is a real button
   at the top-right of the instructor header. Hidden while collapsed (the whole card
   is already the expand target then). */
.instr-min {
  flex: 0 0 auto; width: 26px; height: 22px; padding: 0; margin: 0;
  border: 1px solid var(--border); border-radius: 5px;
  background: var(--bg-elevated); color: var(--text-2);
  font-size: 16px; font-weight: 700; line-height: 1; cursor: pointer;
}
.instr-min:hover { color: var(--text); border-color: var(--text-2); background: color-mix(in srgb, var(--bg-elevated) 70%, var(--text-2)); }
/* FULLY MINIMIZED *(OWNER DIRECTIVE, 2026-08-04: "Need button to be able to fully minimize
   instructor block.")*, #350 item 19. `collapsed` still spends a header plus a one-line
   message preview on the column; `mini` spends the header alone, which is the least that can
   still carry the unseen-content badge — and that badge is the whole reason not to remove the
   card outright, since it is the only cue that the instructor has said something.
   The minimize button therefore steps expanded -> collapsed -> mini and stays reachable in
   all three, rather than hiding itself the moment the card collapses. */
.instructor.mini .instr-body,
.instructor.mini .instr-nav,
.instructor.mini .instr-ack { display: none; }
.instructor.mini .persona { padding-top: 2px; padding-bottom: 2px; }
@keyframes instrAttnPulse {
  0%, 100% { box-shadow: none; }
  45% { box-shadow: inset 0 0 0 2px var(--caution, #d9a441); }
}
.instructor.instr-attn { animation: instrAttnPulse 1.1s ease 2; }
.instructor.collapsed .instr-prev,
.instructor.collapsed .instr-nav,
.instructor.collapsed .instr-ack { display: none; }
.instructor.collapsed .instr-current {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tools.collapsed .tab-body { display: none; }
/* #237: a scenario that declares ui_policy.failures:'locked' owns the Failures
   tab — visible but inert, with the note explaining why. */
.tabpane.fail-locked #failList, .tabpane.fail-locked .advanced-exp,
.tabpane.fail-locked #advFailPanel { pointer-events: none; opacity: 0.45; }
.fail-locked-note {
  font-size: 12px; color: var(--caution, #d9a441); padding: 6px 8px; margin-bottom: 6px;
  border: 1px solid var(--border); border-radius: 6px; background: var(--bg-elevated);
}
.instructor .persona { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); }
.persona .icon { width: 26px; height: 26px; border-radius: 50%; background: var(--bg-elevated); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center; font-size: 14px; }
.persona .role { font-size: 11px; letter-spacing: .06em; color: var(--text-2); font-weight: 700; }
.instr-body { flex: 1 1 auto; padding: 10px; overflow: auto; }
.instr-prev { color: var(--muted); font-size: 12px; margin-bottom: 8px; }
.instr-current { color: var(--text); font-size: 13px; }
.instr-standby { color: var(--muted); font-style: italic; }
.instr-nav { display: flex; gap: 6px; padding: 0 10px 8px; }
.instr-nav[hidden] { display: none; }
.instr-nav .btn { padding: 4px 8px; }
.instr-ack { margin: 0 10px 10px; display: flex; gap: 6px; align-items: stretch; }
.instr-ack[hidden] { display: none; }
.instr-ack .btn { flex: 0 0 auto; }
/* The primary "I've read this, continue" action (M8 §9) — a real, live control. */
.ack-btn { flex: 1 1 auto; padding: 8px; background: var(--bg-elevated); border: 1px solid var(--normal);
  border-radius: 6px; color: var(--normal); font-weight: 700; cursor: pointer; }
.ack-btn:hover { background: color-mix(in srgb, var(--normal) 12%, var(--bg-elevated)); }

/* ===================================================== right col: tools block */
.tabbar { display: flex; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.tabbar button { flex: 1 1 0; background: transparent; border: none; color: var(--text-2);
  padding: 8px 4px; font-size: 11px; cursor: pointer; border-bottom: 2px solid transparent; }
.tabbar button:hover { color: var(--text); }
.tabbar button.on { color: var(--text); border-bottom-color: var(--normal); }
/* fixed height (fills the tools box); overflowing tab content scrolls here */
.tab-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 10px; }
.tabpane { display: none; }
.tabpane.on { display: block; }

/* failures tab rows */
/* Inject Failure group heading *(OWNER DIRECTIVE, 2026-08-04: "organize the list of
   failures into logical groupings.")*. Same type treatment as the Physics tab's
   .phys-grp h4, because both lists are ordered on the same energy-path spine and
   should read as the same idea. No border: the .fail-row rules below already rule
   off every row, and a second line under the heading reads as an empty row. */
.fail-grp { font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
            color: var(--normal); margin: 12px 0 2px; }
.fail-grp:first-child { margin-top: 2px; }
.fail-row { padding: 7px 0; border-bottom: 1px solid #23272d; }
.fail-head { display: flex; align-items: center; gap: 8px; }
.fail-name { flex: 1 1 auto; font-size: 12px; }
/* category LABELS — low-saturation tinted background + brighter hue text (they
   classify a row; they are not warnings, so they don't get a saturated fill). */
.fail-cat { font-size: 9px; text-transform: uppercase; letter-spacing: .04em; padding: 1px 5px; border-radius: 3px; }
/* E4 — desaturated category pills (they classify a row; they are not status). */
.fail-cat.reactivity    { background: #180a18; color: #9050a0; }
.fail-cat.coolant       { background: #0a1820; color: #4a90c0; }
.fail-cat.power         { background: #180d00; color: #b07828; }
.fail-cat.instrument    { background: #141020; color: #6858a0; }
.fail-cat.safety_system { background: #0a1608; color: #508040; }
.fail-slider { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
.fail-slider input[type=range] { flex: 1 1 auto; accent-color: var(--normal); }
.fail-slider .sv { font-size: 11px; color: var(--text-2); min-width: 96px; text-align: right; }
.fail-row.active { background: rgba(34,211,238,.05); }
.fail-row.active .fail-name { color: var(--normal); }
.m-filter { display: block; width: 240px; margin: 6px 0 10px; }
.advanced-exp { margin-top: 10px; font-size: 11px; color: var(--text-2); cursor: pointer; user-select: none; }
.advanced-exp:hover { color: var(--text); }
.advanced-exp.open { color: var(--text); }
/* Advanced instrument failure panel (Failures tab) */
.adv-fail { margin-top: 6px; padding: 8px; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 6px; display: flex; flex-direction: column; gap: 6px; }
.adv-fail[hidden] { display: none; }
.adv-fail .row { display: flex; align-items: center; gap: 6px; }
.adv-fail .row .k { flex: 0 0 76px; font-size: 11px; color: var(--text-2); }
.adv-fail select { flex: 1 1 auto; min-width: 0; background: var(--bg-strip); color: var(--text); border: 1px solid var(--border); border-radius: 5px; padding: 4px 6px; font-size: 12px; }
.adv-fail .num-input { width: 90px; }
.adv-fail .note { font-size: 10px; color: var(--muted); }
.adv-fail .actions { display: flex; gap: 6px; justify-content: flex-end; }
.adv-fail .active-list { font-size: 11px; color: var(--caution); }

/* physics tab — the true-state diagnostic overlay. One column, grouped along the
   energy path; reuses the numeric grid's row styling (.num-line/.nk/.nv). */
.phys-note { font-size: 10px; color: var(--muted); line-height: 1.5; margin: 0 0 10px; }
.phys-note b { color: var(--text-2); font-weight: 600; }
.phys-none { font-size: 11px; color: var(--muted); }
.phys-grp + .phys-grp { margin-top: 12px; }
.phys-grp h4 { margin: 0 0 4px; font-size: 10px; letter-spacing: .06em; color: var(--normal); text-transform: uppercase; }
.phys-grp .num-line { font-size: 12px; }
/* tabular figures: these numbers change every frame, and proportional digits make
   the whole column jitter as they do */
.phys-grp .nv { font-variant-numeric: tabular-nums; white-space: nowrap; }
.phys-grp .nk { padding-right: 8px; }

/* Physics values are BRIGHTER than the quiet-board default and carry the board's
   INDICATION scheme *(OWNER DIRECTIVE, 2026-08-04: "make the physics numbers brighter
   under the physics tab. The contrast is currently too low. Also make these physics
   numbers follow the indication color scheme (grey, green, yellow, red, etc.)")*.
   The generic `.num-line .nv` above paints every numeric grid in
   --clr-status-normal (#4a6070), which is ~2.5:1 on --bg-elevated — deliberate for
   the quiet board, and unreadable for a panel you are reading numbers off. These
   rules are SCOPED to .phys-grp so the quiet default survives everywhere else; the
   All view and the RBMK/BWR numeric grids are untouched.
     grey   #98A3AF  a quantity with no health criterion — most of the panel
     green  --running   a criterion that EXISTS and is currently satisfied
     amber  --caution   caution band
     red    --critical  alarm band
   Grey vs green is the distinction that carries the teaching: green is not
   decoration, it means "something is being checked here and it is fine", so a row
   that is merely informational must stay grey or green stops meaning anything. */
.phys-grp .nv           { color: var(--text-2); }
.phys-grp .nv.q-ok      { color: var(--running); }
.phys-grp .nv.q-caution { color: var(--caution); }
.phys-grp .nv.q-alarm   { color: var(--critical); }

/* settings tab rows */
.set-row { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #23272d; }
/* display:flex above beats the `hidden` ATTRIBUTE, so a row hidden from script
   (the #241 Features row) stays on screen unless this says otherwise. */
.set-row[hidden] { display: none; }
.set-row .k { font-size: 12px; color: var(--text-2); }

/* ============================================ right col: scanner / inspection
   Two tiers on one surface (#96): collapsed is the one-line summary, expanded
   adds the full description, the card an item belongs to, and a link into the
   manual section that documents it. The whole panel is the click target — the
   ⤢ button only makes that affordance visible. */
/* FIXED height, both states (owner, 2026-07-28: "the jumping up and down when
   moving the mouse over things is annoying"). The block used to size to its
   text, so every hover across the board re-laid-out the whole right column and
   the Instructor panel above it jumped. The body is a constant box that scrolls
   its own overflow instead — collapsed fits the longest summary (~4 lines),
   expanded is a stable reading pane. */
.scanner { flex: 0 0 auto; cursor: pointer; }
.scanner .panel-title { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.scanner .body {
  padding: 8px 10px; font-size: 12px; color: var(--text-2); line-height: 1.45;
  height: 74px; overflow-y: auto; overscroll-behavior: contain;
}
.scanner .body strong { color: var(--text); }
.scanner .idle { color: var(--muted); font-style: italic; }
.scan-exp {
  background: transparent; border: 1px solid var(--border); border-radius: 4px;
  color: var(--text-2); font: inherit; font-size: 10px; letter-spacing: .06em;
  padding: 1px 6px; cursor: pointer; text-transform: uppercase;
}
.scan-exp:hover { color: var(--text); border-color: var(--text-2); }
/* Expanded: a taller pane of the SAME fixed size for every entry — a long
   description scrolls inside it rather than growing the panel. Viewport-relative
   so it stays usable on a laptop, clamped so it cannot eat the column. */
.scanner.expanded { cursor: default; }
.scanner.expanded .body { height: 28vh; min-height: 200px; max-height: 260px; }
.scan-detail { margin-top: 6px; color: var(--text-2); }
.scan-meta {
  margin-top: 6px; font-size: 11px; color: var(--muted);
  display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center;
}
.scan-manual {
  background: transparent; border: none; padding: 0; cursor: pointer;
  color: var(--running); font: inherit; font-size: 11px;
}
.scan-manual:hover { text-decoration: underline; }
.scan-hint { font-style: italic; }
/* Live automation-channel status (#214) — what the control the pointer is over is
   ACTUALLY doing, as against the authored copy around it. Its own block so the two
   never read as one sentence: everything else in the scanner is fixed prose, this
   line changes under you. Monospace and dimmed in MANUAL, lit in AUTO, matching how
   the board itself distinguishes the two. */
.scan-live {
  display: block; margin-top: 5px; font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 11px; letter-spacing: .02em; color: var(--muted);
}
.scan-live.on { color: var(--running); }
/* NO hover ring on the inspected object (owner, 2026-07-28) — the first cut drew
   one and it reads as noise, flickering across every control the pointer passes.
   The glows that remain (.instr-glow, .ckl-glow) point at something the player did
   NOT choose, which is the case that needs a marker. */

/* ===================================================== additions (wired UI) */
.num-input {
  background: var(--bg-plant); color: var(--text); border: 1px solid var(--border);
  border-radius: 4px; padding: 3px 6px; font-size: 12px; width: 64px;
}
select.num-input { width: auto; }

/* strip-chart low-profile x-axis (time ticks). The right 14% is a gutter for the
   live value chips (traces stop at CHART_PLOT_FRAC), so reserve it here too — the
   "0" (now) tick then lines up with each trace's end. */
.chart-xaxis { display: flex; justify-content: space-between; font-size: 9px; color: var(--muted);
  padding: 1px 14% 0 6px; line-height: 1.1; height: 12px; box-sizing: border-box; }

/* Automate tab (operator automation toggles) */
.auto-master { display: flex; align-items: center; justify-content: space-between; padding: 2px 0 8px; border-bottom: 1px solid #23272d; }
.auto-master .k { font-size: 12px; color: var(--text-2); }
.auto-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid #23272d; }
.auto-tog { flex: 0 0 auto; width: 46px; padding: 4px 0; font-size: 10px; font-weight: 700; letter-spacing: .05em;
  border: 1px solid #3a4048; border-radius: 5px; background: transparent; color: var(--muted); cursor: pointer; }
.auto-tog.on { color: var(--running); border-color: var(--running-muted); background: rgba(70,163,94,.10); }
.auto-main { flex: 1 1 auto; min-width: 0; }
.auto-name { font-size: 12px; color: var(--text-2); }
.auto-row.on .auto-name { color: var(--text); }
.auto-read { font-size: 10px; color: var(--muted); margin-top: 1px; }
.auto-row.on .auto-read { color: var(--running); }
.auto-spbox { flex: 0 0 auto; display: flex; align-items: center; gap: 4px; }
.auto-splbl { font-size: 9px; color: var(--muted); letter-spacing: .05em; }
.auto-sp { width: 68px; }
.auto-sp:disabled { opacity: .35; }
.auto-spunit { font-size: 10px; color: var(--muted); min-width: 18px; }

/* Graph-tab parameter checklist */
.g-section-title { font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-2); margin: 0 0 6px; }
.param-row { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-2); padding: 4px 0; cursor: pointer; }
/* Grouped plot checklist (2026-08-03). The list went from 16 entries to 48 when the
   physics quantities and the control positions were added, which is past the point a flat
   run of checkboxes is readable. Headers are sticky so the group a row belongs to stays
   named while the list scrolls. */
.param-grp { margin: 0 0 6px; }
.param-grp + .param-grp { border-top: 1px solid var(--border); padding-top: 5px; }
/* TWO COLUMNS WHEN THERE IS ROOM *(OWNER DIRECTIVE, 2026-08-04: "add a second column to
   the graph menu when space allows.")*, #350 item 23. The list is 51 entries on the PWR,
   so on a dragged-wide simulator column it was one long ribbon down a mostly empty panel.
   `auto-fill` + a minmax track is the "when space allows" part with no breakpoint to guess
   and no JS: the panel is operator-resizable between 360 px and 900 px (pwr_board.js
   SIMCOL_*), so any fixed media query would be wrong at some width the operator can choose.
   GRID, NOT CSS `columns`, and the reason is the sticky headers: `position: sticky` does
   not work inside a multicol container, and a group split down a column break would leave
   half its rows under someone else's heading. Each group is one grid item, so it stays
   whole and its header still sticks. */
#graphParams {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  column-gap: 14px; align-items: start;
}
/* In a grid the first item of the SECOND column is not a first-child, so the sibling rule
   above would leave it with a top border and the one beside it without. Uniform reads as a
   per-group rule instead of a mistake. */
#graphParams > .param-grp { border-top: 1px solid var(--border); padding-top: 5px; }
#graphParams > .param-grp:first-child { border-top: none; padding-top: 0; }
.param-grp-h { position: sticky; top: 0; z-index: 1; background: var(--bg-panel, #12181f);
  font-size: 9px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
  padding: 3px 0 2px; }
.param-row i { width: 12px; height: 3px; border-radius: 2px; display: inline-block; }
.param-row input { accent-color: var(--normal); }

/* numeric placeholder — overlay/true tags + boolean states */
.true-tag { color: var(--caution); font-size: 11px; font-weight: 600; margin-left: 4px; }
.hidden-true { color: var(--disabled); font-style: italic; font-size: 11px; }
/* E2 — near-invisible readout (e.g. SUR at steady power: carries no information) */
.dim-info { color: #2c343d; }
.nv.bool-off { color: var(--text-2); }

/* failures-tab inject toggle */
.fail-toggle { background: var(--bg-elevated); color: var(--text-2); border: 1px solid var(--border);
  border-radius: 4px; padding: 2px 8px; font-size: 10px; cursor: pointer; flex: 0 0 auto; min-width: 48px; }
.fail-toggle:hover { color: var(--text); }
.fail-row.active .fail-toggle { background: var(--critical); color: #fff; border-color: var(--critical); }

/* ============================================================================
 * TABBED CONTROL STRIP — the four control sections are stacked behind a tab bar
 * so only ONE is shown at a time, spread across the FULL width of the plant
 * area in a single low row. This makes the control band much skinnier, freeing
 * vertical room for the synoptic and the chart/alarm row.
 *
 * NOTE: this deliberately departs from M8 §5 ("always visible — not tabs").
 * User-directed design change; logged as a deviation in BUILD_DECISIONS.
 * ========================================================================== */
.control-strip {
  flex: 0 0 auto;
  background: var(--bg-strip);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: flex; flex-direction: row; align-items: stretch;
  overflow: hidden;
}
/* the tabbed area takes the remaining width; SCRAM box is pinned to the right */
.ctl-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.scram-box {
  flex: 0 0 auto; width: 150px;
  border-left: 1px solid var(--border);
  display: flex; align-items: stretch; justify-content: center;
  padding: 8px;
}
.scram-box .scram-wrap { width: 100%; height: auto; min-height: 60px; }
.ctl-tabs { display: flex; border-bottom: 1px solid var(--border); }
.ctl-tabs button {
  background: transparent; border: none; color: var(--text-2);
  padding: 7px 16px; font-size: 12px; letter-spacing: .05em; text-transform: uppercase;
  font-weight: 700; cursor: pointer; border-bottom: 2px solid transparent; white-space: nowrap;
}
.ctl-tabs button:hover { color: var(--text); }
.ctl-tabs button.on { color: var(--text); border-bottom-color: var(--normal); }

.ctl-panes { padding: 9px 10px; }
/* nowrap + a min-height floor → every tab's pane is the SAME height (one centered
   row of control groups), so the strip never resizes when you switch tabs. A pane
   with more groups than fit scrolls horizontally rather than growing taller. */
.ctl-pane { display: none; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
  gap: 8px 18px; align-items: center; min-height: 64px; }
.ctl-pane.on { display: flex; }

/* one control = a label-over-control group; groups flow left-to-right */
.cg { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; flex: 0 0 auto; }
.cg-l { font-size: 11px; color: var(--text-2); letter-spacing: .02em; line-height: 1.1; white-space: nowrap; }
.cg-controls { display: flex; align-items: center; gap: 6px; }
/* slightly larger control affordances in the strip */
.ctl-pane .seg button,
.ctl-pane .btn { font-size: 12px; padding: 5px 10px; }
.ctl-pane .num-input { font-size: 12px; padding: 3px 7px; width: 60px; }
.cg.emergency { border: 1px dashed var(--caution); border-radius: 5px; padding: 4px 8px 6px; }
.cg.emergency .cg-l { color: var(--caution); }

/* ============================================================================
 * QUIET-BOARD palette tokens (the board is now quiet-only — the old/“current”
 * look and its A/B toggle were removed). Color is reserved for deviation: the
 * gauge bars (single dim track + colored fill in-band), status words (dim
 * normal), value text/card tint by state, and the muted trace palette all key
 * off these. The state rules themselves live with their components above.
 * ========================================================================== */
:root {
  --clr-normal-value:    #a8b8c8;
  --clr-dim-label:       #62768a;   /* matches the diagram's component-label grey (.comp-label / .lbl-name) */
  --clr-status-normal:   #4a6070;
  --clr-caution:         #d4a020;
  --clr-alarm:           #e05030;
  --clr-cleared:         #40a060;   /* green — cleared alarms ONLY */
  --bar-track-normal:    #1a3040;
  --bar-warn:            #7a5000;
  --bar-alarm:           #7a2010;
  --gauge-bg-normal:     #0d1017;
  --gauge-bg-warn:       #0e0c00;
  --gauge-bg-alarm:      #0e0600;
  --gauge-border-normal: #1a2030;
  --gauge-border-warn:   #3a2800;
  --gauge-border-alarm:  #5a1800;
  --scram-bg-normal:     #0a1208;
  --scram-border-normal: #253a20;
  --scram-text-normal:   #304828;
}

/* SCRAM guard cover — present but dim when armed (the fired state is the
   existing bright-red scram-flash). */
.scram-cover {
  background: var(--scram-bg-normal);
  border: 1.5px solid var(--scram-border-normal);
  color: var(--scram-text-normal);
  font-weight: 600; letter-spacing: .1em;
}

/* ============================================================================
 * PLANT-DISPLAY layout (swappable variant — Dev tab -> "Plant Display").
 * Status bar + 4-view switcher (Diagram / Primary / Secondary / All) replacing
 * the classic tabbed control strip + synoptic table. Scoped so the classic board
 * is untouched under layout-classic. Hexes per the redesign spec.
 * ========================================================================== */
:root {
  --status-bar-bg: #060910;
  --slot-dot-normal: #1a2a38; --slot-dot-caution: #c09020; --slot-dot-alarm: #e04020; --slot-dot-running: #3a9060;
  --slot-name-normal: #1e2e3e; --slot-name-caution: #a07818; --slot-name-alarm: #c03818; --slot-name-running: #306848;
  --slot-badge-alarm-bg: #1a0600; --slot-badge-alarm-color: #e04020; --slot-badge-alarm-border: #6a1808;
  --slot-badge-warn-bg: #1e1800; --slot-badge-warn-color: #c09020; --slot-badge-warn-border: #4a3800;
  --slot-badge-run-bg: #081a10; --slot-badge-run-color: #3a9060; --slot-badge-run-border: #1a4828;
  --view-btn-color: #2a4050; --view-btn-hover: #4a6878; --view-btn-active-color: #7aabb8; --view-btn-active-line: #3a7080;
  --cross-bg: #060910; --cross-label-color: #1a3040; --cross-name-color: #1e3040; --cross-val-color: #2e4a58;
  --section-head-color: #2a4050; --section-head-border: #0e1520;
}

/* system status bar */
.status-bar { flex: 0 0 auto; height: 22px; display: flex; align-items: center;
  background: var(--status-bar-bg); border: 1px solid var(--border); border-top: none; padding: 0 10px; overflow: hidden; }
.bar-sep { width: 0; align-self: stretch; margin: 4px 8px; border-left: 1px solid #131c28; }
.sys-slot { display: flex; align-items: center; gap: 4px; padding: 0 7px; }
.slot-dot { width: 4px; height: 4px; border-radius: 50%; flex-shrink: 0; background: var(--slot-dot-normal); }
.slot-name { font-size: 8px; text-transform: uppercase; letter-spacing: .05em; white-space: nowrap; color: var(--slot-name-normal); }
.slot-badge { font-size: 7px; font-weight: 600; padding: 1px 4px; border-radius: 2px; letter-spacing: .04em; white-space: nowrap; display: none; }
.sys-slot.state-running .slot-dot { background: var(--slot-dot-running); }
.sys-slot.state-running .slot-name { color: var(--slot-name-running); }
.sys-slot.state-running .slot-badge { display: inline; background: var(--slot-badge-run-bg); color: var(--slot-badge-run-color); border: .5px solid var(--slot-badge-run-border); }
.sys-slot.state-caution .slot-dot { background: var(--slot-dot-caution); }
.sys-slot.state-caution .slot-name { color: var(--slot-name-caution); }
.sys-slot.state-caution .slot-badge { display: inline; background: var(--slot-badge-warn-bg); color: var(--slot-badge-warn-color); border: .5px solid var(--slot-badge-warn-border); }
.sys-slot.state-alarm .slot-dot { background: var(--slot-dot-alarm); }
.sys-slot.state-alarm .slot-name { color: var(--slot-name-alarm); }
.sys-slot.state-alarm .slot-badge { display: inline; background: var(--slot-badge-alarm-bg); color: var(--slot-badge-alarm-color); border: .5px solid var(--slot-badge-alarm-border); }
@keyframes status-flash { 0%, 49% { opacity: 1; } 50%, 100% { opacity: .2; } }
.sys-slot.state-alarm .slot-dot, .sys-slot.state-alarm .slot-badge { animation: status-flash .8s step-end infinite; }
.scram-badge { margin-left: auto; font-size: 8px; font-weight: 700; padding: 2px 7px; border-radius: 2px;
  background: #1a0600; color: #e04020; border: .5px solid #6a1808; letter-spacing: .06em; animation: status-flash .5s step-end infinite; display: none; }
.scram-badge.on { display: inline-block; }

/* main area: vertical view switcher (left) + view stack (view-area + control bar) */
.main-area { flex: 1 1 auto; min-height: 0; display: flex; gap: var(--gap); }
.view-switcher { flex: 0 0 96px; display: flex; flex-direction: column; gap: 4px;
  background: #070a0f; border: 1px solid var(--border); border-radius: var(--radius); padding: 6px; }
.view-btn { font-size: 11px; font-weight: 500; color: var(--view-btn-color); padding: 9px 8px; background: transparent;
  border: none; border-left: 2px solid transparent; border-radius: 4px; cursor: pointer; text-align: left; letter-spacing: .03em; }
.view-btn:hover { color: var(--view-btn-hover); }
.view-btn.active { color: var(--view-btn-active-color); border-left-color: var(--view-btn-active-line); background: #0c1118; }
.view-stack { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: var(--gap); }

/* the view-area STRETCHES to fill; the active view fills it (no scroll for diagrams) */
.view-area { flex: 1 1 auto; min-height: 0; background: var(--bg-strip); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; display: flex; position: relative; }
.pdview { display: none; width: 100%; height: 100%; padding: 8px; }
.pdview.on { display: flex; flex-direction: column; }
/* the single child (diagram or grid) fills the panel */
.pdview > .pd-diagram, .pdview > .pd-sections, .pdview > .pd-all-grid { flex: 1 1 auto; min-height: 0; }
.pdview > .pd-sections, .pdview > .pd-all-grid { overflow: auto; }
.view-placeholder { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; color: var(--muted); }
.view-placeholder .placeholder-sub { font-size: 11px; color: #2a3a48; }

/* shared control bar (active view's controls + persistent SCRAM at the right) */
.pd-controlbar { flex: 0 0 auto; min-height: 58px; display: flex; align-items: center; gap: 14px;
  background: var(--bg-strip); border: 1px solid var(--border); border-radius: var(--radius); padding: 6px 10px; }
.pd-ctlrow { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; overflow-x: auto; }
.pd-scram { flex: 0 0 auto; align-self: stretch; font-size: 12px; font-weight: 700; letter-spacing: .1em; cursor: pointer;
  padding: 0 20px; min-width: 96px; border-radius: 5px; background: #0a1208; border: 1.5px solid #253a20; color: #304828; }
.pd-scram.armed { background: #7f2a2a; border-color: #9e3b3b; color: #f1d6d6; }
.pd-scram.fired { background: #1a0600; border: 2px solid #b03020; color: #e04020; animation: scram-flash .5s step-end infinite; }

/* param sections (RBMK/BWR Primary/Secondary) */
.pd-sections { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px 18px; align-content: start; }
.pd-section h5 { margin: 0 0 5px; font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--section-head-color); border-bottom: 1px solid var(--section-head-border); padding-bottom: 3px; font-weight: 700; }
.pd-row { display: flex; justify-content: space-between; gap: 8px; font-size: 13px; padding: 3px 0; border-bottom: 1px dotted #161d27; }
.pd-row .pk { color: var(--text-2); }
.pd-row .pv { font-weight: 600; color: var(--clr-status-normal); }
.pd-row .pv.q-caution { color: var(--caution); }
.pd-row .pv.q-alarm { color: var(--critical); }
.pd-row.subcool { padding: 6px 0; border-top: 1px solid #141b24; border-bottom: 1px solid #141b24; }
.pd-row.subcool .pv { font-size: 15px; }
.pd-row.subcool .pv.warn { color: var(--caution); }
.pd-row.subcool .pv.alarm { color: var(--critical); animation: gauge-alarm-flash .6s steps(1,end) infinite; }
.sat-badge { font-size: 8px; font-weight: 700; color: var(--critical); border: .5px solid #6a1808; background: #1a0600;
  border-radius: 2px; padding: 1px 4px; margin-left: 6px; letter-spacing: .05em; }

/* All-params view */
.pd-all-head { display: flex; justify-content: flex-end; margin-bottom: 8px; }
.pd-all-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; align-content: start; }

/* ============================================================================
 * PWR primary-loop diagram (embedded SVG, wired to the live snapshot). Vars are
 * scoped to .pd-diagram so the schematic's palette (--text/--border/etc.) does
 * not clash with the shell's. Animations driven by --flow-dur/--spin-dur + the
 * .stopped class on #loop, set each frame from RCP flow.
 * ========================================================================== */
.pd-diagram { --pipe-case:#2a3744; --warm:#c98a5a; --cool:#6a9dc0; --dtext:#bcccd8; --ddim:#62768a; --vdim:#3a4e60;
  --tap:#507893; --leader:#36485a; --water:#1e455c; --rod:#4aa0c8;
  background: radial-gradient(ellipse at 42% 45%, #0c1019 0%, #070a0f 82%);
  border: .5px solid #243040; border-radius: 8px; padding: 4px; display: flex; min-height: 0; }
.pd-diagram svg.loop { width: 100%; height: 100%; display: block; }
@keyframes flow { to { stroke-dashoffset: -16; } }
@keyframes spin { to { transform: rotate(360deg); } }
.pd-diagram .pipe-case { fill: none; stroke: var(--pipe-case); stroke-width: 9; stroke-linecap: round; stroke-linejoin: round; }
.pd-diagram .pipe-case.thin { stroke-width: 7; }
.pd-diagram .flow { fill: none; stroke-width: 4; stroke-linecap: butt; stroke-dasharray: 5 11; animation: flow var(--flow-dur, 1.1s) linear infinite; }
.pd-diagram .tube-flow { fill: none; stroke-width: 3; stroke-linecap: butt; stroke-dasharray: 4 8; animation: flow var(--flow-dur, 1.1s) linear infinite; }
.pd-diagram .loop.stopped .flow, .pd-diagram .loop.stopped .tube-flow { animation-play-state: paused; }
.pd-diagram .vessel { fill: #10171f; stroke: #3a5870; stroke-width: 1.2; }
.pd-diagram .vessel-inner { fill: #0e141c; stroke: #28384a; stroke-width: .8; }
.pd-diagram .fuel { stroke: #34504e; stroke-width: 1.4; }
.pd-diagram .comp-label { fill: var(--ddim); font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.pd-diagram .comp-sub { fill: var(--vdim); font-size: 9px; letter-spacing: .04em; }
.pd-diagram .water { fill: var(--water); opacity: .6; }
/* smooth the level/rod motion between broadcasts (10-20 Hz) so geometry updates
   interpolate instead of snapping — kills the per-frame jitter */
.pd-diagram .water, .pd-diagram .rod-fill { transition: y .16s linear, height .16s linear; }
.pd-diagram .surface { fill: none; stroke: #4e88a4; stroke-width: 1.4; opacity: .9; transition: d .16s linear; }
.pd-diagram .steam-space { fill: #121a22; }
.pd-diagram .valve { fill: #10171f; stroke: #4a6680; stroke-width: 1; }
.pd-diagram .pump-body { fill: #10161f; stroke: #3a5870; stroke-width: 1.2; }
.pd-diagram .pump-vane { stroke: #4a7088; stroke-width: 1.4; stroke-linecap: round; }
.pd-diagram #pumpRotor { transform-origin: 440px 405px; animation: spin var(--spin-dur, 1.1s) linear infinite; }
.pd-diagram .loop.stopped #pumpRotor { animation-play-state: paused; }
.pd-diagram .rod-track { fill: #0c121a; stroke: #2c3e4e; stroke-width: 1; }
.pd-diagram .rod-fill { fill: var(--rod); opacity: .85; }
.pd-diagram .rod-cap { fill: #5ab0d8; }
.pd-diagram .sec-arrow { fill: none; stroke: #46586a; stroke-width: 1.4; }
.pd-diagram .sec-label { fill: var(--vdim); font-size: 9.5px; letter-spacing: .04em; }
.pd-diagram .tap { fill: var(--tap); }
.pd-diagram .tap-tick { stroke: var(--tap); stroke-width: 1.2; }
.pd-diagram .leader { stroke: var(--leader); stroke-width: .8; stroke-dasharray: 2 2; fill: none; }
.pd-diagram .lbl-box { fill: #0e1620; stroke: #2c3e4e; stroke-width: .8; }
.pd-diagram .lbl-name { fill: var(--ddim); font-size: 9.5px; letter-spacing: .04em; text-transform: uppercase; }
.pd-diagram .lbl-val { fill: var(--dtext); font-size: 15px; font-weight: 600; }
.pd-diagram .lbl-val.derived { fill: #7aa4b8; }
.pd-diagram .lbl-unit { fill: var(--vdim); font-size: 9px; }
.pd-diagram .lbl-note { fill: var(--vdim); font-size: 8px; font-style: italic; }
.pd-diagram .tmi .lbl-box { stroke: #3a5030; }
.pd-diagram .tmi .lbl-name { fill: #7a8a4a; }

/* secondary-loop diagram additions (steam/turbine/condenser) */
.pd-diagram { --steam:#b4c0cc; --wet:#84a2b2; --cond:#5e92ac; --cw:#4e90ae; }
.pd-diagram .flow.steam-dash { stroke-dasharray: 7 9; }
.pd-diagram .turbine-blade { stroke: #4a7088; stroke-width: 1.2; }
@keyframes bladeSweep { to { transform: translateX(-15px); } }
.pd-diagram #secTurbineRotor { animation: bladeSweep var(--blade-dur, .5s) linear infinite; }
.pd-diagram #secCondPump { transform-origin: 700px 450px; animation: spin var(--spin-dur, 1s) linear infinite; }
.pd-diagram #secFeedPump { transform-origin: 320px 330px; animation: spin var(--spin-dur, 1s) linear infinite; }
.pd-diagram .loop.stopped #secTurbineRotor,
.pd-diagram .loop.stopped #secCondPump,
.pd-diagram .loop.stopped #secFeedPump { animation-play-state: paused; }

/* full-plant diagram (two flow domains: primary + secondary, paused independently) */
.pd-diagram .flow.sec { animation: flow var(--flow-dur-sec, 1.1s) linear infinite; }
.pd-diagram .tube-flow.sec { animation: flow var(--flow-dur-sec, 1.1s) linear infinite; }
.pd-diagram .loop.stopped-pri .flow.pri, .pd-diagram .loop.stopped-pri .tube-flow.pri { animation-play-state: paused; }
.pd-diagram .loop.stopped-sec .flow.sec, .pd-diagram .loop.stopped-sec .tube-flow.sec { animation-play-state: paused; }
.pd-diagram #fpRcp { transform-origin: 400px 355px; animation: spin var(--spin-pri, 1s) linear infinite; }
.pd-diagram #fpTurbineRotor { animation: bladeSweep var(--blade-dur, .5s) linear infinite; }
.pd-diagram #fpCondPump { transform-origin: 840px 450px; animation: spin var(--spin-sec, 1s) linear infinite; }
.pd-diagram #fpFeedPump { transform-origin: 720px 385px; animation: spin var(--spin-sec, 1s) linear infinite; }
.pd-diagram .loop.stopped-pri #fpRcp { animation-play-state: paused; }
.pd-diagram .loop.stopped-sec #fpTurbineRotor,
.pd-diagram .loop.stopped-sec #fpCondPump,
.pd-diagram .loop.stopped-sec #fpFeedPump { animation-play-state: paused; }

/* ============================ Operator's Manual overlay (Phase 3) ========= */
.manual-overlay {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(4, 7, 9, 0.78);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.manual-overlay[hidden] { display: none; }
.manual-modal {
  width: min(1100px, 96vw); height: min(88vh, 900px);
  display: flex; flex-direction: column;
  background: var(--bg-plant); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 12px 48px rgba(0,0,0,0.6); overflow: hidden;
}
.manual-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px; border-bottom: 1px solid var(--border); background: var(--bg-elevated);
}
.manual-title { font-size: 15px; font-weight: 700; color: var(--text); }
.manual-head-ctl { display: flex; align-items: center; gap: 10px; }
.manual-body { flex: 1 1 auto; display: flex; min-height: 0; }
.manual-nav {
  flex: 0 0 172px; border-right: 1px solid var(--border); background: var(--bg-strip);
  padding: 8px; display: flex; flex-direction: column; gap: 2px; overflow-y: auto;
}
.manual-nav button {
  text-align: left; background: transparent; border: none; color: var(--text-2);
  padding: 8px 10px; font-size: 12.5px; border-radius: 5px; cursor: pointer;
}
.manual-nav button:hover { color: var(--text); background: var(--bg-elevated); }
.manual-nav button.on { color: var(--text); background: var(--bg-elevated); font-weight: 600; box-shadow: inset 2px 0 0 var(--running); }
.manual-content { flex: 1 1 auto; overflow-y: auto; padding: 18px 22px; color: var(--text); font-size: 13px; line-height: 1.55; }
.manual-content h2 { font-size: 16px; margin: 0 0 10px; color: var(--text); }
.manual-content h3 { font-size: 13.5px; margin: 18px 0 6px; color: var(--text-2); text-transform: uppercase; letter-spacing: 0.04em; }
.manual-content p { margin: 0 0 10px; color: var(--text); }
.manual-content .muted { color: var(--muted); font-size: 12px; }
.manual-content .one-liner { font-size: 14px; color: var(--running); margin-bottom: 12px; }
.m-table { width: 100%; border-collapse: collapse; margin: 6px 0 14px; font-size: 12px; }
.m-table th, .m-table td { text-align: left; padding: 5px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
.m-table th { color: var(--text-2); font-weight: 600; }
.m-table td.mono, .m-table .mono { font-family: ui-monospace, "Cascadia Code", Consolas, monospace; color: var(--text-2); }
.m-card { border: 1px solid var(--border); border-radius: 6px; padding: 10px 12px; margin: 0 0 10px; background: var(--bg-strip); }
.m-card .m-h { font-weight: 600; color: var(--text); margin-bottom: 2px; }
.m-card .m-sub { font-size: 11px; color: var(--muted); font-family: ui-monospace, Consolas, monospace; }
.m-step { display: flex; gap: 10px; padding: 8px 0; border-bottom: 1px dashed var(--border); }
.m-step .n { flex: 0 0 22px; height: 22px; border-radius: 50%; background: var(--bg-elevated); color: var(--text-2);
  display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; }
.m-step .m-act { color: var(--text); }
.m-step .m-note { color: var(--muted); font-size: 11.5px; margin-top: 2px; }
.m-step .m-cmd { font-family: ui-monospace, Consolas, monospace; font-size: 11px; color: var(--running-muted); }
.m-pill { display: inline-block; padding: 1px 7px; border-radius: 10px; font-size: 10.5px; border: 1px solid var(--border); color: var(--text-2); margin-right: 6px; }
.m-prio-critical { color: #F26; border-color: #63232f; }
.m-prio-warning { color: #FBBF24; border-color: #5a4718; }
.m-prio-caution { color: #38BDF8; border-color: #1d4657; }
.m-prio-status { color: var(--text-2); }
.m-sim-note { border-left: 3px solid var(--running-muted); background: var(--bg-strip); padding: 8px 12px; margin: 8px 0; font-size: 12px; color: var(--text-2); border-radius: 0 5px 5px 0; }

/* manual v2 — rich procedure steps + prereqs/cautions/outcome */
.m-step .m-meta { margin-top: 3px; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: 11px; }
.m-target { color: var(--text-2); }
.m-acc { color: var(--running-muted); font-family: ui-monospace, Consolas, monospace; }
.m-sub2 { font-size: 11px; color: var(--text-2); font-weight: 600; margin: 8px 0 2px; text-transform: uppercase; letter-spacing: .04em; }
.m-ul { margin: 0 0 8px; padding-left: 18px; color: var(--text-2); font-size: 12px; }
.m-ul li { margin: 2px 0; }
.m-caution { border-left: 3px solid #5a4718; background: rgba(251,191,36,0.06); color: #d7b25a; padding: 6px 10px; margin: 8px 0; font-size: 11.5px; border-radius: 0 4px 4px 0; }
.m-outcome { margin-top: 8px; color: var(--running); font-size: 12px; font-weight: 600; }
/* Collapsible step preview on the Procedures (live) selection menu. */
.m-steps { margin-top: 4px; }
.m-steps > summary { cursor: pointer; font-size: 11px; color: var(--text-2); font-weight: 600;
  list-style: none; padding: 4px 0; user-select: none; }
.m-steps > summary::-webkit-details-marker { display: none; }
.m-steps > summary:hover { color: var(--running); }
.m-steps[open] > summary { margin-bottom: 4px; }

.m-follow { float: right; margin: -2px 0 0 8px; font-size: 11px; padding: 3px 8px; color: var(--running); border-color: var(--running-muted); }
.m-follow:hover { color: var(--text); background: var(--running-muted); }

/* ---- packed markdown manual (Manuals/*.md via RD.MANUAL_MD) ---- */
.mnav-sep {
  margin: 10px 4px 2px; padding-top: 8px; border-top: 1px solid var(--border);
  color: var(--muted); font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
}
.mdoc { max-width: 880px; }
.mdoc h1 { font-size: 18px; margin: 0 0 12px; color: var(--text); }
.mdoc h2 { font-size: 15px; margin: 20px 0 8px; color: var(--text); border-bottom: 1px solid var(--border); padding-bottom: 4px; }
.mdoc h3 { font-size: 13.5px; margin: 16px 0 6px; color: var(--text-2); }
.mdoc h4, .mdoc h5, .mdoc h6 { font-size: 12.5px; margin: 12px 0 4px; color: var(--text-2); }
.mdoc p { margin: 0 0 10px; }
.mdoc ul, .mdoc ol { margin: 0 0 10px; padding-left: 22px; }
.mdoc li { margin: 2px 0; }
.mdoc blockquote {
  margin: 0 0 10px; padding: 6px 12px; border-left: 3px solid var(--stopped);
  background: var(--bg-strip); color: var(--text-2);
}
.mdoc hr { border: none; border-top: 1px solid var(--border); margin: 14px 0; }
.mdoc code {
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace; font-size: 11.5px;
  background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 3px; padding: 0 4px;
}
.mdoc .mdoc-code {
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace; font-size: 11.5px;
  background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 5px;
  padding: 8px 10px; overflow-x: auto; margin: 0 0 10px; white-space: pre;
}
.mdoc .mdoc-tw { overflow-x: auto; margin: 6px 0 14px; }
.mdoc table { width: 100%; border-collapse: collapse; font-size: 12px; }
.mdoc th, .mdoc td { text-align: left; padding: 5px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
.mdoc th { color: var(--text-2); font-weight: 600; white-space: nowrap; }
.mdoc a { color: var(--running); text-decoration: none; }
.mdoc a:hover { text-decoration: underline; }

/* ============================================================ M6 Instructor —
   highlight glow (control the current beat/step points at) + Level Complete */
.instr-glow {
  animation: instrGlow 1.6s ease-in-out infinite;
  border-radius: 6px;
  position: relative;
  z-index: 5;
}
@keyframes instrGlow {
  0%, 100% { box-shadow: 0 0 0 1px rgba(122, 176, 255, 0.55), 0 0 10px 2px rgba(122, 176, 255, 0.25); }
  50%      { box-shadow: 0 0 0 2px rgba(122, 176, 255, 0.95), 0 0 18px 5px rgba(122, 176, 255, 0.45); }
}
/* Checklist step-hover preview glow — greener tint, distinct from the directive
   .instr-glow (blue). Points at the controls/indications a step names on hover. */
.ckl-hoverable { cursor: help; }
.ckl-glow {
  animation: cklGlow 1.2s ease-in-out infinite;
  border-radius: 6px; position: relative; z-index: 5;
}
@keyframes cklGlow {
  0%, 100% { box-shadow: 0 0 0 1px rgba(120, 210, 150, 0.60), 0 0 10px 2px rgba(120, 210, 150, 0.28); }
  50%      { box-shadow: 0 0 0 2px rgba(120, 210, 150, 0.98), 0 0 18px 5px rgba(120, 210, 150, 0.50); }
}
.lc-msg { margin-bottom: 8px; }   /* endpoint beat commentary shown above the level-complete panel */
.lc-panel { display: flex; flex-direction: column; gap: 6px; }
.lc-title { font-weight: 700; font-size: 13px; color: var(--text); }
.lc-actions { display: flex; gap: 6px; margin-top: 4px; }
.lc-actions .btn { flex: 0 0 auto; }

/* ---- Scenario cards + walkthrough rows (Plant & Mission window) ---- */
.tr-card {
  border: 1px solid var(--border); border-radius: 6px;
  padding: 8px 10px; margin-bottom: 8px; background: var(--bg-elevated);
}
.tr-card.active { border-color: rgba(122, 176, 255, 0.6); }
.tr-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.tr-title { font-weight: 700; font-size: 12px; color: var(--text); }
.tr-badge {
  font-size: 10px; color: var(--muted); border: 1px solid var(--border);
  border-radius: 3px; padding: 0 5px; white-space: nowrap;
}
.tr-actions { margin-top: 6px; }
.tr-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 4px 2px; border-bottom: 1px dotted var(--border);
}
.tr-ptitle { font-size: 12px; color: var(--text); }

/* ---- Campaign (Plant & Mission window): acts, mission rows, progress ---- */
.camp-head {
  border: 1px solid var(--border); border-radius: 6px;
  padding: 8px 10px; margin-bottom: 8px; background: var(--bg-elevated);
}
.camp-title { font-weight: 700; font-size: 13px; color: var(--text); }
.camp-progress { display: flex; align-items: center; gap: 8px; margin-top: 6px; font-size: 11px; color: var(--muted); }
.camp-bar { flex: 1; height: 4px; border-radius: 2px; background: var(--border); overflow: hidden; }
.camp-fill { height: 100%; background: rgba(122, 176, 255, 0.85); transition: width 300ms ease; }
.camp-continue { margin-top: 8px; }
.camp-done { margin-top: 8px; font-weight: 700; font-size: 12px; color: var(--text); }
.camp-act {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted); margin: 10px 0 4px;
}
.camp-mission {
  display: grid; grid-template-columns: 18px 1fr auto; align-items: center;
  column-gap: 8px; padding: 4px 2px; border-bottom: 1px dotted var(--border);
}
.camp-mission .camp-teaches { grid-column: 2 / 4; font-size: 11px; color: var(--muted); padding-bottom: 2px; }
.camp-mark { font-size: 11px; text-align: center; }
.camp-mtitle { font-size: 12px; color: var(--text); }
.camp-mission.done .camp-mtitle { color: var(--muted); }
.camp-mission.done .camp-mark { color: #79d297; }
.camp-mission.locked { opacity: 0.55; }
.camp-mission.next { background: rgba(122, 176, 255, 0.07); border-radius: 4px; }

/* ---- First-run Hook invitation (prompted, never forced) ---- */
.hook-prompt {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(4, 8, 14, 0.55);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.hook-prompt[hidden] { display: none; }
.hook-card {
  width: min(460px, 92vw);
  background: var(--bg-plant); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 12px 48px rgba(0,0,0,0.6);
  padding: 18px 20px;
}
.hook-title { font-size: 15px; font-weight: 700; color: var(--text); margin-bottom: 8px; }
.hook-body { font-size: 12px; color: var(--muted); line-height: 1.5; margin-bottom: 14px; }
.hook-actions { display: flex; gap: 8px; justify-content: flex-end; }

/* ---- Strip-chart rewind picker (sandbox: click a moment to jump back) ---- */
.strip-chart.rewind-pick .chart-plot { cursor: crosshair; }
.strip-chart.rewind-pick { outline: 1px solid rgba(122, 176, 255, 0.5); border-radius: 4px; }
.rewind-hint {
  position: absolute; top: 4px; left: 50%; transform: translateX(-50%);
  background: rgba(10, 16, 26, 0.9); border: 1px solid rgba(122, 176, 255, 0.5);
  border-radius: 4px; padding: 2px 10px;
  font-size: 11px; color: #a8c6f0; white-space: nowrap; pointer-events: none; z-index: 6;
}
.rewind-hint[hidden] { display: none; }
.scrubber #chartRewindBtn { margin-left: 6px; padding: 0 8px; }
.scrubber #chartRewindBtn:disabled { opacity: 0.35; }

/* ============================================================ chat mode (TMI-2 M5)
   Multi-speaker transcript in the Instructor card. Bubbles stay quiet-board
   muted; color marks WHO is speaking, not urgency (SYS lines borrow caution). */
/* The persona header survives chat mode (#237): it is the always-visible
   collapse affordance and the mid-scenario orientation line (renderChat swaps
   its text to the scenario title — a scene, never a speaker). Only the
   prior-messages line is chat-hidden. */
#instructorCard.chat-mode .instr-prev { display: none; }
/* Collapsed chat card: a short sliver of the transcript, pinned to its LATEST
   lines by script scroll — the one-line nowrap ellipsis further up is for the
   free-play message card and would render a whole transcript as one line. */
.instructor.collapsed.chat-mode .instr-current {
  white-space: normal; overflow: hidden; max-height: 46px; text-overflow: clip;
}
.instructor.collapsed.chat-mode .chat-btns { display: none; }
.chat-log {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 48vh; overflow-y: auto; padding-right: 4px; margin-bottom: 8px;
}
.chat-line { display: flex; flex-direction: column; gap: 2px; max-width: 94%; }
.chat-meta { font-size: 10px; letter-spacing: .05em; color: var(--muted); text-transform: uppercase; }
.chat-txt {
  font-size: 13px; line-height: 1.45; color: var(--text);
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: 8px; padding: 6px 9px; white-space: pre-line;
}
.chat-sup  .chat-txt { border-left: 3px solid var(--stopped); }
.chat-supx .chat-txt { border-left: 3px solid var(--normal); }      /* supervisor reacting to the player */
.chat-aux  .chat-txt { border-left: 3px solid var(--border); color: var(--text-2); }
.chat-chief .chat-txt { border-left: 3px solid #C084FC; }
.chat-sys  .chat-txt {
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11.5px;
  color: var(--caution); border-left: 3px solid var(--caution); background: rgba(217,164,65,.06);
}
.chat-player { align-self: flex-end; align-items: flex-end; }
.chat-player .chat-txt { border-right: 3px solid var(--normal); border-left: 1px solid var(--border);
  background: rgba(91,179,196,.08); }
.chat-gap {
  text-align: center; color: var(--muted); font-size: 11px; font-style: italic;
  border-top: 1px dashed var(--border); margin-top: 4px; padding-top: 6px;
}
.chat-btns { display: flex; flex-direction: column; gap: 6px; }
.chat-btn { width: 100%; padding: 7px 10px; font-weight: 700; }
.chat-btn-ack { border-color: var(--stopped); }
.chat-btn-skip { border-color: var(--caution); color: var(--caution); }
.chat-ff { text-align: center; color: var(--caution); font-size: 11px; font-style: italic; }

/* ============================================================ auto-checklists (Path 3)
   Picker lives in Operate; the live checklist still renders in the Instructor card. */
.ckl-picker { margin: 2px 0 4px; }
.ckl-menu { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; max-height: 40vh; overflow-y: auto; }
.ckl-menu[hidden] { display: none; }
.ckl-menu button {
  text-align: left; background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: 6px; color: var(--text); padding: 6px 9px; font-size: 12.5px; cursor: pointer;
}
.ckl-menu button:hover { border-color: var(--stopped); }
.ckl-cat { display: inline-block; min-width: 62px; margin-right: 6px; color: var(--muted); font-size: 10px; text-transform: uppercase; letter-spacing: .05em; }
.ckl-log { display: flex; flex-direction: column; gap: 8px; max-height: 48vh; overflow-y: auto; padding-right: 4px; margin-bottom: 8px; }
.ckl-head { font-size: 13px; }
.ckl-step { display: flex; gap: 8px; align-items: flex-start; border: 1px solid var(--border); border-radius: 8px; padding: 6px 9px; background: var(--bg-elevated); }
.ckl-ico { font-weight: 700; width: 16px; text-align: center; flex: none; }
.ckl-body { flex: 1; min-width: 0; }
.ckl-txt { font-size: 12.5px; line-height: 1.4; color: var(--text); }
.ckl-sub { font-size: 11px; color: var(--text-2); margin-top: 2px; }
.ckl-done { opacity: 0.62; border-left: 3px solid var(--running); }
.ckl-done .ckl-ico { color: var(--running); }
.ckl-active { border-left: 3px solid var(--caution); }
.ckl-active .ckl-ico { color: var(--caution); }
.ckl-pend { opacity: 0.45; }
.ckl-mark { margin-top: 6px; font-size: 11px; padding: 3px 8px; }
.ckl-complete { text-align: center; border: 1px solid var(--running); border-radius: 8px; padding: 8px; color: var(--running); }
.ckl-btns { display: flex; gap: 6px; }
.ckl-btns .btn { flex: 1; }

/* ============================ Plant & Mission window ======================
   Sim tab → ⚛️ Plant & Mission… — plant column (left), then mode tabs +
   nested content (right). Reuses the .tr-* / .camp-* blocks above. */
.mission-overlay {
  position: fixed; inset: 0; z-index: 210;
  background: rgba(4, 7, 9, 0.78);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.mission-overlay[hidden] { display: none; }
.mission-modal {
  width: min(940px, 96vw); height: min(84vh, 760px);
  display: flex; flex-direction: column;
  background: var(--bg-plant); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 12px 48px rgba(0,0,0,0.6); overflow: hidden;
}
.mission-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
}
.mission-title { font-weight: 700; font-size: 14px; color: var(--text); }
.mission-body { flex: 1; display: grid; grid-template-columns: 260px 1fr; min-height: 0; }
/* step 1 — plant column */
.mp-plants {
  border-right: 1px solid var(--border); overflow-y: auto;
  padding: 10px; display: flex; flex-direction: column; gap: 8px;
}
/* NB: not ".plant-card" — that class belongs to the PWR synoptic (positioned) */
.mplant-card {
  border: 1px solid var(--border); border-radius: 6px; padding: 10px;
  cursor: pointer; background: var(--bg-elevated);
}
.mplant-card:hover { border-color: rgba(122, 176, 255, 0.4); }
.mplant-card.on { border-color: rgba(122, 176, 255, 0.7); background: rgba(122, 176, 255, 0.08); }
.mplant-name { font-weight: 700; font-size: 13px; color: var(--text); }
.mplant-live { font-size: 10px; color: #79d297; font-weight: 400; }
.mplant-sub { font-size: 11px; color: var(--text-2); margin-top: 2px; }
.mplant-desc { font-size: 11px; color: var(--muted); margin-top: 6px; line-height: 1.4; }
/* Engine complete, control room not built yet: visible so the roadmap reads,
   but muted and inert so it doesn't look broken when clicking does nothing. */
.mplant-card.soon { opacity: 0.45; cursor: default; }
.mplant-card.soon:hover { border-color: var(--border); }
.mplant-soon {
  margin-top: 8px; align-self: flex-start; display: inline-block;
  border: 1px solid var(--caution); color: var(--caution); border-radius: 4px;
  padding: 1px 6px; font-size: 9px; font-weight: 700; letter-spacing: 1px;
}
/* step 2 — mode tabs; step 3 — the nested content */
.mp-right { display: flex; flex-direction: column; min-height: 0; }
.mp-modes { display: flex; border-bottom: 1px solid var(--border); }
.mp-modes button {
  flex: 1; padding: 9px 4px; background: none; border: none;
  border-bottom: 2px solid transparent; color: var(--text-2);
  font: inherit; font-size: 12px; cursor: pointer;
}
.mp-modes button:hover { color: var(--text); }
.mp-modes button.on { color: var(--text); border-bottom-color: rgba(122, 176, 255, 0.85); }
.mp-content { flex: 1; overflow-y: auto; padding: 12px 14px; }
/* campaign mission rows in the wide window: pin the Start button to the title
   row (the teaches line spans beneath it), instead of wrapping to its own row */
.mp-content .camp-mission > .btn { grid-column: 3; grid-row: 1; white-space: nowrap; }
/* Coming-soon panel — an area whose content this channel does not offer yet
   (site/flags.js, #241). Deliberately the same amber COMING SOON badge the
   not-yet-built plant cards use: "being finished", not "broken". */
.mp-soon {
  border: 1px dashed var(--border); border-radius: 6px;
  padding: 18px 16px; text-align: center; background: var(--bg-elevated);
}
.mp-soon-tag {
  display: inline-block; border: 1px solid var(--caution); color: var(--caution);
  border-radius: 4px; padding: 2px 8px; font-size: 10px; font-weight: 700;
  letter-spacing: 1px; margin-bottom: 8px;
}
.mp-soon .m-note { max-width: 46ch; margin: 0 auto; line-height: 1.5; }

/* ---- Features window (development flag toggles, #241) ---- */
/* Reuses the mission modal, but it has no plant column — .mission-body's
   260px | 1fr grid would otherwise squeeze the whole board into 260px. */
.mission-body.fl-body { grid-template-columns: 1fr; }
.fl-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px;
  margin: 10px 0 4px; background: var(--bg-elevated);
}
.fl-bar .k { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-2); }
.fl-bar .btn { margin-left: auto; }
.fl-warn {
  border: 1px solid var(--caution); color: var(--caution); border-radius: 6px;
  padding: 6px 10px; font-size: 11.5px; margin-bottom: 4px;
}
.fl-row {
  display: grid; grid-template-columns: 46px 1fr auto auto auto; align-items: center;
  column-gap: 8px; padding: 4px 2px; border-bottom: 1px dotted var(--border);
}
.fl-row.off .fl-name, .fl-row.off .fl-id { color: var(--muted); }
.fl-sw {
  font: inherit; font-size: 9.5px; font-weight: 700; letter-spacing: .08em;
  padding: 2px 0; border-radius: 3px; cursor: pointer;
  border: 1px solid var(--border); background: none; color: var(--muted);
}
.fl-sw.on { border-color: rgba(70,163,94,.65); color: #6FD089; background: rgba(70,163,94,.08); }
.fl-name { font-size: 12px; color: var(--text); }
.fl-id { font-size: 10px; color: var(--text-2); }
.fl-stage {
  font-size: 9px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  border: 1px solid var(--border); border-radius: 3px; padding: 1px 5px; color: var(--muted);
}
.fl-stage.fl-public { border-color: rgba(70,163,94,.55); color: #6FD089; }
.fl-stage.fl-preview { border-color: rgba(217,164,65,.55); color: var(--caution); }
.fl-ov { font-size: 10px; color: var(--caution); cursor: pointer; }

/* Free Play starting-condition rows */
.init-row {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px; margin-bottom: 6px;
  cursor: pointer; font-size: 12px; color: var(--text); background: var(--bg-elevated);
}
.init-row:hover { border-color: rgba(122, 176, 255, 0.4); }
.init-row.on { border-color: rgba(122, 176, 255, 0.7); background: rgba(122, 176, 255, 0.08); }
.init-dot { color: rgba(122, 176, 255, 0.9); }
.mp-start { display: block; width: 100%; margin-top: 12px; padding: 10px; font-weight: 700; }

/* ---- 1/M startup plot (draggable window — ui/panels/one_over_m.js) ---- */
.oom-win {
  position: fixed; top: 90px; right: 340px; width: 356px; z-index: 250;
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 12px 48px rgba(0,0,0,0.6);
  font-size: 12px; color: var(--text);
}
.oom-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 10px; border-bottom: 1px solid var(--border);
  font-weight: 600; user-select: none; touch-action: none;
}
.oom-x { padding: 0 8px; line-height: 20px; }
.oom-svg { display: block; width: 100%; background: var(--bg-plant); }
.oom-foot { display: flex; gap: 8px; align-items: center; padding: 8px 10px 4px; }
.oom-pred { color: var(--text-2); font-size: 11px; }
.oom-msg { min-height: 16px; padding: 0 10px 8px; color: var(--muted); font-size: 11px; }
.oom-msg.warn { color: var(--caution); }
.oom-frame { fill: none; stroke: var(--border); }
.oom-grid { stroke: var(--border); stroke-dasharray: 2 3; }
.oom-zero { stroke: var(--text-2); }
.oom-tick, .oom-lab { fill: var(--muted); font-size: 8px; }
.oom-lab { font-size: 9px; }
.oom-fit { stroke: var(--normal); stroke-dasharray: 5 4; stroke-width: 1.2; }
.oom-crit { stroke: var(--caution); stroke-width: 1.2; }
.oom-critlab { fill: var(--caution); font-size: 10px; font-weight: 600; }
.oom-pt { fill: var(--text); }

/* An expanded card (e.g. the NIS section at a startup lineup) can overflow its
   layout slot under a neighbor; raising the hovered card keeps every control
   reachable, and the neighbor is back on top the moment you move to it. */
.app.pwr-synoptic .plant-card:hover { z-index: 5; }

/* Feedback modal sizes to its form. (.help-modal's height:auto is defeated by
   .mission-modal's fixed height — that rule comes later in the file — so the
   compound selector here outranks it.) */
.mission-modal.fb-modal { height: auto; max-height: min(84vh, 760px); }
