/* Instructor console — same night-console family as the trainee radar, but a
   desk tool rather than an instrument: denser type, more chrome, and the fault
   controls in warning colours so they can never be mistaken for radar controls. */
:root {
  --bg:      #050907;
  --panel:   #0a1310;
  --line:    #173a25;
  --line-hi: #2f7d4b;
  --green:   #00e018;
  --green-br:#7ff0a8;
  --dim:     #6fae86;
  --amber:   #ff9d2e;
  --red:     #ff4a4a;
  --text:    #cfe9d8;
  color-scheme: dark;
}
* { box-sizing: border-box; }
/* `hidden` must beat any display a rule sets. The UA sheet's
   [hidden]{display:none} loses to ANY id or class selector that sets
   display, so a pane styled `#pane { display:flex }` stays on screen with
   the attribute set and nothing looks wrong in the markup. This file had
   grown four separate per-element overrides working around exactly that;
   one rule here replaces them and stops the fifth being needed. */
[hidden] { display: none !important; }
html, body { height: 100%; margin: 0; }
body {
  background: var(--bg); color: var(--text);
  font: 12px/1.4 ui-monospace, "Cascadia Code", Consolas, monospace;
  overflow: hidden;
}
/* THE SHELL IS A TOP BAR AND A PAGE. Nothing frames the work area any more.
   The fault rail used to take 232px down the left and the equipment strip 58px
   across the foot, on every screen, all day, to carry controls that are worked
   in bursts - so the tiles, which are the thing an instructor actually watches,
   were the one part of the window paying for them. Both are on the FAULTS &
   FAILURES page now and TILES has the window. */
#app {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 44px 1fr;        /* top bar · page */
  height: 100vh;
}

/* ── top bar ─────────────────────────────────────────────────────────────── */
#topbar {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 12px; padding: 0 14px;
  background: var(--panel); border-bottom: 1px solid var(--line-hi);
}
#brand { font-size: 14px; letter-spacing: .06em; color: var(--text); }
#brand b { color: var(--green-br); }
#topbar .sp { flex: 1; }
#allbar { display: flex; align-items: center; gap: 8px; }
#allbar .lbl { font-size: 10px; letter-spacing: .12em; color: var(--dim); }
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--green); box-shadow: 0 0 6px var(--green); }
.dot.bad { background: var(--red); box-shadow: 0 0 6px var(--red); }

