/* Qamaria control. Dark first, because this sits beside a terminal all day.
   The neutral is biased cool-teal rather than pure grey, the one accent is a
   signal amber kept for things that need attention, and status colour is
   separate from the accent so a green number never reads as "the brand". */

:root {
  --bg:        #0d1316;
  --bg-2:      #111a1e;
  --panel:     #141f24;
  --panel-2:   #18272d;
  --line:      #22353c;
  --line-soft: #1b2a30;
  --ink:       #dce8ea;
  --ink-2:     #9fb4b8;
  --ink-3:     #6c868c;
  --accent:    #f0a830;
  --accent-dim:#5a4420;
  /* THE BUTTON FACE IS ITS OWN TOKEN, because it was --panel-2 on --panel and
     those are #18272d on #141f24: a 1.1:1 step, with a --line border at 1.6:1
     against the card behind it. Three almost identical colours, so a button
     read as a faint rectangle. --btn-line clears 3:1 against both the card and
     the page, which is what a non-text component boundary needs to be seen. */
  --btn:       #243640;
  --btn-hi:    #2e434e;
  --btn-line:  #4d6e79;
  --good:      #4cc38a;
  --warn:      #e8b339;
  --bad:       #ef6461;
  --info:      #5aa9c7;
  /* chart series, slots 1-4 of the dataviz reference categorical theme in its
     own order, stepped for a dark surface. Assigned BY ENTITY and never by
     rank, so hiding a line never repaints the others.

     Validated against this page's surfaces, not the skill's defaults:
     dark #141f24 -- worst adjacent CVD dE 8.4 (protan), normal-vision 19.8,
     all four >= 4.3:1 contrast. Lines take the ADJACENT pairlist, and the
     order is what keeps the weak pair apart: orange and yellow measure 4.8
     against each other and are deliberately non-adjacent here. No fourth hue
     in the documented set clears ALL pairs in both modes, so the legend and
     the direct end-labels carry identity when two lines cross. */
  --s-book:   #3987e5;
  --s-sp500:  #d95926;
  --s-nasdaq: #199e70;
  --s-gold:   #c98500;
  --grid:     #22353c;
  --axis-ink: #6c868c;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --sans: "IBM Plex Sans", system-ui, -apple-system, Segoe UI, sans-serif;
  --disp: "Archivo", var(--sans);
  --r: 5px;
}

:root[data-theme="light"] {
  --bg:        #f4f6f5;
  --bg-2:      #eceff0;
  --panel:     #ffffff;
  --panel-2:   #f6f8f8;
  --line:      #d4dcdd;
  --line-soft: #e4eaea;
  --ink:       #16242a;
  --ink-2:     #4a5f66;
  --ink-3:     #7b8f95;
  --accent:    #b06d04;
  --accent-dim:#f3e2c2;
  /* the same job on a light ground: a face that is visibly not the card, and
     a border at 3.3:1 against white */
  --btn:       #e9edee;
  --btn-hi:    #dbe2e3;
  --btn-line:  #7f9094;
  --good:      #108050;
  --warn:      #8a6200;
  --bad:       #b3302d;
  --info:      #1f6d8c;
  /* the same four hues stepped for a light surface, not an inversion.
     Against #ffffff: worst adjacent CVD dE 9.1, normal-vision 22.9. Aqua
     (2.82:1) and yellow (2.17:1) fall under 3:1, which the method allows only
     with relief -- the direct end-labels and the by-year table below the
     chart are that relief, and both are always on. */
  --s-book:   #2a78d6;
  --s-sp500:  #eb6834;
  --s-nasdaq: #1baf7a;
  --s-gold:   #eda100;
  --grid:     #e4eaea;
  --axis-ink: #7b8f95;
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

code { font-family: var(--mono); font-size: 0.92em; color: var(--ink-2); }

h1, h2, h3 { font-family: var(--disp); font-weight: 600; text-wrap: balance; }

button {
  font: inherit;
  cursor: pointer;
  border-radius: var(--r);
  border: 1px solid var(--btn-line);
  background: var(--btn);
  color: var(--ink);
  padding: 6px 12px;
}
button:hover { background: var(--btn-hi); border-color: var(--ink-2); }
button:active { background: var(--btn-line); }
button:disabled {
  cursor: default;
  opacity: 0.55;
  border-color: var(--line);
  background: var(--panel-2);
}
button:focus-visible,
input:focus-visible,
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* secondary, and still a button: it was transparent with --ink-2 text and no
   border at all, which reads as dim label text rather than something to click */
button.ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--btn-line);
}
button.ghost:hover { background: var(--btn); border-color: var(--ink-2); }

