/* Mars Arena — mission-control theme.
   Palette per MARS_ARENA_PORTFOLIO_MANIFEST §5: basalt near-black, oxidised
   Mars red, PDS amber, cold telemetry cyan. Monospace is reserved for
   provenance and telemetry so that a number always looks like a measurement. */
:root {
  --bg: #0c0b0a;
  --bg2: #14120f;
  --bg3: #1c1915;
  --bg4: #241f19;
  --fg: #ece7df;
  --fg-dim: #a39a8d;
  --fg-faint: #6d655b;

  --rust: #c65a2e;          /* oxidised Mars red — the product's own accent */
  --rust-dim: #8a3d1e;
  --amber: #e0a13a;         /* PDS amber — archive facts */
  --cyan: #58b6c8;          /* telemetry cyan — computed values */
  --violet: #8e7bc3;        /* knowledge layer, kept away from archive colours */

  --border: #2b251e;
  --border-hi: #3d342a;
  --danger: #d8574f;
  --ok: #6fae72;
  --warn: #d9944f;

  --title-h: 27px;
  --menubar-h: 36px;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Inter", "Helvetica Neue", Arial, sans-serif;
}
* { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden;
  background: var(--bg); color: var(--fg);
  font: 13px/1.45 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* ---------- menubar ---------- */
#menubar {
  position: fixed; top: 0; left: 0; right: 0; height: var(--menubar-h);
  display: flex; align-items: center; gap: 10px; padding: 0 11px;
  background: linear-gradient(#191510, #100d0a);
  border-bottom: 1px solid var(--border);
  z-index: 5000; user-select: none;
}
.mb-title {
  font-weight: 700; letter-spacing: .06em; margin-right: 4px; white-space: nowrap;
  font-size: 13px; text-transform: uppercase;
}
.mb-title span { color: var(--rust); }
.mb-buttons { display: flex; gap: 3px; flex-wrap: nowrap; overflow-x: auto; min-width: 0; scrollbar-width: none; }
.mb-buttons::-webkit-scrollbar { display: none; }
.mb-btn {
  padding: 3px 9px; border-radius: 4px; cursor: pointer; white-space: nowrap;
  color: var(--fg-dim); border: 1px solid transparent; font-size: 12px;
}
.mb-btn:hover { color: var(--fg); background: var(--bg3); }
.mb-btn.on { color: var(--rust); border-color: var(--rust-dim); background: rgba(198,90,46,.10); }
.mb-right { margin-left: auto; display: flex; align-items: center; gap: 9px; }
.mb-stat {
  font-family: var(--mono); font-size: 11px; color: var(--fg-dim);
  padding: 2px 8px; border-radius: 4px; background: var(--bg3); border: 1px solid var(--border);
  white-space: nowrap;
}
.mb-stat b { color: var(--amber); font-weight: 600; }

/* ---------- desktop & windows ---------- */
#desktop { position: fixed; top: var(--menubar-h); left: 0; right: 0; bottom: 0; overflow: hidden; }
.win {
  position: absolute; display: flex; flex-direction: column;
  background: var(--bg2); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0,0,0,.6);
  min-width: 200px; min-height: 120px;
}
.win.focused { border-color: var(--border-hi); box-shadow: 0 12px 38px rgba(0,0,0,.75); }
.win-title {
  height: var(--title-h); flex: 0 0 var(--title-h);
  display: flex; align-items: center; gap: 8px; padding: 0 9px;
  background: linear-gradient(#221d17, #191510);
  border-bottom: 1px solid var(--border); border-radius: 8px 8px 0 0;
  cursor: grab; user-select: none;
  font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: #bdb4a7;
}
.win.focused .win-title { color: var(--fg); }
.win-title:active { cursor: grabbing; }
.win-dock, .win-close {
  width: 17px; height: 17px; border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
  color: var(--fg-faint); cursor: pointer; font-size: 12px; line-height: 1; flex: none;
}
.win-dock { margin-left: auto; font-family: var(--mono); }
.win-dock:hover { color: var(--cyan); background: var(--bg4); }
.win-close:hover { background: var(--danger); color: #fff; }
.win-body { flex: 1 1 auto; overflow: auto; position: relative; }
.win-body.noscroll { overflow: hidden; }
.win-grip { position: absolute; right: 0; bottom: 0; width: 17px; height: 17px; cursor: nwse-resize; z-index: 10; }
.win-grip::after {
  content: ""; position: absolute; right: 3px; bottom: 3px; width: 8px; height: 8px;
  border-right: 2px solid #4b4238; border-bottom: 2px solid #4b4238;
}
/* left/right dock edges — the IDE-style pull the owner asked for */
.win.docked-right, .win.docked-left { border-radius: 0; box-shadow: none; }
.win.docked-right { border-right: 0; border-top: 0; border-bottom: 0; }
.win.docked-left { border-left: 0; border-top: 0; border-bottom: 0; }
.win-edge {
  position: absolute; top: 0; bottom: 0; width: 6px; cursor: ew-resize; z-index: 11;
}
.win-edge.left { left: -3px; }
.win-edge.right { right: -3px; }
.win-edge:hover { background: rgba(88,182,200,.25); }

/* ---------- controls ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--bg3); color: var(--fg); border: 1px solid var(--border);
  border-radius: 5px; padding: 4px 10px; font-size: 12px; cursor: pointer; user-select: none;
}
.btn:hover { border-color: var(--rust-dim); color: #fff; }
.btn:active { background: var(--bg4); }
.btn.primary { background: var(--rust-dim); border-color: var(--rust-dim); color: #fff; }
.btn.primary:hover { background: var(--rust); }
.btn.small { padding: 2px 7px; font-size: 11px; }
.btn.on { color: var(--rust); border-color: var(--rust-dim); background: rgba(198,90,46,.10); }
.btn:disabled { opacity: .42; cursor: default; pointer-events: none; }
.input, .select, textarea.input {
  background: #080706; color: var(--fg); border: 1px solid var(--border);
  border-radius: 5px; padding: 4px 7px; font-size: 12px; outline: none; font-family: var(--mono);
}
.input:focus, .select:focus { border-color: var(--rust-dim); }
.select { font-family: var(--sans); }
label.chk { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; font-size: 12px; color: var(--fg-dim); user-select: none; }
label.chk input { accent-color: var(--rust); }
input[type=range] { accent-color: var(--rust); height: 16px; }

/* ---------- tables ---------- */
.table { width: 100%; border-collapse: collapse; font-size: 12px; }
.table th {
  position: sticky; top: 0; z-index: 2; text-align: left; padding: 5px 8px;
  background: var(--bg3); color: var(--fg-dim); font-weight: 600;
  border-bottom: 1px solid var(--border); white-space: nowrap; user-select: none; cursor: pointer;
  font-size: 10px; letter-spacing: .09em; text-transform: uppercase;
}
.table th:hover { color: var(--fg); }
.table th.sorted { color: var(--amber); }
.table td { padding: 4px 8px; border-bottom: 1px solid #1a1612; white-space: nowrap; }
.table tbody tr { cursor: pointer; }
.table tbody tr:hover { background: rgba(198,90,46,.08); }
.table tbody tr.sel { background: rgba(198,90,46,.17); }
.table .num { font-family: var(--mono); }

/* ---------- score bar (preserves the original arena look) ---------- */
.bar { display: inline-flex; align-items: center; gap: 7px; }
.bar-track { width: 74px; height: 5px; border-radius: 3px; background: #241f19; overflow: hidden; }
.bar-fill { height: 100%; background: linear-gradient(90deg, var(--rust-dim), var(--rust)); }
.bar-val { font-family: var(--mono); font-size: 11.5px; color: var(--fg); min-width: 34px; text-align: right; }

/* ---------- tags ---------- */
.tag {
  font-size: 10px; font-family: var(--mono); padding: 1px 6px; border-radius: 9px;
  background: var(--bg3); color: var(--fg-dim); border: 1px solid var(--border); white-space: nowrap;
}
/* The three claims channels from CONTRACT.md. Every number on screen wears one:
   amber came from the archive unchanged, cyan was computed here, violet was said
   by a person on camera. */
.tag.archive { color: var(--amber); border-color: #6a4f1f; background: rgba(224,161,58,.09); }
.tag.computed { color: var(--cyan); border-color: #24525c; background: rgba(88,182,200,.09); }
.tag.corpus { color: var(--violet); border-color: #463d6b; background: rgba(142,123,195,.10); }
.tag.fact { color: var(--ok); border-color: #2c4c2e; background: rgba(111,174,114,.09); }
.tag.inference { color: var(--cyan); border-color: #24525c; background: rgba(88,182,200,.09); }
.tag.speculation { color: var(--warn); border-color: #6a4a20; background: rgba(217,148,79,.09); }
.tag.p0 { color: var(--fg-faint); }
.tag.p1 { color: var(--fg-dim); }
.tag.p2 { color: var(--amber); border-color: #6a4f1f; }
.tag.p3 { color: var(--rust); border-color: var(--rust-dim); background: rgba(198,90,46,.12); }

/* ---------- misc ---------- */
.pane { padding: 9px; }
.row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.row + .row { margin-top: 7px; }
.col { display: flex; flex-direction: column; gap: 4px; }
.sep { height: 1px; background: var(--border); margin: 9px 0; }
.dim { color: var(--fg-dim); }
.faint { color: var(--fg-faint); }
.mono { font-family: var(--mono); }
.fld-label { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--fg-faint); }
.msg-empty { padding: 20px 12px; color: var(--fg-faint); text-align: center; font-size: 12px; }
.err { color: var(--danger); font-size: 12px; }
.canvas-host { position: absolute; inset: 0; }
.canvas-host canvas { display: block; width: 100%; height: 100%; }
.hud {
  position: absolute; pointer-events: none; font-family: var(--mono); font-size: 10.5px;
  color: var(--fg-dim); background: rgba(8,7,6,.72); padding: 3px 7px; border-radius: 4px;
  border: 1px solid var(--border); white-space: pre;
}
.hud.tl { left: 8px; top: 8px; }
.hud.bl { left: 8px; bottom: 8px; }
.hud.br { right: 8px; bottom: 8px; }
.overlay-btns { position: absolute; right: 8px; top: 8px; display: flex; gap: 4px; z-index: 3; }

/* ---------- the foot of the stage ----------
   The switch and the legend both want the bottom of the globe, and when they were
   positioned independently they overlapped: the legend ran under the switch and its
   last few words came out the other side as loose fragments. Stacking them in one
   column means neither can be placed on top of the other by a change in the length
   of the other's text. */
.stage-foot {
  position: absolute; left: 8px; right: 8px; bottom: 8px; z-index: 4;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  pointer-events: none;
}
.stage-foot > * { pointer-events: auto; max-width: 100%; }

/* Larger than the buttons top-right because it answers a different kind of question.
   Those change how the globe is drawn; this changes what is on it, which is the only
   choice on this screen a first-time reader has to make before anything means
   anything. */
.layer-switch {
  display: flex; gap: 5px;
  padding: 4px; border-radius: 9px;
  background: rgba(8, 7, 6, .82); border: 1px solid var(--border);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  box-shadow: 0 6px 22px rgba(0, 0, 0, .55);
}
.ls-btn {
  display: flex; align-items: center; gap: 7px; cursor: pointer;
  padding: 5px 11px; border-radius: 6px; white-space: nowrap;
  font-family: var(--sans); font-size: 12px; color: var(--fg-faint);
  background: transparent; border: 1px solid transparent;
}
.ls-btn:hover { color: var(--fg-dim); border-color: var(--border-hi); }
/* Off is legible, not hidden: a reader has to be able to find the layer they turned
   off. Only the opacity of the glyph and the weight of the label carry the state. */
.ls-btn .ls-g { font-size: 13px; line-height: 1; opacity: .35; }
.ls-btn.on { color: var(--fg); background: var(--bg3); border-color: var(--border-hi); }
.ls-btn.on .ls-g { opacity: 1; }
.ls-btn .ls-n {
  font-family: var(--mono); font-size: 11px; color: var(--fg-faint);
  padding: 1px 6px; border-radius: 4px; background: rgba(255, 255, 255, .04);
}
.ls-btn.on .ls-n { color: var(--fg-dim); background: rgba(255, 255, 255, .07); }
@media (max-width: 560px) {
  .layer-switch { flex-wrap: wrap; justify-content: center; }
  .ls-btn { padding: 5px 8px; font-size: 11.5px; }
  /* The bar fits the title, the window buttons and one more thing. Measured at 390px it was
     trying to hold 501px of content and pushing 242px of it off the right edge — including the
     way back out, which the note beside that link in the markup calls the difference between an
     instrument and a dead end. The two counters are diagnostics and read "--" until the archive
     answers, so they are what gives way. */
  .mb-stat { display: none; }
  .mb-right { gap: 6px; min-width: 0; }
  /* Hiding the counters was not enough on its own: flex shrinks items in proportion, so the
     button row gave up a share and the link gave up a share, and the link is the one that then
     has nowhere to go. Stated outright instead — the row takes the leftover and scrolls inside
     itself, the title and the way out keep their width. */
  .mb-title { flex: 0 0 auto; }
  .mb-link { flex: 0 0 auto; }

  /* Sharing one row with the title and the way out left the tab bar about 90px, and a scroll
     container that narrow shows one tab: "Places". Every other view — including the globe the
     whole case is about — was reachable only by a horizontal swipe inside a strip with no
     scrollbar, on a bar that gives no sign there is anything to swipe. A view nobody can find is
     a view that is not there. So the tabs take the second row and the whole width of it, which
     is what makes the phone layout's one-view-at-a-time rule navigable rather than a trap. */
  #menubar { flex-wrap: wrap; height: auto; padding: 0 11px 6px; row-gap: 4px; }
  .mb-title, .mb-right { margin-top: 6px; }
  .mb-buttons { order: 3; flex: 1 0 100%; gap: 4px; padding-bottom: 1px; }
  .mb-btn { padding: 5px 11px; font-size: 12.5px; }
  /* The bar is two rows tall now, so the surface below it has to start lower or the first row of
     whichever view is open sits underneath the tabs. */
  #desktop { top: 74px; }
}

/* The window chrome, on a screen with no cursor.
   ---------------------------------------------
   720px is the same threshold main.js uses to switch to one full-screen view at a time, and once
   a window cannot be moved, resized or overlapped there is nothing for a drag grip, a dock toggle
   or a resize edge to do — they are three tap targets that either do nothing or strand the reader
   on an empty desktop. The close button goes with them: switching views is what the menubar is
   for, and closing the only thing on screen is not a thing anyone means to do here. */
@media (max-width: 719px) {
  .win-grip, .win-edge, .win-dock, .win-close { display: none !important; }
  .win-title { cursor: default; }
  /* Rounded corners and a drop shadow say "this floats above something". Nothing is behind it. */
  .win { border-radius: 0; box-shadow: none; }

  /* The globe readout, folded — see the note where the summary row is built in globe.js. The
     `.hud` base rule sets pointer-events:none so the planet can be dragged through the overlays;
     the one line that is now a control has to take them back for itself alone. */
  /* Below the layer/reset buttons rather than beside them: at 390px the two want the same
     corner, and the readout is the one that can move. */
  .hud.tl { max-width: calc(100% - 16px); top: 40px; }
  /* !important because each row carries its own inline `display:flex` from hudRow, and two of
     them are shown and hidden by writing that same inline property at runtime. An inline style
     beats any selector, so without this the fold silently does nothing — which is exactly what
     it did on the first attempt. */
  .hud.tl:not(.open) > div:not(.hud-sum) { display: none !important; }
  .hud-sum {
    display: flex; gap: 8px; align-items: baseline; pointer-events: auto; cursor: pointer;
    color: var(--fg); padding: 1px 0;
  }
  .hud-sum-c { margin-left: auto; color: var(--fg-faint); }

  /* Knowledge sphere: the filter rail goes under the sphere instead of beside it. The picture is
     the point — position encodes node type, first mention and connectivity — and a 194px picture
     encodes none of it legibly. The rail keeps every control, just below the fold. */
  .sph-row { flex-direction: column; }
  .sph-stage { order: 1; flex: 0 0 auto !important; min-height: 54vh; }
  .sph-rail {
    order: 2; width: auto !important; flex: 1 1 auto !important;
    border-right: 0 !important; border-top: 1px solid var(--border);
  }
  /* Both spheres put readouts in the corners of the stage with hand-set widths that assume a
     desktop-sized stage; at 390px those clip mid-word. Let them use the width they have. */
  .hud { max-width: calc(100% - 16px) !important; }
  .hud.br, .hud.bl { white-space: normal; }
  /* A selection readout that grows with the selection can eat the picture it is reporting on. */
  .hud.br { max-height: 34%; overflow: auto; pointer-events: auto; }
  /* Relieved of `position:absolute` by dropping .bl — it is a block in the rail now, not an
     overlay, so it needs the borders of one. */
  .sph-key-inline {
    position: static !important; margin: 0 0 2px; border-radius: 0;
    border-left: 0; border-right: 0; border-top: 0; white-space: normal;
    max-width: 100% !important; padding: 7px 9px;
  }
}
/* Nothing folds on a desktop: there the readout has room beside the planet, and a control that
   hides information the page is arguing with would be a regression. */
@media (min-width: 720px) { .hud-sum { display: none; } }

/* The legend, as the second row of that column. `position:static` overrides .hud's
   absolute placement so the flex column can own where it goes. */
.stage-foot .hud {
  position: static; white-space: normal; line-height: 1.7;
  display: flex; flex-wrap: wrap; gap: 4px 18px; align-items: center;
  justify-content: center;
}
.legend-part { display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: center; }
.legend-part + .legend-part {
  border-left: 1px solid var(--border-hi); padding-left: 14px;
}

/* provenance strip — every data surface carries its source */
.prov {
  font-family: var(--mono); font-size: 10px; color: var(--fg-faint);
  padding: 5px 9px; border-top: 1px solid var(--border); background: #0a0908;
  line-height: 1.5;
}
.prov b { color: var(--fg-dim); font-weight: 600; }

/* ---------- places · the browsing surface ----------
   The arena table is sized to be compared: 12px, monospace, one row per record. This
   is the same data sized to be read — a picture the eye lands on first, a name, and
   enough of a description to know whether to open it. Nothing here is smaller than
   10.5px and nothing is monospaced except the two things that are measurements. */
.pl-seg {
  display: flex; gap: 4px; padding: 3px;
  background: #0a0908; border: 1px solid var(--border); border-radius: 8px;
}
.pl-seg-btn {
  display: flex; align-items: center; gap: 7px; cursor: pointer; user-select: none;
  padding: 4px 11px; border-radius: 6px; white-space: nowrap;
  font-size: 12px; color: var(--fg-faint); border: 1px solid transparent;
}
.pl-seg-btn:hover { color: var(--fg-dim); border-color: var(--border-hi); }
.pl-seg-btn.on { color: var(--fg); background: var(--bg3); border-color: var(--border-hi); }
.pl-seg-n {
  font-family: var(--mono); font-size: 11px; color: var(--fg-faint);
  padding: 1px 6px; border-radius: 4px; background: rgba(255,255,255,.04);
}
.pl-seg-btn.on .pl-seg-n { color: var(--fg-dim); background: rgba(255,255,255,.07); }

.pl-list { display: flex; flex-direction: column; gap: 8px; padding: 9px; }
.pl-card {
  display: flex; gap: 11px; padding: 9px; cursor: pointer;
  background: var(--bg3); border: 1px solid var(--border); border-radius: 8px;
}
.pl-card:hover { background: var(--bg4); border-color: var(--border-hi); }
.pl-card.sel { background: rgba(198,90,46,.14); border-color: var(--rust-dim); }
.pl-card:focus-visible { outline: 1px solid var(--cyan); outline-offset: 1px; }

/* The frame is the div, never the image. A crop arrives seconds after the card that
   asked for it, and a box that takes its size from the picture would shunt the rest of
   the list down the moment the reader started reading it. */
.pl-thumb {
  position: relative; flex: 0 0 auto; width: 108px; height: 108px;
  border-radius: 6px; overflow: hidden;
  background: #100e0c; border: 1px solid var(--border);
}
/* Absolute, not static, and that is the whole of it: a positioned element paints above
   an unpositioned sibling whatever the source order says, so with the placeholder
   absolute and the picture in normal flow, every crop loaded correctly and was covered
   by its own placeholder. Both positioned means DOM order decides, which is what the
   markup was already written to rely on. */
.pl-thumb img {
  position: absolute; inset: 0;
  display: block; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .22s ease;
}
.pl-thumb img.in { opacity: 1; }
.pl-thumb img.now { transition: none; }
/* Neutral until there is something to show, and legible when there never will be.
   Sits under the image, so an arriving crop simply covers it. */
.pl-ph {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase;
  color: #4e463c;
  background:
    repeating-linear-gradient(135deg, #15120f 0 6px, #100e0c 6px 12px);
}
.pl-sub {
  position: absolute; left: 4px; bottom: 4px;
  font-family: var(--mono); font-size: 9px; letter-spacing: .08em;
  padding: 1px 5px; border-radius: 3px;
  color: var(--amber); background: rgba(8,7,6,.78); border: 1px solid #6a4f1f;
}

.pl-text { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.pl-title {
  font-size: 13.5px; font-weight: 600; line-height: 1.3; color: var(--fg);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pl-desc {
  font-size: 11.5px; line-height: 1.5; color: var(--fg-dim);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.pl-meta {
  font-size: 10.5px; line-height: 1.4; color: var(--fg-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pl-foot {
  margin-top: auto; display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: 10.5px; color: var(--fg-faint);
}

/* The two rows that bracket the list: why it starts where it does, and how much of it
   is not built yet. Both are the reader's answer to "is this all of them". */
.pl-lead { padding: 9px 9px 0; }
.pl-lead-btn {
  flex: 1 1 auto; cursor: pointer; user-select: none;
  padding: 5px 9px; border-radius: 6px; font-size: 11px;
  color: var(--fg-dim); background: rgba(198,90,46,.08); border: 1px solid var(--rust-dim);
}
.pl-lead-btn:hover { color: var(--fg); background: rgba(198,90,46,.16); }
.pl-tail { padding: 2px 9px 12px; font-size: 10.5px; color: var(--fg-faint); text-align: center; }

/* scrollbars */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #322b23; border-radius: 5px; border: 2px solid var(--bg2); }
::-webkit-scrollbar-thumb:hover { background: #443b30; }

/* ---- zoom control ---------------------------------------------------------------
   Top-right of the stage, opposite the HUD, so it never covers the readout it
   changes. Same panel treatment as the layer switch: this is a control surface over
   a picture, and two different glass treatments on one canvas read as two apps. */
.foot-row {
  display: flex; align-items: center; justify-content: center;
  gap: 10px; flex-wrap: wrap;
}
.zoom-ctl {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 7px; border-radius: 9px;
  background: rgba(8, 7, 6, .82); border: 1px solid var(--border);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  box-shadow: 0 6px 22px rgba(0, 0, 0, .55);
}
.zc-btn {
  width: 26px; height: 26px; flex: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--sans); font-size: 16px; line-height: 1;
  color: var(--fg-dim); background: var(--bg3);
  border: 1px solid var(--border-hi); border-radius: 6px;
}
.zc-btn:hover:not(:disabled) { color: var(--fg); border-color: var(--gold, #e0a13a); }
.zc-btn:active:not(:disabled) { transform: translateY(1px); }
.zc-btn:disabled { opacity: .3; cursor: default; }
.zc-val {
  min-width: 46px; text-align: center;
  font-family: var(--mono); font-size: 12px; color: var(--fg);
}
.zc-div { width: 1px; height: 18px; background: var(--border-hi); }
.zc-lab { font-family: var(--sans); font-size: 11px; color: var(--fg-faint); }
.zc-sel {
  font-family: var(--sans); font-size: 11.5px; color: var(--fg-dim);
  background: var(--bg3); border: 1px solid var(--border-hi);
  border-radius: 6px; padding: 3px 5px; cursor: pointer;
}
.zc-sel:hover { color: var(--fg); }
@media (max-width: 620px) { .zc-lab { display: none; } }

/* ---- optional background music --------------------------------------------------
   In the menubar rather than on the globe: it is a property of the session, not of
   the map, and a speaker icon floating over Mars invites the reading that the sound
   is data. */
.mb-audio {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  padding: 3px 8px; border-radius: 6px;
  font-family: var(--sans); font-size: 11px; letter-spacing: .04em;
  color: var(--fg-faint); background: transparent;
  border: 1px solid var(--border);
}
.mb-audio:hover { color: var(--fg-dim); border-color: var(--border-hi); }
.mb-audio.on { color: #f0dfc0; border-color: var(--gold, #e0a13a); background: rgba(224, 161, 58, .1); }
.mb-audio span:first-child { font-size: 9px; line-height: 1; }
.mb-audio-note {
  max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--sans); font-size: 10.5px; color: var(--fg-faint);
  text-decoration: none; border-bottom: 1px dotted var(--border-hi);
}
.mb-audio-note:hover { color: var(--fg-dim); }
@media (max-width: 900px) { .mb-audio-note { display: none !important; } }
.mb-link {
  font-family: var(--sans); font-size: 11px; letter-spacing: .04em;
  color: var(--fg-faint); text-decoration: none;
  padding: 3px 8px; border: 1px solid var(--border); border-radius: 6px;
}
.mb-link:hover { color: #f0dfc0; border-color: var(--gold, #e0a13a); }
.zc-btn.wide {
  width: auto; padding: 0 10px;
  font-family: var(--sans); font-size: 11.5px; letter-spacing: .04em;
}

/* ---------- detail · the dossier -------------------------------------------------
   A document, not an instrument. The rest of this app is 10–12px because it is
   telemetry that has to fit beside a globe; this panel is the one surface somebody
   reads end to end, so the body copy is 13px on a 1.6 line and the section headings
   are 15px. Nothing here is monospaced except measurements and identifiers, which is
   what monospace is reserved for everywhere else in this file.

   The three claims channels from CONTRACT.md are reused rather than restated: .tag
   .archive / .computed / .corpus already carry amber / cyan / violet, and the class
   colours already exist as .tag.fact / .inference / .speculation. What is added here
   is the left-border accent that repeats the same three colours at card scale, so a
   speculation is distinguishable from a fact from across the room and not only by
   reading the label on it. */
.dt-root { position: absolute; inset: 0; display: flex; flex-direction: column; min-height: 0; }
.dt-scroll { flex: 1 1 auto; overflow: auto; min-height: 0; position: relative; }
.dt-prov { flex: 0 1 auto; max-height: 28%; overflow: auto; }

/* The segmented control. Deliberately the largest thing in the app: it is the only
   choice a first-time reader has to make before anything else on the screen means
   anything, and the label alone does not say what either state does — so the
   explanation is on the button rather than in a tooltip nobody hovers. */
.dt-head {
  flex: 0 0 auto; padding: 9px; border-bottom: 1px solid var(--border);
  background: linear-gradient(#191510, #100d0a);
}
.dt-seg {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px;
  padding: 5px; background: #0a0908; border: 1px solid var(--border); border-radius: 10px;
}
.dt-seg-btn {
  padding: 9px 12px 10px; border-radius: 7px; cursor: pointer; user-select: none;
  border: 1px solid transparent; background: transparent; min-width: 0;
}
.dt-seg-btn:hover { background: var(--bg3); border-color: var(--border-hi); }
.dt-seg-btn:focus-visible { outline: 2px solid var(--cyan); outline-offset: 1px; }
.dt-seg-btn.on { background: rgba(198,90,46,.13); border-color: var(--rust-dim); }
.dt-seg-label {
  font-size: 16px; font-weight: 700; line-height: 1.2; letter-spacing: -.01em;
  color: var(--fg-dim);
}
.dt-seg-btn.on .dt-seg-label { color: #fff; }
.dt-seg-sub { margin-top: 3px; font-size: 11.5px; line-height: 1.35; color: var(--fg-faint); }
.dt-seg-btn.on .dt-seg-sub { color: var(--fg-dim); }
@media (max-width: 460px) { .dt-seg { grid-template-columns: 1fr; } }

.dt-doc { padding: 13px 14px 22px; }
.dt-title { padding-bottom: 11px; border-bottom: 1px solid var(--border); }
.dt-name {
  margin: 0; font-size: 22px; line-height: 1.14; font-weight: 700; letter-spacing: -.02em;
  color: var(--fg);
}
.dt-kicker {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  margin-top: 6px; font-size: 12px; line-height: 1.45; color: var(--fg-dim);
}

/* Numbered because this is a document with an order, and the number is the reader's
   answer to "how much of this is left". */
.dt-sec { display: flex; gap: 10px; align-items: baseline; margin: 20px 0 9px; }
.dt-sec-n {
  flex: none; font-family: var(--mono); font-size: 12px; font-weight: 700;
  color: var(--rust); padding-top: 3px;
}
.dt-sec-h {
  margin: 0; font-size: 15px; font-weight: 700; line-height: 1.25; color: var(--fg);
  letter-spacing: -.01em;
}
.dt-sec-s { margin-top: 3px; font-size: 11.5px; line-height: 1.45; color: var(--fg-faint); }

.dt-field { display: flex; gap: 11px; padding: 7px 0; border-bottom: 1px solid #171310; }
.dt-field-l { flex: 0 0 104px; padding-top: 3px; }
.dt-field-v { flex: 1 1 auto; min-width: 0; font-size: 13px; line-height: 1.55; }
.dt-why { margin-top: 4px; font-size: 11px; line-height: 1.5; color: var(--fg-faint); }
.dt-break { word-break: break-word; }
.dt-a {
  color: var(--cyan); text-decoration: none;
  border-bottom: 1px solid rgba(88,182,200,.35); word-break: break-word;
}
.dt-a:hover { color: #8fd6e4; }

/* Absence is information, and it is rendered as a sentence rather than as an empty
   heading. A section that says nothing is here, and why, is not the same as a
   section that was never built. */
.dt-absent {
  font-size: 12.5px; line-height: 1.55; color: var(--fg-dim);
  border: 1px dashed var(--border-hi); border-radius: 7px; padding: 9px 11px;
  background: rgba(255,255,255,.012);
}

/* ---- the picture ----
   Capped at the width of the JPEG that was actually fetched. Full-panel width is the
   point of this section, but past 640 px there are no more pixels in the file and the
   browser would upsample a 640-wide crop into a 1,600-wide claim about resolution —
   which is the one thing a panel that prints metres per pixel cannot do. The same cap
   holds the video stills, which YouTube publishes at 480 px. */
.dt-fig, .dt-media { max-width: 640px; }
.dt-hero {
  position: relative; width: 100%; aspect-ratio: 1 / 1;
  background: #080706; border: 1px solid var(--border); border-radius: 7px 7px 0 0;
  overflow: hidden;
}
.dt-hero-img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .22s ease;
}
.dt-hero-img.in { opacity: 1; }
.dt-hero-ph {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
  color: #4e463c; text-align: center; padding: 12px;
  background: repeating-linear-gradient(135deg, #15120f 0 7px, #100e0c 7px 14px);
}
.dt-hero-ph-err { color: var(--warn); }
.dt-hero-badge {
  position: absolute; left: 7px; bottom: 7px;
  font-family: var(--mono); font-size: 10.5px; color: #d7cfc3;
  background: rgba(8,7,6,.82); border: 1px solid var(--border); border-radius: 4px; padding: 2px 7px;
}
.dt-hero-warn {
  font-size: 11.5px; line-height: 1.5; padding: 6px 9px;
  background: rgba(139,122,200,.10); border: 1px solid #4b4270; border-top: 0;
}
.dt-hero-cap {
  padding: 7px 9px 8px; font-size: 11.5px; line-height: 1.5; color: var(--fg-dim);
  border: 1px solid var(--border); border-top: 0; border-radius: 0 0 7px 7px; background: #0a0908;
}
.dt-hero-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 4px;
}
.dt-hero-row:last-child { margin-bottom: 0; }

/* ---- claim vs established: two frames, one weight ---- */
.dt-stanza {
  margin-top: 10px; padding: 9px 11px;
  border: 1px solid var(--border); border-left: 3px solid var(--border-hi);
  border-radius: 0 7px 7px 0;
}
.dt-claim { border-left-color: var(--violet); background: rgba(142,123,195,.05); }
.dt-established { border-left-color: var(--cyan); background: rgba(88,182,200,.045); }
.dt-stanza-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dt-stanza-t { margin-top: 7px; font-size: 13px; line-height: 1.6; color: #ddd5c8; }
.dt-stanza-src { margin-top: 8px; font-size: 11.5px; }

/* ---- moments ---- */
.dt-card {
  margin-top: 11px; border: 1px solid var(--border); border-left-width: 3px;
  border-radius: 7px; background: var(--bg2); overflow: hidden;
}
.dt-card.c-fact { border-left-color: var(--ok); }
.dt-card.c-inference { border-left-color: var(--cyan); }
.dt-card.c-speculation { border-left-color: var(--warn); }
.dt-card-h { padding: 10px 12px 8px; }
.dt-speaker { font-size: 15px; font-weight: 700; line-height: 1.2; color: var(--fg); }
.dt-role { margin-top: 2px; font-size: 11.5px; color: var(--fg-faint); }
.dt-card-b { padding: 9px 12px 12px; }
.dt-media {
  position: relative; margin: 0 12px; aspect-ratio: 16 / 9; cursor: pointer;
  background: #080706; border: 1px solid var(--border); border-radius: 6px; overflow: hidden;
}
.dt-media:focus-visible { outline: 2px solid var(--rust); outline-offset: 1px; }
.dt-still-img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .2s ease;
}
.dt-still-img.in { opacity: .62; }
.dt-media:hover .dt-still-img.in { opacity: .82; }
.dt-still-ph {
  position: absolute; inset: 0; display: none; flex-direction: column;
  align-items: center; justify-content: center; gap: 3px; text-align: center; padding: 10px;
  font-family: var(--mono); font-size: 10px; color: var(--fg-faint);
  background: repeating-linear-gradient(45deg, #131110 0 9px, #181513 9px 18px);
}
.dt-still-ph.on { display: flex; }
.dt-play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 54px; height: 54px; border-radius: 50%; padding-left: 4px;
  display: flex; align-items: center; justify-content: center;
  font-size: 19px; color: #fff; background: rgba(198,90,46,.88);
  box-shadow: 0 3px 15px rgba(0,0,0,.65);
}
.dt-media:hover .dt-play { background: var(--rust); }
.dt-ts {
  position: absolute; left: 7px; top: 7px;
  font-family: var(--mono); font-size: 12px; font-weight: 600; color: #fff;
  background: rgba(8,7,6,.86); border: 1px solid rgba(255,255,255,.16);
  border-radius: 4px; padding: 2px 8px;
}
.dt-ts i { font-style: normal; color: var(--ok); font-size: 9px; letter-spacing: .1em; margin-left: 6px; }
.dt-still-cap {
  position: absolute; left: 7px; right: 7px; bottom: 7px;
  font-family: var(--mono); font-size: 9.5px; line-height: 1.35; color: #c9c0b3;
  background: rgba(8,7,6,.80); border-radius: 4px; padding: 3px 7px;
}
.dt-embed { display: block; width: 100%; height: 100%; border: 0; }
.dt-quote {
  margin: 0 0 9px; padding: 4px 0 4px 11px;
  border-left: 2px solid rgba(142,123,195,.55);
  font-size: 13px; line-height: 1.55; color: #ded6c9;
}
.dt-metarow { display: flex; gap: 5px; flex-wrap: wrap; align-items: center; }
.dt-claim-text { margin-top: 9px; font-size: 12.5px; line-height: 1.55; color: var(--fg-dim); }
.dt-srcline {
  margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--border);
  display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  font-size: 11px; color: var(--fg-faint);
}

/* ---- sources ---- */
.dt-refblock { margin-top: 11px; }
.dt-reflist { margin: 5px 0 0; padding: 0; list-style: none; }
.dt-reflist li {
  position: relative; padding-left: 13px; margin-top: 5px;
  font-size: 12px; line-height: 1.5; color: var(--fg-dim);
}
.dt-reflist li::before { content: "\2022"; position: absolute; left: 3px; color: var(--fg-faint); }
.dt-ref-what { margin-top: 2px; font-size: 11.5px; line-height: 1.5; color: var(--fg-dim); }

/* A contradiction is the most interesting line on the page, so it is the loudest
   frame in this stylesheet and it is placed above what supports the claim. */
.dt-contra {
  border: 1px solid #6a4a20; border-left: 3px solid var(--warn); border-radius: 0 7px 7px 0;
  background: rgba(217,148,79,.07); padding: 10px 12px;
}
.dt-contra-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dt-contra-row { margin-top: 10px; padding-top: 9px; border-top: 1px solid rgba(217,148,79,.20); }
.dt-contra-claim { font-size: 12.5px; line-height: 1.55; color: #e7e0d4; }
.dt-settle {
  margin-top: 12px; border: 1px solid #3d3423; border-radius: 7px;
  background: rgba(224,161,58,.055); padding: 9px 11px;
}
.dt-settle-h { color: var(--amber); font-weight: 700; }
.dt-settle-row { margin-top: 6px; font-size: 12.5px; line-height: 1.5; color: #e7e0d4; }
.dt-prod { padding: 7px 0; border-bottom: 1px solid #171310; font-size: 12px; line-height: 1.5; }

/* ---- connections ---- */
.dt-conns { display: flex; flex-direction: column; gap: 8px; }
.dt-conn {
  padding: 9px 11px; cursor: pointer;
  border: 1px solid var(--border); border-left-width: 3px; border-radius: 0 7px 7px 0;
  background: var(--bg3);
}
.dt-conn:hover { background: var(--bg4); border-color: var(--border-hi); }
.dt-conn:focus-visible { outline: 2px solid var(--cyan); outline-offset: 1px; }
.dt-conn.c-fact { border-left-color: var(--ok); }
.dt-conn.c-inference { border-left-color: var(--cyan); }
.dt-conn.c-speculation { border-left-color: var(--warn); }
.dt-conn-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.dt-conn-rel {
  font-family: var(--mono); font-size: 11px; color: var(--fg-faint);
  text-transform: lowercase; white-space: nowrap;
}
.dt-conn-name { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--fg); }
.dt-conn-meta { display: flex; gap: 5px; flex-wrap: wrap; align-items: center; margin-top: 7px; }
.dt-conn-q {
  margin-top: 8px; padding-left: 10px; border-left: 2px solid rgba(142,123,195,.45);
  font-size: 12px; line-height: 1.5; color: var(--fg-dim);
}

/* ---- scores ---- */
.dt-total { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.dt-total-n { font-size: 26px; font-weight: 700; line-height: 1; color: var(--cyan); }
.dt-score-row { margin-top: 10px; padding-top: 9px; border-top: 1px solid #171310; }
.dt-score-row:first-child { border-top: 0; padding-top: 0; }
.dt-score-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dt-score-n { font-size: 14px; font-weight: 700; color: var(--cyan); }
.dt-score-terms {
  margin-top: 5px; font-size: 10.5px; line-height: 1.6; color: var(--fg-faint);
  word-break: break-word;
}
.dt-table { margin-top: 10px; }
/* The arena's headers are sticky because that table is 1,062 rows inside its own
   scroller. Here the table is four rows inside a document, and a header that detaches
   and floats over the section above it is a bug that only shows up while scrolling. */
.dt-table th { position: static; }
.dt-table td { white-space: normal; vertical-align: top; }
.dt-disclaimer {
  margin-top: 11px; padding: 8px 11px; font-size: 12px; line-height: 1.55; color: var(--fg-dim);
  border: 1px solid var(--border); border-left: 2px solid var(--rust);
  border-radius: 0 6px 6px 0; background: rgba(198,90,46,.06);
}
.dt-prio { margin-top: 11px; padding: 8px 11px; border: 1px solid var(--border); border-radius: 6px; }

/* ---- chat ---- */
.dt-chat { padding: 13px 14px 22px; min-height: 100%; }
.dt-chat-ph {
  border: 1px dashed var(--border-hi); border-radius: 8px; padding: 15px 16px;
  font-size: 13px; line-height: 1.6; color: var(--fg-dim);
  display: flex; flex-direction: column; gap: 10px;
}
.dt-chat-ph h3 { margin: 0; font-size: 16px; font-weight: 700; color: var(--fg); }
.dt-chat-ph-hint { font-size: 12px; color: var(--cyan); }

.dt-empty { padding: 26px 8px; }
.dt-empty-b { margin-top: 10px; font-size: 13px; line-height: 1.6; color: var(--fg-dim); }

/* ==========================================================================
   chat.js — the reader's agent panel                            (MA.chat)

   Appended in one block at the end of the file, as its own section, because two other
   agents were editing this stylesheet while it was written and a change threaded through
   the existing sections would have been a merge conflict rather than an addition.

   Two constraints shape everything below.

   The panel is mounted into a container whose size this module does not know and cannot
   query — detail.js owns it, and it may be a docked sidebar at 320 px or a full-width
   window. So the root is a flex column at height 100% with a min-height floor: inside a
   host that sets a height it fills it and the log scrolls; inside an auto-height host it
   grows to its content instead of collapsing to nothing. `min-height: 0` on the scroller
   is not optional — without it a flex child refuses to shrink below its content and the
   compose row is pushed out of view.

   The citation colours are the app's evidence channels and are not free to choose:
   amber is archive fact, violet is something a person said, cyan is computed, and this
   project's own documentation gets neither. A citation rendered in the wrong channel
   would be the exact confusion the instrument exists to prevent, so the class name comes
   straight from the server's channel field.
   ========================================================================== */
.ch-root {
  display: flex; flex-direction: column;
  height: 100%; min-height: 240px;
  font-family: var(--sans); font-size: 13px; color: var(--fg);
}
.ch-head {
  flex: 0 0 auto; padding: 9px 12px 8px; border-bottom: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 2px;
}
.ch-head-t {
  font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: #bdb4a7;
}
.ch-head-n { font-size: 11px; color: var(--fg-faint); }

.ch-subject {
  flex: 0 0 auto; display: flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-bottom: 1px solid var(--border); background: var(--bg3);
}
.ch-subject-lab {
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-faint);
}
.ch-subject-v {
  font-family: var(--mono); font-size: 11.5px; color: var(--cyan);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ch-subject-x {
  margin-left: auto; cursor: pointer; color: var(--fg-faint); padding: 0 3px; line-height: 1;
}
.ch-subject-x:hover { color: var(--fg); }

/* min-height:0 keeps this shrinkable; see the section note. */
.ch-log { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 4px 0 10px; }

.ch-turn { padding: 10px 12px; border-bottom: 1px solid var(--bg3); }
.ch-turn:last-child { border-bottom: none; }
.ch-who {
  font-size: 10px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--fg-faint); margin-bottom: 5px;
}
.ch-reader { background: var(--bg3); }
.ch-reader .ch-who { color: var(--cyan); }
.ch-agent .ch-who { color: var(--ok); }
.ch-err .ch-who, .ch-err .ch-body { color: var(--warn); }
.ch-working .ch-body { color: var(--fg-faint); font-style: italic; }

.ch-body p { margin: 0 0 8px; line-height: 1.55; }
.ch-body p:last-child { margin-bottom: 0; }
.ch-list { margin: 0 0 8px; padding-left: 17px; }
.ch-list li { margin-bottom: 4px; line-height: 1.5; }

.ch-note {
  font-size: 11.5px; line-height: 1.5; color: var(--warn);
  border-left: 2px solid var(--warn); padding: 5px 0 5px 8px; margin: 0 0 8px;
  background: rgba(217, 148, 79, .07);
}
.ch-opener .ch-body { color: var(--fg-dim); }

/* An inline citation. Monospaced so an id reads as an identifier rather than as a word,
   and sized down so a sentence carrying three of them still reads as a sentence. */
.ch-cite {
  display: inline; font-family: var(--mono); font-size: 10.5px;
  padding: 1px 4px; margin: 0 1px; border-radius: 3px; cursor: pointer;
  border: 1px solid var(--border-hi); color: var(--fg-dim); white-space: nowrap;
}
.ch-cite:hover { border-color: var(--fg-faint); color: var(--fg); }
.ch-cite:focus-visible { outline: 1px solid var(--cyan); outline-offset: 1px; }
.ch-cite .ch-ts { opacity: .8; }
.ch-archive { border-color: var(--rust-dim); color: var(--amber); }
.ch-archive:hover { border-color: var(--amber); }
.ch-corpus { border-color: #4a3f66; color: var(--violet); }
.ch-corpus:hover { border-color: var(--violet); }
.ch-computed { border-color: #2e5b64; color: var(--cyan); }
.ch-computed:hover { border-color: var(--cyan); }
.ch-project, .ch-source, .ch-external { color: var(--fg-faint); }
/* A citation with nowhere to go does not pretend to be a control. */
.ch-inert { cursor: default; }
.ch-inert:hover { border-color: var(--border-hi); color: var(--fg-dim); }

.ch-srcs {
  margin-top: 9px; padding-top: 8px; border-top: 1px dashed var(--border);
  display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
}
.ch-srcs-lab {
  font-size: 10px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--fg-faint); margin-right: 3px;
}
.ch-cite-full { display: inline-flex; align-items: baseline; gap: 5px; }
.ch-src-kind {
  font-family: var(--sans); font-size: 9.5px; letter-spacing: .05em;
  text-transform: uppercase; opacity: .72;
}

.ch-compose {
  flex: 0 0 auto; display: flex; gap: 7px; align-items: flex-end;
  padding: 9px 12px; border-top: 1px solid var(--border); background: var(--bg2);
}
.ch-input {
  flex: 1 1 auto; min-width: 0; resize: none;
  font-family: var(--sans); font-size: 12.5px; line-height: 1.45; color: var(--fg);
  background: var(--bg); border: 1px solid var(--border-hi); border-radius: 6px;
  padding: 7px 8px;
}
.ch-input:focus { outline: none; border-color: var(--cyan); }
.ch-input::placeholder { color: var(--fg-faint); }
.ch-send {
  flex: none; cursor: pointer;
  font-family: var(--sans); font-size: 11.5px; letter-spacing: .04em;
  color: #f0dfc0; background: rgba(198, 90, 46, .16);
  border: 1px solid var(--rust-dim); border-radius: 6px; padding: 7px 13px;
}
.ch-send:hover:not(:disabled) { background: rgba(198, 90, 46, .3); border-color: var(--rust); }
.ch-send:disabled { cursor: default; opacity: .5; color: var(--fg-faint); }

/* The not-connected state. Prose only: no input, no disabled control, nothing that
   invites a reader to type into something that cannot answer. */
.ch-off .ch-log { padding: 0; }
.ch-offbody { padding: 14px 13px; color: var(--fg-dim); font-size: 12.5px; }
.ch-offbody p { line-height: 1.6; }