.btn {
  font: 700 11px ui-monospace, monospace; letter-spacing: .06em;
  padding: 6px 12px; cursor: pointer;
  color: var(--text); background: #10241a;
  border: 1px solid var(--line-hi); border-radius: 4px;
}
.btn:hover:not(:disabled) { background: #16351f; color: #fff; }
.btn:disabled { opacity: .4; cursor: default; }
.btn.warn { border-color: #7a3a12; background: #2a1408; color: var(--amber); }
.btn.warn:hover:not(:disabled) { background: #3a1d0b; }
/* A button that has been pressed once and is waiting for the second press.
   It says so in its own label; this is the colour that stops the pair being
   mistaken for one ordinary press. */
.btn.arm { border-color: #b8860b; background: #4a2409; color: #ffd27a; }
.btn.on { border-color: #7a1414; background: #2a0c0c; color: #ff9c9c; }
.btn.sm { padding: 3px 9px; font-size: 10px; }
/* ALL: PAUSE / RESUME — a split across stations lights neither button, so mark
   both as indeterminate rather than leaving them looking simply "off". */
.btn.mixed { border-color: #7a5a12; background: #2a220c; color: #ffd27a; }
.all-state {
  min-width: 74px; text-align: center; padding: 2px 6px; border-radius: 3px;
  font: 700 10px ui-monospace, monospace; letter-spacing: .06em;
  color: var(--dim); border: 1px solid var(--line-hi);
}
.all-state.run   { color: #7bf29a; border-color: #2f7d4b; background: #0c2c1a; }
.all-state.hold  { color: #ff9c9c; border-color: #7a1414; background: #2a0c0c; }
.all-state.split { color: #ffd27a; border-color: #7a5a12; background: #2a220c; }
/* The class has FINISHED. Not the red of a hold, which is a state to undo. */
.all-state.over  { color: #dfe7e2; border-color: #5f7a6e; background: #2c3a34; }
.btn.wide { width: 100%; margin-top: 5px; }

/* ── station grid ────────────────────────────────────────────────────────── */
#grid {
  position: absolute; inset: 0;
  overflow: auto; padding: 12px;
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(430px, 1fr));
  /* STRETCH, not start: fitTiles gives every frame the height of its row, so
     the rows are meant to divide the area between them rather than sit at
     their natural height with the remainder left empty at the foot. */
  align-content: stretch;
  /* The card is as wide as the console in it (fitTiles sizes the frame), so the
     leftover width is shared either side rather than left in one slab. */
  justify-items: center;
}
.empty { color: var(--dim); padding: 40px; text-align: center; line-height: 1.8; }
.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
  overflow: hidden; cursor: pointer;
  width: max-content; max-width: 100%;
}
.card.sel { border-color: var(--green); box-shadow: 0 0 0 1px var(--green) inset; }
.card.offline { opacity: .65; }
.c-head {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px; background: #0d1f16; border-bottom: 1px solid var(--line);
}
.c-name { flex: 0 0 auto; font-weight: 700; letter-spacing: .05em; color: var(--green-br); }

/* ── WHAT THE TILE SAYS ABOUT ITSELF ─────────────────────────────────────────
   The stats column is off by default now, so the three things worth scanning
   across a wall of tiles moved onto the title bar: the exercise, the fault
   count and the alarm count. The counts appear only when they are not zero -
   a row of zeros across nine tiles is noise, and noise is what stops a real one
   being seen. */
.c-brief {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; overflow: hidden;
}
.cb-exer {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--green-br); letter-spacing: .02em;
}
.cb-exer b { color: var(--text); font-variant-numeric: tabular-nums; }
.cb-exer.muted { color: var(--dim); }
.cb-count {
  flex: 0 0 auto; font-weight: 700; letter-spacing: .06em;
  padding: 1px 7px; border-radius: 3px;
}
.cb-fault { color: var(--amber); background: #3a1d0b; border: 1px solid #7a3a12; }
.cb-alarm { color: #ffdede; background: #5a1414; border: 1px solid #a33; }
.pill { font: 700 10px ui-monospace, monospace; letter-spacing: .1em; padding: 2px 8px; border-radius: 3px; }
.pill.run  { color: #04210c; background: var(--green); }
.pill.hold { color: #2a1a00; background: var(--amber); }
.pill.off  { color: #fff; background: #7a1414; }
/* ENDED is not PAUSED and must not read as it: a held exercise is waiting,
   a finished one is finished. Slate rather than amber, so the eye does not
   go looking for a RESUME to press. */
.pill.over { color: #dfe7e2; background: #2c3a34; border: 1px solid #5f7a6e; }
/* FAST TIME on a tile: amber outline, so it reads as a mode, not an alarm. */
.pill.fast { color: #ffd27a; background: #2a220c; border: 1px solid #b8860b; margin-left: 4px; }
/* Speed boxes: the top bar and the EXERCISE pop-up. */
.rate-in { width: 58px; font: 12px ui-monospace, monospace; padding: 3px 5px;
           background: var(--bg); color: var(--text); border: 1px solid var(--line); border-radius: 3px; }
.rate-row { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.rate-row .btn { padding-inline: 7px; }
.rate-row .rate-in { width: 50px; }
.rate-row .lbl { font-size: 10px; letter-spacing: .12em; color: var(--dim); }
.rate-q.on { color: #ffd27a; border-color: #b8860b; }

.c-zoom {
  background: none; border: 1px solid var(--line-hi); border-radius: 3px;
  color: var(--green-br); font-size: 13px; line-height: 1; padding: 2px 7px; cursor: pointer;
}
.c-zoom:hover { background: #16351f; }

.c-body { display: grid; grid-template-columns: 1fr 152px; }
.c-frame { position: relative; aspect-ratio: 76 / 45; background: #000; overflow: hidden; }
/* The console is given a fixed 1520×900 viewport and main.ts scales it into
   whatever slot the tile has, so enlarging a station is purely a layout change.
   The HEIGHT is what matters: the FMD skin needs ~884px for its left strip, so
   840 clipped the last keys off every tile. See FRAME_W / FRAME_H in main.ts
   and keep the aspect-ratio above in step with them. The width and scale here
   are only a first paint — main.ts sets both from the real slot. */
.c-frame iframe { position: absolute; inset: 0; width: 1520px; height: 900px; border: 0;
  transform-origin: top left; transform: scale(0.45); pointer-events: none; }

/* Enlarged: one station fills the whole grid area. The default grid is
   align-content:start so tiles stay their natural height; in focus mode the
   single row must stretch instead, or the card stays tile-sized. */
#grid.focus-mode {
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  align-content: stretch;
  height: 100%;
  overflow: hidden;
}
.card.focused { display: flex; flex-direction: column; height: 100%; width: 100%; }
.card.focused .c-body { flex: 1; grid-template-columns: 1fr 200px; min-height: 0; }
.card.focused .c-frame { aspect-ratio: auto; height: 100%; }
.card.focused .c-stats { font-size: 12px; }
.f-off { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--red); font-size: 11px; text-align: center; padding: 10px; }

.c-stats { padding: 8px 10px; border-left: 1px solid var(--line); font-size: 11px; }
.c-stats dl { display: grid; grid-template-columns: auto 1fr; gap: 2px 8px; margin: 6px 0 0; }
.c-stats dt { color: var(--dim); font-size: 10px; }
.c-stats dd { margin: 0; color: var(--text); }
.s-exer { color: var(--green-br); }
.s-exer.muted, .s-faults.muted { color: var(--dim); }
.s-faults { margin-top: 7px; display: flex; flex-wrap: wrap; gap: 3px; font-size: 10px; }
.fchip { padding: 1px 6px; border-radius: 3px; background: #3a1d0b; color: var(--amber); border: 1px solid #7a3a12; }

/* ── side panels ─────────────────────────────────────────────────────────── */
#rail {
  /* Scroll rather than hide: on a short window overflow:hidden swallowed rows
     silently, which reads as "those faults were removed". */
  overflow-x: hidden; overflow-y: auto; background: var(--panel);
  border-right: 1px solid var(--line-hi); padding: 8px 8px 6px;
  display: flex; flex-direction: column;
}
#rail h2 {
  display: flex; align-items: baseline; gap: 6px; margin: 0 0 4px;
  font-size: 12px; letter-spacing: .12em; color: var(--green-br);
  border-bottom: 1px solid var(--line); padding-bottom: 3px;
}
#rail h2.mt { margin-top: 8px; }
#rail h2 .target { margin-left: auto; font-size: 10px; letter-spacing: 0; color: var(--dim); }
#centre { position: relative; overflow: hidden; }
.panel { margin-bottom: 8px; }
.panel h2 {
  display: flex; align-items: baseline; gap: 8px; margin: 0 0 5px;
  font-size: 12px; letter-spacing: .14em; color: var(--green-br);
  border-bottom: 1px solid var(--line); padding-bottom: 3px;
}
.panel h2 .target { margin-left: auto; font-size: 10px; letter-spacing: 0; color: var(--dim); }
.note { font-size: 10px; color: var(--dim); line-height: 1.5; margin: 8px 0 0; }
.row { display: flex; gap: 6px; }
.row .btn { flex: 1; }
.fld { display: block; margin: 5px 0 0; }
.fld span { display: block; font-size: 10px; letter-spacing: .1em; color: var(--dim); margin-bottom: 3px; }
.fld select {
  width: 100%; padding: 5px 6px; border-radius: 3px;
  background: #06180f; color: var(--text); border: 1px solid var(--line-hi);
  font: 11px ui-monospace, monospace;
}

/* No prose — the explanation is the row's tooltip. In the RAIL the name gets a
   line to itself and the controls sit under it, so a long name is never clipped;
   the strip overrides this back to a single line. */
.frow {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  padding: 3px 5px; border-bottom: 1px solid #102a19;
}
.frow:hover { background: #0b1f14; }
.f-name {
  flex: 1 0 100%;
  font-weight: 700; font-size: 12px; letter-spacing: .04em; color: var(--amber);
}
.f-params { display: flex; gap: 3px; }
.pin {
  width: 58px; padding: 2px 4px; border-radius: 3px;
  background: #06180f; color: var(--text); border: 1px solid var(--line-hi);
  font: 11px ui-monospace, monospace;
}

/* ── bottom strip: sensor / navigation-input faults ──────────────────────── */

#bottombar .bb-label {
  font-size: 10px; letter-spacing: .12em; color: var(--dim); white-space: nowrap;
}
#bottombar .bb-label b { color: var(--green-br); font-weight: 700; }
#bottombar .bb-sep { width: 1px; align-self: stretch; margin: 8px 2px; background: var(--line-hi); }
#sensors, #equipment { display: flex; align-items: center; gap: 5px; }
#equipment .frow, #sensors .frow { flex: 0 0 auto; }
/* Reuse the fault-row markup, laid out horizontally for the strip. */
#sensors .frow, #equipment .frow {
  border: 1px solid var(--line); border-bottom: 1px solid var(--line); border-radius: 5px;
  padding: 4px 7px; background: #0a1b12; gap: 5px;
}
#sensors .frow:hover, #equipment .frow:hover { background: #10281a; }
#sensors .f-name, #equipment .f-name { flex: 0 0 auto; font-size: 11px; }
#sensors .pin, #equipment .pin { width: 42px; }

/* ── per-target faults ───────────────────────────────────────────────────── */
#targets { max-height: 128px; overflow-y: auto; }
#targets .t-empty { padding: 8px 4px; font-size: 10px; color: var(--dim); }
#targets .trow {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 5px; border-bottom: 1px solid #102a19;
}
#targets .t-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; }
#targets .t-pos { font-size: 9px; color: var(--dim); white-space: nowrap; }
#targets .tchip {
  padding: 2px 6px; cursor: pointer; white-space: nowrap;
  font: 700 9px ui-monospace, monospace; letter-spacing: .04em;
  color: var(--dim); background: #0a1b12;
  border: 1px solid var(--line); border-radius: 3px;
}
#targets .tchip:hover { border-color: var(--line-hi); color: var(--text); }
#targets .tchip.on { color: #ffd9a8; background: #3a1d0b; border-color: #7a3a12; }
#fault-pending span { color: var(--amber); }

/* ── messages: a movable popup, like the trainee's ───────────────────────── */
#chat-pop {
  position: fixed; left: 240px; top: 110px; width: 380px; height: 380px;
  min-width: 280px; min-height: 240px;
  display: flex; flex-direction: column; z-index: 200;
  background: var(--panel); border: 1px solid var(--line-hi); border-radius: 6px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, .7);
  resize: both; overflow: hidden;
}
#chat-head {
  display: flex; align-items: center; gap: 8px; padding: 6px 9px; cursor: move;
  background: #0d1f16; border-bottom: 1px solid var(--line-hi);
}
#chat-head #chat-title { font: 700 12px ui-monospace, monospace; letter-spacing: .1em; color: var(--green-br); }
#chat-head .target { font-size: 10px; color: var(--dim); }
#chat-head .sp { flex: 1; }
#chat-head button {
  font: 700 10px ui-monospace, monospace; padding: 3px 9px; cursor: pointer;
  color: var(--text); background: #10241a; border: 1px solid var(--line-hi); border-radius: 3px;
}
.chat-send-row { display: flex; gap: 5px; padding: 7px 8px; border-top: 1px solid var(--line); }
/* Spoken messages. The player is full width under its own row so the scrub bar
   is usable, with the duration beside it - a long one can then be left for later
   without playing it to find out how long it is. */
.chat-row .c-audio { display: block; width: 100%; height: 30px; margin-top: 4px; }
.chat-row .c-len { font: 10px ui-monospace, monospace; color: #8fb8a0; letter-spacing: .06em; }
#chat-rec.rec { background: #3a1414; color: #ffd7d7; }
#chat-rec.rec:hover:not(:disabled) { background: #5a1c1c; }
#chat-rec:disabled { opacity: .45; cursor: not-allowed; }
#chat-rec.recording { background: #a81d1d; color: #fff; }
#chat-rec-row {
  display: flex; align-items: center; gap: 8px; padding: 5px 10px 8px;
  font: 11px ui-monospace, monospace; color: #ffb4b4;
}
#chat-rec-dot { color: #ff3b3b; animation: chat-rec-blink 1s steps(2, start) infinite; }
#chat-rec-time { font-weight: 700; letter-spacing: .08em; }
#chat-rec-note { color: #8fb8a0; flex: 1; }
@keyframes chat-rec-blink { to { opacity: 0; } }
#open-chat.alert { border-color: var(--amber); color: var(--amber); }

#chat-log {
  flex: 1; overflow-y: auto; padding: 7px 8px;
  background: #071410; border: 0;
}
#chat-log .chat-row { margin-bottom: 8px; }
#chat-log .c-who { font: 700 9px ui-monospace, monospace; letter-spacing: .08em; }
#chat-log .chat-row.ins .c-who { color: #7fdcff; }
#chat-log .chat-row.tr  .c-who { color: var(--amber); }
#chat-log .c-time { margin-left: 6px; font-size: 9px; color: var(--dim); }
#chat-log .c-text {
  margin-top: 2px; padding: 4px 7px; border-radius: 4px;
  font: 11px/1.45 ui-monospace, monospace; color: var(--text);
  white-space: pre-wrap; word-break: break-word;
}
#chat-log .chat-row.ins .c-text { background: #0d2233; border: 1px solid #1d4a66; }
#chat-log .chat-row.tr  .c-text { background: #2a1d08; border: 1px solid #5c4213; }
.chat-to { display: flex; gap: 10px; padding: 6px 8px 0; }
.pick { flex: 1; display: flex; align-items: center; gap: 5px; cursor: pointer; }
.pick span { font-size: 10px; letter-spacing: .06em; color: var(--dim); }
.pick input:checked + span { color: var(--green-br); }
#chat-text {
  flex: 1; min-width: 0; padding: 6px 7px; border-radius: 3px;
  background: #06180f; color: var(--text); border: 1px solid var(--line-hi);
  font: 11px ui-monospace, monospace;
}
#chat-text:focus { outline: none; border-color: var(--green); }

/* ── access gate ─────────────────────────────────────────────────────────── */
#gate {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(ellipse at center, #04120a 0%, #000 70%);
}
#gate .g-box {
  width: 430px; padding: 32px 34px 28px; text-align: center;
  background: var(--panel); border: 1px solid var(--line-hi); border-radius: 10px;
}
#gate .g-title { font-size: 21px; font-weight: 700; letter-spacing: .05em; color: var(--green-br); }
#gate .g-sub { font-size: 15px; color: var(--dim); margin: 10px 0 22px; }
#gate .g-cells { display: flex; gap: 10px; justify-content: center; }
#gate .g-cell {
  width: 50px; height: 62px; text-align: center;
  font: 700 30px/1 ui-monospace, monospace; color: var(--green-br);
  background: #06180f; border: 1px solid var(--line-hi); border-radius: 7px;
}
#gate .g-cell:focus { outline: none; border-color: var(--green); box-shadow: 0 0 8px rgba(0, 224, 24, .5); }
#gate .g-msg { min-height: 22px; margin: 16px 0 6px; font-size: 15px; color: var(--dim); }
#gate .g-msg.bad { color: var(--red); }
#gate .g-go {
  width: 100%; padding: 13px 0; border: none; border-radius: 7px; cursor: pointer;
  font: 700 16px/1 ui-monospace, monospace; letter-spacing: .14em;
  color: #000; background: var(--green);
}
#gate .g-go:disabled { background: #0d3a0d; color: #2a6a2a; cursor: default; }