/* ---------------------------------------------------------------- sign in */

body.gate {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px 16px;
  background:
    radial-gradient(900px 500px at 15% -10%, #16272d 0%, transparent 60%),
    var(--bg);
}

.gate-card {
  width: 100%;
  max-width: 380px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 28px;
}

.gate-mark, .rail-mark {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--disp);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 11px;
  color: var(--ink-2);
}

.gate-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
  flex: none;
}

.gate-card h1 { margin: 18px 0 6px; font-size: 24px; }

.gate-note { margin: 0 0 22px; color: var(--ink-3); font-size: 13px; }

.gate-card label {
  display: block;
  margin: 14px 0 6px;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.gate-card input {
  width: 100%;
  padding: 9px 11px;
  font-family: var(--mono);
  font-size: 14px;
  color: var(--ink);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.gate-card button[type="submit"] {
  width: 100%;
  margin-top: 22px;
  padding: 10px;
  font-weight: 600;
  color: #10181a;
  background: var(--accent);
  border-color: var(--accent);
}

.gate-error {
  margin-bottom: 4px;
  padding: 9px 11px;
  font-size: 13px;
  color: var(--bad);
  background: color-mix(in srgb, var(--bad) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--bad) 35%, transparent);
  border-radius: var(--r);
}

/* ------------------------------------------------- the clock band and tabs */

/* The clock sits above everything because which book is running decides what
   every number below it means, and in a sim it is not the server's clock at
   all. It stays put when the page scrolls for the same reason. */

body.shell { min-height: 100vh; }

/* NOT .bar. That name was already the coverage-bar component further down --
   height 5px, overflow hidden -- so calling the clock band .bar rendered the
   whole thing as a five pixel strip with the clock, the book switch and the
   tabs clipped out of existence, and painted .clock-side i as a green
   coverage fill because .bar i is that component's inner fill. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 15;
  background: var(--bg-2);
  border-bottom: 1px solid var(--line);
}

.topbar-top {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 20px;
  align-items: center;
  padding: 12px 24px 10px;
}

.topbar-acts {
  display: flex;
  gap: 7px;
  align-items: center;
  margin-left: auto;
}
.topbar-acts form { margin: 0; }
.who {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
  margin-right: 4px;
}

.clock {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 5px 14px 5px 10px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 100px;
}

.clock-time {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 21px;
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1.15;
}

/* the money, beside the clock. First thing wanted on a phone and it used to be
   four taps down in the performance tab */
.money {
  display: flex;
  gap: 4px 12px;
  align-items: baseline;
  flex-wrap: wrap;
  padding: 5px 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--ink-3);
  border-radius: 100px;
}
.money.up { border-left-color: var(--good); }
.money.down { border-left-color: var(--bad); }
.money-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.money-big {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 21px;
  font-weight: 600;
  line-height: 1.15;
}
.money-side {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 11.5px;
  color: var(--ink-2);
}
.money.up .money-side { color: var(--good); }
.money.down .money-side { color: var(--bad); }

