/*
 * The application shell: the top bar, the page container, and the list and
 * form pages hung off them.
 *
 * Deliberately NOT `review.css`, and the split is load-bearing rather than
 * tidy. `judgement/render.py` reads `review.css` off disk and inlines it
 * verbatim into every offline static pack. A pack is a downloaded file with no
 * server behind it: it has no navigation, nobody is signed in to it, and it
 * has no build to stamp. Every rule below would be dead weight reprinted into
 * each one. So the questions' styling stays in `review.css`, where both
 * surfaces share it, and the chrome around them lives here, where only the
 * served application sees it.
 *
 * ORDER MATTERS. `review.html` links this file first and `review.css` second,
 * so on the review page `review.css` wins every selector the two happen to
 * share - `.row`, `.note`, `.panes`, `.pane`, `.shot`, `.sub`, `.warn`, `h1`,
 * `main`, `body`. That is the intent: those names were the review page's
 * first, this file's use of them is for the other pages, and the review page's
 * layout is not in scope. The rules that must go the other way are gathered at
 * the bottom of this file and win on specificity instead.
 *
 * Everything page-specific is scoped by a body class - `body.region .note`,
 * `body.capture .grid`. That is what makes it safe for this file and
 * `review.css` to keep using the same names for different things: neither can
 * reach the other's page, so nothing had to be renamed.
 */

:root {
  /* The four `review.css` also declares, at identical values on purpose: two
     stylesheets meet on the review page and neither may move the other's
     ground. `tests/test_shell.py` pins them equal, because "keep these in
     step" is not a thing a person can be relied on to remember. */
  --ink: #1c1c1c;
  --dim: #666;
  --line: #d8d8d8;
  --bg: #fbfbf9;

  /* The shell's own. */
  --panel: #fff;
  --rule: #e6e6e6;
  --muted: #8a8a8a;
  --accent: #1c6ec1;
  --accent-ink: #17558f;
  --accent-wash: #eef4fb;
  --nav-h: 3.25rem;
  --radius: 5px;

  /* Status, one vocabulary for every pill on every page. */
  --ok: #276b27;
  --ok-line: #9c9;
  --busy: #26688a;
  --busy-line: #8ab3c9;
  --warn: #8a7326;
  --warn-line: #c9b98a;
  --bad: #a11;
  --bad-line: #c99;
  --odd: #8a2670;
  --odd-line: #c9a;
}

* { box-sizing: border-box; }

/* The same guard `review.css` carries, for the same reason: this file sets
   `display` on a dozen classes, and any of them would beat the `hidden`
   attribute's own rule. `connect.html` hides its scope warning that way, and
   it is a page that never loads `review.css`. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.55 -apple-system, Segoe UI, Roboto, Helvetica, sans-serif;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---- the top bar -------------------------------------------------------
   The one piece of chrome every page shares. Before it there was no link
   between the documents half and the captures half in either direction, and
   four of the seven pages had no way to sign out. */

.topbar {
  position: sticky;
  top: 0;
  /* above `review.css`'s sticky header, which sits at 5 */
  z-index: 20;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  gap: 1.4rem;
  padding: 0 1.4rem;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}

.brand {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .95rem;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -.01em;
}
.brand:hover { text-decoration: none; }

/* A connector body with two cavities in it. Drawn rather than shipped as a
   file so the bar costs no second request.

   It was two plain stacked bars first, and that was wrong for a reason worth
   recording: two horizontal lines at the left end of a nav bar is the
   universal hamburger, so the mark read as a menu control nobody could open.
   Filling the box and reversing the bars out of it removes the reading. */
.brand .mark {
  position: relative;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  background: var(--accent);
  flex: none;
}
.brand .mark::before,
.brand .mark::after {
  content: "";
  position: absolute;
  left: 3px;
  right: 3px;
  height: 2px;
  border-radius: 1px;
  background: var(--panel);
}
.brand .mark::before { top: 3px; }
.brand .mark::after { bottom: 3px; }

