/* A dark instrument panel, rebuilt for legibility.

   The first version of this UI was dense enough that even its author had to hover things to
   remember what they did. The rules this rewrite follows:

     1  every view says, in a sentence, what it is for - in the sidebar and again at the top
     2  plain words on controls and stats; monospace and jargon only on actual data
     3  one accent; red/green/amber reserved for state that means something
     4  space is information - related things share a card, unrelated things do not share a row

   The one domain rule carried over intact, because it is the most important thing on any of
   these screens: **solid means observed, faint or hollow means assumed.** Belief starts at an
   age prior, and presenting that prior as though it were a finding about a child is the exact
   lie this instrument exists to avoid. */

:root {
  --bg: #0b0e14;
  --surface: #11161f;
  --surface-2: #171d28;
  --surface-3: #1e2531;
  --line: #232b38;
  --line-soft: #1b222d;
  --ink: #e7ecf4;
  --dim: #97a2b2;
  --faint: #5c6778;
  --accent: #5eead4;
  --accent-soft: #5eead422;
  --accent-ink: #052019;
  --good: #4ade80;
  --bad: #fb7185;
  --warn: #fbbf24;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
  --r: 10px;
  --r-s: 7px;
}
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 13.5px/1.55 var(--sans);
  display: grid; grid-template-columns: 232px 1fr; overflow: hidden;
}
a { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 4px; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---- sidebar ------------------------------------------------------------ */

#side {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--surface); border-right: 1px solid var(--line);
}
.brand { padding: 18px 18px 14px; }
.brand .word { font-size: 17px; font-weight: 700; letter-spacing: .2px; }
.brand .word span { color: var(--accent); }
.brand .tag { font: 10.5px/1.4 var(--mono); color: var(--faint); text-transform: uppercase; letter-spacing: 1px; }

#nav { display: flex; flex-direction: column; gap: 2px; padding: 4px 10px; }
.nav-item {
  display: block; padding: 8px 12px; border-radius: var(--r-s);
  text-decoration: none; color: var(--dim); border: 1px solid transparent;
}
.nav-item:hover { background: var(--surface-2); color: var(--ink); }
.nav-item.on { background: var(--surface-3); color: var(--ink); border-color: var(--line); }
.nav-item.on .nav-name { color: var(--accent); }
.nav-name { font-weight: 600; font-size: 13.5px; }
.nav-desc { font-size: 11.5px; color: var(--faint); margin-top: 1px; }
.nav-item.on .nav-desc, .nav-item:hover .nav-desc { color: var(--dim); }

.side-foot { margin-top: auto; padding: 12px; }
#side-status {
  border: 1px solid var(--line); border-radius: var(--r); background: var(--surface-2);
  padding: 10px 12px; display: flex; flex-direction: column; gap: 6px;
}
.status-row { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--dim); min-width: 0; }
.status-row .val { font: 11px var(--mono); color: var(--dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.status-row .lbl { color: var(--faint); font-size: 11px; flex: none; width: 62px; }
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--faint); flex: none; }
.dot.ok { background: var(--good); box-shadow: 0 0 6px #4ade8066; }
.dot.warn { background: var(--warn); }
.dot.bad { background: var(--bad); }

/* ---- main column -------------------------------------------------------- */

#main { display: flex; flex-direction: column; min-height: 0; min-width: 0; }

.topbar {
  display: flex; align-items: center; gap: 16px;
  padding: 12px 20px 10px; border-bottom: 1px solid var(--line); background: var(--surface);
}
#view-title { margin: 0; font-size: 16px; font-weight: 650; letter-spacing: .1px; }
#view-sub { margin: 1px 0 0; font-size: 12px; color: var(--faint); }
.topbar .grow { flex: 1; }

/* The child switcher. Global, because every view answers a question about one child. */
#kids { display: flex; gap: 0; border: 1px solid var(--line); border-radius: var(--r-s); overflow: hidden; flex: none; }
#kids button {
  font: 12.5px var(--sans); color: var(--dim); background: var(--surface-2);
  border: 0; border-right: 1px solid var(--line); padding: 6px 12px; cursor: pointer;
}
#kids button:last-child { border-right: 0; }
#kids button:hover { color: var(--ink); background: var(--surface-3); }
#kids button.on { background: var(--accent); color: var(--accent-ink); font-weight: 650; }
#kids .age { opacity: .65; font-size: 11px; margin-left: 3px; }

