/* Visual 6502 -- design language borrowed from nominate.ai (hard offset shadows,
   2px borders, mono eyebrows, Inter 900 headings) in a cyan/steel palette, so
   it reads as a sibling rather than a copy. */

:root {
  --space: #0b1120;
  --surface: #131c2f;
  --subtle: #1a2740;
  --line: #3d5573;
  --foreground: #eaf2ff;
  --muted: #9fb3cc;
  --accent: #22d3ee;
  --accent-foreground: #06121f;
  --gold: #7dd3fc;
  --pink: #f472b6;
  --mint: #5eead4;
  --warn: #fb7185;
  --hot: #ffd08a;

  --font-sans: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "SFMono-Regular", "SF Mono", ui-monospace, Consolas, "Liberation Mono", monospace;

  --hard: 5px 5px 0 rgba(2, 6, 16, .5);
  --hard-card: 8px 8px 0 rgba(2, 6, 16, .48);

  /* The vertical rhythm between sections. A token rather than a literal because
     anything that wants to sit an equal distance below something has to use the
     SAME expression, not a copy of it: this is responsive, so a matching literal
     is only equal at the width it was eyeballed at. */
  --sec-gap: clamp(2.5rem, 7vw, 4.5rem);

  --panel-w: 20rem;
  /* Safe-area insets so the transport bar clears a phone's home indicator. */
  --sa-b: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; }

/* UA [hidden] is specificity (0,1,0) and loses to the #id rules below. */
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: 5rem;
}

body {
  margin: 0;
  min-height: 100vh;
  position: relative;
  isolation: isolate;
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  background:
    radial-gradient(circle at 12% 6%, #22d3ee1f, transparent 30rem),
    radial-gradient(circle at 88% 10%, #7dd3fc16, transparent 28rem),
    linear-gradient(135deg, var(--space), #0e1830 56%, var(--subtle));
}

/* Stipple, same trick as nominate.ai: two offset dot grids at low opacity. */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: 0; pointer-events: none; opacity: .45;
  background-image:
    radial-gradient(circle, #eaf2ff7a 0 1.5px, transparent 2px),
    radial-gradient(circle, #22d3ee66 0 1px, transparent 1.5px);
  background-size: 140px 128px, 180px 176px;
  background-position: 0 0, 42px 58px;
}

.wrap {
  position: relative; z-index: 1;
  max-width: 78rem; margin: 0 auto;
  padding: 0 1.25rem;
}

h1, h2, h3 { margin: 0; font-weight: 900; letter-spacing: -0.01em; line-height: 1.12; }
h1 { font-size: clamp(2.4rem, 7.5vw, 4.4rem); line-height: .96; }
h2 { font-size: clamp(1.45rem, 3.4vw, 2.15rem); line-height: 1.1; }
h3 { font-size: 1.05rem; }
p { margin: 0; line-height: 1.6; }
a { color: var(--gold); }

.lede { color: var(--muted); font-size: 1.05rem; max-width: 62ch; }
.lede + .lede { margin-top: 1rem; }
.fineprint { margin-top: 1.5rem; color: var(--muted); font-size: .82rem; max-width: 62ch; }

code {
  font-family: var(--font-mono); font-size: .92em;
  padding: .1em .35em; border-radius: .25rem;
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  border: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
  color: var(--gold);
}

.eyebrow {
  font-family: var(--font-mono); font-size: .75rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .14em; line-height: 1;
  color: var(--gold); display: flex; align-items: center; gap: .6rem;
}
.eyebrow::after {
  content: ""; flex: 1; height: 2px; max-width: 4rem;
  background: linear-gradient(90deg, var(--line), transparent);
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 2.9rem; padding: .7rem 1.15rem;
  border: 2px solid; border-radius: .375rem;
  font: inherit; font-weight: 800; font-size: .95rem;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: .15s;
  /* Set explicitly. Without these a bare .btn inherits the user agent's button
     face, which is white, and every secondary button on a dark page looked like
     a mistake. The variants below override where they need to. */
  background: var(--subtle);
  border-color: var(--line);
  color: var(--foreground);
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn:active { transform: translate(2px, 2px); }
/* Stated rather than left to the user agent, for the same reason as the
   background above: a disabled button with no author style takes whatever the
   browser's disabled face is. */
.btn:disabled, .btn:disabled:hover {
  opacity: .45; cursor: default; transform: none;
  border-color: var(--line); color: var(--foreground); background: var(--subtle);
}
.btn-primary {
  border-color: var(--accent); background: var(--accent);
  color: var(--accent-foreground); box-shadow: var(--hard);
}
/* The colour has to be restated here, and this is the same trap as the missing
   background on the base class. `.btn:hover` declares `color: var(--accent)` at
   specificity (0,2,0), which outranks `.btn-primary`'s (0,1,0) -- so hovering a
   primary button left cyan text on the gold background, two light blues one on
   top of the other at a contrast ratio of 1.08. A variant that changes its
   background must restate its colour, because the base class's *state* rules
   outrank the variant's resting one. `_contrast-test.html` checks every button
   in every state for this. */
.btn-primary:hover, .btn-primary:active, .btn-primary:focus {
  border-color: var(--gold); background: var(--gold); color: var(--accent-foreground);
}
.btn-primary:active { box-shadow: 3px 3px 0 rgba(2, 6, 16, .5); }
.btn-ghost { border-color: var(--line); background: transparent; color: var(--foreground); }
.btn-ghost:hover { border-color: var(--gold); color: var(--gold); }
.btn-sm { min-height: 2.4rem; padding: .45rem .8rem; font-size: .85rem; }

.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.9rem; min-height: 2.9rem; padding: .5rem .7rem;
  border: 2px solid color-mix(in srgb, var(--line) 80%, transparent);
  border-radius: .375rem; background: color-mix(in srgb, var(--surface) 70%, transparent);
  color: var(--foreground); cursor: pointer;
  font-family: var(--font-mono); font-size: .95rem; line-height: 1;
  transition: .15s;
}
.iconbtn:hover { border-color: var(--gold); color: var(--gold); }
.iconbtn:active { transform: translate(1px, 1px); }
.iconbtn.primary { border-color: var(--accent); color: var(--accent); }
.iconbtn.primary:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }

:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 2px; }

.tag {
  font-family: var(--font-mono); font-size: .7rem; letter-spacing: .09em;
  text-transform: uppercase; padding: .4rem .65rem; border-radius: .3rem;
  border: 2px solid color-mix(in srgb, var(--line) 75%, transparent);
  background: color-mix(in srgb, var(--surface) 75%, transparent);
  color: var(--muted); white-space: nowrap;
}
.tag.live { border-color: var(--accent); color: var(--gold); }
.tag.live::before { content: "●"; margin-right: .4rem; color: var(--accent); }

/* ---------- boot ---------- */

#boot {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: radial-gradient(ellipse at 50% 40%, #131c2f 0%, var(--space) 70%);
}
.boot-inner { text-align: left; width: min(26rem, 88vw); padding: 1.5rem; }
.boot-inner .eyebrow { margin-bottom: 1rem; }
.boot-title { font-size: clamp(2rem, 9vw, 3rem); margin-bottom: 1.25rem; }
.boot-title span { color: var(--accent); }
#boot-status { color: var(--muted); margin-bottom: 1rem; font-family: var(--font-mono); font-size: .85rem; }
.boot-bar { height: 3px; background: var(--subtle); border-radius: 2px; overflow: hidden; }
#boot-bar-fill {
  height: 100%; width: 0%; background: var(--accent);
  transition: width .25s ease; box-shadow: 0 0 14px var(--accent);
}
#boot-error {
  margin-top: 1.25rem; color: var(--warn); font-family: var(--font-mono);
  font-size: .78rem; white-space: pre-wrap; line-height: 1.5;
}

/* ---------- site header ---------- */

.site-head {
  position: sticky; top: 0; z-index: 30;
  backdrop-filter: blur(12px);
  background: color-mix(in srgb, var(--space) 86%, transparent);
  border-bottom: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
}
.site-head .wrap { position: relative; }
.site-head nav {
  display: flex; flex-wrap: wrap; align-items: center;
  column-gap: .9rem; row-gap: .5rem; min-height: 4.25rem; padding: .5rem 0;
}

.mark {
  font-weight: 900; font-size: 1.1rem; letter-spacing: -.02em;
  text-decoration: none; color: var(--foreground); white-space: nowrap;
}
.mark span { font-family: var(--font-mono); font-weight: 700; color: var(--accent); }

.navlinks { display: none; }

/* The program picker, which replaced the "Run it" call to action and inherits
   its job: choosing a program is how you start the chip on something. The
   names are long enough to blow the header open at any width, so the control
   is capped and left to clip rather than allowed to size to its content. */
/* `flex: 0 0 auto` is load-bearing. As a shrinkable flex item the select
   collapsed to 22px against a nav row that wanted more space than the header
   had -- so the control was unusable while the header still *looked* fine, and
   the 320px overflow harness could not see it because the links are behind the
   menu button at that width. Measure the desktop widths too. */
/* Program, transport and clock as one group, so there is one thing to place
   rather than three competing for the end of the row. Below 52rem the group
   takes a row of its own: at 320px the three controls plus a wordmark and a
   menu button want about 90px more than the viewport has, and a header that
   overflows scrolls the whole page sideways. */
.nav-ctl {
  margin-left: auto; display: flex; align-items: center; gap: .5rem;
  flex: 0 0 auto; min-width: 0;
}
.nav-prog {
  display: flex; align-items: center; gap: .5rem;
  flex: 0 0 auto;
}
.nav-chip { display: flex; align-items: center; gap: .4rem; flex: 0 0 auto; }
/* A page with no chip registers no driver, so the slot stays empty. Decode and
   Timing are measurements taken over 768 runs, not something you can start. */
.nav-chip:empty { display: none; }

.nav-transport { display: inline-flex; gap: 3px; }
/* Square, and sized as one row with the two selects beside them. `width` and
   `height` rather than `min-*`, or the glyph decides the shape and the three
   buttons come out three different widths. 2.25rem is 36px, comfortably over
   the 30px `_navfit-test.html` insists on for a tap target. */
.nav-tbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem; padding: 0; flex: 0 0 auto;
  border: 2px solid color-mix(in srgb, var(--line) 80%, transparent);
  border-radius: .375rem; background: color-mix(in srgb, var(--surface) 82%, transparent);
  color: var(--foreground); cursor: pointer;
  font-family: var(--font-mono); font-size: .72rem; line-height: 1;
  transition: .15s;
}
.nav-tbtn:hover { border-color: var(--gold); color: var(--gold); }
.nav-tbtn:active { transform: translate(1px, 1px); }
.nav-tbtn.is-run { border-color: color-mix(in srgb, var(--accent) 70%, transparent); }
.nav-tbtn.is-run.on {
  border-color: var(--accent); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.nav-tbtn.is-run.on:hover { border-color: var(--gold); color: var(--gold); }

.nav-clock-select {
  min-width: 0; width: 4.9rem; height: 2.25rem; padding: .25rem .3rem;
  border: 2px solid color-mix(in srgb, var(--line) 80%, transparent);
  border-radius: .375rem;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  color: var(--foreground);
  font-family: var(--font-mono); font-size: .72rem; font-weight: 600;
  cursor: pointer; transition: border-color .08s linear, color .08s linear;
}
.nav-clock-select:hover { border-color: var(--gold); color: var(--gold); }

/* The clock control blinks on the chip's own phase.
   `.tick` is set while the half-cycle count is even, so the control goes on and
   off once per *cycle* -- which is what a cycle is: two half-cycles. It is
   driven by reading `halfCycle()` back off the machine, not by a timer, so it
   cannot keep blinking after the chip has stopped and it cannot claim a rate
   the chip is not delivering. At the top of the range it stops reading as a
   blink and becomes a steady glow, which is the honest picture of a chip
   running faster than the display can show. */
.nav-clock-select.tick {
  border-color: var(--accent);
  color: var(--accent);
}
@media (prefers-reduced-motion: reduce) {
  .nav-clock-select.tick { border-color: color-mix(in srgb, var(--line) 80%, transparent); }
}
.nav-prog-label {
  display: none;
  font-family: var(--font-mono); font-size: .65rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
}
.nav-prog-select {
  min-width: 0; max-width: 10.5rem; height: 2.25rem; padding: .25rem .5rem;
  border: 2px solid color-mix(in srgb, var(--line) 80%, transparent);
  border-radius: .375rem;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  color: var(--foreground);
  font-family: var(--font-mono); font-size: .78rem; font-weight: 600;
  cursor: pointer; transition: .15s;
}
.nav-prog-select:hover { border-color: var(--gold); color: var(--gold); }

.menu-btn {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 2.75rem; padding: .4rem .8rem;
  border: 2px solid color-mix(in srgb, var(--line) 80%, transparent);
  border-radius: .375rem; background: transparent; color: var(--muted); cursor: pointer;
  font-family: var(--font-mono); font-size: .7rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; transition: .15s;
}
.menu-btn:hover { border-color: var(--gold); color: var(--gold); }

/* The source link sits immediately left of the menu button and is built to the
   same measurements, so the two read as one pair of affordances rather than a
   button and a stray icon. Square, because it has no label to make it wider. */
.gh-link {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.75rem; height: 2.75rem; flex: none;
  border: 2px solid color-mix(in srgb, var(--line) 80%, transparent);
  border-radius: .375rem; background: transparent; color: var(--muted);
  transition: .15s;
}
.gh-link:hover { border-color: var(--gold); color: var(--gold); }
.gh-link svg { width: 1.15rem; height: 1.15rem; display: block; }
/* The second source link carries its name, so it is not a square. Hidden below
   34rem, where row one is down to the wordmark and two buttons; the menu's
   Developers group carries it at every width. */
.gh-lib { width: auto; padding: 0 .6rem; gap: .4rem; }
.gh-lib span { font-family: var(--font-mono); font-size: .72rem; letter-spacing: .04em; }
@media (max-width: 34rem) { .gh-lib { display: none; } }
.menu-btn .mi { display: grid; gap: 3px; width: .95rem; }
.menu-btn .mi i { display: block; height: 2px; background: currentColor; border-radius: 2px; transition: .15s; }
.menu-btn[aria-expanded="true"] {
  border-color: var(--accent); color: var(--foreground);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.menu-btn[aria-expanded="true"] .mi i:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.menu-btn[aria-expanded="true"] .mi i:nth-child(2) { opacity: 0; }
.menu-btn[aria-expanded="true"] .mi i:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* The menu is one organized panel at every width, rather than a flat row of
   fourteen links that only appeared on a wide screen. Fourteen nouns is not a
   menu -- "Blueprint", "Schematic" and "Exploded" are three drawings of the
   same silicon and the list gave a reader no way to choose between them. It is
   grouped, each entry carries a line of what it is, and the groups go
   side by side when there is room for them. */
.site-head.open .navlinks {
  display: grid; position: absolute; top: 100%; left: 0; right: 0; z-index: 40;
  /* 12.5rem so all five groups land on one row inside a 78rem wrap. At 15rem
     the fifth wrapped, which reads as a sixth group that lost its heading. */
  grid-template-columns: repeat(auto-fit, minmax(12.5rem, 1fr));
  gap: .25rem 1.5rem; align-items: start;
  padding: 1rem 1.25rem 1.25rem;
  /* site-nav.js measures the real room below the header and sets max-height;
     this is the floor for the moment before it runs. */
  max-height: 100vh; overflow-y: auto; overscroll-behavior: contain;
  background: color-mix(in srgb, var(--space) 96%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  box-shadow: 0 14px 24px rgba(2, 6, 16, .5);
}
.navgroup { min-width: 0; padding-bottom: .5rem; }
.navgroup-title {
  margin: .35rem 0 .3rem;
  font-family: var(--font-mono); font-size: .62rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
  padding-bottom: .3rem;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 45%, transparent);
}
.navlinks a {
  display: block; padding: .5rem .3rem; border-radius: .25rem;
  color: var(--foreground); text-decoration: none;
}
.navlinks a:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.navlinks a:hover .navlink-label { color: var(--gold); }
.navlink-label { display: block; font-weight: 700; font-size: .95rem; }

/* A recently changed page. The date is measured (the last commit touching that
   page's own files, stamped at deploy), so the dot is derived rather than kept
   by hand and cannot go stale. Inline after the label so it rides with the
   text at every width, and a fixed colour rather than the label's, so hover
   and current-page recolouring do not swallow it. */
.navlink-dot {
  display: inline-block; width: .42rem; height: .42rem; margin-left: .4rem;
  border-radius: 50%; background: var(--mint); vertical-align: .18em;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--mint) 25%, transparent);
}
/* Text for a screen reader that the dot carries visually. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* The line that a list of nouns cannot carry: what this one is, and therefore
   which of the four drawings of the same chip you actually want. */
.navlink-hint {
  display: block; margin-top: .1rem;
  color: var(--muted); font-size: .76rem; line-height: 1.35;
}
.navlinks a[aria-current="page"] .navlink-label { color: var(--accent); }
.navlinks a[aria-current="page"] { background: color-mix(in srgb, var(--accent) 9%, transparent); }

/* The menu button is present at every width now, because there is exactly one
   menu and it is the organized one. The inline row it replaced could not carry
   a heading or a description -- and it was what forced the links to be hidden
   below 80rem, so a phone and a desktop were navigating different sites. What
   the header gains from dropping fourteen inline links is room, which is why
   the picker can afford to be legible here. */
@media (min-width: 80rem) {
  .nav-prog-label { display: inline; }
  .nav-prog-select { max-width: 12rem; width: 12rem; }
}

/* Room to breathe once there is room. */
@media (min-width: 96rem) {
  .nav-prog-select { max-width: 14rem; width: 14rem; }
}

/* ---------- hero ---------- */

.hero { padding: clamp(2rem, 6vw, 4rem) 1.25rem clamp(1.5rem, 4vw, 2.5rem); }
.hero .eyebrow { margin-bottom: 1.1rem; }
/* A hero heading is set in Inter 900 at clamp() sizes, so at 320px a word of
   about eleven characters is already wider than the column. Every h1 on the
   site happened to be built from short words, which is not a property anyone
   was maintaining on purpose: the first heading written with "photographed" in
   it pushed the whole page sideways by 4px, and a header that overflows scrolls
   the document rather than clipping. `break-word` only acts when a word cannot
   fit on a line of its own, so it changes nothing anywhere else. */
.hero h1 { margin-bottom: 1.25rem; overflow-wrap: break-word; }
.hero h1 .hl { color: var(--accent); }
.cta-row { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.75rem; }
.statbar {
  display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.75rem;
  font-family: var(--font-mono); font-size: .75rem; color: var(--muted);
}

/* ---------- the console ---------- */

.console {
  border: 2px solid var(--line); border-radius: .6rem;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  box-shadow: var(--hard-card);
  overflow: hidden;
  display: flex; flex-direction: column;
}

.console-bar {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .6rem .75rem;
  border-bottom: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  background: color-mix(in srgb, var(--subtle) 70%, transparent);
}
.bar-spacer { flex: 1; }

.console-body { display: flex; flex-direction: column; min-height: 0; }

#stage {
  position: relative; min-width: 0; min-height: 0;
  background: #050912;
  height: clamp(18rem, 52vh, 34rem);
}
#die {
  width: 100%; height: 100%; display: block;
  cursor: grab;
  /* Without this a drag on the canvas scrolls the page instead of panning. */
  touch-action: none;
}
#die.dragging { cursor: grabbing; }

#stage-hint, #fps {
  position: absolute; color: var(--muted); font-size: .7rem;
  pointer-events: none; user-select: none; opacity: .8;
}
#stage-hint { left: .75rem; bottom: .6rem; max-width: 70%; }
#fps { right: .75rem; bottom: .6rem; font-family: var(--font-mono); }

#hover-card {
  position: absolute; pointer-events: none; z-index: 5;
  background: color-mix(in srgb, var(--space) 94%, transparent);
  border: 2px solid var(--line); border-radius: .4rem;
  padding: .5rem .7rem; max-width: 16rem;
  font-family: var(--font-mono); font-size: .72rem; line-height: 1.5;
  box-shadow: var(--hard);
}
#hover-card .hc-name { color: var(--accent); }
#hover-card .hc-meta { color: var(--muted); }
#hover-card .hc-high { color: var(--hot); }
#hover-card .hc-low { color: var(--muted); }

/* ---------- panels ---------- */

#panels {
  min-height: 0;
  border-top: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  background: color-mix(in srgb, var(--space) 55%, transparent);
}

.tabs {
  display: flex; overflow-x: auto; scrollbar-width: none;
  border-bottom: 2px solid color-mix(in srgb, var(--line) 45%, transparent);
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  flex: 1 0 auto; min-height: 2.9rem; padding: .6rem 1rem;
  border: 0; border-bottom: 3px solid transparent; background: transparent;
  color: var(--muted); cursor: pointer;
  font-family: var(--font-mono); font-size: .72rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; transition: .15s;
}
.tab:hover { color: var(--foreground); }
.tab[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }

.panel { padding: 1rem; }
.panel + .panel { border-top: 1px solid color-mix(in srgb, var(--line) 30%, transparent); }
.panel h2 {
  margin: 0 0 .85rem; font-size: .7rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold); font-family: var(--font-mono);
}

/* Below the sidebar breakpoint only the selected tab's panel is shown. */
@media (max-width: 67.999rem) {
  .panel { display: none; }
  #panels[data-active="registers"] .panel[data-tab="registers"],
  #panels[data-active="bus"] .panel[data-tab="bus"],
  #panels[data-active="selection"] .panel[data-tab="selection"],
  #panels[data-active="lab"] .panel[data-tab="lab"],
  #panels[data-active="layers"] .panel[data-tab="layers"],
  #panels[data-active="key"] .panel[data-tab="key"],
  #panels[data-active="memory"] .panel[data-tab="memory"] { display: block; }
}

