/* The instrument design system: tokens, base, components, and the three-pane
   shell for every Twinton page built on the kit (web/factory/demo/dashboard.js). The design
   authority is ~/dev/mockups — zinc near-black surfaces, 1px hairline rules
   doing the separation, 3–6px radii, dense condensed type, mono numerals,
   amber/red/green status, bevelled steel-blue action buttons.

   Dark-first on purpose: this is an ops console, and an ops console does not
   follow the OS — the operator picks. :root carries the dark instrument
   values; light exists only when a page stamps data-theme="light". There is
   deliberately no prefers-color-scheme flip.

   Token discipline: every colour below comes from a token. scene.js reads
   --panel-2, --panel-3, --rule, --rule-bright through cssVar() to paint the
   3D estate, so those four must always resolve to plain colours. */

/* ============ TOKENS ============ */

:root {
  /* Surfaces — the zinc family from mockups/saab-fleet-resilience/tokens.css.
     Four steps so depth reads without shadows: page, panel, raised, control. */
  --ground:#09090b; --panel:#18181b; --panel-2:#1f1f23; --panel-3:#26262b;
  --ink:#f4f4f5; --ink-2:#a1a1aa; --ink-3:#71717a;
  /* Rules: -soft barely parts panel from panel, --rule is the working
     hairline, -bright edges things that must read at a glance (scene.js
     draws selected geometry with it). */
  --rule:#27272a; --rule-soft:#212124; --rule-bright:#3a3a40;
  /* Signal: selection, links, focus — the DNA's steel-blue "you are here",
     kept apart from the action triplet so a selected row never looks like
     a button. */
  --signal:#57a7d8; --signal-dim:#14222e;
  /* Status: a status colour states a condition, never a series. */
  --good:#3fc23c; --good-dim:#102410;
  --warn:#e2a33b; --warn-dim:#271d0d;
  --bad:#f0564a;  --bad-dim:#2b1210;
  /* The two series colours. Blue/amber is the hue-opposed pair the DNA
     already speaks: separation survives deuteranopia and protanopia because
     it rides the blue–yellow axis plus a lightness gap, and both hold
     >= 6.7:1 against --panel (blue 6.7, amber 8.1 by WCAG relative
     luminance), so hairline strokes stay legible on the dark ground.
     A third series is a redesign, not a third colour. */
  --chart-a:#57a7d8; --chart-b:#e2a33b;
  /* Actions: the bevelled steel-blue triplet — base, highlight (gradient
     top), shaded edge (border). Buttons and nothing else wear it. */
  --accent:#4d7fae; --accent-2:#5d92c4; --accent-3:#3e6a94;
  /* Shadow exists for things that genuinely float (tooltips, overlays);
     resting panels are separated by hairlines, not elevation. */
  --shadow:0 8px 28px rgba(0,0,0,.55);

  /* Type: condensed display face for headers and wordmarks (the instrument
     voice), sans for prose, mono for identifiers. */
  --font-display:"Avenir Next Condensed","Roboto Condensed","Arial Narrow",sans-serif;
  --font-sans:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --text-0:11px; --text-1:12.5px; --text-2:13.5px;
  --text-3:15px; --text-4:17px;   --text-5:20px;

  --space-1:4px; --space-2:8px; --space-3:12px;
  --space-4:16px; --space-5:24px; --space-6:32px;
  --radius-1:3px; --radius-2:6px; --radius-3:10px;
  --ease:cubic-bezier(.22,1,.36,1);
  --dur-1:140ms; --dur-2:260ms;
}

/* Light: the same zinc family mirrored, chosen — never inherited from the
   OS. The light series pair is the one already validated with the six-check
   palette validator against white panels; do not eyeball replacements in. */
:root[data-theme="light"] {
  --ground:#f4f4f5; --panel:#ffffff; --panel-2:#ececee; --panel-3:#e0e0e3;
  --ink:#18181b; --ink-2:#52525b; --ink-3:#71717a;
  --rule:#d4d4d8; --rule-soft:#e4e4e7; --rule-bright:#a1a1aa;
  --signal:#2f6f9f; --signal-dim:#e2edf5;
  --good:#1f7a3c; --good-dim:#e2f1e6;
  --warn:#8a5a12; --warn-dim:#f6eee0;
  --bad:#b3271e;  --bad-dim:#f7e3e0;
  --chart-a:#0A7EA0; --chart-b:#8A5A12;
  /* Darkened a step so white button labels keep contrast on light ground. */
  --accent:#40719d; --accent-2:#4d84b4; --accent-3:#33608a;
  --shadow:0 1px 2px rgba(24,24,27,.10), 0 8px 24px rgba(24,24,27,.14);
}