/* ── top-bar tabs ─────────────────────────────────────────────────────────── */
.tabs { display: flex; gap: 3px; margin-left: 8px; }
.tab {
  font: 700 11px ui-monospace, monospace; letter-spacing: .08em;
  padding: 5px 14px; cursor: pointer; border-radius: 4px 4px 0 0;
  color: var(--dim); background: #0a1b12; border: 1px solid var(--line);
  border-bottom: none;
}
.tab.on { color: #04210c; background: var(--green); border-color: var(--green); }
#topbar .lbl { font-size: 10px; letter-spacing: .12em; color: var(--dim); }
#topbar .bar-sep { width: 1px; height: 22px; background: var(--line-hi); margin: 0 4px; }

/* ── chart tab ────────────────────────────────────────────────────────────── */
#chart-pane { position: absolute; inset: 0; display: flex; flex-direction: column; background: #04120b; }
#chart-tools {
  /* WRAPS. Nothing in this row may shrink: they are fixed-width controls,
     and the one item that could give was the hint, which collapsed into a
     column one character wide when the row ran out of room. A narrow window
     now costs a second row instead. */
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px; row-gap: 4px;
  padding: 6px 10px;
  background: var(--panel); border-bottom: 1px solid var(--line-hi);
}
#chart-tools .sp { flex: 1; }
#chart-tools .ct-label { font-size: 10px; letter-spacing: .12em; color: var(--dim); white-space: nowrap; }
#chart-tools .sp { min-width: 4px; }
/* ── session recording ───────────────────────────────────────────────────── */
/* The dot is the only thing on screen that says a run is being captured, so it
   pulses: a static red pip reads as a status light nobody looks at twice. */
.rec-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: #ff2d3f; margin-right: 5px; vertical-align: middle;
  animation: recpulse 1.6s ease-in-out infinite;
}
.rec-dot[hidden] { display: none; }
@keyframes recpulse { 0%,100% { opacity: 1; } 50% { opacity: .25; } }

/* A recording tile carries the same mark, in the corner of the card. */
.card.recording > .c-head::after {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: #ff2d3f; margin-left: 6px; flex: none;
  animation: recpulse 1.6s ease-in-out infinite;
}

.rec-all { font-size: 10px; color: var(--dim); display: flex; align-items: center; gap: 4px; }
.rec-list { max-height: 320px; overflow-y: auto; margin-top: 4px; }
.rec-row {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 8px;
  align-items: center; padding: 6px 7px; border: 1px solid var(--line);
  border-radius: 3px; margin-bottom: 4px; background: #06170e;
}
.rec-row.live { border-color: #7a2530; background: #1a0d10; }
.rec-row .rr-main { grid-column: 1; font-size: 11px; color: var(--green-br); }
.rec-row .rr-main b { font-weight: 700; }
.rec-row .rr-dim { color: var(--dim); font-weight: 400; margin-left: 6px; }
.rec-row .rr-meta { grid-column: 1; font-size: 9px; color: var(--dim); }
.rec-row button[data-del] { grid-column: 2; grid-row: 1 / span 2; }
.rr-none { font-size: 10px; color: var(--dim); padding: 6px 2px; }
.rec-row button[data-play] { grid-column: 2; }

/* ── playback transport ─────────────────────────────────────────────────── */
.pb-row { display: flex; align-items: center; gap: 5px; margin: 5px 0; }
.pb-row .sp { flex: 1; }
.pb-clock { font: 700 11px ui-monospace, monospace; color: var(--green-br); }
.btn.pb-x.on { border-color: #7a3a12; background: #3a1d0b; color: var(--amber); }
/* The bar and its marks share one box so a tick sits over the time it means. */
.pb-bar { position: relative; height: 22px; margin: 2px 0 4px; }
#pb-seek { width: 100%; margin: 0; }
.pb-marks { position: absolute; left: 0; right: 0; bottom: 0; height: 7px; pointer-events: none; }
.pb-marks i {
  position: absolute; width: 2px; height: 7px; border-radius: 1px;
  background: var(--amber); transform: translateX(-1px);
}
.pb-marks i.fault { background: #ff7a2e; }
.pb-marks i.control { background: #4a86ff; }
.pb-marks i.trainee { background: #3ed8a0; height: 4px; }
.pb-marks i.chat { background: #e8e8e8; }
/* Groups that must never be split by a wrap. */
.zoom-grp, .pan-pad { display: inline-flex; align-items: center; gap: 6px; flex: none; }
/* This row carries about twenty controls. Trimming the padding here, and only
   here, is what keeps it to a single line on a 1920-wide screen; the rail and
   the strip elsewhere keep the roomier default. */
#chart-tools .btn { padding: 5px 7px; }
#chart-tools .ct-sel { padding-inline: 4px; }
#chart-tools .ct-label b { color: var(--green-br); }
/* The line under the toolbar: hint on the left, route name box when a route
   is live. One line, always - long text is cut with an ellipsis rather than
   being allowed to push the chart down the screen. */
#chart-sub {
  display: flex; align-items: center; gap: 8px; padding: 3px 10px;
  background: #061a10; border-bottom: 1px solid var(--line);
  min-height: 19px; flex: none;
}
#chart-sub .ct-hint {
  flex: 1; min-width: 0; font-size: 10px; color: var(--dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#chart-sub .ct-name:not([hidden]) { display: block; }
#ct-range { font: 700 11px ui-monospace, monospace; color: var(--green-br); min-width: 56px; text-align: center; }
/* The chart and the contact list share the pane: the canvas takes what is left
   after the list, so hiding the list gives the picture the whole width back. */
#chart-body { flex: 1; display: flex; min-height: 0; }
#chart-area { position: relative; flex: 1; min-width: 0; display: flex; }
#chart { flex: 1; width: 100%; display: block; cursor: default; }

/* Wider since HDG/SPD became boxes; wider again with POSN, which adds a
   latitude and a longitude to every row. */
#ship-list {
  width: 360px; flex: none; display: flex; flex-direction: column;
  border-left: 1px solid var(--line); background: #061a10; min-height: 0;
}
#ship-list.with-pos { width: 560px; }
#ship-list:not(.with-pos) .sl-pos { display: none; }
#ship-list[hidden] { display: none; }
#ship-list .sl-head {
  padding: 5px 8px; font-size: 10px; letter-spacing: .12em; color: var(--dim);
  border-bottom: 1px solid var(--line); white-space: nowrap;
  display: flex; align-items: center; gap: 6px;
}
#ship-list .sl-tog {
  margin-left: auto; border: 1px solid var(--line-hi); background: #10241a; color: var(--dim);
  font: 600 9px ui-monospace, monospace; letter-spacing: .08em; padding: 2px 7px;
  cursor: pointer; border-radius: 2px;
}
#ship-list .sl-tog:hover { color: var(--green-br); }
#ship-list .sl-tog.on { color: #04140c; background: var(--green-br); border-color: var(--green-br); }
#ship-list .sl-head b { color: var(--green-br); }
#ship-list .sl-scroll { flex: 1; overflow-y: auto; min-height: 0; }
/* ── MAP LAYERS, under the contact list ───────────────────────────────────────
   Capped at a third of the column so the contacts - which are what the chart is
   FOR - always keep the lion's share of it, and scrolls inside that. */
#map-layers { flex: none; border-top: 1px solid var(--line); display: flex; flex-direction: column; max-height: 34%; }
#map-layers .sl-head { border-bottom: 1px solid var(--line); border-top: 0; }
#map-layers .sl-tog { margin-left: 0; }
#map-layers .sl-head .sl-tog:first-of-type { margin-left: auto; }
.ml-list { overflow-y: auto; min-height: 0; padding: 2px 0 4px; }
.ml-empty { display: block; padding: 6px 8px; font: 10px ui-monospace, monospace; color: var(--dim); }
.ml-row {
  display: flex; align-items: center; gap: 6px; padding: 2px 8px;
  font: 11px ui-monospace, monospace; color: var(--green); cursor: pointer;
}
.ml-row:hover { background: #0c2a1b; }
.ml-row input { accent-color: var(--green-br); margin: 0; cursor: pointer; }
.ml-row .ml-n { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ml-row .ml-c { color: var(--dim); font-size: 10px; }
.ml-row.off .ml-n { color: var(--dim); }

#sl-table { width: 100%; border-collapse: collapse; font: 11px ui-monospace, monospace; }
#sl-table th {
  position: sticky; top: 0; background: #0a2417; color: var(--dim);
  font-size: 9px; letter-spacing: .08em; font-weight: 600; text-align: left;
  padding: 4px 5px; border-bottom: 1px solid var(--line);
}
#sl-table td { padding: 3px 5px; border-bottom: 1px solid #0d2419; color: var(--green); }
#sl-table tr.own td { color: #7ff0a8; }
#sl-table tr.sel td { background: #10281b; }
#sl-table tr.warn td { color: #ff6a6a; }
#sl-table td.num, #sl-table th.num { text-align: right; }
#sl-table .sl-go {
  border: 1px solid var(--line-hi); background: #10241a; color: var(--green-br);
  font: 9px ui-monospace, monospace; padding: 1px 5px; cursor: pointer; border-radius: 2px;
}
#sl-table .sl-go:hover { background: #16412c; }
/* Each vessel's chart colour, as a small square before her ID. */
#sl-table td[data-f="id"] { white-space: nowrap; }
#sl-table td[data-f="id"]::before {
  content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 5px;
  vertical-align: 0; background: var(--sw, transparent);
}
#sl-table td.sl-nm { max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#sl-table td.sl-pos { white-space: nowrap; }
/* HDG / SPD order boxes. Amber while an order is on its way to the station. */
#sl-table .sl-in {
  width: 42px; box-sizing: border-box; padding: 1px 3px; border-radius: 2px;
  border: 1px solid #14402a; background: #04140c; color: inherit;
  font: inherit; text-align: right;
}
#sl-table .sl-in:hover { border-color: var(--line-hi); }
#sl-table .sl-in:focus { outline: none; border-color: var(--green-br); background: #0b2a1a; color: #eaffef; }
#sl-table .sl-in.pending { color: #ffc861; border-color: #6b5320; }

/* Pan pad: two arrows stacked between two, so it reads as a compass rose and
   takes one button's worth of width in an already full toolbar. */
/* THE PAD MATCHES THE ROW, it does not set it.

   Written as .btn.pan these lost to #chart-tools .btn - an id beats two
   classes - so the pan buttons kept the full padding, the stacked pair grew
   past the fixed height the pad had been given, and the DOWN arrow was pushed
   out of the pad and clipped. Scoped under #chart-tools they win, and the pad
   takes its height from the row rather than naming a number that any change
   to button padding would falsify again. */
#chart-tools .pan-pad {
  display: inline-flex; align-items: stretch; align-self: stretch;
  gap: 1px; flex: none;
}
#chart-tools .pan-v {
  display: flex; flex-direction: column; gap: 1px; min-height: 0;
}
#chart-tools .btn.pan {
  padding: 0 4px; min-width: 16px; font-size: 9px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