@media (min-width: 68rem) {
  .console-body { flex-direction: row; }
  #stage { flex: 1; height: min(64vh, 40rem); }
  #panels {
    flex: none; width: var(--panel-w);
    border-top: 0;
    border-left: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
    overflow-y: auto; overscroll-behavior: contain;
  }
  .tabs { display: none; }
}

.reg-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: .4rem; }
.reg {
  background: color-mix(in srgb, var(--subtle) 80%, transparent);
  border: 2px solid color-mix(in srgb, var(--line) 45%, transparent);
  border-radius: .35rem; padding: .4rem .5rem;
}
.reg.wide { grid-column: span 4; }
.reg label {
  display: block; font-family: var(--font-mono); font-size: .6rem;
  letter-spacing: .12em; color: var(--muted); text-transform: uppercase;
}
.reg span {
  font-family: var(--font-mono); font-size: 1rem; color: var(--hot);
  font-variant-numeric: tabular-nums;
}
.reg.wide span { font-size: 1.25rem; }

.flags { display: flex; gap: .25rem; margin-top: .6rem; }
.flag {
  flex: 1; text-align: center; padding: .3rem 0; border-radius: .25rem;
  font-family: var(--font-mono); font-size: .78rem;
  background: color-mix(in srgb, var(--subtle) 70%, transparent);
  border: 2px solid color-mix(in srgb, var(--line) 40%, transparent);
  color: var(--muted);
}
.flag.on {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  border-color: var(--accent); color: var(--foreground);
}

.disasm {
  margin-top: .7rem; padding: .5rem .6rem; border-radius: .35rem;
  background: color-mix(in srgb, var(--subtle) 80%, transparent);
  border: 2px solid color-mix(in srgb, var(--line) 45%, transparent);
}
.disasm-label {
  display: block; font-family: var(--font-mono); font-size: .6rem;
  letter-spacing: .12em; color: var(--muted); text-transform: uppercase;
}
#disasm { font-family: var(--font-mono); font-size: .9rem; color: var(--accent); }
#disasm.undoc { color: var(--warn); }

.kv { display: flex; justify-content: space-between; padding: .2rem 0; font-size: .85rem; }
.kv label { color: var(--muted); }
.kv span { font-family: var(--font-mono); color: var(--foreground); font-variant-numeric: tabular-nums; }

.pins { display: flex; gap: .3rem; margin: .7rem 0 .6rem; }
.pin {
  flex: 1; text-align: center; padding: .25rem 0; border-radius: .25rem;
  font-family: var(--font-mono); font-size: .65rem; letter-spacing: .06em;
  background: color-mix(in srgb, var(--subtle) 70%, transparent);
  border: 2px solid color-mix(in srgb, var(--line) 40%, transparent); color: var(--muted);
}
.pin.on { background: color-mix(in srgb, var(--accent) 20%, transparent); border-color: var(--accent); color: var(--accent); }

.tstates {
  font-family: var(--font-mono); font-size: .72rem; color: var(--muted);
  background: color-mix(in srgb, var(--subtle) 80%, transparent);
  border: 2px solid color-mix(in srgb, var(--line) 40%, transparent);
  border-radius: .35rem; padding: .45rem .55rem; letter-spacing: .05em;
  white-space: pre; overflow-x: auto;
}
.tstates b { color: var(--accent); font-weight: 700; }

#selection { color: var(--muted); line-height: 1.55; margin-bottom: .7rem; font-size: .85rem; }
#selection .sel-name { font-family: var(--font-mono); color: var(--accent); font-size: .95rem; }
#selection .sel-meta { color: var(--muted); }
#selection .sel-sub { margin-top: .25rem; }
#selection .sel-error { color: var(--warn); }
#selection .sel-list {
  font-family: var(--font-mono); font-size: .7rem; color: var(--muted);
  max-height: 6rem; overflow-y: auto; margin-top: .35rem; line-height: 1.5;
}

.row { display: flex; gap: .4rem; align-items: center; }
input[type=text] {
  flex: 1; min-width: 0; min-height: 2.6rem;
  background: color-mix(in srgb, var(--space) 70%, transparent); color: var(--foreground);
  border: 2px solid color-mix(in srgb, var(--line) 60%, transparent); border-radius: .35rem;
  padding: .4rem .6rem; font-family: var(--font-mono); font-size: 16px; /* 16px: iOS zooms below this */
}
input[type=text]:focus { outline: none; border-color: var(--accent); }

.check, .check.inline { display: flex; align-items: center; gap: .5rem; color: var(--muted); font-size: .85rem; }
.check { margin-top: .7rem; }
.check.inline { margin-top: 0; white-space: nowrap; }
.check input, .layer-row input { accent-color: var(--accent); width: 1.1rem; height: 1.1rem; }

.layer-row { display: flex; align-items: center; gap: .55rem; padding: .3rem 0; }
.layer-swatch { width: .8rem; height: .8rem; border-radius: .2rem; flex: none; }
.layer-row label { color: var(--muted); cursor: pointer; font-size: .85rem; }

/* ---------- lab panel ---------- */

.lab-pick { display: flex; gap: .45rem; align-items: center; min-width: 0; }
.lab-pick select { flex: 1 1 0; min-width: 0; }
/* The option text carries a long blurb; the closed select must not stretch the
   panel to fit it. */
.lab-pick select { max-width: 100%; text-overflow: ellipsis; }

.lab-intro { color: var(--muted); font-size: .84rem; line-height: 1.55; margin-bottom: .7rem; }
.lab-warn { color: color-mix(in srgb, var(--warn) 80%, var(--muted)); font-size: .78rem; }

.lab-asm {
  margin: .7rem 0; padding: .5rem .6rem; border-radius: .35rem;
  background: color-mix(in srgb, var(--space) 70%, transparent);
  border: 2px solid color-mix(in srgb, var(--line) 45%, transparent);
  font-family: var(--font-mono); font-size: .76rem; line-height: 1.6;
  color: var(--muted); overflow-x: auto;
}
.lab-asm:empty { display: none; }
.lab-asm .on { color: var(--accent); font-weight: 700; }
.lab-asm .on::before { content: "▸ "; }
.lab-asm div:not(.on)::before { content: "  "; white-space: pre; }

.lab-step { display: flex; justify-content: space-between; gap: .5rem; flex-wrap: wrap; }
.lab-count, .lab-when {
  font-family: var(--font-mono); font-size: .62rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
}
.lab-count { color: var(--gold); }
.lab-title { margin: .3rem 0 .35rem; font-size: 1rem; color: var(--foreground); }
.lab-text { color: var(--muted); font-size: .84rem; line-height: 1.6; }
.lab-region {
  margin-top: .6rem; font-family: var(--font-mono); font-size: .68rem;
  color: var(--muted);
}
.lab-region b { color: var(--accent); }
.lab-region em { color: var(--warn); font-style: normal; }

.lab-live {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .3rem; margin-top: .7rem;
}
.lab-kv {
  background: color-mix(in srgb, var(--subtle) 80%, transparent);
  border: 2px solid color-mix(in srgb, var(--line) 45%, transparent);
  border-radius: .3rem; padding: .3rem .4rem; min-width: 0;
}
.lab-kv label {
  display: block; font-family: var(--font-mono); font-size: .56rem;
  letter-spacing: .12em; color: var(--muted); text-transform: uppercase;
}
.lab-kv span {
  font-family: var(--font-mono); font-size: .82rem; color: var(--hot);
  font-variant-numeric: tabular-nums;
}

.lab-ctrl-label {
  margin-top: .8rem; font-family: var(--font-mono); font-size: .6rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--gold);
}
.lab-ctrl { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .35rem; }
.lab-line {
  font-family: var(--font-mono); font-size: .62rem; letter-spacing: .04em;
  padding: .18rem .34rem; border-radius: .22rem;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  color: var(--foreground);
}
.lab-none { font-family: var(--font-mono); font-size: .68rem; color: var(--muted); }

.lab-nav { display: flex; gap: .4rem; margin-top: .9rem; }
.lab-nav .btn { flex: 1 1 0; min-width: 0; }
.lab-nav .btn:disabled { opacity: .4; cursor: default; }

/* ---------- key panel ---------- */

.key-row { display: flex; gap: .6rem; align-items: flex-start; padding: .45rem 0; }
.key-row + .key-row { border-top: 1px solid color-mix(in srgb, var(--line) 25%, transparent); }
.key-row b { color: var(--foreground); font-size: .85rem; }
.key-row p { color: var(--muted); font-size: .8rem; line-height: 1.5; margin-top: .15rem; }
.key-row .layer-swatch, .key-dot { margin-top: .3rem; }
.key-dot { width: .8rem; height: .8rem; border-radius: .2rem; flex: none; }
.key-dot.hot { background: var(--hot); box-shadow: 0 0 8px var(--hot); }
.key-dot.mark { background: #fff; }
.key-dot.dim { background: color-mix(in srgb, var(--line) 70%, transparent); }
.key-state { margin-bottom: .3rem; }
.key-note { color: var(--muted); font-size: .8rem; line-height: 1.55; }
.panel[data-tab="key"] h2 + h2 { margin-top: 1rem; }
.panel[data-tab="key"] h2:not(:first-child) { margin-top: 1.1rem; }

.slider { display: block; margin-top: .8rem; }
.slider span { display: block; color: var(--muted); font-size: .7rem; margin-bottom: .3rem; font-family: var(--font-mono); }
.slider input { width: 100%; accent-color: var(--accent); }

#memory {
  margin: .6rem 0 0; font-family: var(--font-mono); font-size: .7rem; line-height: 1.6;
  color: var(--muted); white-space: pre; overflow-x: auto;
}
#memory .addr { color: color-mix(in srgb, var(--muted) 60%, transparent); }
#memory .cur { background: color-mix(in srgb, var(--accent) 30%, transparent); color: var(--foreground); border-radius: 2px; }

.field { display: flex; align-items: center; gap: .45rem; min-width: 0; color: var(--muted); font-family: var(--font-mono); font-size: .68rem; text-transform: uppercase; letter-spacing: .1em; }
select {
  background: color-mix(in srgb, var(--space) 70%, transparent); color: var(--foreground);
  border: 2px solid color-mix(in srgb, var(--line) 60%, transparent); border-radius: .35rem;
  padding: .35rem .5rem; font-family: var(--font-sans); font-size: .82rem; text-transform: none; letter-spacing: 0;
  min-height: 2.4rem;
}
select:focus { outline: none; border-color: var(--accent); }

/* ---------- transport ---------- */

.console-foot {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .6rem .75rem calc(.6rem + var(--sa-b));
  border-top: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  background: color-mix(in srgb, var(--subtle) 70%, transparent);
}
.transport { display: flex; gap: .3rem; }
.timeline { flex: 1 1 14rem; display: flex; align-items: center; gap: .6rem; min-width: 0; }
.timeline input { flex: 1; min-width: 0; accent-color: var(--accent); }
#scrub-label {
  font-family: var(--font-mono); font-size: .68rem; color: var(--muted);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.console-foot .field.speed { margin-left: auto; }

/* ---------- fullscreen ---------- */

/* Keyed on a class, not on `:fullscreen`.

   Two reasons. iOS Safari has no element fullscreen at all, so the console has
   to be able to fill the viewport without the API -- app.js adds `.immersive`
   either way. And an unknown pseudo-class invalidates the *whole* selector
   list, so `.console:fullscreen, .console.immersive { ... }` would silently
   drop everything on any browser that does not know `:fullscreen`. */
.console.immersive {
  border-radius: 0; border: 0; box-shadow: none;
  height: 100vh; height: 100dvh;   /* dvh: excludes mobile browser chrome */
}
.console.immersive .console-body { flex: 1; min-height: 0; }
.console.immersive #stage { height: auto; flex: 1; }

/* On a phone, fullscreen means the die -- so the panels stop taking a share of
   the height and become a drawer over it, collapsed to its handle by default.
   The stage is absolutely positioned and therefore never resizes when a panel
   opens, closes, or changes tab: the die cannot jump, which is what the earlier
   measure-the-tallest-panel approach was working around. */
@media (max-width: 67.999rem) {
  .console.immersive .console-body { position: relative; }
  .console.immersive #stage { position: absolute; inset: 0; }
  .console.immersive #panels {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
    height: auto; max-height: 68%;
    border-top: 2px solid color-mix(in srgb, var(--line) 70%, transparent);
    background: color-mix(in srgb, var(--space) 94%, transparent);
    backdrop-filter: blur(10px);
    overflow-y: auto; overscroll-behavior: contain;
  }
  .console.immersive .drawer-grip { display: flex; }
  /* Collapsed by hiding the content rather than translating by a measured
     offset: the drawer then shrinks to exactly its handle and tab strip, with
     no magic number to drift out of step with either. */
  .console.immersive[data-drawer="closed"] #panels .panel { display: none; }
  .console.immersive[data-drawer="closed"] #panels { max-height: none; }
}

.drawer-grip {
  display: none; width: 100%; align-items: center; gap: .55rem;
  padding: .5rem .75rem; border: 0; cursor: pointer;
  background: color-mix(in srgb, var(--subtle) 70%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 35%, transparent);
  color: var(--muted); font-family: var(--font-mono); font-size: .68rem;
  font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
}
.drawer-grip .grip-bar {
  width: 2.25rem; height: 4px; border-radius: 2px; flex: none;
  background: color-mix(in srgb, var(--line) 90%, transparent);
}
.drawer-grip .grip-chev { margin-left: auto; color: var(--accent); font-size: .7rem; }
.console[data-drawer="open"] .drawer-grip .grip-chev { transform: rotate(180deg); }
.drawer-grip:hover { color: var(--foreground); }

/* The fallback when the Fullscreen API is missing or refuses: cover the
   viewport ourselves. Not as good as real fullscreen -- the browser's own chrome
   stays -- but it is the difference between a button that works and one that
   does nothing on every iPhone. */
.console.faux {
  position: fixed; inset: 0; z-index: 60;
  padding-bottom: var(--sa-b);
  /* Opaque. The normal console is 92% and relies on the page behind it being a
     solid background; once it is fixed over a scrolling page, the hero text
     shows straight through it. */
  background: var(--surface);
}
body.no-scroll { overflow: hidden; overscroll-behavior: none; }

/* The console's own z-index is powerless here, and it took two rounds to see
   why. `.wrap` is `position: relative; z-index: 1`, so every section opens a
   stacking context and confines its descendants: the console's z-index only
   orders it *within* #explorer. Against everything outside, what competes is
   #explorer's own z-index of 1.

   That loses twice over. The header sits at the root with z-index 30, so it
   paints on top; and every later `.wrap` section is also z-index 1, so document
   order puts all of them on top too -- which looks exactly like the console
   being transparent, and is not. Lifting #explorer is the fix; the header is
   simply removed, which an immersive mode wants anyway. */
body.no-scroll .site-head { display: none; }
body.no-scroll #explorer { z-index: 70; }

/* ---------- content sections ---------- */

.sec { padding: var(--sec-gap) 1.25rem 0; }
.sec-head { margin-bottom: 1.5rem; }
.sec-head .eyebrow { margin-bottom: .8rem; }

.cards { display: grid; gap: 1rem; grid-template-columns: 1fr; }
@media (min-width: 44rem) { .cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 68rem) { .cards { grid-template-columns: repeat(3, 1fr); } }

.card {
  border: 2px solid color-mix(in srgb, var(--line) 70%, transparent);
  border-radius: .5rem; padding: 1.25rem;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  box-shadow: var(--hard);
}
.card h3 { margin-bottom: .6rem; color: var(--gold); }
.card p { color: var(--muted); font-size: .92rem; }

/* ---------- footer ---------- */

/* Pinned to the bottom of the viewport, not to the bottom of the document.
   It is a status bar: what this build is and when it shipped, readable without
   scrolling to the end of a long page. That costs a fixed strip of height on
   every screen, so it is a thin one -- and `--foot-h` is declared here rather
   than measured, with `body` reserving exactly that much so the last paragraph
   of a page is never hidden under it.

   Everything is left-aligned and reads in one order: what it is, then which
   build. `margin-left: auto` on the version used to push it to the far edge,
   which on a wide screen put the two halves of one sentence a metre apart. */
:root { --foot-h: 2.6rem; }