.navlinks {
  display: flex;
  align-items: center;
  gap: .3rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.navlinks a {
  display: block;
  padding: .3rem .6rem;
  border-radius: 4px;
  font-size: .88rem;
  color: var(--dim);
}
.navlinks a:hover { background: #f2f2f0; color: var(--ink); text-decoration: none; }
.navlinks a.on { background: var(--accent-wash); color: var(--accent-ink); font-weight: 500; }

/* Pushed to the far right; `margin-left:auto` on the first of them rather than
   a spacer element. */
.acct {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: .7rem;
  font-size: .82rem;
  color: var(--dim);
}
.acct .who { color: var(--ink); font-weight: 500; }
.acct form { display: inline; margin: 0; }

/* `.topbar button` rather than `button`: `review.css` styles the bare element
   for the review page's own footer controls, and this must not reach those. */
.topbar button {
  font: inherit;
  font-size: .82rem;
  padding: .2rem .55rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--dim);
  cursor: pointer;
}
.topbar button:hover { border-color: var(--accent); color: var(--accent); }

/* The build stamp. Monospace because it is an identifier and gets read
   character by character when somebody is checking whether a deploy landed. */
.build {
  font-family: ui-monospace, Menlo, monospace;
  font-size: .72rem;
  color: var(--muted);
  white-space: nowrap;
  border-left: 1px solid var(--rule);
  padding-left: .7rem;
}

@media (max-width: 700px) {
  .topbar { gap: .8rem; padding: 0 .8rem; }
  .build { display: none; }
  .acct .who { display: none; }
}

/* ---- the page container ------------------------------------------------
   Three widths, because the pages genuinely want three: a form is unreadable
   wide, a list wants a comfortable measure, and a grid of crops wants the
   room. Not applied on the review page, which is full-bleed and manages its
   own `main`. */

.page { max-width: 760px; margin: 2.2rem auto 4rem; padding: 0 1.2rem; }
.page.narrow { max-width: 26rem; margin-top: 3.5rem; }
.page.wide { max-width: 1100px; }
.page.widest { max-width: 1300px; }

.pagehead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin: 0 0 .3rem;
}
.pagehead h1 { font-size: 1.2rem; margin: 0; letter-spacing: -.01em; }
.pagehead .count { color: var(--muted); font-size: .8rem; white-space: nowrap; }

.page h1 { font-size: 1.2rem; margin: 0 0 .3rem; }
.page h2 { font-size: .95rem; margin: 2rem 0 .6rem; }
.page p.sub { color: var(--dim); font-size: .85rem; margin: 0 0 1.4rem; max-width: 60ch; }
.page p.hint { color: var(--dim); font-size: .82rem; margin-top: 1.4rem; max-width: 62ch; }
.page .meta { color: var(--muted); font-size: .78rem; }
.page code {
  font-family: ui-monospace, Menlo, monospace;
  font-size: .88em;
  background: #f0efec;
  padding: .05rem .25rem;
  border-radius: 3px;
}

/* ---- pills ------------------------------------------------------------
   One shape and one colour vocabulary for every state on every page: the
   ingest queue's states, a capture's verdict, a claim's method. A reader
   learns it once. */

.pill {
  display: inline-block;
  font-size: .72rem;
  padding: .05rem .4rem;
  border-radius: 3px;
  border: 1px solid #d8d8d2;
  color: var(--dim);
  white-space: nowrap;
}
.pill.queued, .pill.ambiguous, .pill.needs_review { border-color: var(--warn-line); color: var(--warn); }
.pill.running { border-color: var(--busy-line); color: var(--busy); }
.pill.failed, .pill.out_of_scope, .pill.conflicted { border-color: var(--bad-line); color: var(--bad); }
.pill.unrecognised, .pill.vlm { border-color: var(--odd-line); color: var(--odd); }
.pill.in_scope, .pill.done { border-color: var(--ok-line); color: var(--ok); }