#chart-tools .pan-v .btn.pan { flex: 1 1 0; min-height: 0; }
.ct-name {
  width: 110px; background: #06170e; color: var(--green-br);
  border: 1px solid var(--line-hi); border-radius: 2px;
  font: 11px ui-monospace, monospace; padding: 2px 5px;
}

/* Floating panel for the selected target. */
#chart-sel {
  position: absolute; right: 14px; bottom: 14px; width: 244px; padding: 9px 10px;
  background: var(--panel); border: 1px solid var(--green); border-radius: 6px;
  box-shadow: 0 6px 22px rgba(0,0,0,.7);
}
#chart-sel .cs-name { font: 700 12px ui-monospace, monospace; color: var(--green-br); padding-right: 22px; }
/* Opened by a double-click, so it needs its own way out besides open water. */
#chart-sel .cs-x {
  position: absolute; top: 5px; right: 6px; width: 20px; height: 20px; padding: 0;
  background: transparent; border: 1px solid var(--line, #2a3a2a); border-radius: 3px;
  color: var(--dim); font: 700 13px/1 ui-monospace, monospace; cursor: pointer;
}
#chart-sel .cs-x:hover { color: var(--text); border-color: var(--green); }
#chart-sel .cs-pos { font-size: 10px; color: var(--dim); margin: 2px 0 7px; }
/* Three per-ship faults now share this row (AIS FAIL / SART / FALSE ECHO);
   wrapping keeps the longest label readable instead of clipping it. */
#chart-sel .cs-btns { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 6px; }
#chart-sel .cs-btns .btn { flex: 1 1 62px; padding-inline: 4px; }
#chart-sel .cs-pos-row input { width: 9.5em; }
.cs-row { display: flex; align-items: flex-end; gap: 5px; }
#chart-sel .cs-row label { font-size: 9px; color: var(--dim); display: flex; flex-direction: column; gap: 2px; }
#chart-sel .cs-row input {
  width: 52px; padding: 2px 4px; border-radius: 3px;
  background: #06180f; color: var(--text); border: 1px solid var(--line-hi);
  font: 11px ui-monospace, monospace;
}
#chart-sel .cs-note { margin-top: 7px; font-size: 9px; color: var(--dim); }

/* ── popups (exercise · sart/ais · messages) ──────────────────────────────── */
.pop {
  position: fixed; left: 280px; top: 110px; width: 340px;
  display: flex; flex-direction: column; z-index: 200;
  background: var(--panel); border: 1px solid var(--line-hi); border-radius: 6px;
  box-shadow: 0 8px 30px rgba(0,0,0,.7);
  resize: both; overflow: hidden;
}
#chat-pop { width: 380px; height: 380px; min-width: 280px; min-height: 240px; }
#tgt-pop { width: 320px; height: 300px; }
.pop-head {
  display: flex; align-items: center; gap: 8px; padding: 6px 9px; cursor: move;
  background: #0d1f16; border-bottom: 1px solid var(--line-hi);
}
.pop-head .pop-title { font: 700 12px ui-monospace, monospace; letter-spacing: .1em; color: var(--green-br); }
.pop-head .target { font-size: 10px; color: var(--dim); }
.pop-head .sp { flex: 1; }
.pop-head button {
  font: 700 10px ui-monospace, monospace; padding: 3px 9px; cursor: pointer;
  color: var(--text); background: #10241a; border: 1px solid var(--line-hi); border-radius: 3px;
}
.pop-body { padding: 9px 10px; overflow-y: auto; flex: 1; }

