/* The operator console: the board.
 *
 * Designed for one screen, all night, in a dim room, read by someone who may
 * be scanning it at 3am while a site is being broken into. One screen that
 * never scrolls; only the two rails do. The eye moves left to right: what is
 * waiting, what the camera saw and sees, what to do about it. The action
 * column IS the plan: each step carries its own control.
 *
 * Graphite since 29 Oct 2026 (John: "I think it looks better"): neutral warm
 * grey, the configuration site's dark mode, where it was a blue-black. Only
 * the greys moved; what each colour means did not.
 *
 * Colour is a language, not a palette:
 *   red    - nobody is on this yet. Nothing else may use it.
 *   blue   - mine.
 *   amber  - PPE hours, and warnings.
 *   green  - a check passed, a speaker alive.
 * Times always carry their zone, because sites span several.
 *
 * Fonts are vendored (static/fonts, all OFL): the policy allows no other
 * origin, and an alarm desk must not depend on the internet being up.
 */

@font-face { font-family: "Big Shoulders Display"; font-weight: 500; font-display: swap; src: url("../fonts/bigshoulders-500.e1ffd6608051.woff2") format("woff2"); }
@font-face { font-family: "Big Shoulders Display"; font-weight: 700; font-display: swap; src: url("../fonts/bigshoulders-700.e1ffd6608051.woff2") format("woff2"); }
@font-face { font-family: "Big Shoulders Display"; font-weight: 800; font-display: swap; src: url("../fonts/bigshoulders-800.e1ffd6608051.woff2") format("woff2"); }
@font-face { font-family: "Atkinson Hyperlegible"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/atkinson-400.f1f8a8210104.woff2") format("woff2"); }
@font-face { font-family: "Atkinson Hyperlegible"; font-style: italic; font-weight: 400; font-display: swap; src: url("../fonts/atkinson-400-italic.de4c0c22fd4e.woff2") format("woff2"); }
@font-face { font-family: "Atkinson Hyperlegible"; font-style: normal; font-weight: 700; font-display: swap; src: url("../fonts/atkinson-700.13a58e05dfd2.woff2") format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-weight: 400; font-display: swap; src: url("../fonts/jetbrains-400.b636a65da4f0.woff2") format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-weight: 600; font-display: swap; src: url("../fonts/jetbrains-600.b636a65da4f0.woff2") format("woff2"); }

:root {
  color-scheme: dark;
  --bg:       #1b1b1d;
  --bg-2:     #202022;
  --panel:    #242426;
  --panel-2:  #2b2b2e;
  --panel-3:  #333336;
  --line:     #39393c;
  --line-2:   #444448;
  --line-3:   #57575c;
  --text:     #ecebe8;
  --dim:      #b3b1ac;
  --faint:    #8a8884;

  --urgent:    #ff5a52;   /* unclaimed: the only thing allowed to shout */
  --urgent-bg: #2b1517;
  --claimed:   #4a9eff;   /* mine */
  --mine:      #4a9eff;
  --mine-bg:   #14243a;
  --ok:        #3ddc84;
  --ok-bg:     #0f2a1c;
  --warn:      #ffb02e;
  --warn-bg:   #2e2210;

  --display: "Big Shoulders Display", "Arial Narrow", "Segoe UI", sans-serif;
  --body:    "Atkinson Hyperlegible", "Verdana", "Segoe UI", sans-serif;
  --mono:    "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  --radius: 6px;
  --top: 48px;
  --actions: 430px;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 14px/1.45 var(--body); -webkit-font-smoothing: antialiased;
}
body.board-page { overflow: hidden; }
a { color: var(--claimed); }
h1, h2, h3 { margin: 0; font-family: var(--display); font-weight: 700; letter-spacing: .01em; }
p { margin: 0; }
button { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--mine); outline-offset: 2px; }
[hidden] { display: none !important; }
time, .t, .mono { font-family: var(--mono); }
.zone { color: var(--faint); font-size: .82em; margin-left: 3px; }
.dim { color: var(--dim); } .faint { color: var(--faint); }
.small { font-size: 12.5px; }
.suppressed { color: var(--faint); font-size: 12.5px; }
.eyebrow { font: 700 11px var(--body); letter-spacing: .1em; text-transform: uppercase; color: var(--faint); }
.icon { width: 16px; height: 16px; flex: 0 0 auto; vertical-align: -3px; }
form.inline { display: inline; margin: 0; }
form.aside { margin: 0; }

/* ---------- buttons ---------- */