.site-foot {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 25;
  border-top: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  background: color-mix(in srgb, var(--space) 92%, transparent);
  backdrop-filter: blur(12px);
  padding: .45rem 0 calc(.45rem + var(--sa-b));
}
.site-foot .wrap {
  display: flex; flex-wrap: nowrap; gap: .25rem .9rem; align-items: center;
  overflow: hidden;
}
.site-foot .mark { font-size: .82rem; flex: 0 0 auto; }
.foot-meta {
  color: var(--muted); font-family: var(--font-mono); font-size: .72rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Reserve the strip, plus the gap the footer used to get from its own margin.
   Without this the last line of every page sits under the footer, which reads
   as a page that was cut off rather than as a page that ended. */
body { padding-bottom: calc(var(--foot-h) + var(--sa-b) + clamp(2rem, 6vw, 4rem)); }

/* Immersive mode covers the viewport; the header already goes, and a footer
   floating over a fullscreen die would be worse than either. */
body.no-scroll .site-foot { display: none; }

.version-foot {
  display: flex; align-items: center; gap: .5rem;
  font-family: var(--font-mono); font-size: .7rem;
  white-space: nowrap;
}
.version-foot:empty { display: none; }   /* before the fetch resolves, or if it fails */
.vf-rev { display: inline-flex; align-items: center; gap: .35rem; text-decoration: none; }
.vf-pill {
  border: 1px solid var(--line); background: var(--subtle); color: var(--accent);
  padding: .1rem .4rem; letter-spacing: .04em;
}
.vf-hash { color: var(--muted); }
.vf-rev:hover .vf-pill { border-color: var(--accent); }
.vf-rev:hover .vf-hash { color: var(--foreground); }
.vf-built { color: var(--muted); }
.vf-built::before { content: "·"; margin-right: .5rem; opacity: .6; }
/* What changed since the previous deploy: the same list the menu dots, as
   text. The dot answers "which page"; this answers "how many, and where is the
   diff". A literal middot, not an escape -- see the note on the footer. */
.vf-changed { color: var(--muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.vf-changed::before { content: "·"; margin-right: .5rem; opacity: .6; }
.vf-changed a { color: var(--mint); text-decoration: none; }
.vf-changed a:hover { color: var(--foreground); text-decoration: underline; }

/* The "changed since the previous deploy" section on the index, filled at
   runtime by version-footer.js from the same stamp the footer reads. Hidden
   until filled and hidden again when there is nothing to compare against. The
   [hidden] rule is stated with !important on purpose: the UA's own is only
   specificity (0,1,0), and this file already lost that fight once on #boot and
   #app, where a rule declaring display silently un-hid them. */
.changed-since {
  margin-top: 1.25rem; padding: 1rem 1.15rem;
  border: 2px solid var(--line); border-radius: .45rem;
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  box-shadow: var(--hard);
}
.changed-since[hidden] { display: none !important; }
.changed-since .eyebrow { margin-top: 0; }
.changed-list { margin: .55rem 0 .7rem; padding-left: 1.2rem; line-height: 1.7; }
.changed-list a { color: var(--mint); text-decoration: none; font-weight: 600; }
.changed-list a:hover { text-decoration: underline; }
.changed-none, .changed-diff { margin: .4rem 0 0; color: var(--muted); font-size: .9rem; }
.changed-diff a { color: var(--accent); }
.changed-many summary { cursor: pointer; color: var(--foreground); font-weight: 600; margin: .4rem 0; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; }
}

/* Narrow console bar: keep the tag and the fullscreen button on one row and let
   the program picker take a row of its own, rather than pushing the button off
   the end. `order` does this without a second markup path. */
@media (max-width: 43.999rem) {
  .console-bar .bar-spacer { display: none; }
  .console-bar .field.prog { order: 3; flex: 1 1 100%; min-width: 0; }
  .console-bar .field.prog select { flex: 1 1 0; min-width: 0; max-width: 100%; }
  .console-bar #btn-fit { margin-left: auto; }
}

/* At the narrowest common phone width the header's three items -- wordmark,
   call to action, menu -- want ~330px and have ~285px, and the overflow escapes
   the header (unlike the console, which clips). Drop the CTA: it duplicates the
   Explorer link that the menu already contains. Likewise the six transport
   buttons want 302px, so tighten them rather than let the console clip the last
   one off. Both only bite below 384px. */
/* The Lab's calls to action carry a whole phrase, and `.btn` is nowrap so short
   buttons never break mid-label. On a narrow screen one of those phrases is
   wider than the viewport, so here they stack and wrap instead. */
@media (max-width: 30rem) {
  #lab .cta-row { flex-direction: column; align-items: stretch; }
  #lab .cta-row .btn { white-space: normal; }
}

/* The wordmark, the picker and the menu button together want more than a phone
   viewport has. The picker shrinks rather than disappearing: it is the only way
   to change what is running, and the CTA it replaced could afford to go because
   the hero carries a second copy of it. What goes instead is the word "Menu" --
   the hamburger already says it, and the label costs 45px the picker needs.

   This is 34rem, not 24rem, and the difference was a real bug: 24rem is 384px,
   so a 390px phone -- the most common width there is -- fell through every one
   of these rules and overflowed its header by 29px. Write the breakpoint for
   the devices, not for the round number. */
/* The control group takes a row of its own before it has to fight the wordmark
   for space. Three controls beside a brand and a menu button want about 90px
   more than a 320px viewport has, and a header that overflows scrolls the whole
   page sideways rather than clipping -- so the failure is the page, not the
   header. Given its own row the group has the full width to divide up. */
@media (max-width: 52rem) {
  /* Two rows, not three. Source order puts the menu button after the controls,
     so without reordering it wraps to a row of its own and the header eats
     144px of a phone screen to show three things. `order` costs nothing and
     leaves the tab sequence alone. */
  /* The source link is reordered WITH the menu button, not left behind on the
     wordmark's side: they are one pair, and a default `order: 0` would strand
     it beside the brand while the button moved right. The auto margin moves to
     whichever of the two comes first, or a gap opens between them. */
  .gh-link { order: 1; margin-left: auto; }
  .menu-btn { order: 1; margin-left: 0; }
  .nav-ctl { order: 2; flex: 1 0 100%; margin-left: 0; gap: .4rem; }
  .nav-prog { flex: 1 1 auto; min-width: 0; }
  /* Filling the row is not the same as being usable. Given the whole width the
     picker grew to 645px on a page with no transport beside it, which is a
     control four times wider than the longest program name. */
  .nav-prog-select { width: 100%; max-width: 18rem; }
  .nav-chip { margin-left: auto; }
}

@media (max-width: 34rem) {
  .nav-prog-select { min-width: 6rem; height: 2rem; font-size: .72rem; padding: .25rem .35rem; }
  .nav-tbtn { width: 2rem; height: 2rem; font-size: .66rem; }
  .nav-clock-select { width: 4.2rem; height: 2rem; font-size: .66rem; }
  /* The label stays. It was dropped here when the controls still shared this
     row with the wordmark and a 90px call to action; since the control group
     took a row of its own at 52rem, row one holds the brand and these two
     buttons and nothing else, so there is room for the word at 320px. A
     hamburger with no label is the weakest affordance in the header, and it was
     only ever hidden to buy space that is no longer needed. */
  .menu-btn { padding: .4rem .55rem; }
  .site-head nav { column-gap: .5rem; }
}

@media (max-width: 24rem) {
  .transport { flex-wrap: wrap; }
  .transport .iconbtn { min-width: 2.5rem; padding: .5rem .35rem; }
}

/* ---------- the blueprint (blueprint.html) ---------- */

.bp-boot { padding: 2.5rem .9rem; text-align: center; color: var(--muted); font-family: var(--font-mono); font-size: .8rem; }
.bp-boot .error { color: var(--warn); }

/* The diagram is wider than a phone and must scroll inside its own box --
   never widen the page. Same rule as every other wide block on the site. */
.bp-stage { overflow-x: auto; overflow-y: hidden; padding: .9rem .6rem; }
#bp-svg { display: block; width: 100%; min-width: 46rem; height: auto; }

.bp-transport {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .6rem .75rem;
  border-top: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  background: color-mix(in srgb, var(--subtle) 55%, transparent);
}
.bp-readout { margin-left: auto; color: var(--muted); font-size: .72rem; white-space: nowrap; }

/* -- rails and blocks -- */
.rail-line { stroke: var(--line); stroke-width: 3; }
.rail-name { fill: var(--muted); font-family: var(--font-mono); font-size: 11px; letter-spacing: .06em; }
.rail-value { fill: var(--gold); font-family: var(--font-mono); font-size: 12px; }

.block-box { fill: color-mix(in srgb, var(--subtle) 85%, transparent); stroke: var(--line); stroke-width: 2; }
.block-name { fill: var(--foreground); font-family: var(--font-sans); font-weight: 700; font-size: 13px; }
.block-value { fill: var(--gold); font-family: var(--font-mono); font-size: 13px; }

/* -- edges: a switch, and whether it is conducting -- */
.edge-line { stroke: color-mix(in srgb, var(--line) 60%, transparent); stroke-width: 2; }
.edge-switch { fill: var(--space); stroke: var(--line); stroke-width: 2; }
.edge-label { fill: var(--muted); font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .04em; }
.edge-label.partial { fill: var(--hot); }

.bp-edge { cursor: pointer; }
.bp-edge:hover .edge-switch,
.bp-edge:focus-visible .edge-switch { stroke: var(--accent); }
.bp-edge:focus-visible { outline: none; }
.bp-edge:focus-visible .edge-label { fill: var(--foreground); }

/* Open: the control line is high, the eight switches conduct, and the two
   units either side of them are one wire this half-cycle. */
.bp-edge.open .edge-switch { fill: var(--accent); stroke: var(--accent); }
.bp-edge.open .edge-line { stroke: var(--accent); stroke-width: 3; }
.bp-edge.open .edge-label { fill: var(--foreground); }

.bp-edge.picked .edge-switch { stroke: var(--pink); stroke-width: 3; }
.bp-edge.picked .edge-label { fill: var(--pink); }

/* -- the detail panel -- */
.bp-detail {
  padding: .85rem 1rem 1.1rem;
  border-top: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  font-size: .85rem;
}
.bp-detail h3 { margin: 0 0 .3rem; font-family: var(--font-mono); font-size: .82rem; color: var(--accent); letter-spacing: .04em; }
.bp-detail-path { margin: 0 0 .6rem; color: var(--foreground); }
.bp-detail dl { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .25rem .9rem; margin: 0 0 .7rem; }
.bp-detail dt { color: var(--muted); font-family: var(--font-mono); font-size: .68rem; text-transform: uppercase; letter-spacing: .1em; }
.bp-detail dd { margin: 0; color: var(--foreground); overflow-wrap: anywhere; }
.bp-detail-note, .bp-detail-empty { margin: 0; color: var(--muted); font-size: .78rem; }

@media (max-width: 40rem) {
  .bp-readout { margin-left: 0; white-space: normal; }
}

/* Blueprint prose: `p` is margin-free site-wide, and these sections stack
   several plain paragraphs under each heading. Scoped so the explorer's
   sections, which use .lede throughout, are untouched. */
.bp-prose p { max-width: 68ch; }
.bp-prose p + p { margin-top: 1rem; }
.bp-prose .sec-head { margin-top: 2.75rem; }
.bp-prose .sec-head:first-child { margin-top: 0; }

/* ---------- the decode table (decode.html) ---------- */

.bar-note { color: var(--muted); font-family: var(--font-mono); font-size: .68rem; letter-spacing: .06em; }

.decode-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; padding: .9rem; }
@media (min-width: 66rem) {
  .decode-cols { grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); }
}

/* 16x16, and it must scroll inside its own box rather than widen the page. */
.grid-scroll { overflow-x: auto; }
.op-grid {
  display: grid; grid-template-columns: repeat(16, minmax(2.35rem, 1fr));
  gap: 2px; min-width: 34rem;
}
.op-cell {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: .3rem .1rem; border: 1px solid var(--line); border-radius: 3px;
  background: color-mix(in srgb, var(--subtle) 70%, transparent);
  color: var(--foreground); font-family: var(--font-mono); cursor: pointer;
  transition: background .12s, border-color .12s, opacity .12s;
}
.op-cell .op-hex { font-size: .66rem; color: var(--muted); }
.op-cell .op-mn { font-size: .68rem; letter-spacing: .02em; }
.op-cell.undoc { border-style: dashed; }
.op-cell.undoc .op-mn { color: var(--muted); }
.op-cell:hover { border-color: var(--accent); }
.op-cell.picked { border-color: var(--pink); border-width: 2px; }

/* When a term is selected, everything that does not fire it recedes. */
.op-grid.dimmed .op-cell { opacity: .3; }
.op-grid.dimmed .op-cell.lit { opacity: 1; background: color-mix(in srgb, var(--accent) 26%, var(--subtle)); border-color: var(--accent); }
.op-grid.dimmed .op-cell.lit.undoc { background: color-mix(in srgb, var(--hot) 26%, var(--subtle)); border-color: var(--hot); }
.op-grid.dimmed .op-cell.picked { opacity: 1; }

.grid-key { display: flex; flex-wrap: wrap; gap: .9rem; margin: .6rem 0 .2rem; font-family: var(--font-mono); font-size: .66rem; color: var(--muted); }
.grid-key .sw { display: inline-block; width: .7rem; height: .7rem; margin-right: .3rem; border: 1px solid var(--line); border-radius: 2px; vertical-align: -1px; }
.grid-key .sw.und { border-style: dashed; }
.grid-key .sw.lit { background: color-mix(in srgb, var(--accent) 26%, var(--subtle)); border-color: var(--accent); }

.term-head { display: flex; align-items: center; gap: .6rem; margin-bottom: .5rem; }
/* 16px: iOS zooms the viewport on focus below that. */
#term-filter {
  flex: 1; min-width: 0; padding: .45rem .6rem; font-size: 16px;
  border: 2px solid var(--line); border-radius: .3rem;
  background: var(--space); color: var(--foreground); font-family: var(--font-mono);
}
.term-list { max-height: 27rem; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.term {
  display: grid; grid-template-columns: 2.6rem minmax(0, 1fr) 2.2rem; gap: .5rem;
  align-items: center; text-align: left; padding: .3rem .5rem;
  border: 1px solid transparent; border-radius: 3px; cursor: pointer;
  background: color-mix(in srgb, var(--subtle) 45%, transparent);
  color: var(--foreground); font-family: var(--font-mono); font-size: .72rem;
}
.term:hover { border-color: var(--accent); }
.term.picked { border-color: var(--pink); background: color-mix(in srgb, var(--pink) 14%, transparent); }
.term-stage { color: var(--gold); }
.term-label { overflow-wrap: anywhere; }
.term-count { color: var(--muted); text-align: right; }

.panel-box {
  margin-top: .9rem; padding: .75rem .85rem;
  border: 1px solid color-mix(in srgb, var(--line) 60%, transparent); border-radius: .35rem;
  background: color-mix(in srgb, var(--space) 55%, transparent); font-size: .85rem;
}
.panel-box h3 { margin: 0 0 .45rem; font-family: var(--font-mono); font-size: .85rem; color: var(--accent); }
.panel-box h3 .mn { color: var(--foreground); }
.panel-box h3 .mode { color: var(--muted); font-size: .7rem; margin-left: .4rem; }
.panel-box dl { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .25rem .9rem; margin: 0; }
.panel-box dt { color: var(--muted); font-family: var(--font-mono); font-size: .66rem; text-transform: uppercase; letter-spacing: .08em; }
.panel-box dd { margin: 0; overflow-wrap: anywhere; }
.panel-box .muted { color: var(--muted); }
.undoc-list { color: var(--hot); font-family: var(--font-mono); }

.table-scroll { overflow-x: auto; }
.hc-table { border-collapse: collapse; width: 100%; font-size: .74rem; }
.hc-table th { text-align: left; color: var(--muted); font-family: var(--font-mono); font-size: .64rem; text-transform: uppercase; letter-spacing: .08em; padding: .25rem .4rem; border-bottom: 1px solid var(--line); }
.hc-table td { padding: .28rem .4rem; border-bottom: 1px solid color-mix(in srgb, var(--line) 35%, transparent); vertical-align: top; }
.hc-table .hc { color: var(--gold); font-family: var(--font-mono); white-space: nowrap; }
.hc-table .ctl { color: var(--mint); font-family: var(--font-mono); font-size: .68rem; }
.chip {
  display: inline-block; margin: 1px 2px 1px 0; padding: .1rem .35rem;
  border: 1px solid color-mix(in srgb, var(--line) 70%, transparent); border-radius: 3px;
  background: color-mix(in srgb, var(--subtle) 60%, transparent);
  color: var(--foreground); font-family: var(--font-mono); font-size: .68rem; cursor: pointer;
}
.chip:hover { border-color: var(--accent); }
.chip-stage { color: var(--gold); margin-right: .3rem; }

/* ---------- the timing table (timing.html) ---------- */

/* One step per cycle count. Not a rainbow: a single ramp, so "longer" reads as
   "further along" rather than as an unordered set of categories. */
.op-cell.cyc-2 { background: color-mix(in srgb, var(--accent) 10%, var(--subtle)); }
.op-cell.cyc-3 { background: color-mix(in srgb, var(--accent) 20%, var(--subtle)); }
.op-cell.cyc-4 { background: color-mix(in srgb, var(--accent) 30%, var(--subtle)); }
.op-cell.cyc-5 { background: color-mix(in srgb, var(--accent) 42%, var(--subtle)); }
.op-cell.cyc-6 { background: color-mix(in srgb, var(--accent) 54%, var(--subtle)); }
.op-cell.cyc-7 { background: color-mix(in srgb, var(--hot) 46%, var(--subtle)); }
.op-cell.cyc-8 { background: color-mix(in srgb, var(--pink) 46%, var(--subtle)); }
.op-cell.jam { background: color-mix(in srgb, var(--warn) 34%, var(--subtle)); border-style: dotted; }
.op-cell.jam .op-mn { color: var(--foreground); }

.bar-row { display: grid; grid-template-columns: 3.4rem minmax(0, 1fr) 2.2rem; gap: .5rem; align-items: center; width: 100%; }
.bar-label { color: var(--muted); font-size: .66rem; }
.bar { display: block; height: .55rem; background: color-mix(in srgb, var(--line) 30%, transparent); border-radius: 2px; }
.bar i { display: block; height: 100%; border-radius: 2px; }
.bar i.cyc-2 { background: color-mix(in srgb, var(--accent) 30%, var(--subtle)); }
.bar i.cyc-3 { background: color-mix(in srgb, var(--accent) 45%, var(--subtle)); }
.bar i.cyc-4 { background: color-mix(in srgb, var(--accent) 60%, var(--subtle)); }
.bar i.cyc-5 { background: color-mix(in srgb, var(--accent) 75%, var(--subtle)); }
.bar i.cyc-6 { background: var(--accent); }
.bar i.cyc-7 { background: var(--hot); }
.bar i.cyc-8 { background: var(--pink); }
.bar-n { color: var(--muted); font-size: .66rem; text-align: right; }
#histogram { display: flex; flex-direction: column; gap: .25rem; align-items: stretch; }

/* Which terms end an instruction (timing.html detail panel). */
.hc-table tr.final td { color: var(--foreground); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.ends { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .3rem .9rem; margin: .8rem 0 0; font-size: .8rem; }
.ends dt { color: var(--muted); font-family: var(--font-mono); font-size: .64rem; text-transform: uppercase; letter-spacing: .08em; }
.ends dd { margin: 0; }
a.chip { text-decoration: none; }
a.chip:hover { border-color: var(--accent); color: var(--accent); }

/* --- The exploded view --------------------------------------------------- */

.ex-stage { position: relative; display: grid; grid-template-rows: minmax(0, 1fr) auto; }
#ex-canvas {
  display: block;
  width: 100%;
  height: clamp(320px, 62vh, 720px);
  background: #0b0e17;
  touch-action: none;
  cursor: grab;
}
#ex-canvas:active { cursor: grabbing; }

.ex-controls {
  display: grid;
  gap: .55rem .9rem;
  padding: .8rem 1rem;
  border-top: 2px solid var(--line);
  background: var(--surface);
}
@media (min-width: 46rem) {
  .ex-controls { grid-template-columns: repeat(3, minmax(0, 1fr)) auto; align-items: center; }
}

.ex-slider { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: .5rem; align-items: center; }
.ex-s-name { font-size: .68rem; text-transform: uppercase; letter-spacing: .09em; color: var(--muted); }
.ex-s-val { font-size: .68rem; color: var(--accent); min-width: 4.4em; text-align: right; }
.ex-slider input[type=range] { width: 100%; min-width: 0; accent-color: var(--accent); }

.ex-layer-togs { display: flex; gap: .35rem; flex-wrap: wrap; }
.ex-layer-tog {
  font: inherit; font-size: .68rem; padding: .28rem .55rem; cursor: pointer;
  background: transparent; color: var(--muted);
  border: 2px solid var(--line); border-radius: 2px;
}
.ex-layer-tog.on { color: var(--foreground); border-color: var(--accent); }

.ex-legend-wrap { border-top: 2px solid var(--line); padding: .9rem 1rem 1.1rem; }
.ex-legend-head { margin: 0 0 .7rem; font-size: .8rem; }
.ex-legend-head .muted { display: block; font-size: .74rem; }
.ex-legend { display: grid; gap: .5rem; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); }

.ex-block {
  display: grid; gap: .15rem; text-align: left; cursor: pointer;
  padding: .5rem .6rem; font: inherit;
  background: var(--subtle); color: var(--foreground);
  border: 2px solid var(--line); border-radius: 2px;
}
.ex-block:hover { border-color: var(--accent); }
.ex-block.picked { border-color: var(--accent); box-shadow: 3px 3px 0 var(--accent); }
.ex-legend.focused .ex-block:not(.picked) { opacity: .5; }
.ex-block.ghost { border-style: dashed; }
.ex-b-name { font-weight: 700; font-size: .82rem; display: flex; align-items: center; gap: .42rem; }
.ex-sw { width: .72rem; height: .72rem; flex: none; border-radius: 2px;
  background: var(--block-color, var(--muted)); box-shadow: 0 0 0 1px rgba(0,0,0,.5) inset; }
.ex-b-meta { font-family: var(--font-mono); font-size: .64rem; color: var(--accent); }
.ex-b-blurb { font-size: .72rem; color: var(--muted); }
.ex-b-drives { font-size: .7rem; color: var(--foreground); margin-top: .3rem;
  border-top: 1px dashed var(--line); padding-top: .3rem; }
.ex-b-drives .muted { font-size: .66rem; }
.ex-block.logic { border-style: dashed; grid-column: span 2; }
@media (max-width: 40rem) { .ex-block.logic { grid-column: span 1; } }

.ex-zoom { display: flex; align-items: center; gap: .3rem; }
.ex-zoom .btn-icon { min-width: 2rem; padding: .3rem .45rem; font-weight: 700; line-height: 1; }
.ex-zoom-val { font-size: .7rem; color: var(--accent); min-width: 3.2em; text-align: center; }
#ex-canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* --- The schematic ------------------------------------------------------- */

/* Columns as wide as they need to be, rather than a count chosen per
   breakpoint. Three columns from 46rem was far too eager: a field here is a
   label *and* a pair of buttons, and at tablet widths the label ran straight
   through the control beside it while the last button was clipped by the
   console's own `overflow: hidden`. `auto-fit` with a real minimum cannot make
   that mistake at any width, and the label sits above its control at every size
   for the same reason -- beside it, the two compete for a track that is already
   too narrow. */
.sch-controls { display: grid; gap: .7rem .9rem; padding: .8rem 1rem;
  grid-template-columns: repeat(auto-fit, minmax(13.5rem, 1fr)); align-items: end;
  border-bottom: 2px solid var(--line); background: var(--surface); }
.sch-controls .field { display: grid; gap: .25rem; min-width: 0; }
.sch-controls .field > span { font-size: .66rem; text-transform: uppercase;
  letter-spacing: .08em; color: var(--muted); }
.sch-controls select, .sch-controls input[type=search] { width: 100%; min-width: 0; font-size: 16px; }
.sch-controls input[type=range] { width: 100%; accent-color: var(--accent); }