.clock-side { display: flex; flex-direction: column; line-height: 1.3; }
.clock-side b {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-2);
}
.clock-side i {
  font-style: normal;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* the mode is the one thing on this page that must never be misread, so it
   gets a colour of its own rather than the accent every chip uses */
.mode {
  padding: 3px 10px;
  border-radius: 100px;
  font-family: var(--disp);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border: 1px solid transparent;
}
.mode.live  { color: var(--bad);  background: color-mix(in srgb, var(--bad) 15%, transparent);  border-color: color-mix(in srgb, var(--bad) 45%, transparent); }
.mode.paper { color: var(--info); background: color-mix(in srgb, var(--info) 15%, transparent); border-color: color-mix(in srgb, var(--info) 45%, transparent); }
.mode.sim   { color: var(--ink-2); background: var(--panel-2); border-color: var(--line); }

/* the book being looked at. Three buttons and not a dropdown because which
   book a number came from is the thing most worth not having to click to see --
   a closed select shows one value and hides that there are two others. */
.books-wrap { display: flex; flex-direction: column; gap: 4px; }

.books-label {
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-left: 2px;
}

.books {
  display: flex;
  gap: 0;
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--panel);
}
.book {
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--ink-3);
  padding: 7px 18px;
  font-family: var(--disp);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.book + .book { border-left: 1px solid var(--line); }