/* ============ BASE ============ */

* { box-sizing:border-box; margin:0; }
body {
  background:var(--ground); color:var(--ink);
  font:500 var(--text-3)/1.5 var(--font-sans);
  padding:var(--space-5) var(--space-4) 64px;
  -webkit-font-smoothing:antialiased;
}
/* Standalone dashboards are a centred column of cards; a shell page owns the
   whole viewport instead, so the column padding must go. Not restricted to a
   direct child: consoleShell() mounts into whatever root the page hands it. */
body:has(.tw-shell) { padding:0; overflow:hidden; }
main { max-width:980px; margin:0 auto; display:grid; gap:var(--space-4); }
a { color:var(--signal); }
h1 { font:600 var(--text-5)/1.2 var(--font-display); letter-spacing:.02em; }
h2 { font:600 var(--text-0)/1.3 var(--font-display); letter-spacing:.1em;
     text-transform:uppercase; color:var(--ink-3); margin-bottom:var(--space-3); }
:focus-visible { outline:2px solid var(--signal); outline-offset:1px; }
@media (prefers-reduced-motion: reduce) {
  * { transition-duration:1ms !important; animation:none !important; }
}

/* ============ COMPONENTS ============ */

/* Card: the only resting container. Hairline does the separation — shadow
   is reserved for things that float. */
.card { background:var(--panel); border:1px solid var(--rule);
        border-radius:var(--radius-2); padding:var(--space-4); }
header.card { display:flex; flex-wrap:wrap; gap:var(--space-3) var(--space-4);
              align-items:baseline; }
.sub { color:var(--ink-2); font-size:var(--text-2); flex-basis:100%; }
.spacer { flex:1; }

/* Badge: a state word. Rectangular and tracked, like a stencil, because a
   state is a stamp — not a pill. */
.badge { padding:2px 8px; border-radius:var(--radius-1); font-weight:600;
         font-size:var(--text-1); letter-spacing:.04em; }
.b-ok   { background:var(--good-dim); color:var(--good); }
.b-warn { background:var(--warn-dim); color:var(--warn); }
.b-bad  { background:var(--bad-dim);  color:var(--bad); }
.b-none { background:var(--panel-2);  color:var(--ink-2); }

/* Chip: one data source and how much to trust it right now. */
.chips { display:flex; flex-wrap:wrap; gap:var(--space-2); }
.chip { display:inline-flex; gap:6px; align-items:center; font-size:var(--text-1);
        border:1px solid var(--rule); border-radius:var(--radius-1);
        padding:2px 9px; color:var(--ink-2); background:var(--panel-2); }
.chip b { color:var(--ink); font-weight:600; }
.dot { width:8px; height:8px; border-radius:50%; }

/* Signal card: one risk or finding, with its level and what to do. */
.signals { display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
           gap:var(--space-3); }
.signal h3 { font-size:var(--text-3); display:flex; align-items:center;
             gap:10px; margin-bottom:var(--space-2); }
.signal p { font-size:var(--text-2); color:var(--ink-2); }
.signal .rec { margin-top:10px; padding-top:10px;
               border-top:1px solid var(--rule-soft);
               color:var(--ink); font-size:var(--text-2); }

/* Time chart: figure, scrolling wrap, recessive axes, one tooltip. */
figure { margin:0; }
.legend { display:flex; gap:var(--space-4); font-size:var(--text-1);
          color:var(--ink-2); margin:6px 2px 2px; flex-wrap:wrap; }
.legend i { display:inline-block; width:14px; height:8px;
            border-radius:2px; margin-right:6px; vertical-align:baseline; }
.chartwrap { position:relative; overflow-x:auto; }
svg text { font:11px var(--font-sans); fill:var(--ink-3); }
/* The stamp inside the plot: what kind of numbers the picture draws, in the
   tag's own mono voice so it reads as provenance rather than as data. */
svg text.stamp { font:600 10px var(--font-mono); letter-spacing:.05em;
                 text-transform:uppercase; fill:var(--ink-2); }
.tip { position:absolute; pointer-events:none; background:var(--panel-2);
       border:1px solid var(--rule-bright); border-radius:var(--radius-1);
       padding:8px 10px; font-size:var(--text-1); box-shadow:var(--shadow);
       display:none; min-width:150px; }