/* The open-question count. A number with work left reads as a live count; a
   zero reads as finished, and is deliberately quiet rather than green - there
   is nothing to celebrate, only nothing to do. */
.open {
  font-size: .78rem;
  white-space: nowrap;
  color: var(--accent-ink);
  background: var(--accent-wash);
  border-radius: 10px;
  padding: .1rem .55rem;
}
.open.none { color: var(--muted); background: #f2f2f0; }

/* ---- lists -------------------------------------------------------------
   The documents index and the captures index. `.listing` and not `.list`,
   which is close enough to something in `review.css` to be worth avoiding. */

ul.listing { list-style: none; padding: 0; margin: 0; border-top: 1px solid var(--rule); }
ul.listing > li { padding: .6rem .5rem; border-bottom: 1px solid var(--rule); }
ul.listing > li:hover { background: #f7f7f4; }
ul.listing .line {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: baseline;
}
ul.listing .name { font-weight: 500; }
ul.listing .under { color: var(--muted); font-size: .76rem; margin-top: .15rem; }
/* The timestamp the captures list is sorted by. Tabular figures and a fixed
   font so the column reads as a column - proportional digits make a stack of
   times ragged exactly where the eye is trying to compare them. */
ul.listing .under .at {
  font-family: ui-monospace, Menlo, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--dim);
}
ul.listing li.done .name a, ul.listing li.done .name { color: var(--muted); font-weight: 400; }
ul.listing li.empty, ul.listing li.empty:hover { color: var(--muted); background: none; }
ul.listing .err { color: var(--bad); font-size: .78rem; display: block; margin-top: .2rem; }

/* ---- panels and forms --------------------------------------------------
   The upload box, the login form, the connect form. */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
}

