/*
 * The whole theme. One file, served from this origin, so the CSP never needs 'unsafe-inline'
 * for anything the page actually depends on.
 *
 * Two rules drive the look:
 *  - the system decides light or dark (`prefers-color-scheme`), because this console sits next to
 *    a terminal and fighting the OS setting is just glare;
 *  - every number is tabular. Figures that change once a second must not make the column dance,
 *    so `font-variant-numeric: tabular-nums` plus a fixed decimal count (see web/format.ts).
 */

:root {
  --bg: #f7f7f8;
  --surface: #ffffff;
  --surface-2: #f0f0f2;
  --border: #d9d9de;
  --text: #16181d;
  --text-dim: #5b6070;
  --accent: #2f6df6;
  --ok: #1a7f4b;
  --ok-bg: #e3f5eb;
  --warn: #8a6100;
  --warn-bg: #fdf0d5;
  --bad: #b3261e;
  --bad-bg: #fbe4e2;
  --info-bg: #e5edfe;
  --rail: 232px;
  --radius: 8px;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #111214;
    --surface: #17191d;
    --surface-2: #1e2126;
    --border: #2b2f36;
    --text: #e8eaee;
    --text-dim: #9aa1ad;
    --accent: #6f9bff;
    --ok: #63d19b;
    --ok-bg: #133024;
    --warn: #e0b45c;
    --warn-bg: #33270f;
    --bad: #ff8b82;
    --bad-bg: #3a1a18;
    --info-bg: #17243f;
  }
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  background: var(--bg);
  color: var(--text);
  font: 14px/1.45 var(--sans);
  -webkit-text-size-adjust: 100%;
}

/* Every number, everywhere: fixed-width digits so a live column never jitters. */
.num,
.tile-value,
table td.num,
table th.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  text-align: right;
}

.is-empty {
  color: var(--text-dim);
  font-style: italic;
}

/* ---- shell -------------------------------------------------------------- */

.app {
  display: grid;
  min-height: 100%;
  /* Phones first: content above, a bottom bar below (spec §4). */
  grid-template-rows: 1fr auto;
  grid-template-areas: "content" "rail";
}

.rail {
  grid-area: rail;
  background: var(--surface);
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px));
  overflow-x: auto;
}

.content {
  grid-area: content;
  padding: 16px;
  min-width: 0;
}

.brand {
  font-weight: 650;
  letter-spacing: 0.02em;
  color: var(--text-dim);
}

.rail-links {
  display: flex;
  gap: 4px;
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1;
}

.rail-links a {
  display: block;
  padding: 6px 10px;
  border-radius: var(--radius);
  color: var(--text-dim);
  text-decoration: none;
  white-space: nowrap;
}

.rail-links a:hover {
  background: var(--surface-2);
  color: var(--text);
}

.rail-links a.is-active {
  background: var(--info-bg);
  color: var(--accent);
  font-weight: 600;
}

.rail-links a[hidden] {
  display: none;
}

.rail-pills {
  display: none;
}

.rail-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.who {
  color: var(--text-dim);
}

/* Desktop: the bar becomes a left rail. 900 px is the breakpoint in spec §4. */
@media (min-width: 900px) {
  .app {
    grid-template-rows: none;
    grid-template-columns: var(--rail) 1fr;
    grid-template-areas: "rail content";
  }

  .rail {
    flex-direction: column;
    align-items: stretch;
    border-top: none;
    border-right: 1px solid var(--border);
    padding: 16px 12px;
    gap: 14px;
    overflow-x: visible;
  }

  .rail-links {
    flex-direction: column;
    gap: 2px;
    flex: 0;
  }

  .rail-pills {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: auto;
  }

  .pill-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
  }

  .pill-label {
    color: var(--text-dim);
    font-size: 12px;
  }

  .rail-foot {
    flex-wrap: wrap;
    gap: 6px;
  }

  .content {
    padding: 24px;
  }
}

/* ---- components --------------------------------------------------------- */

.badge {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
  background: var(--surface-2);
  color: var(--text-dim);
  white-space: nowrap;
}

.badge-ok {
  background: var(--ok-bg);
  color: var(--ok);
}

.badge-warn {
  background: var(--warn-bg);
  color: var(--warn);
}

.badge-bad {
  background: var(--bad-bg);
  color: var(--bad);
  font-weight: 600;
}

.badge-info {
  background: var(--info-bg);
  color: var(--accent);
}

.tile {
  display: block;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  color: inherit;
  text-decoration: none;
}

a.tile:hover {
  border-color: var(--accent);
}

