/* h5i box console — an HTML rendering of the `h5i ui` screen.
 *
 * This replaces a PNG. A screenshot goes stale the moment the console changes,
 * and the one it replaced was still showing a command surface that no longer
 * exists. Built from the site's own tokens it stays sharp at any density, it
 * costs a few kilobytes instead of a megabyte, and it is real text: selectable,
 * searchable, and readable by a screen reader.
 *
 * Structure and labels follow web/src/SandboxView.tsx. The colour rules are the
 * console's own: red is enforcement that fired, amber is something to look at,
 * grey is weak evidence. The fleet in it is illustrative, which the caption
 * says; the shapes are not.
 *
 * Everything is sized in `em` off one root font-size, and that root scales with
 * the plate's width in `cqw`. One clamp resizes the whole console, so it holds
 * its proportions from a phone to a wide display without a media query.
 */

.console-plate {
  container-type: inline-size;
  border: 1px solid var(--line2);
  background: var(--panel);
  overflow: hidden;
}

/* ── several views of one console, switched without script ──
 *
 * The plate can carry tabs: one thread, the fleet screen, and the browser
 * terminal a box with a browser in it gets. Radio inputs and their labels,
 * because a figure that needs JavaScript to show its second half shows nothing
 * while the script is still in flight, and because arrow keys move between
 * radios for free.
 *
 * Positional rather than by id: the nth input checks the nth label and shows
 * the nth view, so a page adds a tab by adding a pair and nothing here changes.
 * Three is what the front page needs; the rules below carry four.
 */
.tabpick {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.console-tabs { display: flex; flex-wrap: wrap; background: var(--bg); }
.console-tabs label {
  padding: 0.7em 1.2em;
  border-right: 1px solid var(--line2);
  border-bottom: 1px solid var(--line2);
  font-family: var(--mono); font-size: 12px;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--faint); cursor: pointer;
}
.console-tabs label:hover { color: var(--dim); }
.console-views > .console-view { display: none; }

.tabpick:nth-of-type(1):checked ~ .console-tabs label:nth-of-type(1),
.tabpick:nth-of-type(2):checked ~ .console-tabs label:nth-of-type(2),
.tabpick:nth-of-type(3):checked ~ .console-tabs label:nth-of-type(3),
.tabpick:nth-of-type(4):checked ~ .console-tabs label:nth-of-type(4) {
  color: var(--ink);
  background: var(--panel);
  border-bottom-color: transparent;
}
.tabpick:nth-of-type(1):checked ~ .console-views > .console-view:nth-of-type(1),
.tabpick:nth-of-type(2):checked ~ .console-views > .console-view:nth-of-type(2),
.tabpick:nth-of-type(3):checked ~ .console-views > .console-view:nth-of-type(3),
.tabpick:nth-of-type(4):checked ~ .console-views > .console-view:nth-of-type(4) {
  display: block;
}
/* The input is off-screen, so the ring has to land on its label or a keyboard
   reader loses the selection entirely. */
.tabpick:nth-of-type(1):focus-visible ~ .console-tabs label:nth-of-type(1),
.tabpick:nth-of-type(2):focus-visible ~ .console-tabs label:nth-of-type(2),
.tabpick:nth-of-type(3):focus-visible ~ .console-tabs label:nth-of-type(3),
.tabpick:nth-of-type(4):focus-visible ~ .console-tabs label:nth-of-type(4) {
  outline: 2px solid var(--spot-solid);
  outline-offset: -2px;
}

.console {
  /* the one control: everything below is em-relative to this */
  font-size: clamp(5.5px, 1.02cqw, 13px);
  font-family: var(--mono);
  line-height: 1.5;
  color: var(--dim);
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  height: 100%;
  user-select: none;
}