.page label { display: block; font-size: .82rem; color: #444; margin: 0 0 .25rem; }
.page input[type=text],
.page input[type=password],
.page input[type=file],
.page select {
  width: 100%;
  font: inherit;
  font-size: .92rem;
  padding: .4rem .5rem;
  margin: 0 0 .9rem;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: var(--panel);
}
.page input:focus, .page select:focus {
  outline: 2px solid var(--accent-wash);
  border-color: var(--accent);
}

/* Scoped under `.page` for the same reason `.topbar button` is: the review
   page's buttons are `review.css`'s and must not be reached from here. */
.page button {
  font: inherit;
  font-size: .88rem;
  padding: .4rem 1rem;
  border-radius: 4px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink);
  cursor: pointer;
}
.page button.primary { border-color: var(--accent); background: var(--accent); color: #fff; }
.page button.primary:hover:not(:disabled) { background: var(--accent-ink); border-color: var(--accent-ink); }
.page button.ghost { border-color: var(--accent); color: var(--accent); }
.page button:disabled { color: var(--muted); cursor: default; }

.box { border-radius: 4px; padding: .55rem .75rem; font-size: .85rem; margin: 0 0 1.1rem; }
.box.bad { background: #fdecea; border: 1px solid #f5c6c2; }
.box.good { background: #eaf6ec; border: 1px solid #bfe3c6; }
.box.caution { background: #fdf4e3; border: 1px solid #eddcb5; font-size: .8rem; line-height: 1.45; }

/* ---- the documents index ----------------------------------------------- */

body.documents .upload { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
body.documents .upload input[type=file] { flex: 1 1 16rem; margin: 0; font-size: .85rem; }
body.documents .upload button { flex: none; }
body.documents #upmsg { font-size: .82rem; margin: .6rem 0 0; min-height: 1.2em; }
body.documents #upmsg.bad { color: var(--bad); }
body.documents #jobs { margin: .6rem 0 0; border-top: 0; }
body.documents #jobs li { font-size: .82rem; padding: .35rem .5rem; }

/* ---- one capture, and one region ---------------------------------------
   Every rule here is scoped by body class, and that is what makes it safe to
   keep using `.panes`, `.pane`, `.shot` and `.note` - all four are
   `review.css`'s names too, for entirely different things. `body.region .note`
   cannot reach the review page and `review.css`'s `.note` cannot reach this
   one, so neither had to be renamed. */

body.capture .shot, body.region .shot {
  max-width: 100%;
  border: 1px solid #e0e0da;
  background: var(--panel);
  display: block;
}

body.capture .grid {
  display: grid;
  gap: .9rem;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
body.capture .card {
  border: 1px solid #e0e0da;
  border-radius: var(--radius);
  background: var(--panel);
  padding: .6rem;
}
body.capture .card:hover { border-color: var(--line); box-shadow: 0 1px 4px #0000000f; }
body.capture .card img { max-width: 100%; display: block; background: var(--panel); }
body.capture .card .n { font-size: .8rem; margin-top: .4rem; }
body.capture .none, body.region .none {
  color: var(--muted);
  font-size: .8rem;
  padding: 1.4rem 0;
  text-align: center;
  border: 1px dashed #e0e0da;
}
body.capture .zero { color: var(--muted); }

body.region .panes {
  display: grid;
  gap: 1.4rem;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
@media (max-width: 900px) { body.region .panes { grid-template-columns: 1fr; } }
body.region .pane { min-width: 0; }
body.region .pane h2 { margin-top: 0; }
body.region .claim {
  border: 1px solid #e0e0da;
  border-radius: var(--radius);
  background: var(--panel);
  padding: .6rem .7rem;
  margin: 0 0 .7rem;
}
body.region .claim.needs_review { border-left: 3px solid var(--warn-line); }
body.region .claim.conflicted { border-left: 3px solid var(--bad-line); }
body.region .claim h3 { font-size: .85rem; margin: 0 0 .3rem; font-weight: 600; }
body.region .claim dl {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .1rem .6rem;
  font-size: .82rem;
}
body.region .claim dt { color: var(--muted); }
body.region .claim dd {
  margin: 0;
  font-family: ui-monospace, Menlo, monospace;
  font-size: .9em;
  overflow-wrap: anywhere;
}
body.region .note { font-size: .78rem; color: var(--dim); margin-top: .35rem; }
body.region .note.bad { color: var(--bad); }
body.region .said { font-size: .78rem; }
body.region .said.bad { color: var(--bad); }
body.region .answer { margin-top: .45rem; display: flex; gap: .35rem; align-items: center; flex-wrap: wrap; }
body.region .answer-btn {
  font: inherit;
  font-size: .78rem;
  padding: .1rem .45rem;
  border: 1px solid #d8d8d2;
  border-radius: 3px;
  background: var(--panel);
  color: #444;
  cursor: pointer;
}
body.region .answer-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
body.region .answer-btn:disabled { cursor: default; opacity: .45; }
body.region .decided { font-size: .78rem; font-weight: 600; }

/* ---- connecting the extension ------------------------------------------ */

body.connect #wp-token {
  display: block;
  word-break: break-all;
  padding: .5rem .6rem;
  margin: .5rem 0 .7rem;
  background: var(--panel);
  border: 1px solid #cfd8cf;
}

/* ---- what the nav changes on the review page ---------------------------
   Four rules, and they belong here rather than in `review.css` because every
   one of them would be wrong in a static pack, which has no nav for anything
   to sit below. The three that override `review.css` win on specificity
   (`body.review header` beats `header`) rather than on link order, so they
   keep working if somebody ever swaps the two `<link>`s round. */

/* All that is left of the crumb: one link back to the whole queue, shown only
   on a single-question page. `.crumb` is this file's name, not `review.css`'s,
   so the scope is for consistency rather than to avoid a collision. */
body.review .crumb { font-size: .82rem; margin: 0 0 .5rem; }

/* `review.css` parks the question header at `top:0`; with a bar above it the
   two would occupy the same strip. Stacked sticky instead: the nav pins at 0,
   the header pins directly under it. */
body.review header { top: var(--nav-h); }

/* `review.css:25` sets `scroll-margin-top:10rem` so that jumping to a question
   clears the sticky header. The nav is now above that header, so the margin
   has to grow by exactly its height or a linked question lands underneath. */
body.review section { scroll-margin-top: calc(10rem + var(--nav-h)); }

/* The queue notes sit between the nav and the tiles and were flush against a
   header that is no longer the first thing on the page. */
body.review > .warn:first-of-type { margin-top: 1rem; }

/* ---- the wiring browser -------------------------------------------------
   A read-only walk over the parsed graph. Scoped to `body.browse` like every
   other page block in this file, and using the tokens above rather than any
   of its own - the flags borrow the status vocabulary, so a wire the parser
   read badly looks the same shade of wrong as a job that failed. */

/* Two boxes on one row, wrapping on a narrow screen. `position: relative` is
   on the field rather than on the row, because each list has to hang under its
   own input - anchored to the row, the pin list would open under the component
   box. */
body.browse .find {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .5rem;
  margin: 0 0 1rem;
}
body.browse .find .field { position: relative; flex: 1 1 20rem; max-width: 34rem; }
body.browse .find .pinfield { flex: 0 1 11rem; max-width: 11rem; }
body.browse .find label {
  display: block;
  font-size: .78rem;
  color: var(--muted);
  margin-bottom: .25rem;
}
body.browse .find input {
  width: 100%;
  padding: .45rem .6rem;
  font-size: 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
}
body.browse .find input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-wash);
}
/* The pin box before a component has been chosen. Greyed rather than hidden,
   because the second step is worth seeing coming. */
body.browse .find input:disabled {
  background: var(--rule);
  color: var(--muted);
  cursor: not-allowed;
}

/* The result list floats over the tree rather than pushing it down: a list
   that reflows the page under the cursor makes the row you were aiming at
   move as you reach for it. */
body.browse .hits {
  position: absolute;
  z-index: 5;
  top: 100%;
  left: 0;
  width: 100%;
  max-height: 20rem;
  overflow-y: auto;
  margin: .2rem 0 0;
  padding: 0;
  list-style: none;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .09);
}
/* The pin box is narrow because a cavity number is short, but its rows carry
   the wire count and the sheet as well - so the list is allowed to be wider
   than the box it hangs under rather than wrapping every row. */
body.browse #pinhits {
  width: auto;
  min-width: 100%;
  white-space: nowrap;
}
body.browse .hits li {
  padding: .35rem .6rem;
  cursor: pointer;
  border-bottom: 1px solid var(--rule);
}
body.browse .hits li:last-child { border-bottom: 0; }
body.browse .hits li.on,
body.browse .hits li:hover { background: var(--accent-wash); }
body.browse .hits li.empty { color: var(--muted); cursor: default; }
body.browse .hits .nm { font-weight: 600; }
body.browse .hits .meta { display: block; font-size: .76rem; color: var(--muted); }

body.browse .cols { display: flex; gap: 1.25rem; align-items: flex-start; }
body.browse .treecol { flex: 1 1 auto; min-width: 0; }
body.browse .detail { flex: 0 0 20rem; }

body.browse .tree ul {
  list-style: none;
  margin: 0;
  padding-left: 1.1rem;
  border-left: 1px solid var(--rule);
}
body.browse .tree > ul.roots { padding-left: 0; border-left: 0; }
body.browse .tree li { margin: .1rem 0; }
body.browse .tree .row {
  padding: .2rem .35rem;
  border-radius: var(--radius);
  font-size: .88rem;
}
body.browse .branch > .row { cursor: pointer; }
body.browse .branch > .row:hover { background: var(--accent-wash); }
body.browse .root > .row { font-weight: 600; font-size: .95rem; }

/* The disclosure marker is a fixed-width cell so the names below it line up
   whether or not a row can be opened. */
body.browse .tree .tw {
  display: inline-block;
  width: 1rem;
  color: var(--muted);
}
body.browse .tree .kid { font-family: ui-monospace, monospace; font-size: .8rem; color: var(--muted); }
body.browse .tree .color { font-weight: 600; }
body.browse .tree .ckt { color: var(--dim); }
body.browse .tree .arrow { color: var(--muted); margin: 0 .25rem; }
body.browse .tree .dest.go {
  border-bottom: 1px dotted var(--accent);
  color: var(--accent-ink);
  cursor: pointer;
}
body.browse .tree .dest.go:hover { background: var(--accent-wash); }
/* An end nothing can be browsed from is said plainly and not underlined - a
   dead end that looks like a link is a click that does nothing. */
body.browse .tree .dest { color: var(--dim); }
body.browse .tree .pin { color: var(--dim); font-weight: 400; }
body.browse .tree .more {
  margin-left: .4rem;
  font-size: .72rem;
  color: var(--muted);
}
body.browse .tree .muted { color: var(--muted); }
body.browse .tree .cond {
  color: var(--busy);
  border: 1px solid var(--busy-line);
  border-radius: 999px;
  padding: 0 .4rem;
  font-size: .72rem;
}

/* The joints a wire passed through. Dimmed and not clickable, because they
   are not wire ends - but shown, because for somebody checking a parse they
   are exactly where it goes wrong. */
body.browse .via {
  margin: 0 0 .1rem 1.1rem;
  font-size: .74rem;
  color: var(--muted);
  font-family: ui-monospace, monospace;
}
body.browse .flags { margin-left: .4rem; }
body.browse .flag {
  display: inline-block;
  margin-left: .25rem;
  padding: 0 .4rem;
  font-size: .72rem;
  color: var(--warn);
  background: #fdfaf0;
  border: 1px solid var(--warn-line);
  border-radius: 999px;
}
body.browse .tree .warn {
  margin-left: 1.1rem;
  font-size: .76rem;
  color: var(--bad);
}
body.browse .tree .empty, body.browse .hits li.empty { color: var(--muted); font-size: .82rem; }

body.browse .detail .panel { margin-bottom: 1rem; }
body.browse .detail h2 { font-size: 1rem; margin: 0 0 .2rem; }
body.browse .detail .kindline { margin: 0 0 .5rem; font-size: .8rem; color: var(--muted); }
body.browse .detail .facts { margin: 0; padding-left: 1rem; font-size: .82rem; }
body.browse .detail .facts.notes { margin-top: .5rem; color: var(--dim); }
body.browse .netends { margin: 0; padding: 0; list-style: none; font-size: .82rem; }
body.browse .netends li {
  padding: .2rem 0;
  border-bottom: 1px solid var(--rule);
  display: flex;
  justify-content: space-between;
  gap: .5rem;
}
body.browse .netends li:last-child { border-bottom: 0; }
body.browse .netends li.go { cursor: pointer; color: var(--accent-ink); }
body.browse .netends li.go:hover { background: var(--accent-wash); }
body.browse .netends li.muted { color: var(--muted); }
body.browse .netends .kid { font-family: ui-monospace, monospace; font-size: .74rem; color: var(--muted); }

/* The drawing.
 *
 * Its own scroll box rather than a canvas that shrinks to fit: the corpus's
 * worst net is 85 wires, and scaling that into the column would make every
 * label illegible to keep a picture nobody could read anyway. The page itself
 * never scrolls sideways.
 *
 * Every colour here is a token except the picked wire, which is the same
 * `#d35400` `review.css` marks a picked polyline with - the two pages do the
 * same thing and a person who has used one should recognise it in the other.
 */
/* The browse page is as wide as the screen gives it, which every other page
 * here is not. A net is drawn left to right and a chain through two joints is
 * already eight hundred pixels; at the 1100 the other wide pages use, the
 * ordinary case scrolls, and a schematic somebody has to drag sideways to read
 * is not one they can compare against a sheet. Capped rather than uncapped so
 * an ultrawide monitor does not stretch the prose to a single line.
 */
body.browse .page.wide { max-width: 1800px; }

body.browse .dia {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--panel);
  /* Still scrollable, because nothing is truncated and the corpus's worst net
   * is 85 wires. What the width above buys is that the ordinary net does not
   * need it. */
  overflow: auto;
  max-height: 40rem;
  margin-bottom: 1rem;
  padding: .25rem;
}
body.browse .dia .empty, body.browse .dia .warn { padding: .75rem; margin: 0; font-size: .82rem; }
body.browse .dia .empty { color: var(--muted); }
body.browse .dia .warn { color: var(--bad); }
/* Centred while it fits and left-aligned once it does not, which is what
 * `auto` margins do on their own - a wide net starts where you read from. */
body.browse svg.net { display: block; margin: 0 auto; }

/* The wire. Three strokes on one path: a fat transparent one to click, the
 * base colour, and the tracer of a two-tone wire over it. */
body.browse svg.net path { fill: none; }
body.browse svg.net path.hit {
  stroke: transparent;
  stroke-width: 11;
  cursor: pointer;
  pointer-events: stroke;
}
body.browse svg.net path.ink { stroke-width: 2.4; pointer-events: none; }
body.browse svg.net path.tracer {
  stroke-width: 1.1;
  stroke-dasharray: 6 8;
  pointer-events: none;
}
body.browse svg.net path.hit:hover + path.ink { stroke-width: 4; }
body.browse svg.net path.ink.picked, body.browse svg.net path.tracer.picked {
  stroke: #d35400;
  stroke-width: 4;
}

/* The wire's name, punched out of the line it sits on rather than boxed. */
body.browse svg.net text.tag {
  font-size: 10px;
  fill: var(--dim);
  text-anchor: middle;
  paint-order: stroke;
  stroke: var(--panel);
  stroke-width: 3.5;
  stroke-linejoin: round;
  cursor: pointer;
}
body.browse svg.net text.tag.picked { fill: #d35400; }

body.browse svg.net .node text { text-anchor: middle; }
/* Every node answers a click - a named one re-roots the drawing, and a joint
 * or an unresolved end fills the panel instead - so every node says so.
 * Scoped to .go once, which left the parser's junction dots looking inert
 * while still being the thing a person clicks to read what meets there. */
body.browse svg.net .node { cursor: pointer; }
body.browse svg.net .node .nm { font-size: 11px; font-weight: 600; fill: var(--ink); }
body.browse svg.net .node .sub { font-size: 10px; fill: var(--muted); }
body.browse svg.net .block rect {
  fill: var(--bg);
  stroke: var(--line);
  stroke-width: 1;
}
body.browse svg.net .block.go:hover rect { stroke: var(--accent); }
body.browse svg.net .node.focus rect {
  fill: var(--accent-wash);
  stroke: var(--accent);
  stroke-width: 2;
}
body.browse svg.net .dot circle { fill: var(--ink); stroke: var(--panel); stroke-width: 2; }
body.browse svg.net .dot.go:hover circle { fill: var(--accent); }
body.browse svg.net .node.focus circle { fill: var(--accent); stroke: var(--accent); }
/* A vertex whose ends the parser was not sure of. The same shade the tree
 * flags a badly read end in, so the two say the same thing the same way. */
body.browse svg.net .node .mark { fill: var(--warn-line); stroke: none; }
/* The cavities a block is not showing. A way into the cavity list, not a
 * re-root, so it is marked as its own target rather than part of the block. */
body.browse svg.net .cav { fill: var(--accent-ink); cursor: pointer; }
body.browse svg.net .cav:hover { text-decoration: underline; }

body.browse .detail .wireline { margin: 0 0 .5rem; font-size: .82rem; }
body.browse .detail .wireline .color { font-weight: 600; }
body.browse .detail .wireline .ckt, body.browse .detail .wireline .muted { color: var(--muted); }
body.browse .detail .wireline .cond { color: var(--busy); }
body.browse .detail .facts .flags { display: block; margin: .15rem 0 0; }

@media (max-width: 60rem) {
  body.browse .cols { display: block; }
  body.browse .detail { margin-top: 1rem; }
}