.tile-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.tile-title {
  color: var(--text-dim);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.tile-value {
  font-size: 22px;
  margin-top: 6px;
  text-align: left;
}

.tile-sub {
  color: var(--text-dim);
  font-size: 12px;
  margin-top: 2px;
}

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

table {
  border-collapse: collapse;
  width: 100%;
}

th,
td {
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
}

thead th {
  position: sticky;
  top: 0;
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 600;
}

th.sortable {
  cursor: pointer;
  user-select: none;
}

th[data-sort="asc"]::after {
  content: " ▲";
}

th[data-sort="desc"]::after {
  content: " ▼";
}

tbody tr:last-child td {
  border-bottom: none;
}

tr.clickable {
  cursor: pointer;
}

tr.clickable:hover {
  background: var(--surface-2);
}

.empty {
  color: var(--text-dim);
  padding: 16px;
  margin: 0;
  font-style: italic;
}

.empty-detail {
  color: var(--text-dim);
  padding: 0 16px 16px;
  margin: 0;
  font-size: 12px;
}

/* ---- confirmation dialog ------------------------------------------------ */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgb(0 0 0 / 45%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 50;
}

.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  max-width: 420px;
  width: 100%;
}

.modal h2 {
  margin: 0 0 8px;
  font-size: 16px;
}

.modal p {
  margin: 0 0 8px;
  color: var(--text-dim);
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 14px;
}

.btn {
  font: inherit;
  padding: 6px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.btn-danger {
  background: var(--bad);
  border-color: var(--bad);
  color: #fff;
}

.btn:focus-visible,
a:focus-visible,
th:focus-visible,
tr:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ── screens ──────────────────────────────────────────────────────────────────────────────── */

.screen-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 14px;
}

.screen-head h1 {
  font-size: 18px;
  margin: 0;
}

/* The cockpit. `auto-fill` rather than a fixed count: the same ten tiles have to read on a phone
   (spec §4, bottom bar below 900 px) without a second layout. */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 12px;
}

.auth {
  max-width: 360px;
  margin: 40px auto;
}

.auth h1 {
  font-size: 18px;
  margin: 0 0 16px;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--text-dim);
}

.field input {
  font: inherit;
  font-size: 14px;
  padding: 7px 9px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
}

.auth-note {
  min-height: 1.2em;
  font-size: 13px;
  color: var(--text-dim);
}

.auth-alt {
  font-size: 12px;
  color: var(--text-dim);
}

/* ---- solana trades ------------------------------------------------------ */

.chart {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 16px;
  position: relative;
}

.chart-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

/* The provenance of the price is part of the chart, not a caption under it. */
.chart-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
}

.chart-controls {
  display: flex;
  align-items: center;
  gap: 8px;
}

.picker {
  font: inherit;
  font-size: 13px;
  padding: 4px 8px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  max-width: 180px;
}

.tf-picker {
  display: inline-flex;
  gap: 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 2px;
}

.tf-picker .btn {
  padding: 2px 10px;
  font-size: 12px;
  border: 0;
  background: transparent;
  border-radius: 6px;
}

.tf-picker .btn.is-active {
  background: var(--info-bg);
  color: var(--accent);
}

.chart-canvas {
  min-height: 320px;
}

.chart-tooltip {
  position: absolute;
  top: 48px;
  right: 18px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 9px;
  font-family: var(--mono);
  font-size: 12px;
  pointer-events: none;
}

.panels {
  display: grid;
  gap: 16px;
}

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  min-width: 0;
}

.panel h2 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin-bottom: 8px;
}

.load-older {
  margin-top: 10px;
}

.trade-detail h2 {
  font-size: 16px;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text);
}

.detail-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

/* The mint is the identity; it wraps rather than being clipped. */
.mint {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text-dim);
  word-break: break-all;
}

.detail-section {
  margin-top: 14px;
}

.detail-section h3 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin-bottom: 6px;
}

.kv {
  display: grid;
  grid-template-columns: minmax(96px, auto) 1fr;
  gap: 2px 12px;
  font-size: 13px;
}

.kv dt {
  color: var(--text-dim);
}

.kv dd {
  font-family: var(--mono);
  word-break: break-word;
}

@media (min-width: 1100px) {
  .panels {
    grid-template-columns: 2fr 1fr;
  }

  .panel-trades {
    grid-row: span 2;
  }
}

.chart-band-label {
  margin-top: 6px;
  font-size: 11px;
  color: var(--text-dim);
}

.degraded-note {
  background: var(--warn-bg);
  color: var(--warn);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 12px;
  margin-bottom: 12px;
  font-size: 13px;
}

/* ── Solana engine (spec §4.2) ─────────────────────────────────────────────────────────────── */

/* Every panel carries its data age — and the degraded reason when there is one — in the same
   place, so a reader never has to hunt for how old what they are looking at is. */
.panel-note {
  margin-top: 8px;
  font-size: 11px;
  color: var(--text-dim);
}