/* ── top strip: what the host can enforce, then fleet vitals ── */
.console-strip {
  display: flex; align-items: center; gap: 1.2em; flex-wrap: wrap;
  padding: 0.9em 1.2em;
  border-bottom: 1px solid var(--line2);
  background: var(--bg);
}
.console-strip .grp { display: flex; align-items: center; gap: 0.5em; flex-wrap: wrap; }
.console-label {
  color: var(--faint); font-size: 0.85em;
  letter-spacing: 0.16em; text-transform: uppercase;
}
.console-tag {
  border: 1px solid var(--line2); padding: 0.15em 0.55em;
  color: var(--dim); font-size: 0.92em; white-space: nowrap;
}
.console-tag.ok  { color: var(--green); border-color: color-mix(in srgb, var(--green) 40%, transparent); }
.console-tag.off { color: var(--faint); }
.console-vitals { display: flex; gap: 1.4em; margin-left: auto; }
.console-vital { text-align: right; }
.console-vital b {
  display: block; font-family: var(--disp); font-weight: 900;
  font-size: 1.7em; line-height: 1; letter-spacing: -0.04em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.console-vital.alert b { color: var(--danger); }
.console-vital span {
  display: block; margin-top: 0.35em;
  color: var(--faint); font-size: 0.82em;
  letter-spacing: 0.16em; text-transform: uppercase;
}

/* ── body: fleet on the left, one box on the right ── */
.console-body {
  display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 6fr);
  min-height: 0;
}
.console-fleet { border-right: 1px solid var(--line2); min-width: 0; }
.console-detail { min-width: 0; }

.console-head {
  display: flex; align-items: center; gap: 0.7em;
  padding: 0.8em 1.1em; border-bottom: 1px solid var(--line);
  color: var(--ink); font-size: 0.95em;
}
.console-head .count {
  border: 1px solid var(--line2); padding: 0 0.5em; color: var(--faint);
}
.console-head .digest { margin-left: auto; color: var(--faint); font-size: 0.9em; }

.console-chips {
  display: flex; flex-wrap: wrap; gap: 0.4em;
  padding: 0.7em 1.1em; border-bottom: 1px solid var(--line);
}
.console-chip {
  border: 1px solid var(--line2); padding: 0.12em 0.6em;
  color: var(--faint); font-size: 0.88em;
}
.console-chip.active { background: var(--ink); border-color: var(--ink); color: var(--bg); }

/* Fleet rows. The header and the rows share one track list, so the column
   labels sit over their columns; `auto` tracks sized to each row's own content
   and left the labels floating between them. */