button, .btn {
  display: inline-flex; align-items: center; gap: 8px; height: 34px; padding: 0 14px;
  border-radius: var(--radius); border: 1px solid var(--line-2); background: var(--panel-2); color: var(--text);
  font-weight: 700; font-size: 13px; cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: background .1s, border-color .1s;
}
button:hover, .btn:hover { background: var(--panel-3); border-color: var(--line-3); }
button.primary, .btn.primary { background: var(--claimed); border-color: var(--claimed); color: #06182c; }
button.primary:hover, .btn.primary:hover { background: #5aa8ff; }
button.danger, .btn.danger { background: var(--urgent); border-color: var(--urgent); color: #2a0b0c; }
button.ok, .btn.ok { background: var(--ok-bg); border-color: #1f5b3a; color: var(--ok); }
button.ghost, .btn.ghost { background: transparent; border-color: transparent; color: var(--claimed); }
button.ghost:hover, .btn.ghost:hover { background: var(--mine-bg); }
button.small, .btn.small { height: 28px; padding: 0 10px; font-size: 12.5px; }
button.xs, .btn.xs { height: 24px; padding: 0 8px; font-size: 12px; }
button.big, .btn.big { height: 46px; padding: 0 20px; font-size: 15px; }
button.full, .btn.full { width: 100%; justify-content: center; }
button:disabled { opacity: .45; cursor: default; }
button.on { background: var(--ok-bg); border-color: #1f5b3a; color: var(--ok); }

/* ---------- forms ---------- */

input[type=text], input[type=password], input[type=tel], input[type=email], select, textarea {
  width: 100%; padding: 8px 10px; border-radius: 4px; border: 1px solid var(--line-2);
  background: var(--bg-2); color: var(--text); font: 13.5px var(--body);
}
textarea { resize: vertical; min-height: 64px; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--mine); outline-offset: -1px; border-color: var(--mine); }
label { display: block; font-size: 11px; color: var(--faint); text-transform: uppercase; letter-spacing: .06em; margin: 10px 0 4px; }
.error { color: var(--urgent); font-size: 14px; padding: 8px 0; }
.notice { color: var(--warn); font-size: 14px; padding: 8px 0; }
.claimlost { color: var(--warn); font-size: 14px; }

/* ---------- standalone pages: sign in, second factor, refusals ---------- */

body.centred {
  display: grid; place-items: center; min-height: 100vh; padding: 20px;
  align-content: center; gap: 14px; overflow: auto;
}
.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 18px; margin: 0;
}
.card.narrow { width: 340px; max-width: 100%; }
.card.narrow.wide { width: 440px; }
.card h2 { margin: 0 0 14px; font-size: 12px; font-weight: 700; color: var(--faint); text-transform: uppercase; letter-spacing: .08em; font-family: var(--body); }
.card h2.plain { font: 700 22px var(--display); color: var(--text); text-transform: none; letter-spacing: .02em; }
.card p { margin: 0 0 10px; }
.code-input { font: 600 26px var(--mono); letter-spacing: .3em; text-align: center; }
.qr { background: #fff; padding: 12px; border-radius: 8px; display: inline-block; margin-bottom: 10px; }
.qr svg { width: 200px; height: 200px; display: block; }
code.secret { font-family: var(--mono); color: var(--text); word-break: break-all; }
.backup-codes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 20px; font: 600 18px var(--mono); margin: 14px 0; }

/* ---------- top bar ---------- */

.top {
  height: var(--top); display: flex; align-items: center; gap: 18px; padding: 0 18px;
  background: var(--panel); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 30;
}
.top .brand { display: flex; align-items: baseline; gap: 10px; text-decoration: none; color: inherit; }
.top .brand .word { font: 800 22px var(--display); letter-spacing: .02em; }
.top .brand .surface { font: 700 11px var(--body); letter-spacing: .12em; text-transform: uppercase; color: var(--urgent); }
.top .clock { display: flex; align-items: baseline; gap: 10px; font-family: var(--mono); }
.top .clock .big { font: 700 20px var(--mono); letter-spacing: .04em; }
.top .clock .utc { color: var(--faint); font-size: 12px; }
.top .spacer { flex: 1; }
.top .count { display: flex; align-items: center; gap: 10px; }
.top .count .n { font: 800 30px/1 var(--display); color: var(--faint); min-width: 28px; text-align: right; }
.top .count .n.hot { color: var(--urgent); animation: throb 1.2s ease-in-out infinite; }
.top .count .l { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; color: var(--faint); line-height: 1.1; }
@keyframes throb { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
/* The way across to the configuration site, for an admin. Quiet: it is not
   part of working an incident. */
.top .across { color: var(--dim); text-decoration: none; font-size: 13px; padding: 4px 8px; border: 1px solid var(--line-2); border-radius: 6px; }
.top .across:hover { color: inherit; border-color: var(--dim); }
.top button.across { background: transparent; font-weight: 400; }
/* What "Go on duty" does, on hover. Quiet: a hint, not a control. */
.top .duty-info {
  margin-left: -12px; width: 16px; height: 16px; border-radius: 50%;
  border: 1px solid var(--line-2); color: var(--faint);
  display: inline-grid; place-items: center; cursor: help;
  font: italic 700 10px/1 var(--body);
}
.top .duty-info:hover { color: var(--dim); border-color: var(--dim); }
.top .who { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--dim); }
.top .who .avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--mine-bg); color: var(--mine); display: grid; place-items: center; font: 800 12px var(--display); border: 1px solid #244a7a; }

/* ---------- board ---------- */

/* The queue runs along the top (2 Oct 2026). As a left rail it took 360px
   from the evidence and the plan, which is where the work is; along the top
   it costs one row of height and gives the width back. */
.board {
  height: calc(100vh - var(--top));
  display: grid; grid-template-columns: minmax(0, 1fr) var(--actions);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "rail rail" "centre actions";
}
.board > .rail { grid-area: rail; }
.board > .centre { grid-area: centre; }
.board > .actions { grid-area: actions; }
@media (max-width: 1400px) { :root { --actions: 390px; } }
/* ---------- queue strip ---------- */

.rail {
  display: flex; align-items: stretch; min-width: 0;
  border-bottom: 1px solid var(--line); background: var(--bg-2);
}
.rail-head {
  flex: 0 0 auto; display: flex; flex-direction: column; justify-content: center; gap: 6px;
  padding: 8px 14px; border-right: 1px solid var(--line);
}
.rail-head h2 { font-size: 17px; letter-spacing: .08em; line-height: 1; }
/* #queue is the scroller, not .queue: the poll replaces everything inside
   #queue, and only an element that survives the swap keeps its scroll. */
#queue {
  flex: 1; min-width: 0; display: flex; align-items: stretch;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; scrollbar-color: var(--line-2) transparent;
}
.queue { display: flex; gap: 8px; padding: 8px 10px; flex: 1 0 auto; }

/* 420px since 5 Oct 2026: at 292 the chips shared a line with the wait timer
   and an operator saw "PERSON O" of "person, open site". The strip has the
   width; a card takes enough of it that its words are never cut, and four
   still fit across a 1920 screen without a scrollbar. */
.card-row {
  flex: 0 0 min(420px, calc(100vw - 150px)); display: grid; grid-template-columns: 112px minmax(0, 1fr); gap: 10px; padding: 7px 10px 7px 7px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  text-align: left; position: relative; color: inherit; text-decoration: none;
  transition: border-color .1s, background .1s;
}
.card-row:hover { background: var(--panel-2); border-color: var(--line-2); }
.card-row.selected { border-color: var(--mine); box-shadow: 0 0 0 1px var(--mine) inset; background: var(--panel-2); }
.card-row.unclaimed { background: var(--urgent-bg); border-color: #4a2a2c; }
.card-row.unclaimed::before { content: ""; position: absolute; left: 10px; right: 10px; top: -1px; height: 3px; background: var(--urgent); border-radius: 0 0 2px 2px; }
.card-row.unclaimed.selected { border-color: var(--urgent); box-shadow: 0 0 0 1px var(--urgent) inset; }
/* Widescreen, like the cameras: a square crop of a 16:9 yard hid most of it. */
.card-row .thumb { width: 112px; height: 100%; min-height: 63px; align-self: center; border-radius: 4px; background: #000; overflow: hidden; border: 1px solid var(--line); display: grid; place-items: center; }
.card-row .thumb img, .card-row .thumb video { width: 100%; height: 100%; object-fit: cover; display: block; }
.card-row .thumb .none { color: var(--faint); font-size: 10px; text-align: center; padding: 4px; }
/* One grid for the words: the name with who holds it, then where with how
   long it has waited, then what was seen on a line of its own, which wraps
   rather than cutting a chip off. `.foot` dissolves into it. */
.card-row > span:last-child {
  display: grid; min-width: 0; align-content: center; column-gap: 8px; row-gap: 3px;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "site holder" "where wait" "chips chips";
}
.card-row .foot { display: contents; }
.card-row .site { grid-area: site; font: 700 17px/1.15 var(--display); letter-spacing: .01em; display: flex; align-items: baseline; gap: 6px; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card-row .site .badge { flex: 0 0 auto; }
.card-row .where { grid-area: where; min-width: 0; align-self: center; color: var(--dim); font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card-row .chips { grid-area: chips; display: flex; gap: 4px; flex-wrap: wrap; min-width: 0; }
.card-row .chips .chip { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.card-row .foot > .small { display: none; }
.card-row .wait { grid-area: wait; justify-self: end; font: 700 13.5px var(--mono); white-space: nowrap; align-self: center; }
.card-row .wait .l { font: 700 9.5px var(--body); text-transform: uppercase; letter-spacing: .08em; color: var(--faint); margin-left: 4px; }
.card-row .wait.w1 { color: var(--text); } .card-row .wait.w2 { color: var(--warn); } .card-row .wait.w3 { color: var(--urgent); }
.card-row .holder { grid-area: holder; justify-self: end; align-self: start; max-width: 140px; overflow: hidden; text-overflow: ellipsis; }

/* The queue page, with nothing open: the strip becomes a wall of cards. */
.board.home { grid-template-rows: minmax(0, auto) minmax(0, 1fr); }
.board.home .rail { max-height: 64vh; }
.board.home #queue { overflow-x: hidden; overflow-y: auto; }
.board.home .queue { flex: 1 1 0; min-width: 0; flex-wrap: wrap; align-content: flex-start; padding: 12px; gap: 10px; }
.board.home .card-row { flex-basis: min(420px, 100%); flex-grow: 0; }

.badge, .chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 1px 7px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; border: 1px solid transparent; white-space: nowrap;
  vertical-align: middle;
}
.chip.obj { background: var(--panel-3); color: var(--dim); }
.badge.ppe, .chip.ppe { background: transparent; border-color: var(--warn); color: var(--warn); }
/* A trouble plan put this in the queue (1 Oct 2026): equipment, not a person. */
.badge.trouble { background: transparent; border-color: var(--dim); color: var(--dim); }
.badge.new, .chip.new { background: var(--urgent); color: #1a0b0c; }
.badge.claimed, .chip.mine { background: var(--mine-bg); color: var(--mine); border-color: #244a7a; }
.badge.progress, .chip.other { background: rgba(255,176,46,.14); color: var(--warn); }
.chip.ok { background: var(--ok-bg); color: var(--ok); }
.chip.quiet { border-color: var(--line-2); color: var(--dim); }
.chip.armed, .chip.p1 { background: var(--urgent-bg); color: var(--urgent); border-color: #4a2a2c; }
/* On test: a site an operator has paused for minutes. Amber, never red: red
   is for nobody being on something, and this is somebody having decided. */
.chip.test { background: var(--warn-bg); color: var(--warn); border-color: #5b4417; }
/* The speaker has warned the yard on its own. Quiet: information, not a call
   to act, and never red. */
.chip.warned { border-color: var(--line-2); color: var(--dim); }
/* How the site is protected (Site.perimeter). Open is the exception and the
   one that changes how an operator speaks, so it is the one in color. */
.chip.perimeter.closed { border-color: var(--line-2); color: var(--dim); }
.chip.perimeter.open { background: var(--mine-bg); color: var(--mine); border-color: #24466e; }
/* Disarmed over the schedule, usually by the customer, after this incident
   opened. Amber for the same reason: a person decided it. */
.chip.disarmed { background: var(--warn-bg); color: var(--warn); border-color: #5b4417; text-transform: none; letter-spacing: 0; }

/* The block on the incident, and the strip under the queue. */
.site-test.on { border-color: #5b4417; background: var(--warn-bg); }
.site-test .test-now { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.site-test .test-now strong { color: var(--warn); }
.test-form { display: flex; flex-direction: column; gap: 8px; }
.test-minutes { display: flex; gap: 6px; flex-wrap: wrap; }
[data-until] { font: 700 13px var(--mono); color: var(--warn); }
[data-until].soon { color: var(--text); }
.on-test {
  flex: 0 0 auto; position: sticky; right: 0; align-self: stretch; margin: 8px 10px 8px 0; padding: 6px 10px;
  min-width: 200px; max-width: 260px; overflow-y: auto;
  border: 1px solid #5b4417; border-radius: var(--radius); background: var(--warn-bg); box-shadow: -12px 0 16px -6px var(--bg-2);
}
.on-test h3 { margin: 0 0 2px; font: 700 11px var(--body); letter-spacing: .1em; text-transform: uppercase; color: var(--warn); }
.on-test .test-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
.on-test .test-row .site { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; font-size: 13px; }

.centre .empty { margin: 40px 12px; padding: 40px 16px; text-align: center; color: var(--faint); border: 1px dashed var(--line); border-radius: var(--radius); }
.rail .empty { display: flex; align-items: baseline; gap: 12px; padding: 14px 16px; color: var(--faint); font-size: 13px; }
.rail .empty strong { font-size: 18px; margin: 0; }
.empty strong { display: block; color: var(--dim); font: 700 22px var(--display); margin-bottom: 4px; }

/* ---------- centre: evidence ---------- */

.centre { height: 100%; overflow: hidden; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
.centre > * { min-width: 0; }
.centre.blank { place-items: center; grid-template-rows: 1fr; color: var(--faint); }
.centre.blank .msg { text-align: center; }
.centre.blank .msg strong { display: block; font: 700 30px var(--display); color: var(--dim); }

.sitehead { display: flex; align-items: flex-start; gap: 22px; padding: 16px 22px 12px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.sitehead .name { font: 800 34px/1 var(--display); letter-spacing: .01em; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.sitehead .addr { color: var(--dim); font-size: 13.5px; margin-top: 5px; }
.sitehead dl { display: flex; gap: 22px; margin: 0 0 0 auto; flex-wrap: wrap; }
.sitehead dt { font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; color: var(--faint); }
.sitehead dd { margin: 3px 0 0; font: 700 15px var(--mono); overflow-wrap: anywhere; }
.sitehead dd.plain { font-family: var(--body); }
.notes { flex-basis: 100%; font-size: 13px; color: var(--dim); border-left: 3px solid var(--warn); padding: 2px 0 2px 10px; }
.notes strong { color: var(--text); }

/* min-width:0 is load-bearing, not tidiness. A grid item defaults to
   min-width:auto, so a filmstrip's content widened its column instead of
   scrolling inside it, and the whole page grew sideways as alerts arrived
   until nothing lined up. This is what actually broke the old layout. */
.evidence { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; padding: 14px 22px 8px; min-height: 0; }
.evidence > * { min-width: 0; min-height: 0; }
@media (max-width: 1100px) { .evidence { grid-template-columns: 1fr; } }
.stage { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; gap: 8px; min-height: 0; }
.stage-head { display: flex; align-items: baseline; gap: 10px; }
.stage-head h2 { font-size: 16px; letter-spacing: .08em; text-transform: uppercase; color: var(--dim); }
.stage-head .t { font-size: 12.5px; color: var(--faint); }

/* The alert that opened it: the still above the clip (5 Oct 2026; side by
   side, each widescreen picture had half the width), each the full width of
   the stage and sharing its height. What the alert said is in the stage's
   head, once, so the height goes to the pictures. At full size the height
   decides, so each is letterboxed, never cropped; zoomed in (below) each is
   its own 16:9 and the column scrolls. */
.filmstrip.first {
  display: grid; grid-template-rows: minmax(0, 1fr); min-height: 0;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
}
.stage-head .caption { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 8px; font-size: 12.5px; color: var(--dim); overflow-wrap: anywhere; }
.stage-head .caption .lead { color: var(--faint); }
.stage-head .caption .said { display: inline; }
.stage-head .caption .ppe { margin-top: 0; }
.filmstrip.first .stack { display: grid; grid-template-columns: minmax(0, 1fr); grid-auto-rows: minmax(0, 1fr); gap: 2px; min-height: 0; }
.filmstrip.first figure { margin: 0; min-width: 0; min-height: 0; background: #000; display: grid; grid-template-rows: minmax(0, 1fr); }
.filmstrip.first img, .filmstrip.first video { width: 100%; height: 100%; object-fit: contain; display: block; background: #000; min-height: 0; }
.filmstrip.first .missing { display: grid; place-items: center; color: var(--faint); font-size: 12.5px; text-align: center; padding: 20px; min-height: 120px; }
.filmstrip figcaption { padding: 6px 10px; font-size: 12.5px; color: var(--dim); background: var(--panel); border-top: 1px solid var(--line); line-height: 1.35; overflow-wrap: anywhere; }
.filmstrip figcaption .t { color: var(--faint); font-size: 11.5px; margin-left: 6px; }
.said { display: block; color: var(--text); margin-top: 1px; }
.ppe { display: inline-block; margin-top: 3px; padding: 1px 7px; border-radius: 4px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.ppe.ok { background: var(--ok-bg); color: var(--ok); }
.ppe.bad { background: rgba(255,176,46,.16); color: var(--warn); }
.ppe.unknown { border: 1px solid var(--line-2); color: var(--faint); }

/* live view: the Now stage */
.live-stage { min-height: 0; border: 1px solid var(--line); border-radius: var(--radius); background: #000; overflow: hidden; display: grid; grid-template-rows: minmax(0, 1fr) auto; }
.live-stage video { width: 100%; height: 100%; object-fit: contain; display: block; min-height: 0; background: #000; }
.live-meta { display: flex; align-items: center; gap: 12px; padding: 6px 10px; font-size: 12.5px; color: var(--dim); background: var(--panel); border-top: 1px solid var(--line); }
.live-meta span { flex: 1; }
.live-meta span::before { content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--urgent); margin-right: 7px; animation: throb 1s infinite; vertical-align: 1px; }
.live-idle { min-height: 0; border: 1px dashed var(--line); border-radius: var(--radius); display: grid; place-items: center; color: var(--faint); font-size: 13px; text-align: center; padding: 20px; }
.live-cams { display: flex; gap: 6px; flex-wrap: wrap; }
.live-status { font-size: 12.5px; color: var(--faint); }
.live-status.err { color: var(--urgent); }

/* since: the strip along the bottom */
.since { padding: 8px 22px 14px; border-top: 1px solid var(--line); }
.since-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.since-head h2 { font-size: 16px; letter-spacing: .08em; text-transform: uppercase; color: var(--dim); }
/* The polled line lays out as if its children were the head's own. */
#since { display: contents; }
.since-count { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; }
.since-count .count { background: var(--warn); color: #241a05; font: 700 12px var(--mono); border-radius: 11px; padding: 1px 9px; }
.since-none { color: var(--faint); font-size: 12.5px; }
.since-warned { color: var(--dim); font-size: 12.5px; }
.since-warned.dry { color: var(--faint); }
.since-open .filmstrip { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; }
.since-open .filmstrip figure { margin: 0; flex: 0 0 auto; width: 188px; background: var(--panel); border: 1px solid var(--line); border-radius: 4px; overflow: hidden; }
.since-open .filmstrip img, .since-open .filmstrip video { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block; background: #000; }
.since-open .filmstrip .missing { aspect-ratio: 16 / 9; display: grid; place-items: center; color: var(--faint); font-size: 11.5px; text-align: center; padding: 8px; }
.since-open .filmstrip figcaption { font-size: 11.5px; padding: 5px 8px; border-top: 1px solid var(--line); }

/* ---------- a picture or clip made bigger ----------
   Over the alarm rather than instead of it: the panel stops short of the
   window on every side, so what is behind it is still there. The picture is a
   button, so it has none of a button's looks, and fills what the img used to. */
.filmstrip figure { position: relative; }
button.enlarge-pic { all: unset; display: block; width: 100%; cursor: zoom-in; }
button.enlarge-pic:focus-visible { outline: 2px solid var(--claimed); outline-offset: -2px; }
.filmstrip.first button.enlarge-pic { height: 100%; min-width: 0; min-height: 0; }
button.enlarge-clip { position: absolute; top: 6px; right: 6px; background: rgba(12,12,14,.72); }
dialog.enlarge {
  width: min(1120px, 82vw); max-height: calc(100vh - 64px); padding: 0; overflow: hidden;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--line-2); border-radius: 10px;
  box-shadow: 0 24px 60px rgba(0,0,0,.55);
}
dialog.enlarge[open] { display: grid; grid-template-rows: auto minmax(0, 1fr); }
dialog.enlarge::backdrop { background: rgba(6,8,11,.7); }
.enlarge-bar { display: flex; align-items: center; gap: 12px; padding: 8px 8px 8px 14px; border-bottom: 1px solid var(--line); }
.enlarge-caption { flex: 1; min-width: 0; font-size: 13px; color: var(--dim); overflow-wrap: anywhere; }
button.enlarge-close { flex: none; width: 36px; height: 36px; padding: 0; justify-content: center; font-size: 22px; line-height: 1; }
.enlarge-body { min-height: 0; background: #000; display: grid; place-items: center; }
.enlarge-body img, .enlarge-body video { display: block; width: 100%; max-height: calc(100vh - 118px); object-fit: contain; }
.enlarge-body .missing { margin: 0; padding: 60px 20px; color: var(--dim); text-align: center; }

/* ---------- actions column ---------- */

.actions { height: 100%; overflow: auto; border-left: 1px solid var(--line); background: var(--bg-2); display: flex; flex-direction: column; }
#claim {
  position: sticky; top: 0; z-index: 3; padding: 14px 16px; background: var(--bg-2); border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
#claim.unclaimed { background: var(--urgent-bg); }
#claim .who { font-size: 13px; color: var(--dim); }
#claim .who strong { color: var(--text); }
#claim .who .mine { font-weight: 700; color: var(--mine); }
#claim > button, #claim > .btn { margin-left: auto; }
/* Resolved: nothing to press, and quiet, never red. */
#claim.resolved { background: var(--ok-bg); }
.resolved-as { font-size: 13px; color: var(--dim); }
.resolved-as strong { color: var(--text); }
.resolved-as .narrative { margin-top: 6px; color: var(--text); }
.plan { padding: 12px 16px 24px; display: flex; flex-direction: column; gap: 10px; }
/* The steps and their tools. Switched off for anybody but the holder: drawn,
   so the desk sees what is to be done, and nothing in it presses. */
.plan-tools { border: 0; margin: 0; padding: 0; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.plan-tools:disabled input, .plan-tools:disabled textarea { opacity: .55; }
.plan-locked { margin: 0; }
.plan-name { display: flex; align-items: baseline; gap: 8px; margin: 0; }
.plan-name h2 { font-size: 20px; letter-spacing: .03em; text-transform: uppercase; }
.plan-name .v { color: var(--faint); font: 600 12px var(--mono); }
.plan-name .badge { margin-left: auto; }

.step { border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); display: grid; grid-template-columns: 34px 1fr; transition: border-color .15s; }
.step:has(.step-head.done) { opacity: .62; }
.step.now { border-color: var(--mine); box-shadow: 0 0 0 1px var(--mine) inset; }
.step .num {
  display: grid; place-items: center; font: 800 16px var(--display); color: var(--faint);
  border-right: 1px solid var(--line); background: var(--panel-2); border-radius: var(--radius) 0 0 var(--radius);
}
.step:has(.step-head.done) .num { color: var(--ok); background: var(--ok-bg); }
.step.now .num { color: var(--mine); background: var(--mine-bg); }
.step .body { padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; min-width: 0; overflow-wrap: anywhere; }
.step-head { display: flex; flex-direction: column; gap: 4px; }
.step-head .line { display: flex; align-items: baseline; gap: 4px 8px; flex-wrap: wrap; }
.step-head .kind { font-weight: 700; font-size: 14px; }
.step-head.done .kind { text-decoration: line-through; color: var(--dim); }
.step-head .optional { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); }
.step-head .line button, .step-head .line .hint { margin-left: auto; }
.step-head .note { color: var(--dim); font-size: 13px; white-space: pre-wrap; }
.step-head .by { color: var(--faint); font-size: 12px; }
/* An email step goes by itself (1 Oct 2026): one small grey line between
   the steps an operator works, with no number and no button. */
.step.auto { display: block; border: 0; background: none; padding: 0 12px 0 46px; }
.step.auto:has(.step-head.done) { opacity: 1; }
.step-head.auto .line { display: block; color: var(--faint); font-size: 12px; }
.tool { border-top: 1px dashed var(--line); padding-top: 8px; display: flex; flex-direction: column; gap: 8px; }
.tool > h2 { font-size: 13px; letter-spacing: .08em; text-transform: uppercase; color: var(--dim); font-family: var(--body); }
.standalone { border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; }
.standalone > h2 { font-size: 13px; letter-spacing: .08em; text-transform: uppercase; color: var(--dim); font-family: var(--body); }
.plan .hint { font-size: 12.5px; color: var(--dim); }

/* talkdown */
#talkdown { display: flex; flex-direction: column; gap: 8px; }
.ptt, .hs-row { display: flex; align-items: center; gap: 12px; }
.ptt-btn, .hs-btn {
  flex: 0 0 auto; height: 52px; padding: 0 22px; border-radius: 8px; border: 1px solid var(--line-2);
  background: var(--panel-2); color: var(--text); font: 700 15px var(--body); cursor: pointer;
  user-select: none; -webkit-user-select: none; touch-action: none;
}
.ptt-btn:hover:not(:disabled), .hs-btn:hover:not(:disabled) { border-color: var(--mine); background: var(--panel-2); }
.ptt-btn.live, .hs-btn.live { background: var(--urgent-bg); border-color: var(--urgent); color: var(--urgent); }
.ptt-btn:disabled, .hs-btn:disabled { opacity: .45; cursor: default; }
.ptt-meter, .hs-meter { flex: 1; height: 10px; border-radius: 5px; background: var(--line); overflow: hidden; }
.ptt-meter span, .hs-meter span { display: block; height: 100%; width: 0; background: var(--ok); transition: width .08s linear; }
.ptt-status, .hs-status { font-size: 12.5px; color: var(--dim); margin: 0; }
.ptt-status.live, .hs-status.live { color: var(--warn); }
.ptt-status.err, .hs-status.err { color: var(--urgent); }
.ptt-caveat { font-size: 12px; color: var(--dim); border-left: 3px solid var(--line-2); padding-left: 8px; margin: 0; }
.ptt-speakers { display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; }
.speaker { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.speaker .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); flex: 0 0 auto; }
.speaker.down .dot { background: var(--urgent); }
.speaker.unknown .dot { background: var(--faint); }
.speaker .warn { color: var(--warn); }
#talkdown .suppressed { font-size: 12.5px; color: var(--dim); }
#talkdown .suppressed strong { color: var(--text); }
/* How to speak at this site, above everything else in the talk step. */
.tone { font-size: 12.5px; line-height: 1.45; padding: 8px 10px; border-radius: var(--radius); border-left: 3px solid; margin-bottom: 10px; }
.tone.closed { background: var(--panel-2); border-color: var(--line-2); color: var(--dim); }
.tone.open { background: var(--mine-bg); border-color: var(--mine); color: var(--text); }
.tone strong { color: var(--text); }
/* Automatic warnings already given: what the yard was told, in its words. */
.auto-warnings { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.aw-head { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--dim); }
.aw { display: grid; grid-template-columns: 20px auto 1fr; gap: 2px 8px; font-size: 12.5px; align-items: baseline; }
.aw .n { font-family: var(--mono); color: var(--faint); }
.aw .t { font-family: var(--mono); }
.aw .s { color: var(--dim); }
.aw.sent .s { color: var(--ok); }
.aw.failed .s { color: var(--warn); }
.aw q, .aw .suppressed { grid-column: 2 / -1; color: var(--text); font-style: italic; }
/* contacts */
.contacts { display: flex; flex-direction: column; gap: 6px; }
.contact { display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: center; padding: 8px 10px; border-radius: 4px; background: var(--panel-2); }
.contact .name { font-weight: 700; }
.contact .role { color: var(--faint); font-weight: 400; font-size: 12px; margin-left: 6px; }
.contact .phone { font: 700 17px var(--mono); color: var(--text); text-decoration: none; display: block; letter-spacing: .02em; }
.contact .phone + .phone { font-size: 13px; color: var(--dim); font-weight: 400; }
/* A call step that says both phones: neither is the spare. */
.contacts.one .contact .phone + .phone { font-size: 17px; color: var(--text); font-weight: 700; }
.contacts.one .hint { font-size: 12.5px; color: var(--dim); display: block; }
.contact .pass { font-size: 12px; color: var(--dim); margin-top: 3px; display: block; }
.contact .pass code { color: var(--warn); font-family: var(--mono); }
.contact .may-cancel { font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--ok); }
.contact .side { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.contact button.small { margin-top: 4px; }

/* dispatch */
.responder { margin: 6px 0 10px; padding: 10px 12px; border-radius: var(--radius); background: var(--panel-2); border: 1px solid var(--line-2); display: grid; grid-template-columns: 1fr auto; gap: 2px 12px; align-items: end; font-size: 13.5px; }
.responder .who { grid-column: 1 / -1; font-size: 15px; }
.responder .kind { color: var(--dim); font-size: 12px; margin-left: 6px; text-transform: uppercase; letter-spacing: .04em; }
.responder .phone a { font-family: var(--mono); font-size: 19px; color: var(--text); text-decoration: none; }
.responder .permit { font-family: var(--mono); font-size: 13px; }
.responder .notes { grid-column: 1 / -1; color: var(--dim); font-size: 12.5px; }
.responder .dim { color: var(--dim); }
.responder.none { grid-template-columns: 1fr; }
.dispatch-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 8px; }
.dispatch-form .span { grid-column: 1 / -1; }
/* A label that wraps (zoomed in, a narrow plan) must not push its box below
   its neighbour's: each field sits at the bottom of its row. */
.dispatch-form > div { display: flex; flex-direction: column; justify-content: flex-end; min-width: 0; }
.dispatch-form label { margin: 6px 0 3px; }
.dispatch-form p { grid-column: 1 / -1; margin: 10px 0 0; }
.dispatched { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.dispatched .row { padding: 6px 8px; background: var(--urgent-bg); border-radius: 4px; border: 1px solid #4a2a2c; }
.dispatched .row .t { color: var(--dim); font-size: 12px; }
.dispatched .row .by { color: var(--faint); font-size: 12px; }

/* resolve */
.dispositions { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.dispositions label {
  position: relative; margin: 0; text-align: left; padding: 7px 9px; border-radius: 4px; border: 1px solid var(--line-2);
  background: var(--panel-2); font: 12.5px var(--body); text-transform: none; letter-spacing: 0; cursor: pointer; color: var(--dim);
}
.dispositions label:hover { border-color: var(--mine); color: var(--text); }
.dispositions label.false { color: var(--faint); }
.dispositions input { position: absolute; opacity: 0; width: 0; height: 0; }
.dispositions label:has(input:checked) { background: var(--mine-bg); border-color: var(--mine); color: var(--text); }
.dispositions label:has(input:focus-visible) { outline: 2px solid var(--mine); }
.resolve-row { display: flex; align-items: center; gap: 10px; }
.resolve-row button { margin-left: auto; }

/* ---------- the headset check (headset.js) ----------
   Over everything, on going on duty. The talk panel's own button and meter,
   so talking here looks like talking to a yard. */
dialog.headset {
  width: min(520px, calc(100vw - 32px)); padding: 22px 24px 18px;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--line-2); border-radius: 10px;
  box-shadow: 0 24px 60px rgba(0,0,0,.55);
}
dialog.headset::backdrop { background: rgba(6,8,11,.7); }
dialog.headset h2 { font-size: 24px; margin-bottom: 4px; }
dialog.headset > p { margin-bottom: 14px; }
.hs-devices { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 14px; margin: 0 0 16px; font-size: 13px; }
.hs-devices dt { color: var(--faint); }
.hs-devices dd { margin: 0; overflow-wrap: anywhere; }
dialog.headset .hs-row { margin-bottom: 8px; }
dialog.headset .hs-btn { min-width: 132px; justify-content: center; }
.hs-answer { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.hs-help { margin-top: 14px; padding: 10px 12px; background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius); font-size: 12.5px; color: var(--dim); }
.hs-help ul { margin: 6px 0 0; padding-left: 18px; }
.hs-help li + li { margin-top: 4px; }
.hs-foot { display: flex; justify-content: flex-end; margin-top: 16px; }


@media (prefers-reduced-motion: reduce) { .top .count .n.hot, .live-meta span::before, .ptt-meter span, .hs-meter span { animation: none; transition: none; } }

/* ---------- zoom and small screens ----------
   Last in the file so it wins. 150% zoom on a 1440 screen is a 960px page:
   until 2 Oct 2026 that hid the action plan entirely. */
/* Zoomed in, or a small screen: the plan stays on screen, never hidden. The
   evidence stacks and its column scrolls instead. Short as well as narrow
   (5 Oct 2026): under about 820px of height the queue, the site's header
   and the Since strip left the pictures nothing, and THEN and NOW shrank to
   nothing and drew over the strip. */
@media (max-width: 1180px) { :root { --actions: 340px; } }
@media (max-width: 1180px), (max-height: 820px) {
  .centre { overflow: auto; display: block; }
  .evidence { grid-template-columns: minmax(0, 1fr); }
  /* No fixed height to share out any more, so the media sizes itself. */
  .stage { grid-template-rows: auto auto auto; }
  .filmstrip.first .stack { grid-auto-rows: auto; }
  .filmstrip.first img, .filmstrip.first video { height: auto; aspect-ratio: 16 / 9; max-height: 56vh; }
  .filmstrip.first button.enlarge-pic { height: auto; }
  .live-stage video { height: auto; aspect-ratio: 16 / 9; }
  .live-idle { min-height: 160px; }
}
@media (max-width: 860px) {
  body.board-page { overflow: auto; }
  .board { display: block; height: auto; }
  .centre, .actions { height: auto; display: block; overflow: visible; }
  .actions { border-left: 0; border-top: 1px solid var(--line); }
}
@media (max-width: 1000px) {
  .top { gap: 12px; padding: 0 12px; }
  .top .clock .utc, .top .who > span:not(.avatar) { display: none; }
}
@media (max-width: 700px) {
  .top .count .l, .top .brand .surface { display: none; }
  .top .clock .big { font-size: 16px; }
}
.board.home .on-test { align-self: flex-start; margin-top: 12px; }

/* ---------- look up: a customer who called in ---------- */

.centre.lookup { display: block; overflow: auto; }
.lookup-search { padding: 18px 22px 12px; border-bottom: 1px solid var(--line); display: flex; flex-direction: column; gap: 10px; }
.lookup-search h1 { font-size: 28px; }
.lookup-search .row { display: flex; gap: 8px; max-width: 760px; }
.lookup-search .row input { font-size: 16px; }
.lookup-results { padding: 12px 22px 24px; display: flex; flex-direction: column; gap: 6px; max-width: 1100px; }
.lookup-row {
  display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto; gap: 14px; align-items: center;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel);
  color: inherit; text-decoration: none;
}
.lookup-row:hover { background: var(--panel-2); border-color: var(--line-2); }
.lookup-row .who { display: flex; flex-direction: column; min-width: 0; }
.lookup-row .name { font: 700 19px var(--display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lookup-row .cust, .lookup-row .addr { color: var(--dim); font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lookup-row .state { display: flex; gap: 6px; justify-content: flex-end; }
.lookup-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: 14px; padding: 14px 22px 24px; align-items: start; }
.lookup-address { font-style: normal; font-size: 17px; line-height: 1.45; }
.lookup-steps { margin: 0; padding-left: 20px; color: var(--dim); font-size: 13.5px; display: flex; flex-direction: column; gap: 4px; }
.test-form .field { display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; color: var(--dim); }
@media (max-width: 1180px) { .lookup-body { grid-template-columns: minmax(0, 1fr); } }