/* A sentence the panel needs said rather than implied: the gate's D2 caveat, the tick-skip
   window. Deliberately not a heading — it is qualification, not a title. */
.panel-caption {
  font-size: 11px;
  color: var(--text-dim);
  margin-bottom: 8px;
}

.kv {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 3px 0;
  font-size: 13px;
}

.kv-key {
  color: var(--text-dim);
}

.kv-value {
  font-family: var(--mono);
  text-align: right;
  word-break: break-all;
}

.gate-run {
  border-bottom: 1px solid var(--border);
  padding-bottom: 8px;
  margin-bottom: 8px;
}

.equity-picker {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}

.equity-picker .btn {
  padding: 3px 10px;
  font-size: 12px;
}

.equity-picker .btn.is-active {
  border-color: var(--accent);
  color: var(--text);
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.legend-item {
  font-size: 11px;
  color: var(--text-dim);
  font-family: var(--mono);
}

/* The two halves are shown SIDE BY SIDE because neither is the state on its own (ruling D7). */
.sentiment-halves {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px;
}

.sentiment-halves h3 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin-bottom: 6px;
}

/* ── CEX recorder (spec §4.3) ──────────────────────────────────────────────────────────────── */

/* Every panel on this screen polls on its own, so every panel carries its own age badge and its
   own degraded note. The head is where both live, beside the title. */
.panel-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

.panel-head h2 {
  margin-bottom: 0;
}

/* Rows are sockets, columns symbols. The grid scrolls sideways rather than squeezing a cell to
   the point where its status word no longer fits. */
.matrix {
  border-collapse: collapse;
  font-size: 11px;
  display: block;
  overflow-x: auto;
  max-width: 100%;
}

.matrix th {
  font-weight: 500;
  color: var(--text-dim);
  text-align: left;
  padding: 4px 8px;
  white-space: nowrap;
}

.matrix-cell {
  padding: 4px 8px;
  border: 1px solid var(--border);
  font-family: var(--mono);
  white-space: nowrap;
}

/* The recorder's vocabulary, in three bands: an operator scanning the grid is looking for the bad
   cell, not reading a gradient. An ABSENT pair is muted — it is not an ok cell. */
.tone-ok {
  background: var(--ok-bg);
  color: var(--ok);
}

.tone-warn {
  background: var(--warn-bg);
  color: var(--warn);
}

.tone-bad {
  background: var(--bad-bg);
  color: var(--bad);
}

.tone-info {
  background: var(--info-bg);
}

.tone-muted {
  background: var(--surface-2);
  color: var(--text-dim);
}

.liq-legend {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 8px;
  font-size: 11px;
  font-family: var(--mono);
}

.liq-legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.liq-swatch {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  display: inline-block;
}

.archive-hour,
.integrity-symbol {
  margin-top: 14px;
}

.archive-hour h3,
.integrity-symbol h3 {
  font-size: 12px;
  font-family: var(--mono);
}

.integrity-hour {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 10px;
  margin-top: 8px;
}

/* A broken pin is the row the panel exists to show. It is marked on the row itself, so it is
   visible without reading the verdict column. */
.integrity-hour.is-broken {
  border-color: var(--bad);
}

.integrity-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 12px;
}

.pinned-variant {
  font-size: 11px;
  color: var(--text-dim);
}

.pin-events {
  display: grid;
  gap: 4px;
  margin-bottom: 10px;
}

.pin-event {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 12px;
}

/* The numbers behind the stacked bars. The chart shows the shape; this is what can be read. */
.failure-counts {
  margin-top: 10px;
}

/* The pinned variant is marked in the grid as well as beside it, so the pin and the evidence for
   it are not two things the reader has to join up by eye. */
.integrity-hour tbody tr.is-pinned {
  outline: 1px solid var(--accent);
  outline-offset: -1px;
}

/* A grid this build cannot read says so. It never fabricates variant rows. */
.grid-unrecognised {
  color: var(--warn);
}

/* ── Operator panel (spec §4.4) ────────────────────────────────────────────────────────────── */

/* One group per engine, so the pair of buttons that can stop a given engine sit together and a
   click cannot land on the wrong one by proximity. */
.operator-panel .action-groups {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin: 16px 0;
}

.operator-panel .action-group {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px;
  min-width: 220px;
}

.operator-panel .action-group h2 {
  margin: 0 0 8px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}

.operator-panel .action-group .btn {
  display: block;
  width: 100%;
  margin-top: 8px;
}

/* A disabled button is disabled because a request for that engine is still queued. It stays
   visible — the operator needs to see that the action exists and why it cannot be used. */
.operator-panel .btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* What the LAST REQUEST did. Sticky until the operator tries again. */
.operator-panel .panel-message {
  color: var(--warn);
  font-size: 12px;
}