#banner {
  display: none; padding: 8px 20px; font-size: 12.5px;
  background: #2a1417; color: #ffc9d1; border-bottom: 1px solid #4a1f26;
}
#banner.show { display: block; }
#banner.ok { background: #0f2418; color: #b8f0cd; border-color: #1e4034; }

main#view { flex: 1; min-height: 0; display: flex; overflow: hidden; }

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

button, select, input[type="number"] {
  font: inherit; color: var(--ink); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--r-s); padding: 6px 12px; cursor: pointer;
}
select { padding: 5px 8px; }
button:hover, select:hover { border-color: var(--faint); }
button:disabled { opacity: .38; cursor: not-allowed; }
button.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); font-weight: 650; }
button.primary:hover { filter: brightness(1.06); }
button.danger { color: var(--bad); border-color: #4a2229; }
button.danger:hover { background: #2a1417; border-color: var(--bad); }
button.ghost { background: transparent; }
button.small { padding: 3px 9px; font-size: 12px; }

.pill {
  font: 10.5px/1 var(--mono); text-transform: uppercase; letter-spacing: .6px;
  padding: 4px 8px; border-radius: 999px; border: 1px solid var(--line); color: var(--dim);
  white-space: nowrap;
}
.pill.live { color: var(--good); border-color: #1e4034; }

.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 14px 16px; margin-bottom: 14px;
}
.card-title { font-size: 13px; font-weight: 650; margin: 0 0 2px; }
.card-sub { font-size: 12px; color: var(--faint); margin: 0 0 10px; }
.hint { font-size: 11.5px; color: var(--faint); line-height: 1.5; }

.pane { display: flex; flex-direction: column; min-height: 0; min-width: 0; flex: 1; }
.pane + .pane, aside.detail { border-left: 1px solid var(--line); }
.pane-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 10px 16px; border-bottom: 1px solid var(--line); background: var(--surface);
}
.pane-head .t { font-size: 12.5px; font-weight: 650; white-space: nowrap; }
.pane-head .n { font-size: 11.5px; color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.scroll { overflow-y: auto; padding: 14px 16px; flex: 1; min-height: 0; }
.scroll::-webkit-scrollbar { width: 9px; height: 9px; }
.scroll::-webkit-scrollbar-thumb { background: #242c39; border-radius: 5px; }
.empty { color: var(--faint); padding: 28px 8px; text-align: center; font-size: 12.5px; }

/* ---- playground --------------------------------------------------------- */

.pg-left { flex: 1.6; }
.pg-rail { flex: 1; max-width: 400px; min-width: 320px; }

.mode-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 12px; }
.mode-card {
  text-align: left; padding: 10px 12px; border-radius: var(--r-s);
  background: var(--surface-2); border: 1px solid var(--line); cursor: pointer; color: var(--ink);
}
.mode-card:hover { border-color: var(--faint); }
.mode-card.on { border-color: var(--accent); background: var(--accent-soft); }
.mode-card .mn { font-weight: 650; font-size: 13px; }
.mode-card.on .mn { color: var(--accent); }
.mode-card .md { font-size: 11.5px; color: var(--faint); margin-top: 2px; line-height: 1.4; }
.mode-card.on .md { color: var(--dim); }

.setup-row { display: flex; align-items: center; gap: 12px; }
.turns-ctl { display: flex; align-items: center; gap: 8px; color: var(--dim); font-size: 12.5px; }
.turns-ctl input { width: 96px; accent-color: var(--accent); }

.runbar {
  display: none; align-items: center; gap: 10px; padding: 8px 16px;
  border-bottom: 1px solid var(--line); background: var(--surface); font-size: 12.5px; color: var(--dim);
}
.runbar.show { display: flex; }
.runbar .sess { font: 11.5px var(--mono); color: var(--faint); }
.livedot { width: 8px; height: 8px; border-radius: 50%; background: var(--good); animation: breathe 1.8s ease-in-out infinite; }
@keyframes breathe { 0%,100% { opacity: 1 } 50% { opacity: .3 } }

.turn { margin-bottom: 14px; max-width: 720px; }
.who { font: 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .8px; color: var(--faint); margin-bottom: 4px; }
.said {
  font-size: 14px; line-height: 1.5; padding: 9px 13px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line-soft); display: inline-block; max-width: 100%;
}
.turn.kippo .said { border-left: 2px solid var(--accent); color: #d9f5ee; }
.turn.child .said { background: var(--surface-2); color: #f5f0e8; }
.partial { color: var(--dim); font-style: italic; }
.silence { color: var(--faint); font-style: italic; background: transparent; border-style: dashed; }
.meta { font: 10.5px/1.5 var(--mono); color: var(--faint); margin-top: 4px; }
.turn.cut .said { opacity: .55; }
.cut-mark { font: 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .8px;
            color: var(--warn); margin: -6px 0 14px; opacity: .8; }

.intent-line { font-size: 11.5px; color: var(--faint); margin-top: 4px; }
.intent-line b { color: var(--dim); font-weight: 600; }
details.intent-more { margin-top: 3px; font-size: 11.5px; color: var(--faint); }
details.intent-more summary { cursor: pointer; color: var(--faint); font-size: 11px; user-select: none; }
details.intent-more summary:hover { color: var(--dim); }
details.intent-more .row-i { margin: 4px 0 0 12px; font-style: italic; }

.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.stat { background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: var(--r-s); padding: 8px 10px; }
.stat .n { font: 16px/1.2 var(--mono); font-variant-numeric: tabular-nums; }
.stat .l { font-size: 10.5px; color: var(--faint); margin-top: 2px; line-height: 1.3; }
.stat.hot .n { color: var(--warn); }

/* The microphone, made visible. When Kippo gets cut off, this bar answers "by what?" -
   the level has to sit above the tick for a fifth of a second before it counts as a voice. */
.meter { display: flex; align-items: center; gap: 10px; }
.meter-track { position: relative; flex: 1; height: 10px; border-radius: 5px; background: var(--surface-3); overflow: hidden; }
.meter-fill { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--faint); border-radius: 5px; transition: width 90ms linear, background 200ms; }
.meter-fill.voiced { background: var(--accent); }
.meter-tick { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--warn); opacity: .8; }
.meter-state { font: 10.5px var(--mono); color: var(--faint); width: 64px; flex: none; text-align: right; }

details.logbox { border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); margin-bottom: 14px; }
details.logbox summary {
  cursor: pointer; padding: 10px 14px; font-size: 12.5px; font-weight: 650; user-select: none;
  display: flex; align-items: baseline; gap: 8px;
}
details.logbox summary .hint { font-weight: 400; }
details.logbox .logscroll { max-height: 320px; overflow-y: auto; padding: 4px 14px 10px; border-top: 1px solid var(--line-soft); }