/* Strip chips: a single toggle each, so ten fit across without scrolling. */
#equipment .frow, #sensors .frow {
  padding: 3px 4px; gap: 3px;
}
.btn.chip { letter-spacing: 0; padding: 4px 6px; }
.btn.chip.on { border-color: #7a3a12; background: #3a1d0b; color: var(--amber); }
#equipment .pin, #sensors .pin { width: 40px; }

/* Strip rows stay on ONE line — a chip is a single toggle, so it never needs the
   rail's two-line treatment. */
#equipment .frow, #sensors .frow { flex-wrap: nowrap; }
#equipment .f-name, #sensors .f-name { flex: 0 0 auto; }

/* Fault state at a glance: SET lights when the fault IS in force, CLR lights
   when it is not, so a rail row reads without opening anything. */
.btn.sm.lit { border-color: var(--line-hi); background: #10241a; color: var(--green-br); }
.btn.on { border-color: #7a3a12; background: #3a1d0b; color: var(--amber); }
/* State pairs: the lit one says which state the station is IN, not what the
   button would do. ENVIRONMENT joins them - the active RAIN step and SET/CLR are
   selections, not injected abnormalities, so they must not wear the amber the
   fault chips use for "something is wrong with this radar". */
#st-pause.on, #st-resume.on,
#wx-rain .wx-r.on, #wx-set.on, #wx-clr.on { border-color: var(--green); background: #12401f; color: var(--green-br); }

/* ── parameter fields ─────────────────────────────────────────────────────────
   The spin buttons are what made a narrow field look like it held stray
   characters — at 42px the arrows sat on top of the digits. Off everywhere, and
   the field is wide enough for a signed one-decimal value. */
.pin::-webkit-outer-spin-button,
.pin::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pin { -moz-appearance: textfield; appearance: textfield; text-align: center; }

/* A TIME field is not a number field. .pin is 58px and strips the spinners,
   which suits "240" and cuts "12:00" off at the colon - the minutes were
   simply not on screen. Wide enough for hh:mm plus the browser's own clock
   button, and the appearance reset undone so that button still renders. */
/* #env .pin sets 52px and an ID beats a class, so this has to carry the id
   too - as a plain .pin-time it lost the cascade and the field stayed 52px
   with the minutes still cut off. Doubling the class keeps it ahead of
   #env .pin without depending on which rule comes later in the file. */
#env .pin.pin-time {
  width: 92px; text-align: left; padding-right: 2px;
  -moz-appearance: auto; appearance: auto;
}

/* Captioned field: the caption sits above so "lat °" and "lat ′" are readable
   without hovering — an offset is meaningless if you cannot see its units. */
.pinw { display: flex; flex-direction: column; gap: 0; }
.pinw > span {
  font-size: 8px; line-height: 1; letter-spacing: .04em; color: var(--dim); text-align: center;
}
#sensors .pinw .pin, #equipment .pinw .pin { width: 48px; }

/* A parameterised strip fault is a GROUP, not a lone chip: give it a darker
   well and a border so it reads as one unit next to plain toggles like GPS LOST
   and GYRO ERR. */
/* Only the parameterised rows get the well — a plain toggle is its own button
   and a box around it just competes with the chip's own border. */
#sensors .frow.grp, #equipment .frow.grp {
  background: #020a06;
  border: 1px solid var(--line-hi);
  border-radius: 5px;
  padding: 2px 5px;
}
#sensors .frow.grp:hover, #equipment .frow.grp:hover { background: #05130c; }
#sensors .frow:not(.grp), #equipment .frow:not(.grp) { background: none; border: 0; padding: 0; }

/* One convention for state across the whole console:
     .on  = this fault IS in force   (amber, lit)
     .lit = the neutral/cleared side (green outline)
   Used by the rail's SET/CLR, the strip chips, the chart's target panel and
   PAUSE/RESUME, so a lit control always means the same thing. */
#chart-sel .btn.on { border-color: #7a3a12; background: #3a1d0b; color: var(--amber); }
#chart-sel .btn.lit { border-color: var(--line-hi); background: #10241a; color: var(--green-br); }

/* Cursor range/bearing from own ship — a measurement, so give it a fixed width
   and tabular figures or it jitters as the digits change. */
#ct-cursor {
  /* Range and bearing, then the position and the charted depth under the
     pointer. It is the widest thing in the bar and it must not wrap: a readout
     that jumps to a second row moves every control beside it. */
  font: 700 11px ui-monospace, monospace; color: var(--green-br);
  min-width: 108px; text-align: right; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
#ct-lock.on { border-color: var(--green); background: #12401f; color: var(--green-br); }

/* ── right-click ship menu (chart) ────────────────────────────────────────────
   Built on demand at the cursor and removed on the next click anywhere, so it
   holds no state that could drift from the 2 Hz chart redraw underneath it. */
#ship-menu {
  position: fixed; z-index: 1200; min-width: 208px; padding: 4px;
  background: var(--panel); border: 1px solid var(--green); border-radius: 5px;
  box-shadow: 0 8px 26px rgba(0,0,0,.75);
}
#ship-menu .sm-head {
  padding: 4px 8px 6px; margin-bottom: 3px;
  border-bottom: 1px solid var(--line-hi);
  font: 700 11px ui-monospace, monospace; color: var(--green-br);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#ship-menu .sm-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 5px 8px; border: 0; border-radius: 3px; background: none;
  color: var(--text); font: 600 11px ui-monospace, monospace; letter-spacing: .03em;
}
#ship-menu .sm-item:hover { background: #16351f; color: #fff; }


/* ── exercise builder popup ───────────────────────────────────────────────── */
#build-pop { width: 420px; }
#build-pop .pop-body { max-height: 72vh; overflow-y: auto; }
#build-pop .row { display: flex; gap: 6px; }
#build-pop .fld.sm { flex: 1; }
#build-pop textarea {
  width: 100%; resize: vertical; padding: 3px 5px; border-radius: 3px;
  background: #06180f; color: var(--text); border: 1px solid var(--line-hi);
  font: 11px ui-monospace, monospace;
}
.bx-sec {
  margin: 10px 0 5px; padding-bottom: 3px; border-bottom: 1px solid var(--line-hi);
  font: 700 10px ui-monospace, monospace; letter-spacing: .08em; color: var(--green-br);
}
.bx-dim { font-weight: 400; color: var(--dim); letter-spacing: 0; }
.bx-note { margin: 4px 0 8px; font-size: 10px; line-height: 1.4; color: var(--dim); }
.bx-row {
  display: flex; align-items: center; gap: 5px; margin-bottom: 4px;
}
.bx-row input, .bx-row select {
  padding: 3px 4px; border-radius: 3px; background: #06180f; color: var(--text);
  border: 1px solid var(--line-hi); font: 11px ui-monospace, monospace; min-width: 0;
}
.bx-row .bx-name { flex: 1 1 40%; }
.bx-row .bx-type { flex: 1 1 44%; }
.bx-row .bx-pos { font-size: 9px; color: var(--dim); white-space: nowrap; }
.bx-row .bx-x {
  cursor: pointer; border: 1px solid #7a1414; background: #2a0c0c; color: #ff9c9c;
  border-radius: 3px; padding: 2px 6px; font: 700 11px ui-monospace, monospace;
}
/* DEL takes the contact off the station's picture - the one removal here that
   cannot be taken back - so it is amber, apart from the red × that only leaves
   it out of the file. It had no style at all and drew as a grey system button. */