.sch-stage { overflow: auto; background: #080c15; padding: .5rem; max-height: 68vh; }
#sch-svg { display: block; min-width: 100%; }
.sch-caption { margin: 0; padding: .5rem 1rem; font-size: .7rem; color: var(--muted);
  border-top: 2px solid var(--line); }

.sch-wire { stroke: #43506b; stroke-width: 1.6; fill: none; }
.sch-body { fill: #17203a; stroke: var(--accent); stroke-width: 1.6; }
.sch-bubble { fill: #080c15; stroke: var(--accent); stroke-width: 1.6; }
.sch-kind { fill: #cfe3ff; font: 600 9px var(--font-mono); text-anchor: middle; }
.sch-dynamic .sch-body { stroke: #f0a500; }
.sch-dynamic .sch-bubble { stroke: #f0a500; }
.sch-sw-lead { stroke: #43506b; stroke-width: 1.6; }
.sch-sw-plate { stroke: #7f8db0; stroke-width: 2; }
.sch-sw-gate { stroke: #7f8db0; stroke-width: 1.4; stroke-dasharray: 2 2; }
.sch-switch.open .sch-sw-plate, .sch-switch.open .sch-sw-gate { stroke: var(--accent); }
.sch-ctrl { fill: #8fa3c8; font: 500 8.5px var(--font-mono); text-anchor: middle; }
.sch-ctrl:hover { fill: var(--accent); }

/* The outline carries the functional block, in the exploded view's colours.
   A custom property rather than an inline stroke, so the .root and :hover
   rules below still win -- an inline stroke would outrank both. */
.sch-pill { fill: #101829; stroke: var(--block, #2c3a55); stroke-width: 1.4; }
.sch-node { cursor: pointer; }
.sch-node:hover .sch-pill { stroke: var(--accent); }
.sch-node.root .sch-pill { stroke: var(--accent); stroke-width: 2.2; fill: #14243c; }
.sch-node.anon .sch-pill { stroke-dasharray: 3 2; }
.sch-node.hot .sch-pill { fill: #1d3b57; stroke: #6fd3ff; }
.sch-name { fill: #dce9ff; font: 500 10px var(--font-mono); text-anchor: middle; }
.sch-node.anon .sch-name { fill: #7e8db0; }

.sch-compare { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center;
  padding: .8rem 1rem; border-top: 2px solid var(--line); font-size: .8rem; }
.sch-cmp-label { color: var(--muted); }
.sch-compare select { font-size: 16px; }
.sch-differ { color: #ffd166; }
.sch-same { color: #6ee7a8; }
#sch-compare-out { margin: 0 1rem 1rem; }
#sch-compare-out code { font-size: .68rem; background: var(--subtle);
  border: 1px solid var(--line); border-radius: 2px; padding: .05rem .3rem; }
.sch-rail { stroke: #6b7a99; stroke-width: 2.4; }
.sch-rail-label { fill: #6b7a99; font: 500 8.5px var(--font-mono); text-anchor: middle; }

/* --- Schematic: key and signal panel -------------------------------------- */

.sch-keybox { border-top: 2px solid var(--line); padding: .7rem 1rem 1rem; }
.sch-keybox > summary { cursor: pointer; font-size: .72rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted); }
.sch-keybox > summary:hover { color: var(--accent); }
.sch-key { display: grid; gap: .5rem; margin-top: .7rem;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
.sch-key-item { display: grid; grid-template-columns: 74px minmax(0, 1fr); gap: .5rem;
  align-items: center; margin: 0; padding: .35rem .45rem;
  background: var(--subtle); border: 2px solid var(--line); border-radius: 2px; }
.sch-key-svg { width: 70px; height: 44px; background: #080c15; border-radius: 2px; }
.sch-key-item figcaption { display: grid; gap: .1rem; min-width: 0; }
.sch-key-item b { font-size: .76rem; }
.sch-key-item span { font-size: .68rem; color: var(--muted); }
.sch-key-note { margin: .8rem 0 0; font-size: .74rem; color: var(--muted); }

#sch-signal-info { margin: 0 1rem 1rem; }
.sch-sig-name { margin: 0 0 .5rem; font-family: var(--font-mono); font-size: .95rem;
  display: flex; flex-wrap: wrap; gap: .5rem; align-items: baseline; }
.sch-sig-id { font-size: .64rem; color: var(--muted); font-weight: 400; }
.tagm { font-family: var(--font-mono); font-size: .55rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--accent); border: 1px solid var(--line);
  border-radius: 2px; padding: 0 .25rem; margin-left: .35rem; vertical-align: middle; }

/* --- Schematic on a phone -------------------------------------------------- */

@media (max-width: 46rem) {
  /* Labels above their control, not beside it: the row form collapses into a
     scatter of stray words at this width. */
  .sch-controls { gap: .5rem; }
  #sch-shown { order: 2; }
  .sch-compare { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .4rem; align-items: center; }
  .sch-cmp-label, .sch-compare .btn { grid-column: 1 / -1; }
  .sch-compare .muted { display: none; }
  .sch-key { grid-template-columns: minmax(0, 1fr); }
  .sch-stage { max-height: 56vh; }
  /* The term/definition pair is two narrow columns at this width, which wraps
     every value into a ribbon. Stack them instead. */
  #sch-signal-info .ends { grid-template-columns: minmax(0, 1fr); gap: .15rem; }
  #sch-signal-info .ends dd { margin-bottom: .5rem; }
}

/* --- Schematic: compare, fullscreen ---------------------------------------- */

.cmp-head { margin: 0 0 .4rem; font-size: .9rem; }
.cmp-cols { display: grid; gap: .8rem; margin-top: .7rem; }
@media (min-width: 42rem) { .cmp-cols { grid-template-columns: 1fr 1fr; } }
.cmp-cols h4 { margin: 0 0 .3rem; font-size: .74rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: .07em; }
.cmp-list { margin: 0; padding-left: 1rem; display: grid; gap: .2rem; }
.cmp-list li { font-size: .74rem; }
.cmp-lvl { font-family: var(--font-mono); font-size: .62rem; color: var(--accent);
  border: 1px solid var(--line); border-radius: 2px; padding: 0 .22rem; margin-right: .3rem; }
.cmp-note { margin: .8rem 0 0; font-size: .72rem; color: var(--muted); }
.sch-cmp-sep { color: var(--muted); font-size: .74rem; }
.sch-el.cmp-differs .sch-sw-plate, .sch-el.cmp-differs .sch-sw-gate { stroke: #ffd166; }
.sch-el.cmp-differs .sch-sw-lead { stroke: #ffd166; }

/* The console filling the viewport. Keyed on classes, never on :fullscreen --
   an unknown pseudo-class invalidates the whole selector list. */
.console.immersive { display: flex; flex-direction: column; }
.console.immersive .sch-stage { flex: 1; max-height: none; }
.console.faux { position: fixed; inset: 0; z-index: 80; border-radius: 0;
  background: var(--surface); overflow: auto; }
body.no-scroll #view { z-index: 70; }


/* --- Console toolbars ------------------------------------------------------ */

/* The console bar is a toolbar, not a call to action: the page-level .btn size
   is built for the hero and looks oversized sitting next to a tag and a note. */
.console-bar .btn {
  min-height: 2.2rem; padding: .35rem .7rem;
  font-size: .8rem; font-weight: 700; border-radius: .3rem;
}
.console-bar .btn-icon { min-width: 2.2rem; padding: .35rem .5rem; line-height: 1; }
.console-bar select { font-size: .82rem; padding: .3rem .5rem; }

@media (max-width: 46rem) {
  .console-bar .btn { min-height: 2rem; padding: .3rem .55rem; font-size: .76rem; }
  .console-bar { gap: .3rem; }
}

/* The fallback fullscreen must be opaque. The console is normally 92% and
   relies on a solid page behind it; covering the viewport removes that page,
   and a translucent panel then shows whatever it is floating over. This was
   invisible until the background token was corrected -- the declaration named a
   token that does not exist, so there was no background at all. */
.console.faux { background: var(--surface); }

/* --- Schematic: the study view --------------------------------------------
   Fullscreen is not the page with its chrome hidden. It is one level behind the
   selected signal, centred on an empty screen, so the shape of a single island
   is the only thing there is to look at. */

/* The whole immersive surface claims the touch stream, not just the drawing.
   A gesture that starts on any part of it that is not the stage -- a border, the
   space beside the console -- would otherwise reach the browser, and on a tablet
   a downward swipe there is a page scroll or worse. `overscroll-behavior` stops
   the drawer's own scrolling from chaining out to the document when it hits its
   end, which is the other way a pull turns into something the page did not
   intend.

   What this cannot do is stop the *browser's* own fullscreen-exit gesture. That
   one belongs to the platform, which is why the console's configuration and the
   walk are saved: getting dropped out has to be cheap. */
.console.solo { background: #05070d; touch-action: none; overscroll-behavior: contain; }
.console.solo .sp-panel { touch-action: pan-y; overscroll-behavior: contain; }
.console.solo .sp-strip { overscroll-behavior: contain; }
.console.solo > .console-bar,
.console.solo .sch-controls,
.console.solo .sch-caption,
.console.solo #sch-signal-info,
.console.solo .sch-keybox,
.console.solo .sch-compare,
.console.solo #sch-compare-out { display: none; }

/* The stage is two levels down (.console > #sch-main > .sch-stage), so growing
   it needs the middle element to grow too. Without this the stage collapses to
   its content and the drawing sits at the top of an empty screen -- which looked
   centred on a desktop only because the drawing happened to fill the width. */
.console.solo #sch-main { flex: 1; display: flex; flex-direction: column; min-height: 0; }

.console.solo .sch-stage {
  flex: 1; min-height: 0;
  position: relative;
  display: flex; align-items: center; justify-content: center;
  height: 100%; max-height: none; padding: clamp(1rem, 4vw, 3rem);
  background: #05070d; overflow: hidden;
}
/* viewBox plus 100% sizing means the browser centres and scales it for us --
   preserveAspectRatio does the work, so nothing here measures anything. The
   camera then rides on a wrapper group inside, which leaves that arrangement
   intact and keeps getScreenCTM() a correct screen-to-drawing map.

   `touch-action: none` is scoped to this mode on purpose. On the page proper
   the drawing sits in a scrolling stage, and claiming the touch stream there
   would stop a phone scrolling the page at all. */
.console.solo #sch-svg {
  width: 100%; height: 100%;
  touch-action: none; cursor: grab;
}
.console.solo #sch-svg.dragging { cursor: grabbing; }
/* The camera listens on the stage, not the drawing: an <svg> only hit-tests
   where it has been painted, and a bench is mostly empty. So the stage has to
   claim the touch stream too, or a pinch that starts between two islands
   scrolls the page instead of zooming. */
.console.solo .sch-stage { touch-action: none; }

@media (max-width: 46rem) {
  .console.solo .sch-stage { padding: .75rem; }
}

/* --- Schematic: the walk ---------------------------------------------------
   The islands already visited stay on screen, dimmed, joined to the one that
   followed by a thread from the pill that was clicked. They are still live --
   the state overlay paints every island -- so they fade rather than grey out. */

/* Every island on the bench used to be a separate cone, and a signal in two of
   them was drawn twice. Threads joined the copies. Both are gone: the walk is
   merged into one drawing where each node appears exactly once, so there is
   nothing to join and nothing to tell apart. What is left is marking where the
   reader is. */
.sch-bench-card {
  fill: rgba(34, 211, 238, .055);
  stroke: rgba(34, 211, 238, .22);
  stroke-width: 2;
  pointer-events: none;
}

/* --- Schematic: the study view's console -----------------------------------
   One floating panel rather than three clusters pinned to three corners. It is
   draggable because on a screen whose whole content is one drawing, the
   controls are the only thing that can be in the way -- and where they are in
   the way depends on the drawing, which changes with every signal followed. */

.solo-palette { display: none; }
.console.solo .solo-palette {
  display: flex; align-items: flex-start;
  position: absolute; top: 0; left: 0; z-index: 5;
  max-width: calc(100% - 1rem); max-height: calc(100% - 1rem);
}

/* The strip: what is left when the drawer is shut. Its own panel, so the
   drawer can close without the controls going anywhere. */
.sp-strip {
  display: flex; flex-direction: column; align-items: center; gap: .15rem;
  padding: .25rem; flex: none; overflow-y: auto; max-height: 100%;
  border: 2px solid var(--line); border-radius: .45rem;
  background: rgba(10, 14, 24, .95); backdrop-filter: blur(3px);
  box-shadow: var(--hard);
  cursor: grab; touch-action: none; user-select: none; scrollbar-width: none;
}
.sp-strip::-webkit-scrollbar { display: none; }
.solo-palette.dragging .sp-strip { cursor: grabbing; border-color: var(--accent); }
.sp-grip { color: var(--line); font-size: 1rem; line-height: 1; padding: .2rem 0 .3rem; }
.sp-strip-sep { width: 60%; height: 1px; background: var(--line); margin: .2rem 0; flex: none; }

.sp-icon {
  display: flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem; flex: none;
  font: 700 1.15rem/1 var(--font-mono); cursor: pointer;
  color: var(--muted); background: transparent;
  border: 2px solid transparent; border-radius: .25rem;
}
.sp-icon:hover { color: var(--foreground); border-color: var(--line); }
.sp-icon.on { color: var(--accent-foreground); background: var(--accent); border-color: var(--accent); }
.sp-icon.sp-exit:hover { color: var(--warn); border-color: var(--warn); }
.sp-icon.solo-run.on { color: var(--accent-foreground); background: var(--accent); }

/* The drawer: one thing at a time, pulled out beside the strip. */
.sp-drawer {
  display: flex; flex-direction: column; min-height: 0; min-width: 0;
  width: min(20rem, 60vw); max-height: 100%; margin-left: .4rem;
  border: 2px solid var(--line); border-radius: .45rem;
  background: rgba(10, 14, 24, .95); backdrop-filter: blur(3px);
  box-shadow: var(--hard);
}
.solo-palette[data-drawer="shut"] .sp-drawer { display: none; }
.sp-drawer-head {
  display: flex; align-items: center; gap: .15rem; padding: .25rem .3rem .25rem .55rem;
  border-bottom: 2px solid var(--line);
}
.sp-title {
  font: 700 .62rem/1 var(--font-mono); letter-spacing: .14em;
  text-transform: uppercase; color: var(--accent);
}

.solo-btn {
  font: 700 .8rem/1 var(--font-mono); min-width: 2.1rem; padding: .38rem .5rem;
  color: var(--muted); background: transparent; cursor: pointer;
  border: 2px solid transparent; border-radius: .25rem;
}
.solo-btn:hover { color: var(--accent); border-color: var(--line); }
.solo-btn.on { color: var(--accent); border-color: var(--accent); }
.solo-btn[disabled] { opacity: .3; cursor: default; }
.solo-btn[disabled]:hover { color: var(--muted); border-color: transparent; }
.solo-clock {
  font-size: .58rem; color: #6f819f; margin-left: auto; padding: 0 .3rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The rate, reachable in a mode that has no header. Same store as the header's,
   so the two are one setting shown twice. */
.solo-clock-select {
  flex: 0 0 auto; min-width: 0; width: 4.4rem;
  font-family: var(--font-mono); font-size: .58rem; font-weight: 600;
  padding: .2rem .15rem; cursor: pointer;
  color: var(--muted); background: var(--subtle);
  border: 1px solid var(--line); border-radius: .25rem;
}
.solo-clock-select:hover { color: var(--accent); border-color: var(--accent); }

/* The direction pair, which is a labelled choice rather than an icon. */
.sp-dirpair { display: flex; gap: .25rem; margin-bottom: .5rem; }
.sp-dirbtn {
  flex: 1; min-width: 0; font: inherit; font-size: .66rem; padding: .35rem .3rem;
  cursor: pointer; color: var(--muted); background: var(--subtle);
  border: 2px solid var(--line); border-radius: .25rem; white-space: nowrap;
}
.sp-dirbtn:hover { color: var(--foreground); }
.sp-dirbtn.on { color: var(--accent); border-color: var(--accent); }

.sp-panel { padding: .5rem .6rem; overflow: auto; min-height: 0; }
.sp-hint {
  margin: 0; padding: .35rem .6rem .45rem; font-size: .58rem; line-height: 1.5;
  color: #4a5a78; border-top: 1px solid var(--line);
}
.sp-note { margin: .5rem 0 0; font-size: .62rem; line-height: 1.55; color: #6f819f; }
.sp-sub {
  margin: .6rem 0 .3rem; font: 700 .6rem/1 var(--font-mono);
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.sp-empty { margin: .4rem 0 0; font-size: .68rem; color: var(--muted); }

/* Key/value rows, used by I/O and the stack. */
.sp-kv { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .25rem .6rem; margin: 0; }
.sp-kv dt {
  font: 700 .58rem/1.6 var(--font-mono); letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.sp-kv dd { margin: 0; font-size: .72rem; color: var(--foreground); }
.sp-kv dd.sp-write { color: var(--hot); }

.sp-bits { display: inline-flex; gap: 1px; margin-left: .4rem; vertical-align: middle; }
.sp-bits i {
  font: 700 .5rem/1 var(--font-mono); font-style: normal;
  width: .72rem; padding: .2rem 0; text-align: center;
  color: #4a5a78; background: var(--subtle); border-radius: 1px;
}
.sp-bits i.on { color: var(--accent-foreground); background: var(--accent); }

.sp-pins { display: flex; flex-wrap: wrap; gap: .25rem; }
.sp-pin {
  font: 700 .62rem/1 var(--font-mono); letter-spacing: .06em; padding: .4rem .5rem;
  color: var(--muted); background: var(--subtle);
  border: 2px solid var(--line); border-radius: .25rem; cursor: pointer;
}
.sp-pin:hover { color: var(--foreground); }
.sp-pin.low {
  color: var(--accent-foreground); background: var(--hot); border-color: var(--hot);
}

/* The block's boundary as switches, when a block is on the bench.
   Same three states the block page's pills have, and deliberately the same
   reading: off, on, and already-on-screen-through-something-else. */
/* The filter, pinned to the top of the scrolling panel. Sticky rather than a
   sibling above it, so it does not need the drawer restructured and it still
   scrolls into place on a short list. The background is opaque because pills
   scroll underneath it. */
.sp-portfilter {
  position: sticky; top: -.5rem; z-index: 2;
  display: flex; gap: .35rem; align-items: center;
  margin: -.5rem -.6rem .4rem; padding: .5rem .6rem .35rem;
  background: rgba(10, 14, 24, .98);
  border-bottom: 1px solid var(--line);
}
.sp-portfilter input {
  flex: 1 1 auto; min-width: 0;
  padding: .25rem .4rem; font: 500 .66rem var(--font-mono);
  color: var(--foreground); background: var(--space);
  border: 1.4px solid var(--line); border-radius: .2rem;
}
.sp-portfilter input:focus { outline: none; border-color: var(--accent); }
.sp-portfilter .mono { flex: none; font-size: .58rem; color: #6f819f; }

/* Everything at once. Sized to its label so it does not jump as the label
   changes between "all nodes", "all shown" and "none". */
.sp-allbtn {
  flex: none; min-width: 4.4rem; padding: .25rem .35rem; cursor: pointer;
  font: 700 .58rem/1 var(--font-mono); letter-spacing: .04em;
  color: var(--muted); background: var(--space);
  border: 1.4px solid var(--line); border-radius: .2rem; transition: .12s;
}
.sp-allbtn:hover { border-color: var(--accent); color: var(--accent); }
/* After the hover rule, so a lit button is not repainted by hovering it. */
.sp-allbtn.on, .sp-allbtn.on:hover {
  background: color-mix(in srgb, var(--accent) 26%, var(--subtle));
  border-color: var(--accent); color: var(--foreground);
}

/* The toggles are capped to the strip beside them and scroll within it. A
   block like the data bus has 174 ports, and a drawer that grows past the
   console it belongs to stops reading as part of it. `--sp-strip-h` is
   measured, because CSS cannot say "no taller than my sibling". */
/* Note there is no `100%` term here, and that is not an omission. A percentage
   max-height resolves against the palette, whose height is `auto` and therefore
   set BY this drawer -- a circular reference that makes the percentage
   indefinite, and `min(100%, …)` then clamps nothing at all. It applied
   cleanly in the computed style and the drawer stayed 629px against a 479px
   strip. The palette already caps itself against the stage, so the strip height
   is the only bound this needs. */
.solo-palette[data-open="ports"] .sp-drawer {
  max-height: var(--sp-strip-h, 26rem);
}
/* The tracer's View drawer holds a toggle per container kind, and there are
   seventeen kinds now: it grew past the strip, and the study view's drag test
   found the console clamped 35px short of where it was dragged, because the
   drawer it was carrying had got taller than the room above it. Same cap. */
.solo-palette[data-open="view"] .sp-drawer {
  max-height: var(--sp-strip-h, 26rem);
}

.sp-porth {
  margin: .7rem 0 .35rem; font: 700 .58rem/1 var(--font-mono);
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
  display: flex; gap: .4rem; align-items: baseline;
}
.sp-porth .mono { color: #6f819f; }
.sp-ports { display: flex; flex-wrap: wrap; gap: .25rem; }
.sp-port {
  display: inline-flex; align-items: center; gap: .25rem; cursor: pointer;
  padding: .2rem .35rem; font: 500 .62rem var(--font-mono);
  color: #dce9ff; background: var(--subtle);
  border: 1.4px solid var(--line); border-radius: .2rem; transition: .12s;
}
.sp-port i { width: .4rem; height: .4rem; border-radius: 50%; flex: none; }
.sp-port .mono { color: var(--muted); }
.sp-port:hover { border-color: var(--accent); }
/* After the hover rule on purpose: the two tie on specificity and source order
   decides, so an `on` pill must not be repainted by hovering it. */
.sp-port.on, .sp-port.on:hover {
  background: color-mix(in srgb, var(--accent) 26%, var(--subtle));
  border-color: var(--accent); color: var(--foreground);
}
.sp-port.shown {
  border-style: dashed; color: var(--muted);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}
.sp-port.shown::after {
  content: 'shown'; font-size: .5rem; letter-spacing: .06em;
  text-transform: uppercase; color: color-mix(in srgb, var(--accent) 75%, var(--muted));
}

/* Memory, as a hex dump of the bus the chip is talking to. */
.sp-fields { display: flex; gap: .4rem; align-items: flex-end; flex-wrap: wrap; }
.sp-field { display: grid; gap: .15rem; flex: 1 1 8rem; min-width: 0; }
.sp-field.sp-narrow { flex: 0 0 5.5rem; }
.sp-field > span {
  font: 700 .55rem/1 var(--font-mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
}
.sp-field select, .sp-field input {
  width: 100%; min-width: 0; font: inherit; font-size: .7rem; padding: .3rem .35rem;
  color: var(--foreground); background: var(--subtle);
  border: 2px solid var(--line); border-radius: .25rem;
}
.sp-dump { margin-top: .5rem; font-size: .64rem; line-height: 1.7; }
.sp-dump-row { display: flex; gap: .3rem; white-space: nowrap; }
.sp-dump-row b { color: var(--muted); font-weight: 700; }
.sp-dump-row i {
  font-style: normal; color: var(--foreground); padding: 0 .1rem; border-radius: 2px;
}
.sp-dump-row i.at { outline: 1px solid var(--accent); color: var(--accent); }
.sp-dump-row i.pc { color: var(--accent-foreground); background: var(--hot); }

.sp-stack { margin-top: .5rem; font-size: .68rem; }
.sp-stack-row { display: flex; align-items: baseline; gap: .5rem; padding: .1rem 0; }
.sp-stack-row b { color: var(--muted); font-weight: 700; }
.sp-stack-row i { font-style: normal; color: var(--foreground); }
.sp-stack-row.top i { color: var(--accent); }
.sp-stack-note { font-size: .58rem; color: #6f819f; }

/* The walk. */
.sp-walk { display: flex; flex-direction: column; gap: .2rem; }
.sp-step {
  display: flex; align-items: center; gap: .5rem; text-align: left;
  font: inherit; font-size: .72rem; padding: .3rem .4rem; cursor: pointer;
  color: var(--muted); background: var(--subtle);
  border: 2px solid transparent; border-radius: .25rem;
}
.sp-step:hover { color: var(--foreground); border-color: var(--line); }
.sp-step.on { color: var(--accent); border-color: var(--accent); }
.sp-step-n { font-size: .58rem; color: #6f819f; min-width: 1rem; }
.sp-actions { margin-top: .5rem; }
.solo-btn.sp-wide {
  width: 100%; font-size: .66rem; letter-spacing: .06em;
  border-color: var(--line); background: var(--subtle);
}

/* The signal card, in a panel a third the width it has on the page. */
.sp-card .sch-sig-name { margin: 0 0 .4rem; font-size: .85rem; }
.sp-card .ends { margin: 0; }
.sp-card .ends dt { font-size: .55rem; }
.sp-card .ends dd { font-size: .7rem; }

@media (max-width: 46rem) {
  /* Capped so the drawing keeps most of a phone screen. The panel scrolls, and
     a console that fills the viewport is not a console, it is a page. */
  .sp-drawer { width: min(17rem, 68vw); max-height: 24rem; }
  .sp-icon { width: 2.25rem; height: 2.25rem; font-size: 1rem; }
}

/* --- Schematic: direction ---------------------------------------------------- */

.sch-dir { display: flex; gap: .3rem; }
.sch-dir-btn {
  flex: 1; min-width: 0; font: inherit; font-size: .74rem; padding: .35rem .5rem;
  cursor: pointer; color: var(--muted); background: var(--subtle);
  border: 2px solid var(--line); border-radius: .25rem; white-space: nowrap;
}
.sch-dir-btn:hover { color: var(--accent); }
.sch-dir-btn.on { color: var(--accent); border-color: var(--accent); }
.sch-dir-btn[disabled] { opacity: .38; cursor: default; }
.sch-dir-btn[disabled]:hover { color: var(--muted); }
.solo-dir.on { color: var(--accent); border-color: var(--accent); }

/* --- Trace: one instruction, half-cycle by half-cycle ----------------------
   Only real tokens here. A `var()` naming a token that does not exist drops the
   whole declaration silently, which is how three invented names spread across
   two pages before anything looked wrong. */

.tr-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem;
  padding: .7rem .9rem; margin: 0 0 .8rem;
  border: 2px solid var(--line); border-radius: .4rem; background: var(--subtle);
  font-size: .82rem; color: var(--muted);
}
.tr-op { font-weight: 800; color: var(--accent); font-size: 1rem; }
.tr-mn { font-weight: 700; color: var(--foreground); font-size: 1rem; }
.tr-head b { color: var(--foreground); }
.tr-sep { color: var(--line); }
.tr-flag {
  font-size: .66rem; letter-spacing: .08em; text-transform: uppercase;
  padding: .18rem .4rem; border-radius: .2rem;
  background: var(--accent); color: var(--accent-foreground); font-weight: 800;
}
.tr-flag.tr-tail { background: var(--hot); }

.tr-warn {
  margin: 0 0 .8rem; padding: .6rem .8rem; font-size: .8rem;
  border: 2px solid var(--warn); border-radius: .4rem; color: var(--warn);
}

/* The architectural state. A changed field is the point of the row, so it is
   marked rather than left for the reader to diff by eye. */
.tr-state {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(5.2rem, 1fr));
  gap: .4rem; margin: 0 0 1rem;
}
.tr-reg {
  padding: .45rem .5rem; border: 2px solid var(--line); border-radius: .3rem;
  background: var(--surface); min-width: 0;
}
.tr-reg.moved { border-color: var(--accent); background: #16283a; }
.tr-reg-k {
  display: block; font: 700 .6rem/1 var(--font-mono);
  letter-spacing: .1em; color: var(--muted); text-transform: uppercase;
}
.tr-reg-v {
  display: block; font: 800 1rem/1.3 var(--font-mono); color: var(--foreground);
  overflow-wrap: anywhere;
}
.tr-reg.moved .tr-reg-v { color: var(--accent); }
.tr-reg-was { display: block; font: .58rem/1 var(--font-mono); color: var(--muted); }

.tr-cols { display: grid; gap: .8rem; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 62rem) {
  .tr-cols { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
.tr-h { margin: 0 0 .3rem; font-size: .9rem; }
.tr-h4 { margin: .9rem 0 .3rem; font-size: .74rem; color: var(--muted);
         text-transform: uppercase; letter-spacing: .08em; }
.tr-note { margin: 0 0 .6rem; font-size: .74rem; color: var(--muted); line-height: 1.5; }

.tr-joins, .tr-switches { list-style: none; margin: 0; padding: 0;
                          display: flex; flex-direction: column; gap: .3rem; }
.tr-joins li {
  display: flex; flex-wrap: wrap; align-items: center; gap: .35rem;
  padding: .35rem .5rem; border: 2px solid var(--line); border-radius: .3rem;
  background: var(--surface); font-size: .78rem;
}
.tr-joins li.fresh { border-color: var(--accent); background: #16283a; }
.tr-joins li.muted { border-style: dashed; color: var(--muted); }
.tr-wire { font: 700 .78rem/1 var(--font-mono); color: var(--foreground); }
.tr-eq { color: var(--accent); font-weight: 800; }
.tr-lvl {
  margin-left: auto; font: 800 .7rem/1 var(--font-mono);
  padding: .18rem .35rem; border-radius: .2rem;
}
.tr-lvl.hi { background: var(--accent); color: var(--accent-foreground); }
.tr-lvl.lo { background: var(--subtle); color: var(--muted); }
.tr-watch { margin: .6rem 0 0; font-size: .62rem; color: var(--line); }

.tr-changed { display: flex; flex-direction: column; gap: .5rem;
              max-height: 17rem; overflow: auto; }
.tr-blk h4 { margin: 0 0 .2rem; font-size: .68rem; color: var(--muted);
             text-transform: uppercase; letter-spacing: .08em; }
.tr-blk p { margin: 0; line-height: 1.9; }
.tr-node {
  font: 700 .64rem/1 var(--font-mono); padding: .16rem .3rem;
  border-radius: .2rem; background: var(--subtle); color: var(--muted);
  white-space: nowrap;
}
.tr-node.up { color: var(--accent); }
.tr-node.down { color: var(--muted); }
.tr-node i { font-style: normal; opacity: .7; margin-left: .1rem; }

.tr-switches li {
  padding: .3rem .5rem; border-left: 3px solid var(--line);
  background: var(--surface); font-size: .74rem;
}
.tr-switches li.opened { border-left-color: var(--accent); }
.tr-switches li.closed { border-left-color: var(--line); }
.tr-switches li.muted { border-left-style: dashed; color: var(--muted); }

.tr-tablewrap { margin: 1rem 0 .4rem; overflow-x: auto; max-height: 26rem; overflow-y: auto; }
.tr-table { border-collapse: collapse; width: 100%; font-size: .7rem; }
.tr-table th, .tr-table td { padding: .28rem .5rem; text-align: right; white-space: nowrap; }
.tr-table th {
  position: sticky; top: 0; z-index: 1;
  background: var(--subtle); color: var(--muted);
  font: 700 .62rem/1.6 var(--font-mono); letter-spacing: .06em;
  text-transform: uppercase; border-bottom: 2px solid var(--line);
}
.tr-table tbody tr { cursor: pointer; border-bottom: 1px solid #1c2b45; }
.tr-table tbody tr:hover { background: var(--subtle); }
.tr-table tbody tr.tail td { color: var(--hot); }
.tr-table tbody tr.here { background: #16283a; outline: 2px solid var(--accent);
                          outline-offset: -2px; }

/* --- Primer: the explanatory page ------------------------------------------
   No numbers of its own. Every figure is a `data-fact` slot filled from the
   published measurements, so a page whose whole job is explanation cannot drift
   away from the thing it explains. */

.pr-table-wrap { overflow-x: auto; margin: 1.2rem 0; }
.pr-table {
  width: 100%; border-collapse: collapse; font-size: .84rem;
  border: 2px solid var(--line);
}
.pr-table th {
  text-align: left; padding: .5rem .7rem; white-space: nowrap;
  font: 700 .62rem/1 var(--font-mono); letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); background: var(--subtle);
  border-bottom: 2px solid var(--line);
}
.pr-table td { padding: .5rem .7rem; border-bottom: 1px solid var(--line); vertical-align: top; }
.pr-table tr:last-child td { border-bottom: 0; }
.pr-pin { color: var(--accent); white-space: nowrap; }
.pr-dir {
  font: 700 .58rem/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  white-space: nowrap; color: var(--muted);
}
.pr-in { color: var(--hot); }
.pr-out { color: var(--mint); }
.pr-both { color: var(--gold); }

.pr-seealso {
  margin-top: 1rem; padding: .6rem .8rem; font-size: .82rem;
  border-left: 3px solid var(--accent); background: var(--subtle); color: var(--muted);
}
.pr-seealso a { color: var(--accent); }

#pr-statbar [data-fact] { color: var(--foreground); font-weight: 700; }


/* The study view's own depth slider, the page's being out of sight in there. */
.sp-depth { margin-bottom: .55rem; }
.sp-depth input[type=range] { width: 100%; accent-color: var(--accent); }

/* --- The primer's runnable examples ----------------------------------------
   One chip, five views of it: they share a machine and a clock, so the
   transports are five copies of one control and paint from the chip rather than
   from whichever was last pressed. */

.dm {
  margin: 1.4rem 0; padding: 0;
  border: 2px solid var(--line); border-radius: .45rem; background: var(--surface);
  overflow: hidden;
}
.dm-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem;
  padding: .55rem .8rem; border-bottom: 2px solid var(--line); background: var(--subtle);
}
.dm-tag {
  font: 700 .58rem/1 var(--font-mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent-foreground); background: var(--accent);
  padding: .25rem .4rem; border-radius: .2rem;
}
.dm-title { font-weight: 800; font-size: .9rem; }
.dm-sub { font-size: .74rem; color: var(--muted); }
.dm-body { padding: .7rem .8rem; }

.dm-bar { display: flex; align-items: center; gap: .25rem; flex-wrap: wrap; margin-bottom: .6rem; }
.dm-btn {
  font: 700 .8rem/1 var(--font-mono); min-width: 2.2rem; padding: .4rem .5rem;
  color: var(--muted); background: var(--subtle); cursor: pointer;
  border: 2px solid var(--line); border-radius: .25rem;
}
.dm-btn:hover { color: var(--accent); border-color: var(--accent); }
.dm-btn.on { color: var(--accent-foreground); background: var(--accent); border-color: var(--accent); }
.dm-clock { font-size: .66rem; color: #6f819f; margin-left: auto; white-space: nowrap; }

.dm-kv { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .35rem .8rem; margin: 0; }
.dm-kv dt {
  font: 700 .58rem/1.6 var(--font-mono); letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.dm-kv dd { margin: 0; font-size: .8rem; min-width: 0; }
.dm-write { color: var(--hot); }

.dm-lamps { display: inline-flex; flex-wrap: wrap; gap: 1px; margin-left: .45rem; vertical-align: middle; }
.dm-lamps i {
  font: 700 .5rem/1 var(--font-mono); font-style: normal;
  width: .74rem; padding: .2rem 0; text-align: center;
  color: #4a5a78; background: var(--subtle); border-radius: 1px;
}
.dm-lamps i.on { color: var(--accent-foreground); background: var(--accent); }

.dm-pins { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .7rem; }
.dm-pin {
  font: 700 .64rem/1 var(--font-mono); letter-spacing: .06em; padding: .45rem .55rem;
  color: var(--muted); background: var(--subtle);
  border: 2px solid var(--line); border-radius: .25rem; cursor: pointer;
}
.dm-pin:hover { color: var(--foreground); border-color: var(--accent); }
.dm-pin.low { color: var(--accent-foreground); background: var(--hot); border-color: var(--hot); }

.dm-terms { display: flex; flex-wrap: wrap; gap: .25rem; }
.dm-terms i, .dm-join i {
  font: 600 .66rem/1 var(--font-mono); font-style: normal;
  padding: .25rem .4rem; border-radius: .2rem;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.dm-join { display: inline-flex; align-items: center; gap: .2rem; flex-wrap: wrap; }
.dm-join b { color: var(--muted); font-size: .7rem; }
.dm-level {
  display: inline-block; margin-left: .5rem; padding: .1rem .35rem;
  font: 700 .62rem/1.5 var(--font-mono);
  color: var(--accent-foreground); background: var(--accent); border-radius: .2rem;
}

.dm-note { margin: .7rem 0 0; font-size: .72rem; line-height: 1.6; color: var(--muted); }

/* The scope: a recording of what the pins did, not a diagram of what they
   should have done. */
.dm-scope { display: block; width: 100%; height: auto; margin: .2rem 0 .6rem; }
.dm-scope-label {
  fill: var(--muted); font: 700 9px var(--font-mono); letter-spacing: .06em;
}
.dm-scope-tick { stroke: var(--line); stroke-width: 1; opacity: .5; }
.dm-scope-now { stroke: var(--hot); stroke-width: 1.5; opacity: .8; }
.dm-scope-trace { fill: none; stroke: var(--accent); stroke-width: 2; }
.dm-scope-trace.dm-ch-sync { stroke: var(--mint); }
.dm-scope-trace.dm-ch-rw { stroke: var(--hot); }

/* ---------- the Programs page (programs.html) ---------- */

.pg-cols { display: grid; grid-template-columns: minmax(0, 1fr); }
.pg-list {
  display: grid; gap: .4rem; padding: .9rem;
  border-bottom: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
}
.pg-item {
  display: grid; gap: .15rem; text-align: left;
  padding: .6rem .7rem; cursor: pointer; transition: .15s;
  border: 2px solid color-mix(in srgb, var(--line) 60%, transparent);
  border-radius: .375rem;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  color: var(--foreground);
}
.pg-item strong { font-size: .88rem; font-weight: 700; }
.pg-item-size { font-size: .68rem; color: var(--muted); }
.pg-item:hover { border-color: var(--gold); }
.pg-item:hover strong { color: var(--gold); }
.pg-item.on {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.pg-item.on strong { color: var(--accent); }

.pg-main { padding: 1rem .9rem 1.4rem; min-width: 0; }
.pg-head h2 { margin: 0 0 .35rem; font-size: 1.35rem; letter-spacing: -.01em; }
.pg-blurb { margin: 0 0 1.1rem; color: var(--muted); max-width: 60ch; line-height: 1.65; }
.pg-main h3 {
  margin: 1.6rem 0 .5rem; font-family: var(--font-mono); font-size: .78rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--accent);
}

/* The listing is wider than a phone at any font size that stays readable, so
   it scrolls inside its own box rather than pushing the page sideways. */
.pg-listing-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.pg-listing { border-collapse: collapse; width: 100%; min-width: 30rem; font-size: .8rem; }
.pg-listing th {
  position: sticky; top: 0; z-index: 1;
  padding: .35rem .5rem; text-align: left;
  font-family: var(--font-mono); font-size: .62rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
  background: color-mix(in srgb, var(--space) 94%, transparent);
  border-bottom: 2px solid color-mix(in srgb, var(--line) 60%, transparent);
}
.pg-listing td { padding: .18rem .5rem; vertical-align: baseline; }
.pg-listing .c-addr { width: 4.2rem; color: var(--muted); white-space: nowrap; }
.pg-listing .c-bytes { width: 6.4rem; color: var(--mint); white-space: nowrap; }
.pg-listing .c-cyc { width: 2.6rem; text-align: right; color: var(--muted); }
.pg-listing .c-len { width: 2.6rem; text-align: right; color: var(--muted); }
/* The assembler and the chip disagreeing about an instruction's length. Two
   independent measurements of one thing, so this is a bug in one of them and
   is loud on purpose. It should never appear. */
.pg-listing .c-len.pg-mismatch { color: var(--warn); font-weight: 700; }
.pg-listing .c-src { width: auto; }
.pg-src { display: block; white-space: pre; font-size: .8rem; color: var(--muted); }
.pg-src.has-op { color: var(--foreground); }
.pg-row.is-org .c-addr { color: var(--gold); }

.pg-note td { padding: .35rem .5rem .7rem; }
.pg-note p {
  margin: 0; max-width: 62ch; font-size: .78rem; line-height: 1.65;
  color: var(--muted);
  border-left: 2px solid color-mix(in srgb, var(--accent) 55%, transparent);
  padding-left: .7rem;
}

.pg-binary-note { margin: 0 0 .5rem; font-size: .78rem; line-height: 1.6; max-width: 62ch; }
.pg-dump {
  margin: 0; padding: .7rem .8rem; overflow-x: auto;
  border: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  border-radius: .375rem;
  background: color-mix(in srgb, var(--space) 70%, transparent);
  font-family: var(--font-mono); font-size: .75rem; line-height: 1.7; color: var(--mint);
}

.pg-run-host {
  padding: .8rem; border-radius: .375rem;
  border: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
  background: color-mix(in srgb, var(--surface) 65%, transparent);
}
.pg-regs, .pg-watch { margin-top: .6rem; }
.pg-watch { padding-top: .6rem; border-top: 1px solid color-mix(in srgb, var(--line) 45%, transparent); }

.pg-go-links { display: grid; gap: .5rem; }
.pg-go-link {
  display: grid; gap: .1rem; padding: .6rem .7rem; text-decoration: none;
  border: 2px solid color-mix(in srgb, var(--line) 60%, transparent);
  border-radius: .375rem; color: var(--foreground); transition: .15s;
}
.pg-go-link strong { font-size: .88rem; }
.pg-go-link span { font-size: .74rem; color: var(--muted); }
.pg-go-link:hover { border-color: var(--gold); }
.pg-go-link:hover strong { color: var(--gold); }

@media (min-width: 56rem) {
  .pg-cols { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); }
  .pg-list {
    border-bottom: 0;
    border-right: 2px solid color-mix(in srgb, var(--line) 55%, transparent);
    align-content: start;
  }
  .pg-main { padding: 1.2rem 1.2rem 1.6rem; }
  .pg-go-links { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
}

/* The region key, drawn only for the blocks currently on the diagram. Same
   palette as the exploded view -- one file, block-palette.js, so the two pages
   cannot come to disagree about what colour the ALU is. */
.sch-blockkey {
  display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .9rem;
  margin: .1rem 0 .8rem; font-family: var(--font-mono); font-size: .68rem;
}
.sch-blockkey-label {
  color: var(--muted); letter-spacing: .1em; text-transform: uppercase;
  font-size: .6rem; font-weight: 700;
}
.sch-blockkey-item { display: inline-flex; align-items: center; gap: .35rem; color: var(--muted); }
.sch-blockkey-item i {
  width: .7rem; height: .7rem; border-radius: 2px; display: inline-block;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .5) inset;
}

/* The pinned pin: an anchor, not a step. Gold rather than the accent, so it
   reads as "the edge of the chip" rather than "the signal you are on". */
.sch-node.pin .sch-pill { stroke: var(--gold); stroke-width: 2.2; fill: #2a2210; }
.sch-node.pin .sch-name { fill: var(--gold); font-weight: 700; }

.sp-check {
  display: flex; align-items: center; gap: .5rem; margin: .1rem 0 .6rem;
  font-size: .78rem; color: var(--muted); cursor: pointer;
}
.sp-check input { width: 1rem; height: 1rem; accent-color: var(--accent); }
.sch-pinio { font-size: .8rem; }

/* ---------------------------------------------------------------------------
   The pinout (pinout.html)
   ---------------------------------------------------------------------------
   A package has one shape, so this is the one drawing on the site whose layout
   is not derived. Everything a pin is coloured or labelled BY still is. */

.po-layout { display: grid; gap: 1rem; padding: 1rem 1.1rem; min-width: 0; }
.po-stage { overflow-x: auto; min-width: 0; }
#po-svg { width: 100%; max-width: 40rem; height: auto; display: block; margin: 0 auto;
          min-width: 22rem; }

.po-body { fill: var(--surface); stroke: var(--line); stroke-width: 2; }
.po-notch { fill: var(--space); stroke: var(--line); stroke-width: 2; }
.po-part { font: 700 11px var(--font-mono); letter-spacing: .16em; fill: var(--muted); }
.po-pad { fill: var(--subtle); stroke: var(--line); stroke-width: 1.4; }
.po-num { font: 500 9px var(--font-mono); fill: var(--muted); }
.po-lab { font: 700 11px var(--font-mono); fill: var(--foreground); }
/* An invisible target the height of the row, so a pin is clickable by its
   label as well as by its pad. The pads are 16 units tall and a finger is not. */
.po-hit { fill: transparent; cursor: pointer; }
.po-pin { cursor: pointer; }
.po-pin:hover .po-pad { fill: color-mix(in srgb, var(--accent) 30%, var(--subtle)); }
.po-pin.on .po-pad { fill: var(--accent); stroke: var(--accent); }
.po-pin.on .po-num { fill: var(--accent-foreground); }

/* Direction, measured. A pin with nothing behind it gets neither. */
.po-output .po-pad { stroke: var(--mint); }
.po-input .po-pad { stroke: var(--gold); }
.po-bidirectional .po-pad { stroke: var(--pink); }
.po-none .po-pad { stroke-dasharray: 3 3; }
/* Not a direction: a rail is not a signal, and the question does not apply. */
.po-power .po-pad { fill: var(--line); stroke: var(--muted); }

.po-picked {
  margin: 0; padding: .7rem .8rem; font-size: .82rem; line-height: 1.55;
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  border: 1.4px solid color-mix(in srgb, var(--line) 42%, transparent);
  border-left: 3px solid var(--accent); border-radius: .4rem; min-height: 3.4rem;
}
#po-rows tr { cursor: pointer; }
#po-rows tr:hover td { background: #16203a; }
#po-rows tr.on td { background: #1b2947; }
#po-rows tr.on td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.po-nc td { color: var(--muted); }

@media (min-width: 56rem) {
  .po-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); align-items: start; }
}

/* ---------------------------------------------------------------------------
   The die graph (diegraph.html)
   ---------------------------------------------------------------------------
   Node fill is set inline from block-palette.js, because the hue IS the
   measurement's identity -- the same reason the block pages set it there and
   not in CSS. Everything else is here. */

.dg-stage {
  overflow: hidden; touch-action: none; cursor: grab;
  background: color-mix(in srgb, var(--space) 70%, #000);
  border-top: 2px solid var(--line); border-bottom: 2px solid var(--line);
}
.dg-stage:active { cursor: grabbing; }
/* Tall, because the die is nearly square and the console is wide: a short
   stage letterboxes the chip and throws away most of the drawing area on
   empty sides. The limiting dimension is the height, so that is what to give. */
#dg-svg { width: 100%; height: min(86vh, 58rem); display: block; }

/* Two relations, two weights. A pass transistor joins two wires without either
   causing the other; a gate input reaches the output it helps produce. Drawing
   them alike would lose the only structural distinction in the picture. */
.dg-e { stroke-width: 3; }
.dg-e-gate { stroke: color-mix(in srgb, var(--line) 55%, transparent); }
.dg-e-switch { stroke: color-mix(in srgb, var(--accent) 62%, transparent); stroke-width: 5; }

.dg-n { stroke: rgba(2, 6, 16, .55); stroke-width: 3; }
.dg-named { stroke: rgba(2, 6, 16, .75); }
.dg-n.on { stroke: var(--foreground); stroke-width: 14; }
.dg-n:hover { stroke: var(--gold); stroke-width: 10; }

#dg-picked { font-size: .76rem; overflow-wrap: anywhere; }

/* ---------------------------------------------------------------------------
   The published block diagram (blockdiagram.html)
   ---------------------------------------------------------------------------
   Drawn from the dataset rather than traced, so the styling is this site's own
   and deliberately not the original plate's: dark, our palette, our fonts. The
   measurement sits beside each claim inside the box rather than in a caption,
   because the comparison is the whole page. */

.bd-stage { overflow-x: auto; padding: 1rem 1.1rem; min-width: 0; }
#bd-svg { width: 100%; height: auto; min-width: 34rem; display: block; }

.bd-rail rect {
  fill: color-mix(in srgb, var(--accent) 14%, transparent);
  stroke: color-mix(in srgb, var(--accent) 50%, transparent); stroke-width: 1.2;
}
/* A bus the published figure does not draw. Dashed because the difference IS
   the finding, and a reader should see it without reading the caption. */
.bd-rail-extra rect {
  fill: color-mix(in srgb, var(--gold) 12%, transparent);
  stroke: var(--gold); stroke-dasharray: 5 4;
}
.bd-raillabel {
  font: 700 10px var(--font-mono); letter-spacing: .1em;
  fill: var(--muted); text-transform: uppercase;
}

.bd-section {
  font: 700 10px var(--font-mono); letter-spacing: .18em;
  fill: var(--muted); text-transform: uppercase;
}
/* One mark standing for every control line reaching into the datapath. A line
   per block would be 46 wires across the drawing, which is a picture of a mess;
   the count is on the page in words instead. */
.bd-control-wire {
  fill: none; stroke: color-mix(in srgb, var(--pink) 60%, transparent);
  stroke-width: 1.4; stroke-dasharray: 4 4;
}

.bd-box { fill: var(--surface); stroke: var(--bd-hue, var(--line)); stroke-width: 1.6; }
.bd-wire { stroke: color-mix(in srgb, var(--line) 80%, transparent); stroke-width: 1.4; }
.bd-label { font: 600 13px var(--font-sans); fill: var(--foreground); }
.bd-meas { font: 500 11px var(--font-mono); fill: var(--accent); }
/* The one box in the figure that is a journey rather than a place. Marked,
   because "8 out, 5 steps in" is not the same kind of fact as a width and
   should not look like one. */
.bd-journey .bd-box { stroke-dasharray: 2 3; }

/* On the die, not in the published figure. The same gold the omitted bus
   carries, because it is the same kind of fact. */
.bd-extra .bd-box { stroke: var(--gold); stroke-dasharray: 5 4; }
.bd-extra .bd-meas { fill: var(--gold); }

/* A claim the die does not answer. Nothing is hidden: it is drawn, and marked. */
.bd-missing .bd-box { stroke: var(--warn); stroke-dasharray: 4 3; }
.bd-missing .bd-meas { fill: var(--warn); }

/* ---------------------------------------------------------------------------
   The functional block pages (block.html)
   ---------------------------------------------------------------------------
   One document serves all twelve, so there is one set of rules here rather than
   twelve stylesheets that would eventually disagree about what a port looks
   like. Colours come from the block palette via an inline `background` on the
   dot, which is the only thing on these pages that is not a token: the hue IS
   the measurement's identity, and hardcoding thirteen of them in CSS would be a
   second copy of block-palette.js. */

/* The statbar packs a value and its label into one cell, and without a gap they
   run together: "290transistors 168signals". The site's own .statbar is a row of
   plain strings; these are pairs, so they need their own rule. */
/* `.statbar` is a flex row with a .5rem gap, written for plain strings
   separated by dots. These are label-and-value pairs stacked in columns, so at
   that gap the columns touch and read as one run of digits. */
/* The one authored paragraph on a block page, set as a quote block.
 *
 * It is a reading rather than a measurement, and giving it its own surface says
 * so at a glance, before the `interface · derived` tag on the console below it
 * has to. That is the same separation block-notes.js exists to keep, expressed
 * in the layout instead of only in a caption.
 *
 * The spacing is the point as much as the tint. This paragraph replaced a
 * heading and a lede, and inherited their box: `.sec` supplies a generous pad
 * above and exactly none below, and `p` has no margin, so the text sat flush on
 * top of the console with 72px of air above it and zero beneath. `--sec-gap` is
 * the section's own rhythm, so using it here makes the two buffers equal at
 * every width rather than at the one they were measured at.
 */
.bk-does {
  max-width: 68ch;
  margin: 0 0 var(--sec-gap);
  /* Equal top and bottom, so the tint reads as a band around the text rather
     than as a box the text is sitting at the top of. */
  padding: 1.15rem 1.35rem;
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  border: 1.4px solid color-mix(in srgb, var(--line) 42%, transparent);
  border-left: 3px solid color-mix(in srgb, var(--accent) 65%, transparent);
  border-radius: .4rem;
}

.bk-statbar { gap: .55rem 1.9rem; align-items: baseline; }
.bk-stat { display: flex; flex-direction: column; gap: .1rem; }
.bk-stat b { font-size: .92rem; color: var(--foreground); }
.bk-stat span { font-size: .68rem; color: var(--muted); letter-spacing: .04em; }

.bk-hero-dot {
  display: inline-block; width: .58em; height: .58em; border-radius: 50%;
  margin-right: .45em; vertical-align: .06em;
}

/* The directory ---------------------------------------------------------- */

.bk-grid {
  display: grid; gap: 1rem; margin: 1.5rem 0;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.bk-card {
  display: block; padding: 1rem 1.1rem 1.1rem; text-decoration: none;
  background: var(--surface); border: 2px solid var(--line);
  border-radius: .5rem; box-shadow: var(--hard-card); transition: .15s;
}
.bk-card:hover { border-color: var(--accent); transform: translate(-2px, -2px); }
.bk-card-bar { display: block; height: 4px; border-radius: 2px; margin-bottom: .7rem; }
.bk-card h3 { margin: 0 0 .35rem; font-size: 1.05rem; color: var(--foreground); }
.bk-card-blurb { margin: 0 0 .6rem; color: var(--muted); font-size: .88rem; line-height: 1.45; }
.bk-card-stats { display: flex; flex-wrap: wrap; gap: .25rem .8rem; margin: 0;
  font-size: .72rem; color: var(--muted); }
.bk-coverage { max-width: 46rem; color: var(--muted); font-size: .88rem; }

/* The interface ---------------------------------------------------------- */

.bk-ports {
  display: grid; gap: 1.1rem 1.5rem; padding: 1rem 1.1rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.bk-portgroup { min-width: 0; }
.bk-portgroup h3 {
  margin: 0 0 .15rem; font-size: .95rem; color: var(--foreground);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem;
}
.bk-count { font-size: .68rem; font-weight: 500; color: var(--muted); }
.bk-why { margin: 0 0 .55rem; font-size: .76rem; line-height: 1.4; color: var(--muted); }
.bk-portlist { display: flex; flex-wrap: wrap; gap: .3rem; }
.bk-port {
  display: inline-flex; align-items: center; gap: .35rem; cursor: pointer;
  padding: .22rem .45rem; font: 500 .74rem var(--font-mono);
  background: #101829; color: #dce9ff;
  border: 1.4px solid var(--line); border-radius: .25rem; transition: .12s;
}
.bk-port:hover { border-color: var(--accent); color: var(--accent); }

/* A pill is a switch, so it needs a resting state that reads as OFF and an on
   state that reads as on without being mistaken for hover. The variant restates
   its colour: `.bk-port:hover` declares one at (0,2,0) and would otherwise
   outrank a variant's resting (0,2,0)... it ties, and source order decides, so
   the on rules come after the hover rule on purpose. Same trap the primary
   button hit, where hover put cyan text on a gold background at 1.08:1. */
.bk-port.on,
.bk-port.on:hover {
  background: color-mix(in srgb, var(--accent) 22%, #101829);
  border-color: var(--accent);
  color: var(--foreground);
}

/* Already on screen through a different heading. Dashed rather than filled:
   this pill is not switched on, and drawing it as though it were would be the
   page claiming the reader did something they did not. */
.bk-port.shown {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  color: var(--muted);
}
.bk-port.shown::after {
  content: 'shown';
  font-size: .62rem; letter-spacing: .06em; text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 75%, var(--muted));
}
.bk-port-w { color: var(--muted); }
.bk-dot { display: inline-block; width: .5rem; height: .5rem; border-radius: 50%; flex: none; }
.bk-chip { display: inline-flex; align-items: center; gap: .35rem; }
.bk-foot { padding: 0 1.1rem 1rem; margin: 0; font-size: .76rem; line-height: 1.45; }

/* The circuit ------------------------------------------------------------ */

.bk-stage { max-height: 60vh; }
.bk-dirs { display: flex; gap: .35rem; }
.bk-dirs .btn { padding: .35rem .6rem; font-size: .76rem; }
.bk-dirs .btn.on { border-color: var(--accent); color: var(--accent); }
.bk-root-line { margin: .6rem 0 0; font-size: .82rem; }

/* `.bp-prose` puts a gap between adjacent paragraphs, which is what a column of
   prose wants and not what a card or a lab row wants -- there, two paragraphs in
   a row are a caption and its result, not two thoughts. Scoped to the
   components rather than turned off on the section, because the section's own
   ledes do want it. */
.bk-notes p + p, .bk-lab p + p, .bk-lab-row p + p, .bk-ports p + p { margin-top: 0; }
/* A port pill says where it goes. Muted, because it is the edge of the drawing
   rather than part of the circuit, and it must not read as a signal you can
   walk to -- clicking one does nothing here on purpose. */
.sch-node.port .sch-pill { stroke-dasharray: 4 2; opacity: .85; }
.sch-node.port { cursor: default; }
/* An attributed static gate is part of the circuit and can be walked, but it is
   a weaker claim than membership -- it is here because of what it drives, not
   because blocks.rs placed it here. Hollow rather than dashed, so it reads as
   "part of this drawing" where a port reads as "the edge of it". */
.sch-node.logic .sch-pill { fill: #0a1120; stroke-dasharray: 2 2; }
.sch-port-label { fill: #7e8db0; font: 500 7.5px var(--font-mono); text-anchor: middle; }

/* The reading, and the labs ---------------------------------------------- */

.bk-notes { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); }
.bk-note {
  padding: .9rem 1rem; background: var(--surface);
  border: 2px solid var(--line); border-radius: .5rem;
}
.bk-note h3 { margin: 0 0 .4rem; font-size: .98rem; color: var(--accent); }
.bk-note p { margin: 0; font-size: .88rem; line-height: 1.55; color: var(--muted); }
.bk-note code, .bk-lab-blurb code, .bk-lab-note code {
  font: 500 .92em var(--font-mono); color: #dce9ff;
}

.bk-labs { display: grid; gap: 1.25rem; }
.bk-lab {
  padding: 1rem 1.1rem 1.1rem; background: var(--surface);
  border: 2px solid var(--line); border-radius: .5rem; box-shadow: var(--hard-card);
}
.bk-lab h3 { margin: 0 0 .35rem; font-size: 1.02rem; }
.bk-lab-blurb { margin: 0 0 .8rem; color: var(--muted); font-size: .88rem; line-height: 1.5; }
.bk-lab-src {
  margin: 0 0 1rem; padding: .7rem .8rem; overflow-x: auto;
  background: #080c15; border: 1px solid var(--line); border-radius: .35rem;
  font-size: .76rem; line-height: 1.5; color: #9fb4d8;
}
.bk-lab-failed { margin: 0; color: var(--warn); font-size: .85rem; }
.bk-lab-rows { display: grid; gap: .55rem; }
.bk-lab-row {
  display: grid; gap: .3rem .9rem; padding: .6rem .7rem;
  grid-template-columns: 8.5rem minmax(0, 1fr);
  background: #0d1524; border: 1px solid var(--line); border-radius: .35rem;
}
.bk-lab-when { grid-row: span 2; font-size: .74rem; color: var(--muted); line-height: 1.5; }
.bk-lab-when b { display: block; font-size: 1.05rem; color: var(--accent); }
.bk-lab-note { margin: 0; font-size: .85rem; line-height: 1.5; color: var(--foreground); }
.bk-lab-buses { display: flex; flex-wrap: wrap; gap: .3rem; }
.bk-bus {
  display: inline-flex; align-items: baseline; gap: .35rem;
  padding: .15rem .4rem; font-size: .72rem;
  background: #101829; border: 1px solid var(--line); border-radius: .25rem;
}
.bk-bus i { font-style: normal; color: var(--muted); }
.bk-bus b { color: #dce9ff; }
.bk-bus-reg b { color: var(--gold); }
.bk-check { grid-column: 2; margin: 0; display: flex; gap: .45rem; font-size: .8rem; }
.bk-check-mark { font-weight: 700; }
.bk-check.held .bk-check-mark { color: var(--mint); }
.bk-check.broke { color: var(--hot); }
.bk-check.broke .bk-check-mark { color: var(--hot); }

/* Where to go next ------------------------------------------------------- */

.bk-seealso { display: flex; flex-wrap: wrap; gap: .6rem; margin-bottom: 1.25rem; }
.bk-seealso-link {
  display: grid; gap: .1rem; padding: .55rem .8rem; text-decoration: none;
  background: var(--surface); border: 2px solid var(--line); border-radius: .4rem;
  transition: .15s;
}
.bk-seealso-link:hover { border-color: var(--accent); }
.bk-seealso-link b { font-size: .9rem; color: var(--foreground); }
.bk-seealso-link span { font-size: .76rem; color: var(--muted); }

.bk-blocknav { display: flex; flex-wrap: wrap; gap: .6rem; align-items: stretch; }
.bk-step {
  display: grid; gap: .1rem; padding: .55rem .8rem; text-decoration: none;
  background: var(--surface); border: 2px solid var(--line); border-radius: .4rem;
  transition: .15s; align-content: center;
}
.bk-step:hover { border-color: var(--accent); }
.bk-step-dir { font: 700 .62rem var(--font-mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted); }
.bk-step b { font-size: .9rem; color: var(--foreground); }
.bk-step-all { margin-left: auto; }

.bk-error { color: var(--warn); }

/* A phone has no room for a fixed label column beside every lab row, and the
   port grid wants to be one column rather than three squeezed ones. */
@media (max-width: 40rem) {
  .bk-lab-row { grid-template-columns: minmax(0, 1fr); }
  .bk-lab-when { grid-row: auto; }
  .bk-check { grid-column: 1; }
  .bk-step-all { margin-left: 0; }
}

/* ---------------------------------------------------------------------------
   The talk (talk.html): where the die data came from, and its claims re-checked

   Two visual registers on one page, because the page has two kinds of content
   and conflating them is exactly what it is arguing against. The history
   sections are plain prose. The verification rows are cards with a computed
   verdict, and the verdict colours the card rather than sitting beside it as an
   icon: a reader scanning the section should be able to see the one that
   differs without reading a word.
   --------------------------------------------------------------------------- */

.tk-links { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.4rem; }

/* The claim card, shared by talk.html and designer.html and rendered by
   claim-table.js. Named for what it is rather than for either page: it was
   `.tk-*` while the talk was the only caller, and a second page inheriting a
   first page's prefix is how a component stops being recognisable as one. */

.claim-list { display: grid; gap: .9rem; padding: 1rem 1.1rem; }

.claim {
  display: grid; gap: .45rem; padding: .85rem .9rem; min-width: 0;
  background: #101829; border: 1.4px solid var(--line);
  border-left: 3px solid var(--mint); border-radius: .35rem;
}
.claim-differs { border-left-color: var(--gold); }

.claim-says { font-size: .92rem; line-height: 1.5; color: var(--foreground); }

/* The verdict reads as a label on the claim, not as a separate column, so it
   stays on the same line and wraps with it. */
.claim-verdict {
  display: inline-block; margin-right: .5rem; padding: .1rem .4rem;
  font: 700 .6rem var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--space); background: var(--mint); border-radius: .2rem;
  vertical-align: .1em;
}
.claim-differs .claim-verdict { background: var(--gold); }

.claim-got {
  font: 500 .8rem var(--font-mono); line-height: 1.55; color: #dce9ff;
  overflow-wrap: anywhere;
}
.claim-got .tag { margin-right: .45rem; }

.claim-note { margin: 0; font-size: .78rem; line-height: 1.5; max-width: 68ch; }
.claim-where { margin: 0; font-size: .78rem; }
.claim-where a { color: var(--accent); }

/* What the talk asked for ------------------------------------------------- */

.tk-since {
  display: grid; gap: 1rem; margin-top: 1.4rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}
.tk-item {
  min-width: 0; padding: 1rem 1.1rem;
  background: var(--surface); border: 2px solid var(--line); border-radius: .45rem;
}
.tk-item h3 { margin: 0 0 .5rem; font-size: .98rem; color: var(--foreground); }
.tk-item p { margin: 0 0 .6rem; font-size: .84rem; line-height: 1.55; }
.tk-item p:last-child { margin-bottom: 0; }

/* The pushed-value table --------------------------------------------------- */

/* Wide content scrolls inside its own box rather than widening the page: the
   console clips its overflow, so without this the last column is simply gone. */
.tk-table-wrap { overflow-x: auto; padding: 0 1.1rem 1rem; min-width: 0; }
.tk-table { width: 100%; border-collapse: collapse; font-size: .82rem; }
.tk-table th, .tk-table td {
  padding: .45rem .6rem; text-align: left; border-bottom: 1.4px solid var(--line);
  vertical-align: top;
}
.tk-table th {
  font: 700 .62rem var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); white-space: nowrap;
}
.tk-table tbody tr:last-child td { border-bottom: 0; }
.tk-table .mono { color: #dce9ff; }
.tk-hit td { background: #16203a; }
.tk-hit td:first-child { box-shadow: inset 3px 0 0 var(--accent); }

/* ---------- halfshot (halfshot.html) ---------- */

/* The console is a plate beside an island, and the plate is the Blueprint's
   whole drawing; at the site's usual column width it would scroll sideways on
   every screen. This one section is allowed wider, and the grid gives the plate
   two thirds of it. */
.hs-wide { max-width: 100rem; }

/* The strip: one tick per frame, grouped under the instruction it belongs to.
   It scrolls sideways inside its own box, never widening the page, and the
   current frame is scrolled into view rather than the strip re-laid. */
.hs-strip {
  display: flex; gap: .55rem; align-items: flex-end;
  overflow-x: auto; overflow-y: hidden; padding: .7rem .9rem .5rem;
  border-bottom: 2px solid var(--line); background: var(--surface);
  scrollbar-width: thin;
}
.hs-op { flex: 0 0 auto; display: flex; flex-direction: column; gap: .25rem; }
.hs-op-label { font-size: .6rem; color: var(--muted); white-space: nowrap; letter-spacing: .04em; }
.hs-op.reset .hs-op-label { color: var(--hot); }
.hs-op.gap { padding-left: .55rem; border-left: 2px dashed var(--hot); }
.hs-op.gap .hs-op-label { color: var(--hot); }
.hs-ticks { display: flex; gap: 2px; padding: 2px; border: 1px solid var(--line); border-radius: 3px; }
.hs-ticks i {
  display: block; width: 8px; height: 14px; border-radius: 1px;
  background: color-mix(in srgb, var(--line) 55%, transparent); cursor: pointer;
}
.hs-ticks i:nth-child(odd) { background: color-mix(in srgb, var(--line) 85%, transparent); }
.hs-ticks i:hover { background: var(--muted); }
.hs-ticks i.here { background: var(--accent); box-shadow: 0 0 0 1px var(--accent); }

/* The page's own program and clock selects, and where the chip is. */
.hs-controls { grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); }
.hs-machine { margin: 0; font-size: .74rem; color: var(--muted); line-height: 1.5;
  padding: .3rem 0; }
.hs-rec.on { border-color: var(--warn); color: var(--warn); }
.hs-rec.on::before { content: "●"; margin-right: .35rem; }
.hs-rec:not(.on) { color: var(--muted); }

/* The manual's figure, redrawn from the recording: the two clock phases, RDY,
   SYNC and the timing states across the frames either side of the cursor. */
.hs-scope { padding: .4rem .9rem 0; border-bottom: 2px solid var(--line); background: var(--surface);
  overflow-x: auto; }
.hs-scope .dm-scope { margin: 0 0 .3rem; min-width: 44rem; }

/* Centred rather than on the baseline, with a floor: the sync badge and the
   flags come and go from frame to frame, and on the baseline they changed the
   line box by a pixel, which the whole console below then inherited. */
.hs-head {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
  min-height: 2.75rem;
  padding: .6rem .9rem; margin: 0;
  border-bottom: 2px solid var(--line); background: var(--subtle);
  font-size: .8rem; color: var(--muted);
}
.hs-head b { color: var(--foreground); }

/* The plate on the left, the island on the right; stacked on a phone. The
   plate's minimum matches the blueprint's own drawing, which is wider than a
   phone and scrolls inside its stage. */
.hs-grid { display: grid; gap: .8rem; grid-template-columns: minmax(0, 1fr); padding: .8rem .9rem; }
@media (min-width: 72rem) {
  .hs-grid { grid-template-columns: minmax(0, 2fr) minmax(19rem, 1fr); }
}
.hs-plate { display: grid; gap: .6rem; min-width: 0; align-content: start; }
.hs-stage { padding: .4rem 0; border: 2px solid var(--line); border-radius: .3rem; background: #080c15; }
.hs-svg { display: block; width: 100%; min-width: 58rem; height: auto; }

/* Pins: the two buses as lamps with their hex beside them, then the control
   pins as level readouts. A pin that just changed is marked like a register. */
.hs-pins { display: grid; gap: .35rem; font-size: .74rem; }
.hs-bus { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap;
  padding: .3rem .5rem; border: 2px solid var(--line); border-radius: .3rem; background: var(--surface); }
.hs-bus b { font: 700 .62rem/1 var(--font-mono); letter-spacing: .1em; color: var(--muted); min-width: 1.6rem; }
.hs-bus .dm-lamps { margin-left: 0; }
.hs-hex { font: 800 .85rem/1 var(--font-mono); color: var(--gold); margin-left: .3rem; }
.hs-bus.moved { border-color: var(--accent); }
.hs-bus.moved .hs-hex { color: var(--accent); }
.hs-pinrow { display: flex; flex-wrap: wrap; gap: .3rem; }
.hs-pin { display: inline-flex; align-items: center; gap: .3rem; padding: .22rem .45rem;
  border: 2px solid var(--line); border-radius: .3rem; background: var(--surface); }
.hs-pin b { font: 700 .6rem/1 var(--font-mono); letter-spacing: .08em; color: var(--muted); }
.hs-pin i { font: 800 .7rem/1 var(--font-mono); font-style: normal; color: var(--muted);
  padding: .1rem .3rem; border-radius: .2rem; background: var(--subtle); }
.hs-pin.hi i { background: var(--accent); color: var(--accent-foreground); }
.hs-pin.moved { border-color: var(--accent); }

.hs-regs { display: grid; grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr)); gap: .4rem; }
.hs-regs .tr-reg-v { font-size: .92rem; }

/* Memory: the window around the last access, and what the program has written. */
.hs-mem { display: grid; gap: .3rem; padding: .5rem .6rem; border: 2px solid var(--line);
  border-radius: .3rem; background: var(--surface); font-size: .74rem; }
/* Both lines have a floor and centre their contents for the same reason as
   the head: what they hold changes size from frame to frame and the plate
   must not. */
.hs-memhead { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; min-height: 1.5rem; }
.hs-memhead b, .hs-written b { font: 700 .62rem/1 var(--font-mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); }
.hs-access { font: 700 .78rem/1 var(--font-mono); }
.hs-access.rd { color: var(--accent); }
.hs-access.wr { color: var(--hot); }
.hs-memrow { display: flex; gap: 3px; align-items: center; font-family: var(--font-mono); overflow-x: auto; }
.hs-memrow b { color: var(--muted); font-weight: 500; font-size: .66rem; min-width: 3.4rem; }
.hs-memrow i { font-style: normal; font-size: .72rem; padding: .08rem .18rem; border-radius: 2px;
  color: var(--foreground); background: var(--subtle); }
.hs-memrow i.hit.rd { background: var(--accent); color: var(--accent-foreground); font-weight: 800; }
.hs-memrow i.hit.wr { background: var(--hot); color: var(--accent-foreground); font-weight: 800; }
.hs-memrow i.last { box-shadow: inset 0 0 0 1px var(--muted); }
.hs-written { display: flex; flex-wrap: wrap; gap: .3rem .5rem; align-items: center; min-height: 1.5rem; }
.hs-w { font-size: .7rem; color: var(--hot); }
.hs-mem .muted, .hs-events .muted { color: var(--muted); }

/* The island: a small schematic on the same dark ground the workbench uses,
   sized to its drawing. */
.hs-island { min-width: 0; }
/* Beside the plate, the island is as tall as the plate and no taller: its
   contents scroll inside it. Its own height must not reach the grid row, or a
   frame with a long list of events would push the whole console taller and the
   page would jump on every step. So the row is sized by the plate alone and the
   island's contents are taken out of flow. On a phone the columns stack and it
   is in flow again. */
@media (min-width: 72rem) {
  .hs-island { position: relative; min-height: 0; padding: 0; margin-top: 0; }
  .hs-island-inner { position: absolute; inset: 0; overflow-y: auto; overscroll-behavior: contain;
    padding: .75rem .85rem; scrollbar-width: thin; }
}
.hs-island-stage { background: #080c15; border: 2px solid var(--line); border-radius: .3rem;
  overflow-x: auto; }
#hs-island-svg { display: block; width: 100%; min-height: 0; }
.hs-island .sch-switch.opened .sch-sw-plate, .hs-island .sch-switch.opened .sch-sw-gate { stroke: var(--accent); }
.hs-island .sch-switch.closed .sch-sw-plate { stroke: var(--warn); }
.hs-island .sch-switch.closed .sch-sw-gate { stroke: var(--warn); }
.hs-stats { font-size: .66rem; }
.hs-events ul { list-style: none; margin: .6rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; }
.hs-ev { padding: .35rem .5rem; border: 2px solid var(--line); border-radius: .3rem;
  background: var(--surface); font-size: .76rem; }
.hs-ev b { color: var(--foreground); }
.hs-ev.rd b { color: var(--accent); }
.hs-ev.wr b { color: var(--hot); }
.hs-ev.unit { border-color: var(--accent); }
.hs-ev.term.off { opacity: .7; }
.hs-ev.n { border-style: dashed; color: var(--muted); }

/* On the plate a unit whose stored value moved this frame, and a switch that
   changed state this frame, are marked so the eye finds them. */
.hs-svg .bp-block.moved .block-box { stroke: var(--accent); }
.hs-svg .bp-block.moved .block-value, .hs-svg .bp-rail.moved .rail-value { fill: var(--accent); }
.hs-svg .bp-edge.toggled .edge-switch { stroke: var(--hot); stroke-width: 3; }
.hs-svg .bp-edge.toggled .edge-label { fill: var(--hot); }

/* ---------------------------------------------------------------------------
   The tracer (tracer.html)
   ---------------------------------------------------------------------------
   The die graph with a clock. Node fill is the block colour, set inline from
   block-palette.js as the die graph does; level, change and watch are classes,
   because they change every half-cycle and a class is the cheapest thing to
   change on three thousand elements. */

.tc-grid { display: grid; gap: .8rem; grid-template-columns: minmax(0, 1fr); padding: .8rem .9rem; }
@media (min-width: 72rem) {
  .tc-grid { grid-template-columns: minmax(0, 1fr) minmax(21rem, 26rem); }
}
/* The whole circuit is the point, so the stage gets the height. On a wide
   screen the side column scrolls inside itself to match. */
.tc-stage { border: 2px solid var(--line); border-radius: .3rem; }
#tc-svg { width: 100%; height: min(82vh, 60rem); display: block; }
/* The side column is a flex column exactly the stage's height on a wide
   screen: everything above the moved list keeps its size (flex-shrink 0), the
   code box has a fixed height, and the moved list takes what is left and
   scrolls inside itself. The first version was a grid stretched to the stage's
   height, and a scroll box's automatic minimum is zero, so the grid squeezed
   the code box to one line to fit the rest. Measured, then rebuilt. */
.tc-side { display: flex; flex-direction: column; gap: .6rem; min-width: 0; }
.tc-side > * { flex: 0 0 auto; }
.tc-moved-wrap { flex: 1 1 auto; min-height: 8rem; }
@media (min-width: 72rem) {
  .tc-side { height: min(82vh, 60rem); }
}
.tc-controls { grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
.tc-watch-field { grid-column: 1 / -1; }
.tc-watch-row { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.tc-watch-row input { flex: 1 1 14rem; min-width: 0; font-size: 16px; }
.tc-controls .bk-dirs { flex-wrap: wrap; }
.tc-controls .btn[aria-pressed="true"] { border-color: var(--hot); color: var(--hot); }
#tc-picked { font-size: .76rem; overflow-wrap: anywhere; }

/* Edges. A gate edge reaches an output; a switch edge joins two wires. A
   switch is bright while its control is high (the two wires are one wire), and
   marked when the control just moved; a gate edge flashes when its output did. */
.tc-e { stroke-width: 3; }
.tc-e-gate { stroke: color-mix(in srgb, var(--line) 40%, transparent); }
.tc-e-gate.fired { stroke: color-mix(in srgb, var(--hot) 75%, transparent); stroke-width: 5; }
.tc-e-switch { stroke: color-mix(in srgb, var(--accent) 28%, transparent); stroke-width: 5; }
.tc-e-switch.on { stroke: color-mix(in srgb, var(--accent) 80%, transparent); stroke-width: 7; }
.tc-e-switch.tog { stroke: var(--hot); stroke-width: 9; }

/* The block regions behind the graph: a tinted, outlined union of discs per
   block in its own hue (block-regions.js). Pointer-transparent, so a click
   still reaches the node under it; the label goes when node labels arrive,
   because by then the reader is inside one block. */
.tc-regions.off { display: none; }
.tc-rg { fill: color-mix(in srgb, var(--bc) 10%, transparent); stroke: color-mix(in srgb, var(--bc) 38%, transparent);
         stroke-width: 9; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-rg:hover { fill: color-mix(in srgb, var(--bc) 16%, transparent); }
/* A selected block: its region brightens and everything else steps back. A
   node of the block is lit wherever it sits, an edge with either end in it
   stays, because that edge is the block's boundary. */
.tc-rg.sel { fill: color-mix(in srgb, var(--bc) 20%, transparent); stroke: color-mix(in srgb, var(--bc) 85%, transparent); stroke-width: 16; }
.tc-cam.has-sel .tc-rg:not(.sel) { fill: color-mix(in srgb, var(--bc) 4%, transparent); stroke: color-mix(in srgb, var(--bc) 14%, transparent); }
.tc-cam.has-sel .tc-rg-lb:not(.sel) { opacity: .3; }
.tc-cam.has-sel .tc-n.sel-out { opacity: .12; }
.tc-cam.has-sel .tc-n.sel-out.chg, .tc-cam.has-sel .tc-n.sel-out.wt, .tc-cam.has-sel .tc-n.sel-out.on-pick { opacity: .45; }
.tc-cam.has-sel .tc-e.sel-out { opacity: .12; }
.tc-cam.has-sel .tc-lb.sel-out { opacity: .3; }
/* The static-logic clusters: dashed, tinted by the block they drive, counted
   only once the reader is zoomed in. */
.tc-cluster-regions.off { display: none; }
.tc-cg { fill: color-mix(in srgb, var(--bc) 7%, transparent); stroke: color-mix(in srgb, var(--bc) 55%, transparent);
         stroke-width: 6; stroke-dasharray: 22 14; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-cg:hover { fill: color-mix(in srgb, var(--bc) 14%, transparent); }
.tc-cg.sel { fill: color-mix(in srgb, var(--bc) 18%, transparent); stroke: var(--bc); stroke-width: 12; stroke-dasharray: none; }
.tc-cam.has-sel .tc-cg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 16%, transparent); fill: none; }
.tc-cl-lb { display: none; font: 700 54px var(--font-mono); fill: color-mix(in srgb, var(--bc) 85%, transparent); text-anchor: middle;
            dominant-baseline: middle; pointer-events: none; paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 8px; }
.tc-cam.z-labels .tc-cl-lb, .tc-cl-lb.sel { display: block; }
.tc-cam.has-sel .tc-cl-lb:not(.sel) { opacity: .3; }
.tc-bk-drive { color: var(--foreground); font-weight: 700; }

/* The decode terms by stage: beads coloured by stage, labelled on the largest run. */
.tc-stage-regions.off { display: none; }
.tc-tg { fill: color-mix(in srgb, var(--bc) 22%, transparent); stroke: color-mix(in srgb, var(--bc) 70%, transparent);
         stroke-width: 5; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-tg:hover { fill: color-mix(in srgb, var(--bc) 35%, transparent); }
.tc-tg.sel { fill: color-mix(in srgb, var(--bc) 45%, transparent); stroke: var(--bc); stroke-width: 10; }
.tc-cam.has-sel .tc-tg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 6%, transparent); }
.tc-tg-lb { font: 800 90px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-tg-lb { font-size: 50px; stroke-width: 8px; }
.tc-cam.has-sel .tc-tg-lb:not(.sel) { opacity: .3; }
#tc-block .tc-node { font-size: .72rem; }

/* The control lines by the unit they operate: dotted, in the unit's hue. */
.tc-control-regions.off { display: none; }
.tc-kg { fill: color-mix(in srgb, var(--bc) 14%, transparent); stroke: color-mix(in srgb, var(--bc) 80%, transparent);
         stroke-width: 7; stroke-dasharray: 4 12; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-kg:hover { fill: color-mix(in srgb, var(--bc) 24%, transparent); }
.tc-kg.sel { fill: color-mix(in srgb, var(--bc) 30%, transparent); stroke: var(--bc); stroke-width: 12; stroke-dasharray: none; }
.tc-cam.has-sel .tc-kg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: none; }
.tc-kg-lb { display: none; font: 700 60px var(--font-mono); fill: var(--bc); text-anchor: middle; dominant-baseline: middle;
            pointer-events: none; paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 9px; }
.tc-cam.z-labels .tc-kg-lb, .tc-kg-lb.sel { display: block; }
.tc-cam.has-sel .tc-kg-lb:not(.sel) { opacity: .3; }

/* Collapsed containers: one node at the mean of its members, lit by the share
   high, ringed if any member changed; bundles as wide as the edges they stand
   for. Hidden members and edges keep their elements and their classes. */
.tc-n.hid, .tc-lb.hid, .tc-e.hid { display: none; }
.tc-sn { stroke: color-mix(in srgb, var(--foreground) 70%, transparent); stroke-width: 6; cursor: pointer; }
.tc-sn.chg { stroke: var(--hot); stroke-width: 22; }
.tc-sn.sel { stroke: var(--foreground); stroke-width: 26; }
.tc-sn:hover { stroke: var(--foreground); stroke-width: 16; }
.tc-sn.sel-out, .tc-sn-lb.sel-out { opacity: .2; }
.tc-sn-lb { font: 800 64px var(--font-sans); fill: var(--foreground); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .8); stroke-width: 10px; }
.tc-bundle { stroke: color-mix(in srgb, var(--line) 70%, transparent); stroke-linecap: round; }
.tc-bundle.sw { stroke: color-mix(in srgb, var(--accent) 60%, transparent); }
.tc-bundle.fired { stroke: var(--hot); }
.tc-bundle.sel-out { opacity: .12; }

/* The timing chain as cells: long-dashed beads in the stage's hue, named by the output. */
.tc-chain-regions.off { display: none; }
.tc-hg { fill: color-mix(in srgb, var(--bc) 18%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 6; stroke-dasharray: 28 10; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-hg:hover { fill: color-mix(in srgb, var(--bc) 30%, transparent); }
.tc-hg.sel { fill: color-mix(in srgb, var(--bc) 42%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-hg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-hg-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-hg-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-hg-lb:not(.sel) { opacity: .3; }
#tc-block .tc-bk-active { color: var(--hot); }

/* The clock generator: one bright outline around the circuit the designer page derives. */
.tc-clock-regions.off { display: none; }
.tc-qg { fill: color-mix(in srgb, var(--bc) 10%, transparent); stroke: color-mix(in srgb, var(--bc) 85%, transparent);
         stroke-width: 8; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-qg:hover { fill: color-mix(in srgb, var(--bc) 20%, transparent); }
.tc-qg.sel { fill: color-mix(in srgb, var(--bc) 30%, transparent); stroke: var(--bc); stroke-width: 14; }
.tc-cam.has-sel .tc-qg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 25%, transparent); fill: none; }
.tc-qg-lb { font: 800 96px var(--font-sans); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 16px; }
.tc-cam.z-labels .tc-qg-lb { font-size: 50px; stroke-width: 8px; }
.tc-cam.has-sel .tc-qg-lb:not(.sel) { opacity: .3; }

/* The interrupt logic: double-ringed beads, one hue per pin path, the go and the vector. */
.tc-intr-regions.off { display: none; }
.tc-ig { fill: color-mix(in srgb, var(--bc) 16%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 3 6; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-ig:hover { fill: color-mix(in srgb, var(--bc) 28%, transparent); }
.tc-ig.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-ig:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-ig-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-ig-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-ig-lb:not(.sel) { opacity: .3; }

/* The branch logic: dash-dot beads, taken / direction / cross each in its own hue. */
.tc-branch-regions.off { display: none; }
.tc-bg { fill: color-mix(in srgb, var(--bc) 16%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 16 7 3 7; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-bg:hover { fill: color-mix(in srgb, var(--bc) 28%, transparent); }
.tc-bg.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-bg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-bg-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-bg-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-bg-lb:not(.sel) { opacity: .3; }

/* The decimal correction: one orange outline around everything the decimal names are wired into. */
.tc-decimal-regions.off { display: none; }
.tc-dg { fill: color-mix(in srgb, var(--bc) 10%, transparent); stroke: color-mix(in srgb, var(--bc) 80%, transparent);
         stroke-width: 7; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-dg:hover { fill: color-mix(in srgb, var(--bc) 20%, transparent); }
.tc-dg.sel { fill: color-mix(in srgb, var(--bc) 30%, transparent); stroke: var(--bc); stroke-width: 13; }
.tc-cam.has-sel .tc-dg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 25%, transparent); fill: none; }
.tc-dg-lb { font: 800 96px var(--font-sans); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 16px; }
.tc-cam.z-labels .tc-dg-lb { font-size: 50px; stroke-width: 8px; }
.tc-cam.has-sel .tc-dg-lb:not(.sel) { opacity: .3; }

/* The registers: square-dotted beads, each register and its lines in the register's hue. */
.tc-reg-regions.off { display: none; }
.tc-xg { fill: color-mix(in srgb, var(--bc) 16%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 6 8; stroke-linecap: square; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-xg:hover { fill: color-mix(in srgb, var(--bc) 28%, transparent); }
.tc-xg.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-xg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-xg-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-xg-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-xg-lb:not(.sel) { opacity: .3; }

/* The program counter's incrementer: one red outline between the counter and its next value. */
.tc-incr-regions.off { display: none; }
.tc-ng { fill: color-mix(in srgb, var(--bc) 9%, transparent); stroke: color-mix(in srgb, var(--bc) 80%, transparent);
         stroke-width: 7; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-ng:hover { fill: color-mix(in srgb, var(--bc) 18%, transparent); }
.tc-ng.sel { fill: color-mix(in srgb, var(--bc) 28%, transparent); stroke: var(--bc); stroke-width: 13; }
.tc-cam.has-sel .tc-ng:not(.sel) { stroke: color-mix(in srgb, var(--bc) 25%, transparent); fill: none; }
.tc-ng-lb { font: 800 96px var(--font-sans); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 16px; }
.tc-cam.z-labels .tc-ng-lb { font-size: 50px; stroke-width: 8px; }
.tc-cam.has-sel .tc-ng-lb:not(.sel) { opacity: .3; }

/* The flags: ringed beads (a double stroke), one hue per flag, white for the shared enables, cyan for P out. */
.tc-flag-regions.off { display: none; }
.tc-fg { fill: color-mix(in srgb, var(--bc) 16%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 1 5; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-fg:hover { fill: color-mix(in srgb, var(--bc) 28%, transparent); }
.tc-fg.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-fg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-fg-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-fg-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-fg-lb:not(.sel) { opacity: .3; }

/* The address latches: blue beads for the halves and their load lines, violet for the constants. */
.tc-alat-regions.off { display: none; }
.tc-ag { fill: color-mix(in srgb, var(--bc) 14%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 10 4 2 4; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-ag:hover { fill: color-mix(in srgb, var(--bc) 26%, transparent); }
.tc-ag.sel { fill: color-mix(in srgb, var(--bc) 38%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-ag:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-ag-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-ag-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-ag-lb:not(.sel) { opacity: .3; }

/* The ALU: beads in a hue per bit, the inputs, ends and line groups in their own. */
.tc-alu-regions.off { display: none; }
.tc-ug { fill: color-mix(in srgb, var(--bc) 15%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 2 2; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-ug:hover { fill: color-mix(in srgb, var(--bc) 27%, transparent); }
.tc-ug.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-ug:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-ug-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-ug-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-ug-lb:not(.sel) { opacity: .3; }

/* The data latch and bus: teal, orange, pale blue, magenta beads. */
.tc-dbus-regions.off { display: none; }
.tc-vg { fill: color-mix(in srgb, var(--bc) 15%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 12 3 3 3; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-vg:hover { fill: color-mix(in srgb, var(--bc) 27%, transparent); }
.tc-vg.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-vg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-vg-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-vg-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-vg-lb:not(.sel) { opacity: .3; }

/* The instruction register and predecode: gold, teal, white and violet beads. */
.tc-irp-regions.off { display: none; }
.tc-ig2 { fill: color-mix(in srgb, var(--bc) 15%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
          stroke-width: 5; stroke-dasharray: 8 5; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-ig2:hover { fill: color-mix(in srgb, var(--bc) 27%, transparent); }
.tc-ig2.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-ig2:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-ig2-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
             paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-ig2-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-ig2-lb:not(.sel) { opacity: .3; }

/* The special bus: gold beads for the bits and the adjusted copy, green and blue for the lines by direction. */
.tc-sbus-regions.off { display: none; }
.tc-yg { fill: color-mix(in srgb, var(--bc) 15%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 4 4 12 4; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-yg:hover { fill: color-mix(in srgb, var(--bc) 27%, transparent); }
.tc-yg.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-yg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-yg-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-yg-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-yg-lb:not(.sel) { opacity: .3; }

/* The store-data pipeline: amber beads for the detect and the two latches. */
.tc-sdp-regions.off { display: none; }
.tc-wg { fill: color-mix(in srgb, var(--bc) 15%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
         stroke-width: 5; stroke-dasharray: 14 6; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-wg:hover { fill: color-mix(in srgb, var(--bc) 27%, transparent); }
.tc-wg.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-wg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-wg-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-wg-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-wg-lb:not(.sel) { opacity: .3; }

/* The ready logic: sky beads for the receiver, the master and the copies. */
.tc-rdy-regions.off { display: none; }
.tc-rg2 { fill: color-mix(in srgb, var(--bc) 15%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
          stroke-width: 5; stroke-dasharray: 6 3; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-rg2:hover { fill: color-mix(in srgb, var(--bc) 27%, transparent); }
.tc-rg2.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-rg2:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-rg2-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
             paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-rg2-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-rg2-lb:not(.sel) { opacity: .3; }

/* The last three: the PC's bytes, the pipe latch file, the SYNC generator. */
.tc-pcr-regions.off, .tc-pipe-regions.off, .tc-sync-regions.off { display: none; }
.tc-pg2, .tc-pp, .tc-sy { fill: color-mix(in srgb, var(--bc) 15%, transparent); stroke: color-mix(in srgb, var(--bc) 75%, transparent);
          stroke-width: 5; stroke-dasharray: 9 4; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-pp { stroke-dasharray: 3 4; }
.tc-sy { stroke-dasharray: 1 8; stroke-width: 7; }
.tc-pg2:hover, .tc-pp:hover, .tc-sy:hover { fill: color-mix(in srgb, var(--bc) 27%, transparent); }
.tc-pg2.sel, .tc-pp.sel, .tc-sy.sel { fill: color-mix(in srgb, var(--bc) 40%, transparent); stroke: var(--bc); stroke-width: 11; stroke-dasharray: none; }
.tc-cam.has-sel .tc-pg2:not(.sel), .tc-cam.has-sel .tc-pp:not(.sel), .tc-cam.has-sel .tc-sy:not(.sel) { stroke: color-mix(in srgb, var(--bc) 20%, transparent); fill: color-mix(in srgb, var(--bc) 5%, transparent); }
.tc-pg2-lb, .tc-pp-lb, .tc-sy-lb { font: 800 80px var(--font-mono); fill: var(--bc); text-anchor: middle; pointer-events: none;
             paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 14px; }
.tc-cam.z-labels .tc-pg2-lb, .tc-cam.z-labels .tc-pp-lb, .tc-cam.z-labels .tc-sy-lb { font-size: 46px; stroke-width: 8px; }
.tc-cam.has-sel .tc-pg2-lb:not(.sel), .tc-cam.has-sel .tc-pp-lb:not(.sel), .tc-cam.has-sel .tc-sy-lb:not(.sel) { opacity: .3; }

/* The pins by measured direction: a halo on each pad, in the direction's hue. */
.tc-pin-regions.off { display: none; }
.tc-pg { fill: color-mix(in srgb, var(--bc) 9%, transparent); stroke: color-mix(in srgb, var(--bc) 55%, transparent);
         stroke-width: 7; stroke-dasharray: 2 10; stroke-linecap: round; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-pg:hover { fill: color-mix(in srgb, var(--bc) 18%, transparent); }
.tc-pg.sel { fill: color-mix(in srgb, var(--bc) 26%, transparent); stroke: var(--bc); stroke-width: 12; stroke-dasharray: none; }
.tc-cam.has-sel .tc-pg:not(.sel) { stroke: color-mix(in srgb, var(--bc) 16%, transparent); fill: none; }
.tc-pg-lb { font: 800 110px var(--font-sans); fill: var(--bc); text-anchor: middle; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .75); stroke-width: 16px; }
.tc-cam.z-labels .tc-pg-lb { font-size: 54px; stroke-width: 8px; }
.tc-cam.has-sel .tc-pg-lb:not(.sel) { opacity: .3; }
#tc-block .tc-node.tc-mv { outline: 2px solid var(--hot); }

/* The bus and latch capsules: thinner, in the watch colour, named above. */
.tc-stem-regions.off { display: none; }
.tc-sg { fill: color-mix(in srgb, var(--gold) 6%, transparent); stroke: color-mix(in srgb, var(--gold) 65%, transparent);
         stroke-width: 8; stroke-linejoin: round; pointer-events: visibleFill; cursor: pointer; outline: none; }
.tc-sg:hover { fill: color-mix(in srgb, var(--gold) 12%, transparent); }
.tc-sg.sel { fill: color-mix(in srgb, var(--gold) 16%, transparent); stroke: var(--gold); stroke-width: 12; }
.tc-cam.has-sel .tc-sg:not(.sel) { stroke: color-mix(in srgb, var(--gold) 14%, transparent); fill: none; }
.tc-sg-lb { font: 700 110px var(--font-mono); fill: color-mix(in srgb, var(--gold) 80%, transparent); text-anchor: middle;
            pointer-events: none; paint-order: stroke; stroke: rgba(2, 6, 16, .7); stroke-width: 16px; }
.tc-sg-lb.sel { fill: var(--gold); }
.tc-cam.has-sel .tc-sg-lb:not(.sel) { opacity: .3; }
.tc-cam.z-labels .tc-sg-lb { font-size: 60px; stroke-width: 9px; }
.tc-bk-val { color: var(--gold); font-weight: 800; }
.tc-bk-watch, .tc-bk-collapse { font: inherit; color: var(--gold); background: none; border: 1px solid var(--line); border-radius: .25rem;
               padding: 0 .35rem; cursor: pointer; }
.tc-bk-watch:hover, .tc-bk-collapse:hover { border-color: var(--gold); }
.tc-bk-name { color: var(--foreground); font-weight: 800; }
.tc-bk-moved { color: var(--hot); font-weight: 800; }
#tc-block a { color: var(--gold); }
.tc-blk.sel h4 { color: var(--gold); }
.tc-blk.sel-out { opacity: .45; }
.tc-rg-lb { font: 800 170px var(--font-sans); fill: color-mix(in srgb, var(--bc) 75%, transparent);
            text-anchor: middle; dominant-baseline: middle; letter-spacing: .02em; pointer-events: none;
            paint-order: stroke; stroke: rgba(2, 6, 16, .7); stroke-width: 24px; }
.tc-cam.z-labels .tc-rg-lb { display: none; }

/* Nodes. Dark when low, lit when high; a ring for this half-cycle, a fainter
   ring for the last one. */
.tc-n { stroke: rgba(2, 6, 16, .6); stroke-width: 3; opacity: .38; }
.tc-n.hi { opacity: 1; }
/* A precharged (dynamic) gate output: pulled to vcc by a clocked transistor,
   then discharged or left holding charge. Dashed, because holding a level and
   being driven to one are different things and look the same otherwise. The
   dash is on the resting outline only; a ring for a change still wins. */
.tc-n.tc-pre { stroke: color-mix(in srgb, var(--foreground) 70%, transparent); stroke-width: 5; stroke-dasharray: 7 6; }
.tc-n.tc-pre.chg, .tc-n.tc-pre.was, .tc-n.tc-pre.wt, .tc-n.tc-pre.on-pick, .tc-n.tc-pre:hover { stroke-dasharray: none; }
.tc-n.was { stroke: color-mix(in srgb, var(--hot) 55%, transparent); stroke-width: 12; opacity: .8; }
.tc-n.chg { stroke: var(--hot); stroke-width: 20; opacity: 1; }
.tc-n.wt { stroke: var(--gold); stroke-width: 10; }
.tc-n.wt.chg { stroke: var(--hot); }
.tc-n.on-pick { stroke: var(--foreground); stroke-width: 22; }
.tc-n:hover { stroke: var(--foreground); stroke-width: 14; }
.tc-bus { fill: none; stroke: color-mix(in srgb, var(--gold) 45%, transparent); stroke-width: 4; stroke-dasharray: 26 18; pointer-events: none; }

/* Labels: watched bits and moved names always, every name when zoomed in. */
.tc-lb { display: none; font: 700 44px var(--font-mono); fill: var(--muted); pointer-events: none;
         paint-order: stroke; stroke: #080c15; stroke-width: 10px; }
.tc-lb.wt { display: block; fill: var(--gold); }
.tc-lb.chg { display: block; fill: var(--hot); }
.tc-cam.z-labels .tc-lb { display: block; }

/* Only what moved: everything else steps aside, the watch stays. */
.tc-cam.only .tc-n:not(.chg):not(.was):not(.wt):not(.on-pick) { display: none; }
.tc-cam.only .tc-e:not(.fired):not(.tog) { display: none; }
.tc-cam.only .tc-lb:not(.chg):not(.wt) { display: none; }

/* Fullscreen is the study view, as the workbench has it: the console covers
   the viewport (the shared .immersive/.faux rules), the stage takes all of it,
   and the controls ride on the floating strip-and-drawer console (the shared
   .solo-palette rules, built by solo-palette.js). `.console.solo` is the same
   class the schematic uses for the mode, so the bar and the control fields
   hide under the rules already written for it. #bench needs lifting like #view
   does: every .wrap is its own stacking context. */
body.no-scroll #bench { z-index: 70; }
.console.solo .tc-grid { display: flex; flex: 1; min-height: 0; padding: 0; gap: 0; }
.console.solo .tc-stage {
  flex: 1; min-height: 0; position: relative;
  border: 0; border-radius: 0; background: #05070d;
}
.console.solo #tc-svg { height: 100%; }
.console.solo .tc-side, .console.solo #tc-caption { display: none; }

/* The drawers show the side column's own elements, borrowed, so the rules
   below are the few places their sizes differ in a drawer from in a column:
   the listing and the moved list can be tall, because the panel scrolls as a
   whole and the drawer is capped to the stage; the controls are toolbar-sized
   rather than hero-sized. */
.sp-panel .tc-head { margin-bottom: .5rem; }
.sp-panel .tc-code { height: auto; max-height: min(60vh, 30rem); margin-top: 0; }
.sp-panel .tc-moved { max-height: min(55vh, 28rem); margin-top: .3rem; }
/* Out of .sch-controls a .field is a flex row; in a drawer the label belongs
   above its control, as it does on the page. */
.sp-panel .field { display: grid; grid-template-columns: minmax(0, 1fr); gap: .25rem; align-items: start; }
.sp-panel .tc-watch-field { margin-bottom: .5rem; }
.sp-panel .tc-watch-field > span,
.sp-panel #tc-picked-field > span {
  display: block; font: 700 .58rem/1.6 var(--font-mono); letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
/* The listing needs its columns: a 20rem drawer cuts the source off. */
.solo-palette[data-open="code"] .sp-drawer { width: min(27rem, 70vw); }
.sp-panel .tc-watch-row input { font-size: 16px; }
.sp-panel .bk-dirs { flex-wrap: wrap; }
.sp-panel .btn { min-height: 0; padding: .3rem .5rem; font-size: .7rem; }
.sp-panel #tc-modes { margin-bottom: .6rem; }
.sp-panel .tc-zoomctl { display: flex; align-items: center; gap: .35rem; margin-bottom: .6rem; }
.sp-panel #tc-zoom { min-width: 2.6rem; font-size: .7rem; }
.sp-panel #tc-picked { display: block; font-size: .72rem; }
.tc-zoomctl { display: inline-flex; align-items: center; gap: .35rem; }

/* The side column. */
.tc-head {
  padding: .55rem .7rem; border: 2px solid var(--line); border-radius: .4rem; background: var(--subtle);
  font-size: .78rem; color: var(--muted); line-height: 1.7; min-height: 2.6rem;
}
.tc-head b { color: var(--foreground); }
.tc-sep { color: var(--line); }
.tc-span { color: var(--hot); }
.tc-transport { flex-wrap: wrap; }
.tc-regs { display: grid; grid-template-columns: repeat(auto-fit, minmax(4.4rem, 1fr)); gap: .35rem; }
.tc-reg { padding: .35rem .45rem; border: 2px solid var(--line); border-radius: .3rem; background: var(--surface); min-width: 0; }
.tc-reg.moved { border-color: var(--hot); }
.tc-reg-k { display: block; font: 700 .58rem/1 var(--font-mono); letter-spacing: .1em; color: var(--muted); text-transform: uppercase; }
.tc-reg-v { display: block; font: 800 .92rem/1.3 var(--font-mono); color: var(--foreground); overflow-wrap: anywhere; }
.tc-reg.moved .tc-reg-v { color: var(--hot); }
.tc-reg-flags { grid-column: 1 / -1; }

.tc-watch { display: grid; gap: .25rem; }
.tc-w {
  display: flex; align-items: center; gap: .5rem; width: 100%; text-align: left;
  padding: .3rem .5rem; border: 2px solid var(--line); border-radius: .3rem;
  background: var(--surface); color: var(--foreground); cursor: pointer; font: inherit;
}
.tc-w:hover { border-color: var(--gold); }
.tc-w-none { cursor: default; color: var(--muted); border-style: dashed; }
.tc-w-k { font-weight: 800; font-size: .74rem; min-width: 2.6rem; color: var(--gold); }
.tc-w-v { margin-left: auto; font-weight: 800; font-size: .8rem; }
.tc-w-note { font-size: .7rem; }
.tc-lamps { display: inline-flex; flex-wrap: wrap; gap: 1px; }
.tc-lamps i {
  font: 700 .5rem/1 var(--font-mono); font-style: normal;
  width: .74rem; padding: .2rem 0; text-align: center;
  color: #4a5a78; background: var(--subtle); border-radius: 1px;
}
.tc-lamps i.on { color: var(--accent-foreground); background: var(--accent); }
.tc-lamps i.moved { box-shadow: 0 0 0 2px var(--hot); }
.tc-lamps i.none { color: var(--line); background: transparent; }

.tc-code {
  border: 2px solid var(--line); border-radius: .3rem; background: #080c15;
  height: 13rem; overflow: auto; font-size: .72rem; padding: .3rem 0;
}
.tc-code-title { padding: .2rem .6rem .35rem; font: 700 .62rem/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.tc-row { display: grid; grid-template-columns: 1.6rem 3.4rem 5.4rem minmax(0, 1fr); gap: .4rem; padding: .12rem .6rem; align-items: baseline; }
.tc-row.cur { background: color-mix(in srgb, var(--hot) 22%, transparent); }
.tc-row.cur .tc-c-src { color: var(--hot); }
.tc-c-n { color: var(--muted); font-size: .62rem; text-align: right; }
.tc-c-addr { color: var(--accent); }
.tc-c-bytes { color: var(--muted); }
.tc-c-src { color: var(--foreground); white-space: pre; overflow: hidden; text-overflow: ellipsis; font-family: var(--font-mono); }
.tc-row:not(.has-op) .tc-c-src { color: var(--muted); }

.tc-moved-wrap { display: flex; flex-direction: column; gap: .3rem; }
.tc-moved-sum { margin: 0; font-size: .68rem; color: var(--muted); }
.tc-moved { display: flex; flex-direction: column; gap: .45rem; flex: 1 1 auto; min-height: 6rem; overflow: auto; }
@media (max-width: 71.99rem) { .tc-moved { max-height: 22rem; } }
.tc-blk h4 { margin: 0 0 .2rem; font-size: .64rem; color: var(--muted); text-transform: uppercase; letter-spacing: .08em; }
.tc-blk h4 span { color: var(--foreground); margin-left: .3rem; }
.tc-blk p { margin: 0; line-height: 1.9; }
.tc-node {
  font: 700 .62rem/1 var(--font-mono); padding: .16rem .3rem; margin: 0 .15rem .15rem 0;
  border: 0; border-radius: .2rem; background: var(--subtle); color: var(--muted);
  white-space: nowrap; cursor: pointer;
}
.tc-node:hover { outline: 2px solid var(--gold); }
.tc-node.up { color: var(--accent); }
.tc-node.down { color: var(--muted); }
.tc-node i { font-style: normal; opacity: .7; margin-left: .1rem; }
.tc-node.tc-unnamed { cursor: default; color: var(--line); }

/* --- The chip map: the whole chip as one schematic (chipmap.html) --------- */
/* The stage borrows .dg-stage; only the svg's height is its own, because the
   drawing is wider than tall (sixteen columns of pin distance). */
#cm-svg { width: 100%; height: min(78vh, 52rem); display: block; }

.cm-bd {
  stroke: color-mix(in srgb, var(--line) 60%, transparent);
  opacity: var(--bw, 0.2);
}
.cm-bd-sw { stroke: color-mix(in srgb, var(--accent) 55%, transparent); }
.cm-bd.open { stroke: var(--accent); }
.cm-bd.fired { stroke: var(--gold); opacity: 0.9; }
/* With a selection the drawing answers for it: its bundles read, the rest recede. */
#cm-svg.has-sel .cm-bd { opacity: 0.05; }
#cm-svg.has-sel .cm-bd.sel { opacity: 0.95; }

.cm-box { cursor: pointer; }
.cm-box .cm-bg {
  fill: color-mix(in srgb, var(--surface) 82%, #000);
  stroke: var(--line); stroke-width: 1.2;
}
/* The live overlay: the share of the group's members high right now. */
.cm-box .cm-hi { fill: var(--accent); fill-opacity: var(--hi, 0); pointer-events: none; }
.cm-box.mv .cm-bg { stroke: var(--gold); stroke-width: 2; }
.cm-box.sel .cm-bg { stroke: var(--foreground); stroke-width: 2.5; }
#cm-svg.has-sel .cm-box:not(.sel):not(.adj) { opacity: 0.35; }
.cm-box:hover .cm-bg { stroke: var(--gold); }
.cm-kind {
  fill: var(--muted); font: 700 8px var(--font-mono, monospace);
  letter-spacing: 0.06em; text-transform: uppercase; pointer-events: none;
}
.cm-name { fill: var(--foreground); font: 600 10px var(--font-mono, monospace); pointer-events: none; }

.cm-card { padding: 0.7rem 1rem; border-top: 1px solid var(--line); }
.cm-card p { margin: 0 0 0.4rem; }
.cm-card-head b { color: var(--gold); }
.cm-pill {
  font: 500 11px var(--font-mono, monospace);
  color: var(--foreground); background: color-mix(in srgb, var(--surface) 70%, #000);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0.1rem 0.55rem; margin: 0 0.15rem 0.25rem 0; cursor: pointer;
}
.cm-pill:hover { border-color: var(--gold); color: var(--gold); }

/* The chip map's guided tour panel, inside the map's own console. */
.cmt-panel { border-top: 1px solid var(--line); padding: 0.8rem 1rem; }
.cmt-cols { display: grid; grid-template-columns: minmax(11rem, 16rem) minmax(0, 1fr); gap: 1.2rem; }
@media (max-width: 52rem) { .cmt-cols { grid-template-columns: minmax(0, 1fr); } }
.cmt-src {
  margin: 0; padding: 0.6rem 0.8rem; font-size: 0.78rem; line-height: 1.5;
  border: 1px solid var(--line); border-radius: 0.4rem;
  background: color-mix(in srgb, var(--space) 70%, #000); overflow-x: auto;
}
.cmt-body h3 { margin: 0.1rem 0 0.35rem; }
.cmt-body p { margin: 0 0 0.5rem; }
.cmt-check { display: flex; gap: 0.45rem; font-size: 0.85rem; margin: 0 0 0.25rem; }
.cmt-check.held .cmt-mark { color: var(--mint); font-weight: 700; }
.cmt-check.broke { color: var(--hot); }
.cmt-check.broke .cmt-mark { color: var(--hot); font-weight: 700; }
.cmt-nav { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* The chip map's opened boxes: member nodes snapped to a grid. A square holds
   switches (filled while they conduct); a dot is any other node, lit while
   high, ringed while it just changed. */
.cm-nd { fill: color-mix(in srgb, var(--muted) 40%, transparent); stroke: none; }
.cm-nd.on { fill: var(--accent); }
.cm-sw { fill: none; stroke: color-mix(in srgb, var(--foreground) 55%, transparent); stroke-width: 1.2; }
.cm-sw.on { fill: var(--accent); stroke: var(--accent); }
.cm-nd.mv, .cm-sw.mv { stroke: var(--gold); stroke-width: 1.6; }

/* The chip map's study view: the drawing covers the viewport and the
   controls ride on the floating console, the tracer's arrangement. */
.console.solo > .console-bar, .console.solo > .bk-foot,
.console.solo > .cm-card, .console.solo > .cmt-panel { display: none; }
.console.solo .cm-stage {
  flex: 1; min-height: 0; position: relative;
  border: 0; border-radius: 0;
}
.console.solo #cm-svg { height: 100%; }
/* Borrowed into a drawer, the page's own elements shed their page framing. */
.sp-panel .cm-card { border-top: 0; padding: 0.2rem 0; }
.sp-panel .cmt-panel { border-top: 0; padding: 0.2rem 0; }
.sp-panel .cmt-cols { grid-template-columns: minmax(0, 1fr); gap: 0.6rem; }
.sp-panel .cmt-src { max-height: 9rem; overflow: auto; }

/* The chip map's key: drawn with the drawing's own classes, on the page's
   own background so the resting states read as they do on the stage. */
.cm-key { display: grid; gap: 0.35rem; margin: 1rem 0; }
.cm-key-row {
  display: flex; align-items: center; gap: 0.8rem;
  font-size: 0.85rem; color: var(--muted);
}
/* The samples' live values, scoped: an inline style attribute would be the
   exact CSP violation the tracer shipped with once. */
.cm-key .cm-hi { fill-opacity: 0.35; }
.cm-key .cm-bd { opacity: 0.5; }
.cm-key .cm-bd.open, .cm-key .cm-bd.fired { opacity: 0.9; }
.cm-key-row svg {
  flex: 0 0 auto; width: 3.4rem; height: 1.1rem; overflow: visible;
  background: color-mix(in srgb, var(--space) 70%, #000);
  border: 1px solid var(--line); border-radius: 0.25rem;
}