.tip b { display:block; color:var(--ink); margin-bottom:2px; }
.tip span { color:var(--ink-2); display:block; }

/* Stat tile: one measured value, wearing its quality and its age. Numerals
   are tabular so a column of readings lines up like an instrument. */
.tiles { display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
         gap:var(--space-3); }
.tile .v { font:600 26px/1.2 var(--font-display);
           font-variant-numeric:tabular-nums; }
.tile .u { color:var(--ink-2); font-size:var(--text-2); }
/* No reading held: the same recessive italic a kv row uses for an absence, so
   nothing about it reads as a measured value. */
.tile .v.absent { font:400 italic var(--text-2)/1.6 var(--font-sans);
                  color:var(--ink-3); }
.tag { font:600 10px/1.6 var(--font-mono); letter-spacing:.05em;
       text-transform:uppercase; padding:1px 6px; border-radius:var(--radius-1);
       background:var(--warn-dim); color:var(--warn); }
.tag.good { background:var(--good-dim); color:var(--good); }
/* a tag says which quality the number carries, so the tones are the status
   tones: uncertain reads as a warning, bad and stale as a fault */
.tag.warn { background:var(--warn-dim); color:var(--warn); }
.tag.bad  { background:var(--bad-dim);  color:var(--bad); }
.meta { color:var(--ink-3); font-size:var(--text-1); margin-top:4px;
        font-variant-numeric:tabular-nums; }

/* Evidence: what the page rests on, in words. */
.evidence { font-size:var(--text-2); color:var(--ink-2); }
.evidence b { color:var(--ink); }

/* Buttons: the DNA's bevelled steel-blue instrument key — gradient, shaded
   edge, and the inset top highlight that makes it read as pressable metal. */
button { background:linear-gradient(180deg, var(--accent-2), var(--accent));
         color:#fff; border:1px solid var(--accent-3);
         border-radius:var(--radius-1); padding:6px 14px;
         font:600 var(--text-2)/1.4 var(--font-sans); cursor:pointer;
         box-shadow:inset 0 1px 0 rgba(255,255,255,.25);
         transition:filter var(--dur-1) var(--ease); }
button:hover { filter:brightness(1.12); }
button:active { transform:translateY(1px); }
button[disabled] { filter:grayscale(.7) brightness(.7); cursor:wait;
                   transform:none; }
.note { font-size:var(--text-1); color:var(--ink-3); }
.error { color:var(--bad); }

/* Custom map (customMap): glyph markers over stored geometry. Marker stroke
   is a status tone (state, never a series); shape carries identity. */
.mapwrap { position:relative; overflow:hidden; }
.mapwrap svg { display:block; width:100%; height:auto; }
.mk { cursor:pointer; }
.mk .halo { fill:none; }
.mk:focus-visible { outline:none; }
.mk:focus-visible .halo { stroke:var(--signal); stroke-width:2; }
.mk.sel .halo { stroke:var(--signal); stroke-width:1.5; stroke-dasharray:3 3; }
/* View switcher: ghost keys, not action keys — pressing one changes what you
   look at, not what the twin does, so it must not wear the accent bevel. */
.map-views { display:flex; gap:6px; }
.map-views button { background:var(--panel-2); color:var(--ink-2);
  border:1px solid var(--rule); border-radius:var(--radius-1);
  padding:3px 11px; box-shadow:none; }
.map-views button[aria-pressed="true"] { background:var(--signal-dim);
  color:var(--signal); border-color:var(--signal); }
.map-day { width:100%; margin-top:var(--space-2); accent-color:var(--signal); }

/* ============ SHELL — the three-pane console (.tw-*) ============ */

/* assets | stage | actions+AI. Rail widths live in local vars so closing a
   rail is one attribute on the shell; the rail itself is display:none so its
   hairline cannot leave a stripe, and every child is placed on an explicit
   column so nothing reflows into the wrong pane. */
.tw-shell { --tw-l:320px; --tw-r:384px;
  display:grid; height:100dvh;
  grid-template-rows:48px minmax(0,1fr);
  grid-template-columns:var(--tw-l) minmax(0,1fr) var(--tw-r); }
.tw-shell[data-left="closed"]  { --tw-l:0px; }
.tw-shell[data-right="closed"] { --tw-r:0px; }
.tw-shell[data-left="closed"]  > .tw-left  { display:none; }
.tw-shell[data-right="closed"] > .tw-right { display:none; }