.bx-row .bx-del {
  cursor: pointer; border: 1px solid #7a3a12; background: #2a1408; color: var(--amber);
  border-radius: 3px; padding: 2px 6px; font: 700 10px ui-monospace, monospace; letter-spacing: .04em;
}
.bx-row .bx-del:hover { background: #3a1d0b; }
.bx-row .bx-val { width: 56px; }
.bx-row .bx-w { width: 44px; }
.bx-msg { min-height: 16px; margin: 8px 0 2px; font-size: 10px; line-height: 1.4; }
.bx-msg.ok  { color: #7bf29a; }
.bx-msg.bad { color: #ff9c9c; }

/* ── exercise builder: the result / refusal / name-taken dialog ────────────
   A MODAL over everything, centred. These three dialogs had no style at all,
   so each was appended to the end of the page as plain text - bottom left,
   pushing the whole layout up - instead of standing in front of it. */
.save-ok {
  position: fixed; inset: 0; z-index: 5000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, .6);
}
.save-ok .so-box {
  width: 420px; max-width: calc(100vw - 32px); max-height: calc(100vh - 32px); overflow-y: auto;
  padding: 18px 20px 16px; text-align: center;
  background: var(--panel); border: 1px solid var(--line-hi); border-radius: 6px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, .8);
  font: 12px ui-monospace, monospace; color: var(--text);
}
.save-ok.partial .so-box { border-color: #7a3a12; }
.save-ok .so-head {
  font: 700 14px ui-monospace, monospace; letter-spacing: .12em; color: var(--green-br);
  padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
.save-ok.partial .so-head { color: var(--amber); }
.save-ok .so-title { margin: 12px 0 4px; font-size: 15px; font-weight: 700; color: #fff; word-break: break-word; }
.save-ok .so-sub { margin: 4px 0; color: var(--dim); line-height: 1.45; }
.save-ok .so-sub b { color: var(--text); }
.save-ok .so-list { list-style: none; margin: 6px 0 12px; padding: 0; }
.save-ok .so-list li { padding: 2px 0; font-weight: 700; color: var(--green-br); }
.save-ok .so-list li::before { content: "\2713  "; color: var(--green); }
.save-ok .so-bad, .save-ok .so-warn {
  margin: 8px 0 12px; padding: 7px 9px; border-radius: 3px; text-align: left; line-height: 1.45;
}
.save-ok .so-bad { border: 1px solid #7a1414; background: #2a0c0c; color: #ff9c9c; }
.save-ok .so-bad ul { margin: 4px 0 0; padding-left: 16px; }
.save-ok .so-warn { border: 1px solid #7a3a12; background: #2a1408; color: var(--amber); }
.save-ok .fld { margin: 4px 0 12px; }
.save-ok input[type="text"] {
  width: 100%; padding: 5px 6px; border-radius: 3px;
  background: #06180f; color: var(--text); border: 1px solid var(--line-hi);
  font: 12px ui-monospace, monospace;
}
.save-ok input[type="text"]:focus { outline: none; border-color: var(--green); }
.save-ok .so-btns { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.save-ok #so-close { min-width: 110px; margin-top: 4px; }
.save-ok .so-btns .btn { flex: 1 1 auto; min-width: 118px; }
/* Replacing destroys an exercise somebody arranged by hand, so it does not look
   like the safe option sitting next to it. */
.save-ok #so-replace { border-color: #7a1414; background: #2a0c0c; color: #ff9c9c; }
.save-ok #so-replace:hover { background: #4a1010; }
/* A ghost reads as an ordinary row otherwise, and a ghost saved as real traffic
   is not visibly wrong until the trainee sees an echo that should not exist. */
.bx-row.ghost .bx-name { border-style: dashed; color: #9fd3ff; }
.bx-note.warn { color: #ffb84d; }

/* ════════════════════════════════════════════════════════════════════════════
   RESTORED 16 Sep 2026. Everything from here to the next rule of this kind was
   in this file on 6 Sep (patch/2026-09-06-playback) and had gone missing since:
   the AI and REPORT windows, and the route/profile pickers, had no style left
   at all and drew as bare browser controls.
   ════════════════════════════════════════════════════════════════════════════ */

/* Route and profile pickers. The picker is narrow on purpose: the route's own
   label is drawn on the chart, so this only has to disambiguate. */
.ct-sel {
  background: #10241a; color: var(--text); border: 1px solid var(--line-hi);
  border-radius: 4px; font: 700 11px ui-monospace, monospace; padding: 5px 6px; max-width: 150px;
}
#bx-prof.ct-sel { max-width: none; width: 100%; }
#ct-route-new.on, #ct-route-loop.on {
  border-color: var(--green); background: #12401f; color: var(--green-br);
}

/* ── instructor AI, as a chat ─────────────────────────────────────────────────
   Modes on top, the conversation filling the middle, the composer pinned to
   the bottom. */
#ai-pop { width: 620px; height: 560px; }
.ai-body { display: flex; flex-direction: column; min-height: 0; height: 100%; }
.ai-modebar { display: flex; gap: 6px; }
.ai-modebar .btn { flex: 1; }
.ai-modebar .btn.on { border-color: var(--green); background: #12401f; color: var(--green-br); }
.ai-modedesc { margin: 6px 0; font-size: 10px; color: var(--dim); line-height: 1.5; }

#ai-log {
  flex: 1; min-height: 0; overflow-y: auto;
  border: 1px solid var(--line); border-radius: 4px; background: #04120b;
  padding: 8px; display: flex; flex-direction: column; gap: 8px;
}
.ai-msg { border: 1px solid var(--line); border-radius: 4px; padding: 6px 8px; font-size: 11px; line-height: 1.55; }
.ai-msg .who { display: block; font: 700 9px ui-monospace, monospace; letter-spacing: .1em; color: var(--dim); margin-bottom: 3px; }
.ai-msg.me { background: #0d2318; border-color: var(--line-hi); align-self: flex-end; max-width: 85%; }
.ai-msg.ai { background: var(--panel); align-self: flex-start; max-width: 92%; white-space: pre-wrap; }
.ai-msg.err { border-color: #7a1414; background: #2a0c0c; color: #ff9c9c; }
.ai-msg.busy { color: var(--dim); font-style: italic; }

/* Proposed actions: buttons, never auto-fired. The model suggests, the
   instructor commits. */
.ai-act { display: flex; align-items: center; gap: 6px; margin-top: 5px;
          border: 1px solid #7a3a12; border-radius: 4px; padding: 4px 6px; background: #2a1408; }
.ai-act span { flex: 1; color: var(--amber); }
.ai-act.done { opacity: .5; border-color: var(--line); background: var(--panel); }
.ai-act.done span { color: var(--dim); }
/* What the assistant changed (green tick) and what it refused (amber cross).
   Confirmation only - it has already been applied. */
.ai-done, .ai-refused {
  display: flex; align-items: baseline; gap: 7px; margin-top: 4px;
  padding: 3px 7px; border-radius: 3px; white-space: normal;
}
.ai-done { border: 1px solid #1f5a36; background: #0b2417; color: var(--green-br); }
.ai-refused { border: 1px solid #7a3a12; background: #2a1408; color: var(--amber); }
.ai-done b, .ai-refused b { flex: none; }

.ai-input { display: flex; gap: 6px; margin-top: 8px; }
.ai-input textarea {
  flex: 1; resize: none; background: #04120b; color: var(--text);
  border: 1px solid var(--line-hi); border-radius: 4px; padding: 6px 8px;
  font: 11px/1.45 ui-monospace, monospace;
}
.ai-input textarea:focus { outline: none; border-color: var(--green); }
.ai-btns { display: flex; flex-direction: column; gap: 4px; }
.ai-btns button {
  font: 700 10px ui-monospace, monospace; letter-spacing: .06em; cursor: pointer;
  color: var(--text); background: #10241a; border: 1px solid var(--line-hi);
  border-radius: 4px; padding: 5px 9px;
}
.ai-btns button:hover:not(:disabled) { background: #16351f; color: #fff; }
.ai-btns button:disabled { opacity: .4; cursor: default; }
#ai-go { border-color: var(--green); background: #12401f; color: var(--green-br); }

/* ── session assessment (REPORT) ──────────────────────────────────────────────
   The deterministic header, then the debrief, with the actions in the title
   bar. */
#assess-pop { width: 780px; height: 600px; }
.assess-body { display: flex; flex-direction: column; min-height: 0; height: 100%; }
#assess-stats {
  white-space: pre-wrap; font: 11px/1.55 ui-monospace, monospace; color: var(--green-br);
  border-bottom: 1px solid var(--line); padding-bottom: 6px; margin-bottom: 6px;
}
#assess-log {
  flex: 1; min-height: 0; overflow-y: auto; font-size: 11px; line-height: 1.6;
  color: var(--text); padding-right: 4px;
}
#assess-log h1, #assess-log h2, #assess-log h3 { font-size: 12px; color: var(--green-br); margin: 10px 0 4px; }
#assess-log ul, #assess-log ol { margin: 4px 0 8px; padding-left: 18px; }
#assess-log li { margin: 2px 0; }
#assess-log strong { color: var(--green-br); }
#assess-log p { margin: 4px 0; }
#assess-log code { color: var(--amber); }
.assess-note { color: var(--dim); font-style: italic; }

#assess-history { max-height: 190px; overflow-y: auto; border-bottom: 1px solid var(--line); margin-bottom: 6px; }
.hist-row {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; cursor: pointer;
  background: var(--panel); color: var(--text); border: 1px solid var(--line);
  border-radius: 4px; padding: 4px 6px; margin-bottom: 3px; font: 10px ui-monospace, monospace;
}
.hist-row:hover { background: #16351f; }
.hist-when { color: var(--dim); }
.hist-scn { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--green-br); }
.hist-v { font-weight: 700; }
.hist-v.pass { color: var(--green-br); }
.hist-v.fail { color: var(--red); }
.hist-meta { color: var(--dim); }
.hist-empty { color: var(--dim); font-size: 10px; padding: 6px; }
#assess-hist.on { border-color: var(--green); background: #12401f; color: var(--green-br); }
/* ═══════════════════════════ end of restored rules ═══════════════════════════ */

/* A ship stopped by charted land. The loudest state on a tile: nothing else
   there needs the instructor to act before the exercise can continue. */
.pill.aground { color: #fff; background: #7a1414; border-color: #ff5a5a; }

/* Why an embedded station view could not be shown. Configuration, not failure,
   so it reads as an instruction rather than an error. */
.f-off.f-why {
  padding: 10px 12px; text-align: left; line-height: 1.5;
  color: #ffd9b0; font-size: 10px; white-space: normal;
}

/* Heading entry, opened from the right-click ship menu. Same shell as the menu
   so it reads as the menu changing shape, not a new window appearing. */
#ship-menu .sm-row { display: flex; align-items: center; gap: 5px; padding: 5px 6px 3px; }
#ship-menu .sm-row input {
  width: 74px; padding: 4px 6px; border-radius: 3px; text-align: center;
  background: #06180f; color: var(--text); border: 1px solid var(--line-hi);
  font: 700 13px ui-monospace, monospace; appearance: textfield;
}
#ship-menu .sm-unit { color: var(--dim); font: 700 12px ui-monospace, monospace; }
#ship-menu .sm-go {
  margin-left: auto; cursor: pointer; padding: 4px 12px; border-radius: 3px;
  background: #16351f; color: var(--green-br); border: 1px solid var(--green);
  font: 700 11px ui-monospace, monospace; letter-spacing: .06em;
}
#ship-menu .sm-go:hover { background: #1d4a2b; color: #fff; }
#ship-menu .sm-note { padding: 2px 7px 5px; font-size: 9px; color: var(--dim); }

/* ── ENVIRONMENT (left rail) ──────────────────────────────────────────────────
   Sea state and precipitation. Sits with the faults because it is injected the
   same way, but is deliberately titled apart: nothing here is broken. */
.wx-lbl {
  margin: 6px 0 3px; font: 700 9px ui-monospace, monospace;
  letter-spacing: .08em; color: var(--dim);
}
.wx-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 4px; }
.wx-row .btn.sm { flex: 1 1 auto; padding: 3px 4px; font-size: 9px; }
/* No colour of its own: the active RAIN step and the SET/CLR pair light with the
   console-wide .btn.on amber, the same signal the fault chips and PAUSE/RESUME
   already use for "this is what the station is currently doing". */
#env .pin { width: 52px; }
#wx-now { margin-top: 6px; color: var(--dim); }

/* ── builder SAVE TO scope ────────────────────────────────────────────────────
   Two mutually exclusive targets for the file, lit with the same state-pair
   green the rest of the console uses for "this is the one in force". */
.bx-scope { display: flex; gap: 4px; margin: 2px 0 4px; }
.bx-scope .btn { flex: 1 1 0; }
.bx-scope .btn.on { border-color: var(--green); background: #12401f; color: var(--green-br); }

/* ── SCHEDULE tab ─────────────────────────────────────────────────────────────
   Faults on the exercise clock: an editor on the left, the plan and its timeline
   on the right. Same furniture as the CHART tab so the two read as siblings. */
/* FAULTS AND FAILURES, on one page.
   Left: what changes the PICTURE and the conditions - faults, measurement
   errors, weather, antenna. Right: the schedule that fires any of them on the
   exercise clock. Across the foot: the outright failures, which are a single
   row of keys and read better as a strip than as another column.
   The rail scrolls on its own so a short window loses nothing. */

/* ── SCHEDULE (restored) ─────────────────────────────────────────────────────
   The rules for the schedule's own two-column body, its form and its timeline.
   They were lost when the faults page was redesigned - the replacement reached
   further down the file than it should have - and without them the body fell
   back to `display: block`: one stacked column, with the timeline squeezed into
   a strip too narrow to read a tick off. The overrides for THIS page (padding,
   colours, the heading) come after and still win. */
#sched-tools {
  display: flex; align-items: center; gap: 10px; padding: 6px 10px;
  background: var(--panel); border-bottom: 1px solid var(--line);
}
#sched-tools .sp { flex: 1; }
.sched-clock {
  font: 700 15px ui-monospace, monospace; color: var(--green-br);
  padding: 1px 8px; border: 1px solid var(--line-hi); border-radius: 3px; background: #0c2c1a;
}
.sched-state { font-size: 11px; color: var(--dim); }
#sched-body { flex: 1; display: grid; grid-template-columns: 330px 1fr; gap: 12px; padding: 12px; overflow: hidden; }
.sched-form { align-self: start; background: var(--panel); border: 1px solid var(--line); border-radius: 6px; padding: 10px; }
.sf-row { display: flex; gap: 6px; align-items: flex-end; }
.sf-row .fld { flex: 1; }
.sf-params { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.sf-params .fld { flex: 1 1 44%; }
.sched-right { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
/* timeline */
#sched-timeline { flex: 0 0 auto; margin-bottom: 10px; }
.tl-axis { position: relative; height: 14px; font: 10px ui-monospace, monospace; color: var(--dim); }
.tl-tick { position: absolute; transform: translateX(-50%); }
.tl-track {
  position: relative; height: 34px; background: #0b1a12;
  border: 1px solid var(--line); border-radius: 4px; overflow: hidden;
}
.tl-ev { position: absolute; top: 4px; bottom: 4px; border-radius: 2px; min-width: 3px;
         border: 1px solid #7a5a12; background: #3a2d0b; }
.tl-ev.armed { border-color: #2f7d4b; background: #123f22; }
.tl-ev.on    { border-color: var(--amber); background: #5a3410; box-shadow: 0 0 6px rgba(255,157,46,.5); }
.tl-ev.done  { border-color: var(--line); background: #14201a; }
/* NOW: the exercise clock. Stops moving when the exercise is paused, which is
   exactly what the schedule does. */
.tl-now { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--green);
          box-shadow: 0 0 6px var(--green); }
/* list */
#sched-list { flex: 1; overflow-y: auto; }
.se-row {
  display: grid; grid-template-columns: 52px 52px 1fr 62px auto auto auto;
  gap: 6px; align-items: center; padding: 4px 6px; font-size: 11px;
  border: 1px solid var(--line); border-radius: 4px; margin-bottom: 4px; background: var(--panel);
}
.se-row.on { border-color: var(--amber); }
.se-row.done { opacity: .55; }
.se-row.editing { border-color: var(--green); box-shadow: 0 0 0 1px var(--green) inset; }
.se-at, .se-for { font: 700 11px ui-monospace, monospace; color: var(--green-br); }
.se-for { color: var(--dim); }
.se-name { color: var(--text); }
.se-p { display: block; font-size: 10px; color: var(--dim); }
.se-state { font: 700 9px ui-monospace, monospace; letter-spacing: .08em; color: var(--dim); }
.se-row.on .se-state { color: var(--amber); }

/* ════════════════════════════════════════════════════════════════════════════
   FAULTS AND FAILURES

   One page about ONE station, in three parts: what is BROKEN, what the
   CONDITIONS are, and what is SCHEDULED to break later.

   The rules that make it read as one page rather than seven tools:

   - ONE TYPE SIZE. 12px for every label, key and field. The blocks came from a
     232px rail, a 58px foot strip and a full-width schedule, each set to
     whatever fitted the space it used to live in; side by side that reads as
     carelessness, and a smaller size says "this matters less" when it does not.
   - ONE LABEL COLOUR. Every name, legend and caption is --text. Before, fault
     names were amber, field legends dim, headings bright green and the strip
     labels grey - four colours doing no work. Colour is left to say only two
     things now: a section heading (green, structure) and a control that is ON
     (amber, state).
   - THE STATION IS NAMED ONCE. Every control on the page acts on it, so a tag
     on each box was the same word four times.
   ════════════════════════════════════════════════════════════════════════════ */
#faults-pane {
  position: absolute; inset: 0;
  overflow-y: auto;
  padding: 12px;
  background: var(--bg);
  display: flex; flex-direction: column; gap: 12px;
  font-size: 12px;
  /* CAPITALS THROUGHOUT. Half this page was already shouting - fault names,
     section headings, every key - and the other half was sentence case, which
     read as two pages stitched together. One case, decided here rather than in
     forty strings, so a name added later cannot get it wrong. Typed values are
     exempt below: what an instructor types is data, not a label. */
  text-transform: uppercase;
}
#faults-pane input,
#faults-pane select { text-transform: none; }

/* The page's own head: what this is, which station, and the one key that
   undoes all of it. */
#fp-head {
  display: flex; align-items: center; gap: 12px;
  padding: 0 2px 8px;
  border-bottom: 1px solid var(--line-hi);
}
#fp-title { font-size: 12px; font-weight: 700; letter-spacing: .14em; color: var(--green-br); }
.fp-target { font-size: 12px; color: var(--text); letter-spacing: .04em; }
#fp-head .sp { flex: 1; }

.fp-sec {
  background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
  padding: 10px 12px 12px;
  min-width: 0;
}
.fp-sec > h2 {
  display: flex; align-items: baseline; gap: 8px; margin: 0 0 8px;
  font-size: 12px; font-weight: 700; letter-spacing: .14em; color: var(--green-br);
  border-bottom: 1px solid var(--line); padding-bottom: 5px;
}
.fp-sec > h2 .h2-note {
  font-size: 12px; font-weight: 400; letter-spacing: 0; color: var(--dim);
}
/* Groups inside a section: a quiet caption, not a second heading competing
   with the one above it. */
.fp-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 14px;
  align-items: start;
}
.fp-grp { min-width: 0; }
/* Two groups sharing one column: EQUIPMENT over ANTENNA, SENSOR & NAV over
   ENVIRONMENT. The short fault groups leave room under them, and filling it
   is what lets the whole page fit on one screen. */
.fp-stack { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
/* A CONDITION sits among the faults but is not one - the caption says so, in
   the quiet tone of a note rather than a second heading. */
.fp-grp > h3 .h3-note {
  margin-left: 6px; font-weight: 400; letter-spacing: .06em; color: var(--dim);
}
.fp-grp > h3 {
  margin: 0 0 5px;
  font-size: 12px; font-weight: 700; letter-spacing: .1em; color: var(--text);
  border-bottom: 1px solid var(--line); padding-bottom: 3px;
}

/* ── ONE LABEL COLOUR, ONE SIZE ──────────────────────────────────────────── */
#faults-pane .f-name,
#faults-pane .wx-lbl,
#faults-pane .pinw > span,
#faults-pane label,
#faults-pane .fld > span,
#faults-pane .note,
#faults-pane .sched-state,
#faults-pane .ct-label { color: var(--text); font-size: 12px; letter-spacing: .04em; }
#faults-pane .wx-lbl { margin: 8px 0 3px; font-weight: 700; }
#faults-pane .note { color: var(--dim); line-height: 1.5; }
#faults-pane .target { display: none; }        /* named once, at the top */

/* Rows: no hairline per row inside a group - the group already has an edge,
   and a rule under every line turned a short list into a ledger. */
#faults-pane .frow {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  padding: 4px 2px; border-bottom: 0;
}
#faults-pane .frow:hover { background: transparent; }
#faults-pane .f-name { flex: 1 0 100%; font-weight: 700; }
/* EQUIPMENT and SENSOR & NAV read DOWN their column, one fault to a line, like
   the two groups beside them. Wrapped into rows they packed tight and saved
   width the page does not need - it has height - while a fault carrying four
   inputs (GPS SPOOF) broke across two lines and stopped looking like one
   control. Down a column, every fault is one row and the eye counts them. */
#faults-pane #equipment, #faults-pane #sensors {
  display: flex; flex-direction: column; gap: 4px;
  /* Against the LEFT edge, like every other group on the page. The base rule
     these share with the old foot strip centres them, which in a column pushes
     each row to the middle and leaves the list with no edge to read down. */
  align-items: flex-start;
}
#faults-pane #equipment .frow, #faults-pane #sensors .frow {
  flex: 0 0 auto; border: 1px solid var(--line); border-radius: 4px;
  padding: 4px 7px; background: transparent;
  justify-content: flex-start;
}
#faults-pane #equipment .frow:hover, #faults-pane #sensors .frow:hover { background: #10281a; }
#faults-pane #equipment .f-name, #faults-pane #sensors .f-name { flex: 0 0 auto; font-size: 12px; }
#faults-pane .pin { font-size: 12px; padding: 3px 5px; }
#faults-pane .btn, #faults-pane button { font-size: 12px; }
#faults-pane .btn.sm { font-size: 12px; padding: 3px 8px; }
#faults-pane .wx-row .btn.sm { flex: 0 1 auto; }

/* ── THE SCHEDULE ────────────────────────────────────────────────────────── */
/* The schedule takes whatever height the page has left, and its list scrolls
   inside it - so the page itself never needs a scrollbar on a normal screen.
   It used to hold a fixed 420px, most of it empty, which pushed the page past
   the bottom of the window. */
#sched-pane.fp-wide { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 250px; }
#sched-pane #sched-tools {
  background: transparent; border-bottom: 1px solid var(--line);
  padding: 0 0 8px; margin-bottom: 10px; flex-wrap: wrap; row-gap: 6px;
}
#sched-pane #sched-body { padding: 0; overflow: visible; min-height: 0; }
/* The schedule's own caption is the section heading, set like the other two.
   Its station tag goes with the rest: the page says which station once. */
#faults-pane #sched-target { display: none; }
#faults-pane #sched-tools .ct-label {
  font-size: 12px; font-weight: 700; letter-spacing: .14em; color: var(--green-br);
}
#faults-pane .sched-clock { font-size: 12px; }
#faults-pane .tl-tick { font-size: 12px; }

/* ── FRAME SIZE BENCH ────────────────────────────────────────────────────────
   A tuning tool for deciding what viewport a tile should hand the console.
   Deliberately plain: it is not part of the instructor's working console and
   should not look like it is. */
#frame-bench {
  position: fixed; right: 12px; top: 52px; width: 300px; z-index: 80;
  background: var(--panel); border: 1px solid var(--line-hi); border-radius: 6px;
  box-shadow: 0 10px 30px rgba(0,0,0,.6);
}
#fb-head {
  display: flex; align-items: center; gap: 8px; padding: 6px 10px;
  background: #0d1f16; border-bottom: 1px solid var(--line);
}
#fb-title { flex: 1; font-size: 12px; font-weight: 700; letter-spacing: .1em; color: var(--green-br); }
#fb-close {
  background: #021002; border: 1px solid var(--box-line); color: var(--amber);
  border-radius: 2px; font: inherit; font-size: 11px; padding: 2px 8px; cursor: pointer;
}
#fb-body { padding: 10px; display: flex; flex-direction: column; gap: 8px; }
#fb-body .fb-row { display: flex; gap: 6px; align-items: flex-end; flex-wrap: wrap; }
#fb-body .fb-row.fb-sep { border-top: 1px solid var(--line); padding-top: 8px; }
.fb-fld { flex: 1; display: flex; flex-direction: column; gap: 3px; }
.fb-fld span { font-size: 10px; letter-spacing: .1em; color: var(--dim); }
.fb-fld input {
  background: #071107; border: 1px solid var(--box-line); color: var(--text);
  font: inherit; font-size: 13px; padding: 4px 6px; border-radius: 3px; width: 100%;
}
.fb-read {
  margin: 0; font-size: 11px; line-height: 1.5; color: var(--green-br);
  background: #071107; border: 1px solid var(--line); border-radius: 3px; padding: 5px 7px;
}
#fb-body .btn.sm { font-size: 11px; padding: 3px 7px; }
#fb-body .btn.wide { width: 100%; }
#fb-stats.on { border-color: var(--amber); color: var(--amber); }

/* Stats column hidden: the console takes the whole tile. The layout maths is
   told separately (STATS_W in main.ts) - CSS alone would leave it computing
   column counts against a width that is no longer spent. */
body.no-stats .c-body { grid-template-columns: 1fr; }
body.no-stats .c-stats { display: none; }
body.no-stats .card.focused .c-body { grid-template-columns: 1fr; }

/* Two-number PICTURE faults caption each box (BLIND: START / END, SHADOW:
   START / LENGTH) and keep the two boxes side by side under the heading. */
.f-params { display: inline-flex; gap: 6px; align-items: flex-end; }

/* ── WHICH SENSOR THE STATION IS USING ───────────────────────────────────────
   A setting, not a failure, so it has its own group beside ANTENNA rather than
   a chip among the ones that kill the units: two pickers and the compass error.
   It lives in that column because the sensor column is the tallest on the page
   and this one has room - and the page must not need a scrollbar.

   The live reading underneath is what the station actually landed on, which is
   not the same thing as what was asked for: a forced unit that has since died
   falls back, and that is exactly the moment this needs reading. */
.src-row { display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap; }
.src-row .pin-sel {
  width: auto; min-width: 62px; padding: 2px 3px;
  font: 11px ui-monospace, monospace;
}
.src-row .pinw .pin { width: auto; }
.src-live {
  flex: 1 0 100%; font-size: 10px; letter-spacing: .06em; color: var(--dim);
  white-space: nowrap;
}
.src-live.bad { color: var(--red); }

/* ── THE SENSOR UNITS FLOW, THE PARAMETERISED FAULTS DO NOT ──────────────────
   GPS1, GPS2, GYRO1, GYRO2, MAG and LOG FAIL are single words with nothing to
   type: one per line down a narrow column is six lines to say what fits in two,
   and the page has no spare height. The faults that carry numbers keep their
   own full-width line, where the boxes stay beside their captions. */
#faults-pane #sensors { flex-flow: row wrap; gap: 4px 5px; }
#faults-pane #sensors .frow.grp { flex: 1 0 100%; }
/* Superseded, still injectable from an older plan or recording: no chip. */
#faults-pane .frow.legacy { display: none; }

/* The exercise-state line under PAUSE/RESUME/STOP when the run has ENDED.
   The one state on that panel an instructor must not miss. */
.bx-note.bad { color: #ff9b9b; }

/* The three names on the assessment form. One row, because they are one
   thought - who sat down, at what rank, assessed by whom - and three
   stacked fields would push the debrief off the panel. */
.assess-who { display: flex; gap: 8px; margin: 0 0 10px; }
.assess-who .fld { flex: 1 1 0; min-width: 0; }

/* THE ICE PICKER holds type names with their draughts - "Iceberg (Medium)
   (75m draft)" - and the draught is the number that decides where the piece
   grounds, so it has to be readable. The shared .ct-sel cap of 150px (and the
   tighter padding inside #chart-tools) squeezed it to the width of its own
   arrow on the crowded first row; it now sits on the second, where there is
   room, and is allowed to take it. */
#chart-tools .ct-ice-sel { max-width: 260px; min-width: 190px; padding-inline: 6px; }