.console-row, .console-colhead {
  display: grid; grid-template-columns: minmax(0, 1fr) 8em 5.5em 7.5em;
  gap: 0.4em 0.8em; align-items: baseline;
}
.console-row { padding: 0.75em 1.1em; border-bottom: 1px solid var(--line); }
.console-row.selected { background: color-mix(in srgb, var(--spot-solid) 7%, transparent); }
.console-row .name { color: var(--ink); font-size: 0.98em; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.console-row .sub { grid-column: 1 / -1; color: var(--faint); font-size: 0.85em; }
.console-row .console-tag { justify-self: start; }
.console-row .status { color: var(--dim); font-size: 0.92em; }
.console-row .sig, .console-colhead > :last-child { justify-self: end; }
.console-colhead {
  padding: 0.55em 1.1em;
  border-bottom: 1px solid var(--line);
  color: var(--faint); font-size: 0.8em;
  letter-spacing: 0.16em; text-transform: uppercase;
}

/* the signal badge: never a score, only what was recorded */
.sig { font-size: 0.9em; white-space: nowrap; }
.sig.blocked { color: var(--danger); }
.sig.attention { color: var(--warn); }
.sig.clean { color: var(--green); }
.sig.weak, .sig.none { color: var(--faint); }

/* ── detail pane ── */
.console-note {
  margin: 1.1em; padding: 0.7em 0.9em;
  border: 1px solid var(--line2); border-left: 2px solid var(--faint);
  color: var(--dim); font-size: 0.92em; line-height: 1.6;
}
.console-note.bad  { border-left-color: var(--spot-solid); }
.console-note.bad b  { color: var(--danger); font-weight: 400; }
.console-note.good { border-left-color: var(--green); }
.console-note.good b { color: var(--green); font-weight: 400; }

.console-panel { margin: 1.1em; border: 1px solid var(--line2); }
.console-panel-head {
  padding: 0.55em 0.9em; border-bottom: 1px solid var(--line2);
  background: var(--bg);
  color: var(--faint); font-size: 0.82em;
  letter-spacing: 0.16em; text-transform: uppercase;
}

/* the flight recorder: one row per receipt, five lanes */
.lane-row {
  display: grid;
  grid-template-columns: minmax(0, 2.6fr) repeat(5, minmax(0, 1fr));
  border-bottom: 1px solid var(--line);
}
.lane-row:last-child { border-bottom: 0; }
.lane-row.head { background: var(--bg); }
.lane-row > div { padding: 0.55em 0.7em; min-width: 0; border-left: 1px solid var(--line); }
.lane-row > div:first-child { border-left: 0; }
.lane-name { color: var(--faint); font-size: 0.8em; letter-spacing: 0.14em; }
.lane-allow { color: var(--dim); font-size: 0.85em; margin-top: 0.2em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.run-cmd { color: var(--ink); font-size: 0.95em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.run-meta { color: var(--faint); font-size: 0.82em; margin-top: 0.2em; }
/* the most load-bearing label on the screen: who observed this run */
.src { border: 1px solid var(--line2); padding: 0 0.35em; margin-right: 0.4em; }
.src.observed { color: var(--dim); }
.src.claimed { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.v { font-size: 0.88em; }
.v.ok { color: var(--green); }
.v.bad { color: var(--danger); }
.v.warn { color: var(--warn); }
.v.info { color: var(--dim); }
.v.none { color: var(--line2); }

/* enforced policy */
.pol { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.pol div {
  display: flex; gap: 0.7em; padding: 0.45em 0.9em;
  border-top: 1px solid var(--line); border-left: 1px solid var(--line);
  font-size: 0.9em; min-width: 0;
}
.pol div:nth-child(-n + 2) { border-top: 0; }
.pol div:nth-child(odd) { border-left: 0; }
.pol .k { color: var(--faint); flex: 0 0 7.5em; }
.pol .val { color: var(--dim); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pol .val.on { color: var(--green); }

/* a share admitting somebody into a box right now. Its own line in the row,
   and never red: red on this screen is enforcement that fired, and nothing was
   refused here — a door is standing open because somebody opened it. */
.console-row .shared {
  grid-column: 1 / -1;
  color: var(--warn); font-size: 0.85em;
}

/* ── the browser terminal ──────────────────────────────────────
 *
 * The second view: for a box with a browser in it, what that browser did.
 * Structure and wording follow web/src/BrowserTerminal.tsx, including the two
 * labels every row carries — the lane that observed it, and how complete that
 * record is. Both are words here for the same reason they are words there: the
 * colour carries severity, provenance is not severity, and a reader who is
 * colour-blind or looking at a screenshot still has to be able to tell.
 */
.bt {
  font-size: clamp(5.5px, 1.02cqw, 13px);
  font-family: var(--mono);
  line-height: 1.5;
  color: var(--dim);
  user-select: none;
}

/* the row the page cannot reach: host-derived values only */
.bt-status {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.4em 0.7em;
  padding: 0.8em 1.2em;
  border-bottom: 1px solid var(--line2);
  background: var(--bg);
  font-size: 0.92em;
}
.bt-badge {
  color: var(--faint); font-size: 0.82em;
  letter-spacing: 0.16em; text-transform: uppercase;
}
.bt-val { color: var(--ink); margin-right: 0.6em; min-width: 0; max-width: 100%; }
/* `min-width: 0` and a shrink factor, or the flex item's automatic minimum is
   the whole URL: it refuses to shrink, the plate grows past the viewport, and
   a phone gets a page that scrolls sideways. */
.bt-val.url {
  color: var(--dim); flex: 0 1 auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bt-val em { font-style: normal; color: var(--danger); }

.bt-pane { border-bottom: 1px solid var(--line); min-width: 0; }
.bt-pane header { padding: 0.6em 1.1em; border-bottom: 1px solid var(--line); background: var(--bg); }
.bt-pane h3 {
  margin: 0; color: var(--faint); font-size: 0.82em; font-weight: 400;
  letter-spacing: 0.16em; text-transform: uppercase;
}
/* What this pane's evidence actually is, said in the pane rather than in
   documentation nobody reads while looking at a refusal. */
.bt-pane header p { margin: 0.25em 0 0; color: var(--dim); font-size: 0.85em; line-height: 1.5; }

.bt-page-body { padding: 1.1em; }

/* ── the frame: the page the box rendered ──
 *
 * Drawn as a page, in a page's own palette, because that is what a frame is:
 * pixels from inside the box, arriving on a screen made of everything else.
 * The seam is the point — nothing in here is evidence, and the caption under
 * it says so in the console's own words.
 *
 * Centred, and capped rather than stretched: a checkout page run out to the
 * full width of a wide display stops looking like a page somebody opened.
 */
.bt-frame { margin: 0 auto; min-width: 0; max-width: 42em; }
.bt-shot {
  border: 1px solid var(--line2);
  background: #f4f5f7;
  color: #14141a;
  font-family: var(--sans);
  font-size: 1.05em; line-height: 1.4;
}
.shot-nav {
  display: flex; align-items: baseline; gap: 1em;
  padding: 0.55em 0.9em;
  border-bottom: 1px solid #d9dbe0; background: #fff;
  font-size: 0.85em; color: #6b6f78;
}
.shot-nav b { color: #14141a; letter-spacing: -0.02em; }
.shot-nav .on { color: #14141a; box-shadow: inset 0 -2px 0 var(--spot-solid); }
.shot-body { padding: 0.9em 1em 1.1em; }
.shot-body h4 { margin: 0 0 0.7em; font-size: 1.25em; font-weight: 700; letter-spacing: -0.02em; }
.shot-line {
  display: flex; justify-content: space-between; gap: 1em;
  padding: 0.4em 0; border-bottom: 1px solid #e3e5ea;
  font-size: 0.9em; color: #43474f;
}
.shot-line b { color: #14141a; font-weight: 500; }
.shot-line.total { border-bottom: 0; margin-top: 0.2em; font-size: 1em; color: #14141a; }
/* The symptom the console pane names one column over: `total is undefined`
   threw, so the page rendered this instead of a number. */
.shot-line .broken { color: #b0121a; font-weight: 700; }
.shot-pay {
  margin-top: 0.8em; padding: 0.5em 1em;
  background: #14141a; color: #fff;
  font-size: 0.9em; text-align: center;
}
.shot-foot { margin-top: 0.6em; color: #83878f; font-size: 0.78em; }
.bt-frame figcaption { margin-top: 0.4em; color: var(--faint); font-size: 0.78em; line-height: 1.5; }

.bt-tabs { display: flex; flex-wrap: wrap; background: var(--bg); border-bottom: 1px solid var(--line2); }
.bt-tabs span {
  padding: 0.5em 0.9em; border-right: 1px solid var(--line);
  color: var(--faint); font-size: 0.85em;
}
.bt-tabs span.on { color: var(--ink); background: var(--panel); }
.bt-tabs b { margin-left: 0.5em; color: var(--faint); font-weight: 400; }

.bt-panes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.bt-panes > .bt-pane { border-right: 1px solid var(--line); }
.bt-panes > .bt-pane:nth-child(2n) { border-right: 0; }
.bt-rows { padding: 0.3em 0; }

.bt-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 0.6em; align-items: baseline;
  padding: 0.35em 1.1em;
  font-size: 0.88em;
}
.bt-row .text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the link a source actually carried, never one inferred from timing */
.bt-row .cause { color: var(--faint); font-size: 0.9em; }
.bt-row.ok .text { color: var(--dim); }
.bt-row.action .text { color: var(--ink); }
.bt-row.warn .text { color: var(--warn); }
.bt-row.error .text,
.bt-row.refused .text { color: var(--danger); }

.prov { display: inline-flex; gap: 0.3em; }
.prov .lane, .prov .grade { border: 1px solid var(--line2); padding: 0 0.35em; font-size: 0.85em; }
.prov .lane.host { color: var(--dim); }
.prov .lane.box { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.prov .grade.closed { color: var(--green); border-color: color-mix(in srgb, var(--green) 40%, transparent); }
.prov .grade.effort { color: var(--faint); }

/* Below the point where five lanes stop being legible, the console becomes the
   fleet alone. A shrunken-to-illegible screenshot is worse than a smaller one
   that still says something. */
@container (max-width: 620px) {
  .console-body { grid-template-columns: minmax(0, 1fr); }
  .console-detail { display: none; }
  .console { font-size: clamp(8px, 2.1cqw, 13px); }
  .console-vitals { margin-left: 0; }
  /* Two tabs, one row, split evenly: left-aligned they wrap, and a tab strip
     whose second tab sits on its own line under a gap reads as two things. */
  .console-tabs label { flex: 1 1 0; text-align: center; padding: 0.7em 0.6em; font-size: 11px; }
  /* The browser terminal keeps every pane — its panes are rows of text, which
     stack down to a phone; it is the five-lane grid that does not. */
  .bt { font-size: clamp(8px, 2.1cqw, 13px); }
  .bt-panes { grid-template-columns: minmax(0, 1fr); }
  .bt-panes > .bt-pane { border-right: 0; }
}

/* ── the forum ─────────────────────────────────────────────────
 *
 * The third view: one thread, as `h5i ui` draws it. Structure and labels
 * follow web/src/ForumView.tsx.
 *
 * The whole argument of this screen is one seam, so the markup makes it a
 * literal one. Every post is a header line the *host* wrote — sender, role,
 * box, and which lane observed it — above a fenced body the *box* staged. A
 * reader can see which half of a post the agent controls without being told,
 * because the two halves do not look alike.
 *
 * Sized off the same clamp as the other views, so all three hold their
 * proportions together inside one plate.
 */
.bd {
  font-size: clamp(5.5px, 1.02cqw, 13px);
  font-family: var(--mono);
  line-height: 1.5;
  color: var(--dim);
  user-select: none;
}
.bd-body {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 6.5fr) minmax(0, 3fr);
  min-height: 0;
}
.bd-threads { border-right: 1px solid var(--line2); min-width: 0; }
.bd-posts   { min-width: 0; }
.bd-people  { border-left: 1px solid var(--line2); min-width: 0; }

/* ── the thread list ── */
.bd-trow { padding: 0.75em 1.1em; border-bottom: 1px solid var(--line); }
.bd-trow.selected { background: color-mix(in srgb, var(--spot-solid) 7%, transparent); }
.bd-trow .t { color: var(--ink); font-size: 0.95em; line-height: 1.45; }
.bd-trow .m { margin-top: 0.4em; color: var(--faint); font-size: 0.82em; }
.bd-state {
  border: 1px solid var(--line2); padding: 0 0.4em; margin-right: 0.5em;
  font-size: 0.95em; color: var(--dim);
}
.bd-state.open    { color: var(--green); border-color: color-mix(in srgb, var(--green) 40%, transparent); }
.bd-state.claimed { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }

/* ── one post ──
 * `.bd-head` is the host's line. `.bd-said` is the box's, and it is fenced on
 * the left for exactly as long as it takes a reader to notice that the fence
 * starts where the host's knowledge stops. */
.bd-post { padding: 0.9em 2.2em; border-bottom: 1px solid var(--line); }
.bd-head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.35em 0.6em;
  font-size: 0.9em;
}
.bd-head b { color: var(--ink); font-weight: 400; }
.bd-kind {
  border: 1px solid var(--line2); padding: 0 0.45em;
  color: var(--faint); font-size: 0.88em;
  letter-spacing: 0.12em;
}
.bd-kind.finding  { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.bd-kind.proposal { color: var(--dim); }
.bd-kind.task     { color: var(--ink); border-color: var(--line2); }
.bd-role { color: var(--faint); }
.bd-when { margin-left: auto; color: var(--faint); font-size: 0.9em; }
.bd-where { color: var(--faint); font-size: 0.88em; }
.bd-said {
  margin: 0.55em 0 0;
  padding: 0.1em 0 0.1em 0.9em;
  border-left: 1px solid var(--line2);
  color: var(--dim); font-size: 0.95em; line-height: 1.65;
}
.bd-vote { margin-top: 0.5em; color: var(--faint); font-size: 0.85em; }
.bd-vote b { color: var(--green); font-weight: 400; }

/* ── participants ── */
.bd-who { padding: 0.8em 1.1em; border-bottom: 1px solid var(--line); }
.bd-who .n { color: var(--ink); font-size: 0.95em; }
.bd-kv { display: flex; gap: 0.7em; margin-top: 0.3em; font-size: 0.85em; }
.bd-kv .k { color: var(--faint); flex: 0 0 4.2em; }
.bd-kv .val { color: var(--dim); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── the thread's own header ──
 *
 * Without it the pane opened on a reply to a question the reader could not
 * see, which made the left-hand list the only place the subject was ever
 * stated. Just the title: the id, the state and the claimant are all on the
 * selected row in that list already, and a thread id means nothing to someone
 * looking at a picture. */
.bd-thread {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.45em 0.85em;
  padding: 1.3em 2.2em 1.5em; border-bottom: 1px solid var(--line);
}
/* The chip carries its own margin for the thread list, where it sits against
   running text. Here the flex gap already does that job. */
.bd-thread .bd-state { margin-right: 0; }
.bd-id { color: var(--faint); font-size: 0.92em; }
.bd-title {
  margin: 0; color: var(--ink);
  font-family: var(--sans); font-size: 1.5em; font-weight: 600;
  letter-spacing: -0.015em; line-height: 1.3;
}