.tw-topbar { grid-row:1; grid-column:1 / -1;
  display:flex; align-items:center; gap:var(--space-3); min-width:0;
  padding:0 var(--space-4);
  background:linear-gradient(180deg, var(--panel), var(--ground));
  border-bottom:1px solid var(--rule); }
.tw-topbar h1 { font-size:var(--text-4); white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; }
.tw-scope { font:500 var(--text-1)/1.4 var(--font-mono); color:var(--ink-3);
  white-space:nowrap; }
.tw-note { font-size:var(--text-0); color:var(--ink-3); white-space:nowrap; }
/* Rail toggles: looking-controls, not actions — ghost keys; pressed = the
   rail is open. A closed rail is display:none, so these are the way back. */
.tw-railtoggle { background:var(--panel-2); color:var(--ink-3);
  border:1px solid var(--rule); border-radius:var(--radius-1);
  padding:3px 10px; font:600 var(--text-0)/1.4 var(--font-sans);
  letter-spacing:.05em; text-transform:uppercase; box-shadow:none; }
.tw-railtoggle[aria-pressed="true"] { background:var(--signal-dim);
  color:var(--signal); border-color:var(--signal); }

.tw-rail { grid-row:2; min-width:0; min-height:0; overflow-y:auto;
  background:var(--ground); font-size:var(--text-2); }
.tw-shell > .tw-left  { grid-column:1; border-right:1px solid var(--rule); }
.tw-shell > .tw-right { grid-column:3; border-left:1px solid var(--rule); }
.tw-rail-hd { display:flex; align-items:center; gap:var(--space-2);
  padding:var(--space-2) var(--space-4);
  border-bottom:1px solid var(--rule-soft); }
.tw-rail-hd h2 { margin:0; flex:1; }
/* Collapse: chromeless — a chevron in the corner is furniture, not a key. */
.tw-collapse { background:none; border:0; box-shadow:none;
  color:var(--ink-3); padding:0 var(--space-1); font-size:var(--text-2);
  line-height:1; cursor:pointer; }
.tw-collapse:hover { color:var(--ink); filter:none; }
.tw-collapse:active { transform:none; }

.tw-stage { grid-row:2; grid-column:2; display:flex; flex-direction:column;
  min-width:0; min-height:0; background:var(--ground);
  /* the stage is a <main>, and the base main rule's max-width + auto margins
     would shrink a grid item to its content — undo both explicitly */
  max-width:none; margin:0; }
.tw-views { display:flex; gap:6px; flex-wrap:wrap; flex:none;
  padding:var(--space-2) var(--space-3);
  border-bottom:1px solid var(--rule-soft); }
/* Same ghost-key rule as .map-views: switching what you look at must not
   wear the action bevel. */
.tw-views button { background:var(--panel-2); color:var(--ink-2);
  border:1px solid var(--rule); border-radius:var(--radius-1);
  padding:3px 11px; box-shadow:none; }
.tw-views button[aria-pressed="true"] { background:var(--signal-dim);
  color:var(--signal); border-color:var(--signal); }
.tw-stage-body { flex:1; min-height:0; position:relative; overflow:auto;
  padding:var(--space-3); }
/* scene and canvas views own the pane edge to edge */
.tw-stage-body[data-fill="1"] { padding:0; overflow:hidden; }

/* Asset tree. .arow / .arow.sel / .hdot are pinned by studio_check.js —
   restyle them, never rename them. Selection is the steel-blue edge bar, so
   the eye finds "where am I" the same way in tree, chips and map. */
.tw-tree { padding:var(--space-2) 0; }
.tw-tree section { border-bottom:1px solid var(--rule-soft);
  padding:var(--space-1) 0; }
.tw-tree h3 { display:flex; align-items:center; gap:8px; cursor:pointer;
  font:600 var(--text-0)/1.4 var(--font-display); letter-spacing:.1em;
  text-transform:uppercase; color:var(--ink-2);
  padding:7px var(--space-4) 4px; }
.tw-tree h3 .count { color:var(--ink-3); font-weight:400; margin-left:auto;
  font-variant-numeric:tabular-nums; }
.tw-search { display:block; width:calc(100% - 2 * var(--space-4));
  margin:var(--space-2) var(--space-4); background:var(--panel);
  color:var(--ink); border:1px solid var(--rule);
  border-radius:var(--radius-1); padding:6px 9px;
  font:inherit; font-size:var(--text-2); }
.arow { display:flex; align-items:center; gap:8px;
  padding:5px var(--space-4); cursor:pointer; color:var(--ink-2);
  border-left:2px solid transparent;
  transition:background var(--dur-1) var(--ease); }