.book:hover { color: var(--ink); background: var(--panel-2); }
.book.on {
  color: #10181a;
  background: var(--accent);
}
:root[data-theme="light"] .book.on { color: #fff; }
/* a dot on the book a process is actually running right now */
.book.hot::after {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  margin-left: 7px;
  border-radius: 50%;
  background: var(--good);
  vertical-align: middle;
}
.book.on.hot::after { background: #10181a; }

.tabs {
  display: flex;
  gap: 2px;
  padding: 0 20px;
  overflow-x: auto;
}

.tab-btn {
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--ink-3);
  padding: 9px 14px 10px;
  font-family: var(--disp);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.tab-btn:hover { color: var(--ink); border-color: var(--line); }
.tab-btn.on { color: var(--ink); border-color: var(--accent); }

.tab-page { display: none; }
.tab-page.on { display: block; }

.main { min-width: 0; padding: 22px 24px 160px; }

/* the two tiles at the top of Jobs: what just happened, what happens next */
.duo {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}
.tile {
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.tile .sub { margin-bottom: 10px; }
.tile-line {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  align-items: baseline;
  margin-bottom: 6px;
}
.tile-name { font-family: var(--disp); font-size: 15px; font-weight: 600; }
.tile-note { margin: 6px 0 0; font-size: 12px; color: var(--ink-3); }
.tile-big {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 19px;
}

/* warm up: one button and its state. The whole job layer used to be eight
   cards each with a name to type, which is what buried the two numbers the tab
   is actually for */
.warm {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--ink-3);
  border-radius: 8px;
}
.warm.ok  { border-left-color: var(--good); }
.warm.bad { border-left-color: var(--bad); }
.warm.run { border-left-color: var(--warn); }

.warm-go {
  min-width: 142px;
  padding: 11px 20px;
  font-family: var(--disp);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.03em;
  /* ITS OWN FACE, not the parent's. The three state rules below paint the
     state button green, red or amber and put near-black ink on top of it --
     but a .warm-go with no state behind it (the Stop beside the warm-up
     button, the collector's Run) kept that near-black ink and fell back to the
     plain button background, which is dark text on a dark panel */
  color: var(--ink);
  background: var(--btn);
  border: 1px solid var(--btn-line);
}
/* only the FIRST one carries the state. The others in the row are actions, and
   painting Stop the same amber as "Warming up…" says they are the same thing */
.warm.ok  > .warm-go:first-of-type { background: var(--good); }
.warm.bad > .warm-go:first-of-type { background: var(--bad); }
.warm.run > .warm-go:first-of-type { background: var(--warn); }
.warm > .warm-go:first-of-type {
  color: #10181a;
  border-color: transparent;
}
.warm-go:disabled { cursor: default; opacity: 0.9; }
.warm > .warm-go:first-of-type:disabled { opacity: 1; }
:root[data-theme="light"] .warm > .warm-go:first-of-type { color: #fff; }

/* run / resume / stop, as one group: they are three answers to one question
   and only ever one of them is the live option */
.engine-acts { display: flex; gap: 0; }
.engine-acts .warm-go {
  min-width: 96px;
  border-radius: 0;
  padding: 11px 16px;
  background: var(--btn);
  color: var(--ink);
  border: 1px solid var(--btn-line);
}
.engine-acts .warm-go + .warm-go { border-left-width: 0; }
.engine-acts .warm-go:not(:disabled):hover { background: var(--btn-hi); }
.engine-acts .warm-go:first-child { border-radius: var(--r) 0 0 var(--r); }
.engine-acts .warm-go:last-child { border-radius: 0 var(--r) var(--r) 0; }
.engine-acts .warm-go + .warm-go { border-left: 0; }
.engine-acts .warm-go:not(:disabled):hover { border-color: var(--ink-3); }
.engine-acts .warm-go:disabled { color: var(--ink-3); opacity: 0.5; }
.engine-acts .warm-go:not(:disabled):first-child { background: var(--good); color: #10181a; border-color: var(--good); }
.engine-acts .warm-go:not(:disabled):last-child { background: var(--bad); color: #10181a; border-color: var(--bad); }
:root[data-theme="light"] .engine-acts .warm-go:not(:disabled):first-child,
:root[data-theme="light"] .engine-acts .warm-go:not(:disabled):last-child { color: #fff; }

.engine-when {
  display: flex;
  gap: 7px;
  align-items: center;
  margin-left: auto;
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.engine-when input { width: 150px; }

.warm-side { display: flex; flex-direction: column; line-height: 1.4; }
.warm-side b {
  font-family: var(--disp);
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.warm.ok  .warm-side b { color: var(--good); }
.warm.bad .warm-side b { color: var(--bad); }
.warm.run .warm-side b { color: var(--warn); }
.warm-side span { font-size: 12.5px; color: var(--ink-3); }

.controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-end;
  padding-bottom: 14px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--line-soft);
}
.controls label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.controls select,
.controls input {
  padding: 6px 9px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.crumbs {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-left: auto;
  font-family: var(--mono);
  font-size: 12px;
}
.crumbs button {
  padding: 3px 9px;
  font-size: 12px;
  background: var(--panel-2);
}
.crumbs span { color: var(--ink-3); }

/* ------------------------------------------------------------------ chart */

.chart { margin-bottom: 18px; }

.chart-head {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  align-items: center;
  margin-bottom: 10px;
}

/* the legend is always present at two or more series, so identity never rests
   on colour alone; the end-labels on the plot repeat it a second time */
.legend { display: flex; flex-wrap: wrap; gap: 4px 16px; align-items: center; }
.legend-item {
  display: flex;
  gap: 7px;
  align-items: center;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  user-select: none;
}
.legend-item.off { color: var(--ink-3); opacity: 0.55; }
.legend-key { width: 14px; height: 2px; border-radius: 1px; flex: none; }
.legend-item.off .legend-key { opacity: 0.4; }
.legend-val {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 11.5px;
  color: var(--ink-3);
}

.scale-switch { display: flex; gap: 0; margin-left: auto; }
.scale-switch button {
  border-radius: 0;
  padding: 4px 12px;
  font-size: 11.5px;
  color: var(--ink-3);
}
.scale-switch button:first-child { border-radius: var(--r) 0 0 var(--r); }
.scale-switch button:last-child { border-radius: 0 var(--r) var(--r) 0; }
.scale-switch button + button { border-left: 0; }
.scale-switch button.on { color: var(--ink); background: var(--panel-2); }

.plot {
  position: relative;
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
}
.plot svg { display: block; width: 100%; height: auto; }

.gridline { stroke: var(--grid); stroke-width: 1; }
.axis-text {
  fill: var(--axis-ink);
  font-family: var(--mono);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
}
.series-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.end-label {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  paint-order: stroke;
  stroke: var(--panel);
  stroke-width: 3px;
}
.crosshair { stroke: var(--ink-3); stroke-width: 1; stroke-dasharray: 3 3; }

.tip {
  position: absolute;
  z-index: 5;
  min-width: 170px;
  padding: 8px 10px;
  pointer-events: none;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28);
  font-size: 12px;
}
.tip b { display: block; margin-bottom: 5px; font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.tip-row { display: flex; gap: 8px; align-items: center; justify-content: space-between; }
.tip-row span { display: flex; gap: 6px; align-items: center; color: var(--ink-2); }
.tip-row b {
  display: inline;
  margin: 0;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  font-size: 12px;
}

/* the colour-free channel, for forced-colors and print: each line keeps its
   identity by dash pattern when the hues are taken away */
@media (forced-colors: active), print {
  .series-line[data-key="sp500"]  { stroke-dasharray: 7 3; }
  .series-line[data-key="nasdaq"] { stroke-dasharray: 2 3; }
  .series-line[data-key="gold"]   { stroke-dasharray: 9 3 2 3; }
}

/* a row of label/number pairs, which is what most of Performance is */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  overflow: hidden;
  margin-bottom: 16px;
}
.stat { padding: 9px 11px; background: var(--panel); }
.stat em {
  display: block;
  font-style: normal;
  font-size: 10px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 3px;
}
.stat b {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 15px;
  font-weight: 500;
}

/* the globals editor: an input per row, and a pending row is visibly pending */
.gv-input {
  width: 100%;
  min-width: 90px;
  padding: 4px 7px;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--ink);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
tr.pending td { background: color-mix(in srgb, var(--warn) 10%, transparent); }
tr.pending td:first-child { box-shadow: inset 2px 0 0 var(--warn); }

.save-row {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  align-items: center;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}
.save-row input {
  padding: 6px 9px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.save-row input.note { flex: 1; min-width: 180px; }

.chip {
  display: flex;
  gap: 7px;
  align-items: baseline;
  padding: 4px 9px;
  background: var(--panel);
  border: 1px solid var(--line-soft);
  border-radius: 100px;
  font-size: 11px;
}
.chip span { color: var(--ink-3); }
.chip b { font-family: var(--mono); font-weight: 500; }

/* ------------------------------------------------------------------ cards */

.card {
  margin-bottom: 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  scroll-margin-top: 16px;
}

.card-head {
  padding: 15px 18px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--panel-2);
}
.card-head h2 { margin: 0; font-size: 15px; letter-spacing: 0.01em; }
.card-head p { margin: 5px 0 0; max-width: 88ch; color: var(--ink-3); font-size: 12.5px; }

.card-body { padding: 14px 18px 18px; }

.wait { color: var(--ink-3); font-family: var(--mono); font-size: 12px; }

/* ------------------------------------------------------------------ data */

table { width: 100%; border-collapse: collapse; font-size: 13px; }

th {
  text-align: left;
  font-weight: 500;
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 6px 10px 6px 0;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

td {
  padding: 6px 10px 6px 0;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: baseline;
}

tr:last-child td { border-bottom: 0; }

td.n, th.n {
  text-align: right;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  padding-right: 14px;
}

td.k { font-family: var(--mono); font-size: 12px; color: var(--ink-2); }

.scroll { overflow-x: auto; }

.grid2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 18px;
}

.kv { display: grid; grid-template-columns: auto 1fr; gap: 3px 14px; font-size: 13px; }
.kv dt { color: var(--ink-3); }
.kv dd {
  margin: 0;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.sub {
  margin: 0 0 9px;
  font-family: var(--disp);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* a coverage bar, because 58/60 reads faster as a shape than as a ratio */
.bar {
  position: relative;
  height: 5px;
  min-width: 70px;
  border-radius: 3px;
  background: var(--line-soft);
  overflow: hidden;
}
.bar i {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: 3px;
  background: var(--good);
}
.bar.part i { background: var(--warn); }
.bar.none i { background: var(--bad); }

.pill {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 100px;
  font-family: var(--mono);
  font-size: 11px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.pill.ok   { color: var(--good); background: color-mix(in srgb, var(--good) 13%, transparent); border-color: color-mix(in srgb, var(--good) 32%, transparent); }
.pill.warn { color: var(--warn); background: color-mix(in srgb, var(--warn) 13%, transparent); border-color: color-mix(in srgb, var(--warn) 32%, transparent); }
.pill.bad  { color: var(--bad);  background: color-mix(in srgb, var(--bad) 13%, transparent);  border-color: color-mix(in srgb, var(--bad) 32%, transparent); }
.pill.info { color: var(--info); background: color-mix(in srgb, var(--info) 13%, transparent); border-color: color-mix(in srgb, var(--info) 32%, transparent); }
.pill.mute { color: var(--ink-3); border-color: var(--line); }

.warn-ink { color: var(--warn); }
.bad-ink  { color: var(--bad); }
.good-ink { color: var(--good); }
.dim      { color: var(--ink-3); }

.note {
  margin: 12px 0 0;
  padding: 9px 11px;
  font-size: 12.5px;
  color: var(--ink-2);
  background: var(--bg-2);
  border-left: 2px solid var(--accent);
  border-radius: 0 var(--r) var(--r) 0;
}

/* the selected band, which is the one actually sizing the book */
tr.live td { background: color-mix(in srgb, var(--accent) 9%, transparent); }
tr.live td:first-child { box-shadow: inset 2px 0 0 var(--accent); }

/* ------------------------------------------------------------------ jobs */

.jobs { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 12px; }

.job {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 13px;
  background: var(--panel-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
}
.job.writes { border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.job h3 { margin: 0; font-size: 13.5px; }
.job p { margin: 0; font-size: 12px; color: var(--ink-3); }
.job-row { display: flex; gap: 7px; align-items: center; margin-top: auto; }
.job input {
  flex: 1;
  min-width: 0;
  padding: 5px 8px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.runs { margin-top: 18px; }

/* ----------------------------------------------------------------- modal */

.modal[hidden] { display: none; }

.modal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
  background: rgba(0, 0, 0, 0.55);
}

.modal-box {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 900px;
  max-height: 82vh;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
}

.modal-head {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--panel-2);
  border-radius: 8px 8px 0 0;
}
.modal-head b { font-family: var(--disp); font-size: 14px; }

.modal-body { padding: 16px 18px 20px; overflow: auto; }

/* how far through a step is. Separate from .bar, which is the coverage
   component -- naming this .bar is the mistake that rendered the whole clock
   band five pixels tall */
.pbar-wrap { display: flex; gap: 9px; align-items: center; min-width: 118px; }
.pbar {
  position: relative;
  flex: 1;
  height: 6px;
  min-width: 56px;
  border-radius: 3px;
  background: var(--line-soft);
  overflow: hidden;
}
.pbar i {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: 3px;
  background: var(--warn);
  transition: width 0.4s ease;
}
.pbar.full i { background: var(--good); }
.pbar-txt {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--ink-3);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .pbar i { transition: none; }
}

/* TWS and the collector: one dot each, green up or red down. The dot is never
   the only signal -- the word beside it says the same thing, because colour
   alone fails for a colour-blind reader and in a forced-colours mode */
.lamps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 10px;
  margin-bottom: 14px;
}
.lamp {
  display: flex;
  flex-direction: column;
  gap: 7px;
  align-items: flex-start;
  padding: 12px 14px;
  border: 1px solid var(--line-soft);
  border-radius: 7px;
  background: var(--panel-2);
}
.lamp-top { display: flex; gap: 9px; align-items: center; }
.lamp-top b { font-size: 13.5px; }
.lamp .dot {
  width: 11px;
  height: 11px;
  flex: 0 0 11px;
  border-radius: 50%;
  background: var(--ink-3);
}
.lamp.up .dot { background: var(--good); box-shadow: 0 0 0 3px var(--grid); }
.lamp.down .dot { background: var(--bad); box-shadow: 0 0 0 3px var(--grid); }
.lamp-state {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-2);
}
.lamp.up .lamp-state { color: var(--good); }
.lamp.down .lamp-state { color: var(--bad); }
.lamp-note {
  margin: 0;
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-3);
}

/* warm-up as its two stages. Each one is a title, a bar and the line that says
   where it is -- a left edge in the state's colour carries the state, so the
   pill is confirmation rather than the only signal */
.stage {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 11px 14px;
  margin-bottom: 10px;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--ink-3);
  border-radius: 7px;
  background: var(--panel-2);
}
.stage.running { border-left-color: var(--warn); }
.stage.ok { border-left-color: var(--good); }
.stage.failed,
.stage.stopped { border-left-color: var(--bad); }
.stage-top { display: flex; gap: 9px; align-items: center; }
.stage-top b { font-size: 13px; }
.stage .pbar { height: 8px; }
.stage-at {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-2);
}
.stage .dim { font-size: 11px; line-height: 1.45; }

/* the dates themselves, because "165 missing" is a number and the question is
   always which ones */
.gap-group { margin-bottom: 18px; }
.gap-head {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: baseline;
  margin-bottom: 6px;
}
.gap-head b { font-family: var(--mono); font-size: 13px; }
.gap-years {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 7px;
}
.gap-year {
  padding: 2px 8px;
  border-radius: var(--r);
  background: var(--panel-2);
  border: 1px solid var(--line-soft);
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-2);
}
.gap-dates {
  max-height: 128px;
  overflow: auto;
  padding: 8px 10px;
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.7;
  color: var(--ink-2);
  word-spacing: 6px;
}

/* --------------------------------------------------------------- console */

/* display:flex on a class BEATS the browser's own [hidden] { display: none },
   so without this line the console ignores its hidden attribute and sits over
   the bottom of every tab from the moment the page loads */
.console[hidden] { display: none; }

.console {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  height: 42vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-2);
  border-top: 1px solid var(--line);
  box-shadow: 0 -14px 34px rgba(0, 0, 0, 0.3);
  z-index: 20;
}

.console-head {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  padding: 9px 16px;
  border-bottom: 1px solid var(--line-soft);
}
.console-head b { font-family: var(--disp); font-size: 13px; }
.console-meta { margin-left: 10px; font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.console-acts { display: flex; gap: 7px; }

.console pre {
  flex: 1;
  margin: 0;
  padding: 12px 16px;
  overflow: auto;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-2);
  white-space: pre-wrap;
  word-break: break-word;
}

.foot {
  margin-top: 26px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
  font-size: 12px;
  color: var(--ink-3);
}

/* ----------------------------------------------------------------- small */

@media (max-width: 860px) {
  .topbar-top { padding: 10px 16px 8px; }
  .topbar-acts { margin-left: 0; width: 100%; }
  .tabs { padding: 0 10px; }
  .clock-time { font-size: 18px; }
  .controls { align-items: stretch; }
  .crumbs { margin-left: 0; flex-wrap: wrap; }
  .main { padding: 18px 16px 150px; }
  .console { height: 50vh; }
}

/* ----------------------------------------------------------------- phone
   A REAL LAYOUT, not the desktop one squeezed. The two things wanted on a
   phone are the balance and whether anything is broken, so those go first and
   full width; the identity mark and the signed-in name go away, because they
   answer a question nobody asks twice. Every tap target is >=44px, because the
   buttons were 6px of padding on a 13px font, which is about 28px.
   Tables keep their own horizontal scroll rather than making the page slide. */
@media (max-width: 560px) {
  .rail-mark,
  .who { display: none; }

  .topbar { position: sticky; }
  .topbar-top {
    gap: 8px 10px;
    padding: 9px 14px 7px;
  }

  /* the balance first and across the width, the clock under it */
  .money {
    order: -1;
    width: 100%;
    justify-content: space-between;
    border-radius: 9px;
    padding: 8px 14px;
  }
  .money-big { font-size: 25px; }
  .money-label { display: none; }

  .clock {
    width: 100%;
    justify-content: space-between;
    border-radius: 9px;
    padding: 7px 14px;
  }
  .clock-time { font-size: 17px; }
  .clock-side { align-items: flex-end; text-align: right; }

  .books-wrap { width: 100%; }
  .books { width: 100%; }
  .books-label { display: none; }
  .book { flex: 1; padding: 11px 0; font-size: 13px; }

  .topbar-acts { justify-content: flex-start; flex-wrap: wrap; }

  /* the tabs scroll sideways instead of wrapping to two rows that push the
     content off the first screen */
  .tabs {
    overflow-x: auto;
    scrollbar-width: none;
    flex-wrap: nowrap;
    padding: 0 8px;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tab-btn { flex: 0 0 auto; padding: 12px 13px; }

  .main { padding: 14px 16px 120px; }
  .duo { grid-template-columns: 1fr; }
  .lamps { grid-template-columns: 1fr; }

  /* 44px tap targets */
  button { padding: 11px 15px; min-height: 44px; }
  .warm-go { width: 100%; min-width: 0; min-height: 48px; }
  .warm { gap: 10px; padding: 12px 13px; }
  .warm-side { width: 100%; }
  .engine-acts { width: 100%; }
  .engine-acts .warm-go { flex: 1; width: auto; padding: 13px 8px; }

  .controls { flex-direction: column; align-items: stretch; }
  .controls label,
  .controls input,
  .controls select,
  .controls button { width: 100%; }

  .card-head h2 { font-size: 17px; }

  /* EVERY TABLE BECOMES CARDS. A six column table of text inputs -- the
     globals editor -- cannot be read at 400px however it is scaled, and
     sideways scrolling to reach the input you want to edit is worse than
     useless on a touch screen. So each row becomes a block, each cell a
     label/value line taking its label from the data-label the table helper
     stamps on it, and the header row goes away because every cell now carries
     its own. Numeric cells stop being right-aligned here: there is no column
     for them to line up in any more, and a right-aligned value sitting
     opposite its own label is the layout that makes this read like a form. */
  table, thead, tbody, tr, td { display: block; }
  thead { display: none; }
  .scroll { overflow-x: visible; }

  tbody tr {
    margin-bottom: 9px;
    padding: 9px 11px;
    border: 1px solid var(--line-soft);
    border-radius: 7px;
    background: var(--panel-2);
  }
  tbody td {
    display: flex;
    gap: 12px;
    align-items: center;
    justify-content: space-between;
    padding: 4px 0;
    border: 0;
    text-align: left;
    font-size: 12.5px;
  }
  tbody td.n { text-align: left; }
  tbody td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 38%;
    color: var(--ink-3);
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.02em;
  }
  /* the first cell is the row's name, so it reads as the card's title */
  tbody td:first-child {
    margin-bottom: 3px;
    padding-bottom: 7px;
    border-bottom: 1px solid var(--line-soft);
    font-size: 13.5px;
    font-weight: 600;
  }
  tbody td:first-child::before { display: none; }
  tbody td:empty { display: none; }

  /* a text field takes the width left after its label; a checkbox does not
     stretch, and a 44px tap target makes it a thing a thumb can hit */
  tbody td > input.gv-input { flex: 1; min-width: 0; min-height: 40px; }
  tbody td > input[type="checkbox"] {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    margin: 7px 0;
  }
  tbody td > button { flex: 0 0 auto; min-height: 40px; }

  .gv-input { min-width: 0; }
  .save-row { flex-direction: column; align-items: stretch; }
  .save-row input,
  .save-row button { width: 100%; }

  /* the popup is the whole screen, because a centred box with margins on a
     phone is a small box inside a dim screen */
  .modal { padding: 0; }
  .modal-box {
    max-width: none;
    width: 100%;
    height: 100%;
    max-height: none;
    border-radius: 0;
  }
  .modal-head { padding: 12px 14px; }
  .modal-body { padding: 12px 14px 90px; }

  .console { height: 62vh; }
  .stage { padding: 11px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}