.ev { font: 11.5px/1.6 var(--mono); padding: 3px 0; border-bottom: 1px solid var(--line-soft);
      display: flex; gap: 8px; align-items: baseline; }
.ev .t { color: var(--faint); font-variant-numeric: tabular-nums; flex: none; }
.ev .k { color: var(--dim); flex: none; width: 104px; }
.ev .v { color: var(--ink); word-break: break-word; }
.ev.err .k, .ev.err .v { color: var(--bad); }
.ev.ok .k { color: var(--good); }
.lag { color: var(--warn); }

/* ---- graph -------------------------------------------------------------- */

/* The story band, the map, and the key: three stacked rows, not three panels floating on
   top of the picture. They used to be absolutely positioned over the canvas and covered two
   of its four quadrants - a legend obscuring the thing it explains. Stacking them means the
   overlap cannot come back, at any window size, without anyone remembering to check. */
.graph-wrap { flex: 1; position: relative; overflow: hidden; user-select: none; min-height: 0;
  background: radial-gradient(ellipse at 35% 20%, #121826 0%, #0a0d13 70%); }
.graph-wrap canvas { position: absolute; inset: 0; width: 100%; height: 100%; cursor: grab; touch-action: none; }
.graph-wrap canvas.dragging { cursor: grabbing; }

.g-top { display: flex; gap: 8px; align-items: flex-start; padding: 10px 12px 8px; }
.g-chip {
  background: #11161fdd; border: 1px solid var(--line); border-radius: var(--r-s);
  padding: 6px 10px; font-size: 12px; color: var(--dim); backdrop-filter: blur(4px);
}
.g-chip b { color: var(--ink); }

/* The story header: sentences, not counters. Reads like a person explaining the picture. */
.g-story {
  flex: 1; max-width: 720px; font-size: 12.5px; line-height: 1.6; color: var(--dim);
}
.g-story b { color: var(--ink); font-weight: 600; }
.g-story i { color: var(--warn); font-style: italic; }

/* No `.g-axis` here any more. The axis is drawn inside the scene by graph3d.js, with a tick
   and a year on it, because height is now age and age has a unit. A CSS rail beside the
   canvas could only ever say "first things / later things" - which is what it said. */

/* One sentence when a belief moves: the flash says something happened, this says what. */
.g-caption {
  background: #131c17e8; border: 1px solid #2c4a3a; border-radius: var(--r);
  padding: 8px 12px; font-size: 12.5px; line-height: 1.55; color: var(--dim);
  backdrop-filter: blur(4px); opacity: 0; transition: opacity .45s;
}
.g-caption.show { opacity: 1; }
.g-caption { max-width: 340px; flex: 0 1 340px; }
.g-caption b { color: var(--ink); font-weight: 600; }

/* The key band, under the map. The live caption sits to its left so the sentence about what
   just happened and the standing explanation of the marks share a row without stacking on
   the picture. */
.g-foot {
  display: flex; align-items: flex-start; gap: 14px; padding: 8px 12px 10px;
  border-top: 1px solid var(--line);
}
.legend {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 1px 18px;
  flex: 1; font-size: 11.5px; line-height: 1.7; color: var(--dim);
}
.legend b { color: var(--ink); font-weight: 600; }
.legend .sw { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 6px; vertical-align: -1px; }

.g-caption:empty { display: none; }

/* Colour means subject now, so the key is not optional. Generated from the same strand list
   and the same hues the canvas uses - see `strandKey` - so it cannot drift out of agreement
   with the picture when a strand is added. */
.g-controls { position: absolute; right: 12px; bottom: 12px; display: flex; gap: 8px; align-items: center; }
.strands { display: flex; flex-direction: column; gap: 5px; flex: 0 0 auto;
  padding-left: 14px; border-left: 1px solid var(--line); }
.skey { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--dim); white-space: nowrap; }
.skey i { width: 9px; height: 9px; border-radius: 50%; }

/* The 2D fallback keeps its old classes. */
.edge { fill: none; stroke: #2b3340; stroke-width: 1.4; }
.edge.soft { stroke-dasharray: 3 4; stroke: #232a34; }
.edge.lit { stroke: var(--accent); stroke-width: 2.2; opacity: .9; }
.edge.dim { opacity: .25; }
.node circle.body { stroke-width: 2; transition: fill .6s ease, stroke .3s ease; }
.node.untested circle.body { fill: #161c25; stroke-dasharray: 3 3; }
.node circle.ring { fill: none; stroke: var(--accent); stroke-width: 1.6; opacity: .8; }
.node circle.target { fill: none; stroke: var(--accent); stroke-width: 2.5; animation: pulse 1.6s ease-in-out infinite; }
.node text.label { font: 9.5px/1.1 var(--sans); fill: var(--dim); text-anchor: middle; }
.node.hot text.label { fill: var(--ink); }
.node { cursor: pointer; }
.node:hover circle.body { stroke: var(--ink); }
.node.faded { opacity: .18; }
.node text.badge { font: 9px var(--mono); fill: #07110f; text-anchor: middle; }
.node .moved { animation: flash 1.6s ease-out; }
@keyframes flash { from { r: 26px; opacity: .9; } to { r: 17px; opacity: 0; } }
@keyframes pulse { 0%,100% { r: 22px; opacity: .9; } 50% { r: 27px; opacity: .3; } }

aside.detail { width: 340px; flex: none; background: var(--surface); display: flex; flex-direction: column; min-height: 0; }

/* ---- lists, bars, tables ------------------------------------------------ */

.strand { font: 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .9px;
          color: var(--faint); margin: 18px 0 7px; }
.strand:first-child { margin-top: 0; }
.node-row { padding: 5px 0 6px 10px; border-left: 2px solid transparent; margin-left: -10px; }
.node-row.target { border-left-color: var(--accent); background: #10201d; }
.node-row.moved { border-left-color: var(--warn); }
.node-top { display: flex; align-items: baseline; gap: 8px; }
.node-label { flex: 1; font-size: 12.5px; }
.node-row.untested .node-label { color: var(--dim); }
.p { font: 11px/1 var(--mono); color: var(--dim); font-variant-numeric: tabular-nums; }
.node-row.untested .p { opacity: .55; }
.delta { font: 10px/1 var(--mono); font-variant-numeric: tabular-nums; }
.delta.up { color: var(--good); } .delta.down { color: var(--bad); }
.bar { height: 3px; background: var(--surface-3); border-radius: 2px; margin-top: 4px; overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--faint); transition: width .5s ease; }
.node-row.untested .bar > i {
  background: repeating-linear-gradient(90deg, #2b3340 0 3px, transparent 3px 6px);
}
.node-row.known .bar > i { background: var(--good); }
.node-row.target .bar > i { background: var(--accent); }
.flag { font: 10px/1 var(--mono); color: var(--warn); margin-top: 4px; }

.table-scroll { overflow-x: auto; }
.table-scroll td, .table-scroll th { white-space: nowrap; }
table { border-collapse: collapse; width: 100%; font-size: 12.5px; }
th { text-align: left; font: 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .8px;
     color: var(--faint); padding: 6px 10px 6px 0; border-bottom: 1px solid var(--line); }
td { padding: 7px 10px 7px 0; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
td.num { font: 11.5px var(--mono); font-variant-numeric: tabular-nums; color: var(--dim); }
tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: var(--surface-2); }
tr.picked td { background: var(--accent-soft); }

/* ---- the diff view ------------------------------------------------------ */

.diff { border: 1px solid var(--line); border-radius: var(--r); margin-bottom: 14px; overflow: hidden;
        background: var(--surface); max-width: 860px; }
.diff > header { background: var(--surface-2); padding: 7px 12px; border-bottom: 1px solid var(--line);
                 font: 10.5px/1.6 var(--mono); color: var(--dim); letter-spacing: .4px;
                 display: flex; gap: 10px; flex-wrap: wrap; align-items: baseline; }
.diff > header .grow { flex: 1; }
.diff .body { padding: 11px 12px; }
.quote { border-left: 2px solid var(--accent); padding: 2px 0 2px 10px; margin: 6px 0;
         color: #f5f0e8; font-size: 13px; }
.reading { display: flex; gap: 10px; align-items: baseline; padding: 6px 0; border-top: 1px solid var(--line-soft); }
.pol { font: 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .6px;
       padding: 3px 6px; border-radius: 4px; flex: none; }
.pol.demonstrated { color: var(--good); background: #0f2418; }
.pol.contradicted { color: var(--bad); background: #2a1418; }
.pol.attempted { color: var(--warn); background: #2a2211; }
.pol.silent { color: var(--dim); background: var(--surface-3); }
.moves { font: 11px/1.7 var(--mono); color: var(--dim); margin-top: 8px; }
.moves .up { color: var(--good); } .moves .down { color: var(--bad); }
.moves .cause { color: var(--faint); }

.note-block { color: var(--dim); font-size: 12.5px; background: var(--surface-2); border-radius: var(--r-s);
              padding: 9px 11px; border-left: 2px solid var(--line); margin-bottom: 14px; }