.arow:hover { background:var(--panel); }
.arow.sel { background:var(--signal-dim); color:var(--ink);
  border-left-color:var(--arow-accent, var(--signal)); }
/* The card icon: a drawn glyph (js/icons.js) or a literal the operator typed.
   Both sit on the row's baseline; the glyph takes the type's accent when the
   card carries one, so a type reads the same colour in the tree and in the
   asset panel. */
.arow .icon { flex:none; font-size:var(--text-1); display:inline-flex;
  align-items:center; color:var(--arow-accent, inherit); }
.arow .icon svg { display:block; }
.hdot { width:8px; height:8px; border-radius:50%; flex:none; }

/* Panel: one subject on a rail. Hairline below, brushed-steel header strip
   straight from the DNA for the panels that must read across the room. */
.tw-panel { border-bottom:1px solid var(--rule);
  padding:0 0 var(--space-3); }
.tw-panel.closed { padding-bottom:0; }
.tw-panel-hd { display:flex; align-items:baseline; gap:var(--space-2);
  background:linear-gradient(180deg, var(--ink), var(--ink-2));
  color:var(--ground); font:700 var(--text-4)/1.3 var(--font-display);
  letter-spacing:.03em; padding:5px var(--space-4);
  margin-bottom:var(--space-3); }
.tw-panel-hd h3 { font:inherit; flex:1; min-width:0; }
.tw-panel-meta { font:500 var(--text-0)/1.4 var(--font-sans);
  color:var(--ground); opacity:.75; white-space:nowrap; }
.tw-panel-hd .tw-collapse { color:var(--ground); opacity:.75; }
.tw-panel-hd .tw-collapse:hover { color:var(--ground); opacity:1; }
.tw-panel > :not(.tw-panel-hd) {
  margin-left:var(--space-4); margin-right:var(--space-4); }

/* KV rows: the instrument readout. Values right-aligned and tabular so a
   column scans like a gauge cluster; the quality tag rides each value
   because a number without its quality is not an answer. */
.tw-kv { display:flex; align-items:baseline; gap:var(--space-2);
  padding:3px 0; }
.tw-k { color:var(--ink-2); flex:1; min-width:0; }
.tw-v { color:var(--ink); font-weight:600; text-align:right;
  font-variant-numeric:tabular-nums; display:flex; align-items:baseline;
  gap:6px; }
/* a stated absence must not read like a held value */
.tw-v.absent { color:var(--ink-3); font-weight:400; font-style:italic; }

/* Ranked actions: an <ol> whose order is the rank — flex drops the UA
   markers, so the rank numeral is drawn back on with a counter. The button
   inside inherits the global bevel, so the pressable thing is unmistakable. */
.tw-actions { display:flex; flex-direction:column; gap:var(--space-2);
  list-style:none; padding:0; counter-reset:tw-rank; }
.tw-action { display:flex; align-items:center; flex-wrap:wrap;
  gap:var(--space-1) var(--space-2); padding-bottom:var(--space-2);
  border-bottom:1px solid var(--rule-soft); counter-increment:tw-rank; }
.tw-action::before { content:counter(tw-rank); flex:none;
  font:600 var(--text-1)/1.6 var(--font-mono); color:var(--ink-3);
  min-width:14px; text-align:right; }
.tw-action > b { flex:1; min-width:0; }
.tw-action:last-child { border-bottom:0; padding-bottom:0; }
/* the why is a second line under the title, full width — squeezing the
   reason into a sliver beside the button made it unreadable */
.tw-action .why { color:var(--ink-2); font-size:var(--text-1);
  flex:1 1 100%; order:2; margin-left:calc(14px + var(--space-2)); }
.tw-action button { white-space:nowrap; flex:none; }
.tw-action.accent { border-left:2px solid var(--accent);
  padding-left:var(--space-2); }

/* Chat: the one conversation UI. Questions read as the operator's line;
   answers stand on a raised panel with the accent edge — grounded output,
   visibly distinct from measured readouts. */
.tw-chat { display:flex; flex-direction:column; gap:var(--space-2); }
.tw-chatlog { display:flex; flex-direction:column; gap:var(--space-2);
  overflow-y:auto; max-height:300px; }
.tw-chat .q { align-self:flex-end; max-width:90%;
  background:var(--panel-2); border:1px solid var(--rule);
  border-radius:var(--radius-2); padding:6px 10px; color:var(--ink); }
.tw-chat .a { background:var(--panel); border:1px solid var(--rule);
  border-left:2px solid var(--accent); border-radius:var(--radius-1);
  padding:8px 10px; color:var(--ink-2); }
.tw-chat .a b { color:var(--ink); }
.tw-chat form { display:flex; gap:var(--space-2); }
.tw-chat form input { flex:1; min-width:0; background:var(--panel);
  color:var(--ink); border:1px solid var(--rule);
  border-radius:var(--radius-1); padding:6px 9px; font:inherit;
  font-size:var(--text-2); }
.tw-chat.busy form { opacity:.75; }

/* Chips (shell): view switchers and scope facts — ghost keys, same rule as
   .map-views: looking, not acting, so no accent bevel. */
.tw-chips { display:flex; flex-wrap:wrap; gap:6px; }
.tw-chip { background:var(--panel-2); color:var(--ink-2);
  border:1px solid var(--rule); border-radius:var(--radius-1);
  padding:3px 11px; font:600 var(--text-1)/1.4 var(--font-sans);
  cursor:pointer; box-shadow:none; }
.tw-chip:hover { color:var(--ink); }
.tw-chip[aria-pressed="true"] { background:var(--signal-dim);
  color:var(--signal); border-color:var(--signal); }
/* A chip that cannot act: still shown, because the twin's type offers it and
   hiding it would leave the reader wondering — but plainly out of reach, with
   the reason beside it rather than only in a tooltip. */
.tw-chip:disabled { cursor:not-allowed; color:var(--ink-3);
  border-style:dashed; background:transparent; }
.tw-chip:disabled:hover { color:var(--ink-3); }
.tw-chip .why { font-weight:400; color:var(--ink-3); }

/* Asset panel (assetPanel): the per-asset detail, whatever kind of twin it
   is. No new colours — the identity wears the presentation card's accent
   through --tw-asset-accent when the workspace set one, and falls back to the
   same steel-blue "you are here" every other selection uses. */
.tw-asset { display:flex; flex-direction:column; gap:var(--space-3); }
.tw-asset-hd { display:flex; align-items:center; gap:var(--space-2);
  border-left:2px solid var(--tw-asset-accent, var(--rule-bright));
  padding-left:var(--space-2); }
.tw-asset-icon { flex:none; display:inline-flex; align-items:center;
  color:var(--tw-asset-accent, var(--ink-2)); }
.tw-asset-name { flex:1; min-width:0;
  font:700 var(--text-4)/1.25 var(--font-display); letter-spacing:.02em; }
.tw-asset-hd .badge { flex:none; }
.tw-asset-sub { color:var(--ink-2); font-size:var(--text-1); }
.tw-asset-chips { display:flex; flex-wrap:wrap; gap:var(--space-2); }
/* The card's own words, or the stated absence of a card — either way it is
   commentary, so it recedes the way .note does. */
.tw-asset-blurb { color:var(--ink-3); font-size:var(--text-1); }
.tw-asset-sec { display:flex; flex-direction:column; gap:var(--space-2); }
.tw-asset-sec h4 { font:600 var(--text-0)/1.3 var(--font-display);
  letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3); }

/* Readings: the same hairline-gap grid as .tw-statgrid, each cell a kit
   stat tile that can be picked to re-scope the history below it. */
.tw-chans { display:grid; gap:1px; background:var(--rule);
  border:1px solid var(--rule); border-radius:var(--radius-1);
  overflow:hidden;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); }
.tw-chan { background:var(--panel); padding:var(--space-2) var(--space-3);
  cursor:pointer; border-left:2px solid transparent;
  transition:background var(--dur-1) var(--ease); }
.tw-chan:hover { background:var(--panel-2); }
.tw-chan.sel { background:var(--signal-dim);
  border-left-color:var(--tw-asset-accent, var(--signal)); }
/* a tile in a rail is one of several, not the headline of a page */
.tw-chan .tile .v { font-size:var(--text-5); }

/* Stat grid: 1px gaps over the rule colour so the hairlines themselves
   divide the tiles — separation without borders piling up at the joins. */
.tw-statgrid { display:grid; gap:1px; background:var(--rule);
  border:1px solid var(--rule); border-radius:var(--radius-1);
  overflow:hidden;
  grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); }
.tw-stat { background:var(--panel); padding:var(--space-2) var(--space-3); }
.tw-stat .v { font:600 22px/1.2 var(--font-display);
  font-variant-numeric:tabular-nums; }
.tw-stat .u { color:var(--ink-2); font-size:var(--text-1); }
