:root {
  --canvas-bg: #ffffff;
  --terminal-bg: #f8f9fa;
  --terminal-text: #24292e;
  --panel-bg: #ffffff;
  --slot-bg: #e1e4e8;
  --slot-border-light: #ffffff;
  --slot-border-dark: #959da5;
  --border-color: #d1d5da;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html,
body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  /* Rubber-banding on iOS drags the whole document under the browser
     chrome, which is one of the ways the footer went missing. Nothing here
     scrolls, so there is nothing to lose by refusing the gesture. */
  overscroll-behavior: none;
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background-color: #f1f3f5;
}

/* Viewport height, in the only units a phone browser tells the truth in.
   100vh on iOS is the LARGE viewport — the page as it would be with the URL
   bar collapsed — so the last flex item in this column (#ro-bar) was laid
   out under Safari's chrome and clean off the bottom in Chrome iOS. 100svh
   is the SMALL viewport and is always on screen; --app-h, set from
   visualViewport by mobile.js, is exact where that exists. Each step only
   overrides the one before it in a browser that understands it, so an old
   one still gets 100vh. */
#app-container {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}
@supports (height: 100svh) {
  #app-container {
    height: 100svh;
    height: var(--app-h, 100svh);
  }
}

#canvas-wrapper {
  flex: 4;
  min-height: 0;
  position: relative;
  background-color: var(--canvas-bg);
  overflow: hidden;
}

canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
  touch-action: none;
}
canvas:active {
  cursor: grabbing;
}

/* HUD — semantic-zoom readout */
#hud {
  position: absolute;
  top: 10px;
  left: 12px;
  display: flex;
  gap: 8px;
  pointer-events: none;
  font-family: "Courier New", monospace;
  font-size: 11px;
}
#hud .tag {
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid var(--border-color);
  border-radius: 3px;
  padding: 5px 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #586069;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
#hud .tag b {
  color: #0366d6;
  font-weight: 600;
}

/* Toolbar — undo/redo + save/load, top-right of the canvas */
#toolbar {
  position: absolute;
  top: 10px;
  right: 12px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: "Courier New", monospace;
}
.tool-btn {
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid var(--border-color);
  border-radius: 4px;
  padding: 6px 10px;
  font-size: 13px;
  font-family: "Courier New", monospace;
  color: #24292e;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  transition:
    background 0.08s ease,
    opacity 0.08s ease;
}
.tool-btn:hover:not(:disabled) {
  background: #eef2f6;
}
.tool-btn:active:not(:disabled) {
  background: #dde3e9;
}
.tool-btn:disabled {
  opacity: 0.35;
  cursor: default;
}
.tool-btn-wide {
  padding: 6px 12px;
  letter-spacing: 0.02em;
}
.toolbar-sep {
  width: 1px;
  height: 18px;
  background: var(--border-color);
  margin: 0 2px;
}

/* Box-drawing tool cursor feedback */
canvas.box-tool-cursor {
  cursor: crosshair;
}

/* Alt-held cursor feedback: dragging a part will clone it, not move it */
canvas.clone-cursor {
  cursor: copy;
}

#tip {
  position: absolute;
  bottom: 10px;
  left: 12px;
  right: 12px;
  text-align: center;
  pointer-events: none;
  font-family: "Courier New", monospace;
  font-size: 10.5px;
  color: #6a737d;
  background: rgba(255, 255, 255, 0.8);
  padding: 4px;
  border-radius: 4px;
}

/* --- Terminal resize handle -----------------------------------------------
   A real flex item (not an overlay) between the canvas pane and the terminal.
   Dragging it sets an explicit pixel flex-basis on #terminal-container; main.js
   re-runs resize() on every move so the canvas backing store always matches its
   CSS box exactly — that is what guarantees nothing on the board distorts.    */
#terminal-resizer {
  flex: 0 0 9px;
  cursor: ns-resize;
  background: var(--terminal-bg);
  border-top: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: center;
  touch-action: none;
  transition: background 0.12s ease;
}
#terminal-resizer .grip {
  width: 46px;
  height: 3px;
  border-radius: 2px;
  background: #c3ccd5;
  transition: background 0.12s ease;
}
#terminal-resizer:hover .grip,
#terminal-resizer.dragging .grip {
  background: #0366d6;
}
#terminal-resizer.dragging {
  background: #eef4fb;
}
/* while dragging, keep the ns-resize cursor everywhere and stop the pointer
   selecting text or landing on the canvas */
body.resizing-terminal {
  cursor: ns-resize !important;
  user-select: none;
}

/* --- Three-column white terminal --- */
#terminal-container {
  flex: 1;
  min-height: 0;
  display: flex;
  border-top: 2px solid var(--border-color);
  background-color: var(--terminal-bg);
  color: var(--terminal-text);
  font-family: "Courier New", Courier, monospace;
  font-size: 14px;
}

/* left: system log */
#terminal-log {
  flex: 3;
  padding: 12px;
  overflow-y: auto;
  border-right: 2px solid var(--border-color);
  background-color: #ffffff;
}
.log-entry {
  margin-bottom: 8px;
  line-height: 1.5;
  color: #24292e;
  word-break: break-word;
}
.log-entry::before {
  content: "> ";
  color: #adb5bd;
}

/* log severity — a quick colour read on what just happened */
.log-entry.log-error {
  color: #cf222e;
}
.log-entry.log-success {
  color: #1a7f37;
}
.log-entry.log-warn {
  color: #9a6700;
}

/* component-id chips: a stable hue per id (hashed in logFormat.js) so the
   same part reads as the same colour everywhere in the log — this is what
   makes "what got wired to what" scannable at a glance. */
.log-chip {
  display: inline-block;
  padding: 0px 6px;
  border-radius: 4px;
  font-weight: 700;
  font-size: 12px;
  color: #ffffff;
  background: hsl(var(--chip-h) 62% 42%);
  white-space: nowrap;
}
.log-dot {
  color: #8a97a3;
  padding: 0 1px;
}
.log-pin {
  font-weight: 700;
  color: #0550ae;
  background: #ddf4ff;
  border-radius: 3px;
  padding: 0px 4px;
  font-size: 12px;
}
.log-type {
  color: #57606a;
  font-style: italic;
}
.log-arrow {
  color: #8a97a3;
  margin: 0 4px;
  font-weight: 700;
}

/* middle: toolbox (widest) */
#inventory-panel {
  flex: 6;
  min-width: 0;
  display: flex;
  flex-direction: column;
  border-right: 2px solid var(--border-color);
  background: var(--panel-bg);
}
.inv-header {
  font-size: 12px;
  color: #586069;
  letter-spacing: 0.16em;
  padding: 10px 12px 8px;
  border-bottom: 1px solid var(--border-color);
}
#inventory-grid {
  flex: 1;
  min-height: 0;
  padding: 12px;
  display: grid;
  grid-template-columns: repeat(auto-fill, 74px);
  /* min-content, not a fixed 74px: slot rows still come out at exactly 74px
     (slots are border-box with height:74px), but a full-width section heading
     row can collapse to its own text height instead of eating a whole slot
     row's worth of space. */
  grid-auto-rows: min-content;
  gap: 8px;
  overflow-y: auto;
  align-content: start;
}

/* Full-width divider between the toolbox's three sections: single components,
   discrete-logic gate assemblies, and modal drawing tools. */
.inv-section {
  grid-column: 1 / -1;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: #97a3af;
  padding-top: 4px;
}
.inv-section + .inv-section,
.slot + .inv-section {
  margin-top: 6px;
  padding-top: 10px;
  border-top: 1px solid var(--border-color);
}

/* Scrollbars stay fully functional (wheel / trackpad / keyboard scrolling
   all still work via overflow:auto) but are never visually shown, per the
   "scroll works, scrollbar invisible" requirement. */
#terminal-log,
#inventory-grid,
#terminal-state,
#load-list {
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* old Edge / IE */
}
#terminal-log::-webkit-scrollbar,
#inventory-grid::-webkit-scrollbar,
#terminal-state::-webkit-scrollbar,
#load-list::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;
}

/* Minecraft-style white theme beveled slot */
/* =========================================================================
   Toolbox slots
   -------------------------------------------------------------------------
   A card, not a 90s bevel: the old 3px light/dark borders read as a Windows
   toolbar and fought the flat schematic art inside them. Icon on top, label
   under it, in normal flow — the label used to be absolutely positioned over
   the bottom of the icon, which is why the taller symbols looked crowded.
   ========================================================================= */
.slot {
  position: relative;
  width: 74px;
  height: 74px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 4px 3px 3px;
  border-radius: 13px;
  background: #ffffff;
  /* Barely-there: the border is here to separate a slot from its neighbour,
     not to draw a box around the artwork. */
  border: 1px solid rgba(16, 24, 40, 0.055);
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
  cursor: grab;
  user-select: none;
  transition:
    border-color 0.13s ease,
    box-shadow 0.13s ease,
    transform 0.13s ease,
    background 0.13s ease;
}
.slot:hover {
  background: #fbfdff;
  border-color: rgba(3, 102, 214, 0.28);
  box-shadow: 0 4px 12px rgba(3, 102, 214, 0.13);
  transform: translateY(-1px);
}
.slot:active {
  cursor: grabbing;
  transform: translateY(0) scale(0.96);
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.08);
}
.slot canvas {
  width: 46px;
  height: 46px;
  pointer-events: none;
}
.slot .lbl {
  max-width: 100%;
  text-align: center;
  font-size: 9px;
  line-height: 1.15;
  letter-spacing: 0.02em;
  color: #6b7885;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}

/* Corner badges — a pill, so "TOOL" / "RTL" / "CMOS" read as a tag rather
   than as stray text floating over the artwork. */
.slot.tool-slot::after,
.slot.assembly-slot::after {
  position: absolute;
  top: 4px;
  right: 4px;
  padding: 1px 4px;
  border-radius: 5px;
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.5;
  pointer-events: none;
}

/* Modal drawing tools (e.g. Dashed Box) get an "armed" state so it's obvious
   the canvas is in a special interaction mode. */
.slot.tool-slot::after {
  content: "TOOL";
  color: #64748b;
  background: #f1f5f9;
}
.slot.tool-slot.active {
  background: #eff6ff;
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.18);
}
.slot.tool-slot.active .lbl {
  color: #1d4ed8;
}

/* Discrete-logic assemblies: one drag drops a whole pre-wired gate rather
   than a single part, so they get their own badge and accent. */
.slot.assembly-slot::after {
  content: "RTL";
  color: #7c3aed;
  background: #f3efff;
}
.slot.assembly-slot:hover {
  border-color: rgba(124, 58, 237, 0.28);
  box-shadow: 0 4px 12px rgba(124, 58, 237, 0.14);
}
.slot.assembly-slot .lbl {
  color: #6d3fc0;
}

/* The CMOS family reuses the assembly-slot layout but gets its own badge and
   accent, so the two gate families are never confused for each other in the
   toolbox. Blue = the N-channel tint used on the MOSFET symbol itself. */
.slot.assembly-slot.cmos-slot::after {
  content: "CMOS";
  color: #1c7ed6;
  background: #e7f2fd;
}
.slot.assembly-slot.cmos-slot:hover {
  border-color: rgba(28, 126, 214, 0.28);
  box-shadow: 0 4px 12px rgba(28, 126, 214, 0.14);
}
.slot.assembly-slot.cmos-slot .lbl {
  color: #1462a8;
}

/* right: raw state */
#terminal-state {
  flex: 3;
  padding: 12px;
  background-color: #ffffff;
  color: #24292e;
  overflow-y: auto;
}
.state-header {
  font-size: 12px;
  color: #586069;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border-color);
  padding-bottom: 4px;
  letter-spacing: 0.12em;
}
.state-section {
  margin-bottom: 14px;
}
.state-section-title {
  font-size: 10px;
  letter-spacing: 0.14em;
  color: #8a97a3;
  margin-bottom: 6px;
}
.srow {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}
.srow span:first-child {
  color: #57606a;
}
.srow .v {
  font-weight: bold;
  text-align: right;
}
.srow .v.lo {
  color: #6a737d;
  font-weight: normal;
}
.srow .v.hot {
  color: #0366d6;
}
.srow .v.warn {
  color: #cf222e;
}
.srow .v.good {
  color: #1a7f37;
}

/* --- Inspector modal --- */
#transistor-modal {
  display: none;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #ffffff;
  border: 2px solid #0366d6;
  color: #24292e;
  padding: 20px;
  border-radius: 8px;
  font-family: -apple-system, sans-serif;
  width: 420px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
  z-index: 100;
}
#transistor-modal h2 {
  color: #0366d6;
  margin-bottom: 15px;
  font-size: 18px;
}
#transistor-modal .state-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 15px;
  font-family: monospace;
}
#transistor-modal .explainer {
  background-color: #f6f8fa;
  padding: 12px;
  border-left: 4px solid #0366d6;
  font-size: 13px;
  line-height: 1.5;
  margin-bottom: 15px;
}
#transistor-modal .fact-check {
  font-size: 11px;
  color: #586069;
  font-style: italic;
  margin-bottom: 15px;
  line-height: 1.5;
}
#transistor-modal button {
  background-color: #0366d6;
  color: #ffffff;
  border: none;
  padding: 8px 16px;
  cursor: pointer;
  border-radius: 4px;
  font-weight: bold;
}

/* =========================================================================
   Save As / Load dialogs
   ========================================================================= */
.dialog-overlay {
  position: absolute;
  inset: 0;
  background: rgba(15, 20, 25, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
}
.dialog-overlay[hidden] {
  display: none;
}
.dialog-box {
  background: #ffffff;
  border-radius: 8px;
  border: 1px solid var(--border-color);
  width: 360px;
  max-width: calc(100% - 40px);
  max-height: calc(100% - 40px);
  padding: 18px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.22);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  display: flex;
  flex-direction: column;
}
.dialog-box h3 {
  margin-bottom: 12px;
  font-size: 15px;
  color: #24292e;
}
.dialog-box input[type="text"] {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border-color);
  border-radius: 5px;
  font-size: 13px;
  font-family: "Courier New", monospace;
  color: #24292e;
  outline: none;
}
.dialog-box input[type="text"]:focus {
  border-color: #0366d6;
  box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.15);
}
.dialog-msg {
  min-height: 16px;
  font-size: 11.5px;
  color: #9a6700;
  margin-top: 6px;
  line-height: 1.4;
}
.dialog-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
}
.dialog-spacer {
  flex: 1;
}
.btn-primary,
.btn-secondary {
  border-radius: 5px;
  padding: 7px 14px;
  font-size: 12.5px;
  cursor: pointer;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.btn-primary {
  background: #0366d6;
  color: #ffffff;
  border: none;
  font-weight: 600;
}
.btn-primary:hover {
  background: #0356b6;
}
.btn-secondary {
  background: #ffffff;
  color: #24292e;
  border: 1px solid var(--border-color);
}
.btn-secondary:hover {
  background: #f1f3f5;
}

.load-list {
  max-height: 320px;
  overflow-y: auto;
  border: 1px solid var(--border-color);
  border-radius: 6px;
}
.load-empty {
  padding: 18px 12px;
  text-align: center;
  color: #8a97a3;
  font-size: 12.5px;
}
.load-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 12px;
  border-bottom: 1px solid #eef1f4;
  cursor: pointer;
}
.load-item:last-child {
  border-bottom: none;
}
.load-item:hover {
  background: #f6f8fa;
}
.load-item-name {
  font-weight: 600;
  font-size: 13px;
  color: #24292e;
  font-family: "Courier New", monospace;
}
.load-item-meta {
  font-size: 11px;
  color: #8a97a3;
  margin-top: 2px;
}
.load-item-del {
  background: none;
  border: none;
  color: #8a97a3;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: 4px;
}
.load-item-del:hover {
  color: #cf222e;
  background: #ffebe9;
}

/* =========================================================================
   Inline text-label editor — a borderless input floated exactly over the
   canvas text it's replacing, so typing feels like editing in place.
   ========================================================================= */
.canvas-text-editor {
  position: fixed;
  z-index: 150;
  background: #ffffff;
  border: 1.5px dashed #0366d6;
  border-radius: 3px;
  padding: 0 3px;
  font:
    700 16px "Courier New",
    monospace;
  color: #24292e;
  outline: none;
  min-width: 60px;
  box-shadow: 0 2px 8px rgba(3, 102, 214, 0.2);
}

/* =========================================================================
   Dashed-box parametric popover
   ========================================================================= */
.box-editor-panel {
  position: fixed;
  z-index: 150;
  background: #ffffff;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 12px;
  width: 190px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.box-editor-row {
  margin-bottom: 10px;
}
.box-editor-row label {
  display: block;
  font-size: 10.5px;
  color: #586069;
  margin-bottom: 4px;
  letter-spacing: 0.03em;
}
.box-editor-row input[type="range"] {
  width: 100%;
}
.box-editor-row.swatches {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.swatch {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--sw);
  border: 2px solid transparent;
  cursor: pointer;
  padding: 0;
}
.swatch.selected {
  border-color: #24292e;
}
.box-editor-actions {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 4px;
}
.box-editor-actions button {
  flex: 1;
  padding: 6px 8px;
  font-size: 12px;
}

/* =========================================================================
   FIELD MANUAL — the Tab-key wiki overlay
   -------------------------------------------------------------------------
   Full-viewport scrim + a centred panel with a fixed left rail and a scrolling
   article pane. Both scrollers use the same "scrolls fine, scrollbar never
   shown" treatment as the log and the toolbox.
   ========================================================================= */
#wiki-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
#wiki-overlay[hidden] {
  display: none;
}
.wiki-scrim {
  position: absolute;
  inset: 0;
  background: rgba(16, 24, 34, 0.42);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.wiki-panel {
  position: relative;
  width: min(1180px, 94vw);
  height: min(860px, 92vh);
  display: flex;
  flex-direction: column;
  background: #ffffff;
  border-radius: 14px;
  box-shadow:
    0 24px 70px rgba(15, 25, 40, 0.34),
    0 2px 6px rgba(15, 25, 40, 0.16);
  overflow: hidden;
}

/* ---- header ---- */
.wiki-head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-color);
  background: linear-gradient(180deg, #fbfcfe 0%, #f4f6f9 100%);
  flex: 0 0 auto;
}
.wiki-brand {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.wiki-title {
  font-size: 13px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: #24292e;
}
.wiki-sub {
  font-size: 11px;
  letter-spacing: 0.04em;
  color: #8a97a3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#wiki-search {
  margin-left: auto;
  width: 260px;
  max-width: 38vw;
  padding: 7px 11px;
  font-size: 13px;
  font-family: inherit;
  color: #24292e;
  background: #ffffff;
  border: 1px solid var(--border-color);
  border-radius: 7px;
  outline: none;
}
#wiki-search:focus {
  border-color: #0366d6;
  box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.14);
}
.wiki-close {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  font-size: 20px;
  line-height: 1;
  color: #8a97a3;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 7px;
  cursor: pointer;
}
.wiki-close:hover {
  background: #eceff2;
  color: #24292e;
}

/* ---- body: rail + article ---- */
.wiki-body {
  flex: 1;
  min-height: 0;
  display: flex;
}
.wiki-nav {
  flex: 0 0 244px;
  min-height: 0;
  overflow-y: auto;
  padding: 12px 6px 24px 12px;
  border-right: 1px solid var(--border-color);
  background: #fbfcfd;
}
.wiki-content {
  flex: 1;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  padding: 26px 40px 60px;
  outline: none;
  color: #24292e;
  font-size: 15px;
  line-height: 1.66;
}
.wiki-nav,
.wiki-content {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.wiki-nav::-webkit-scrollbar,
.wiki-content::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;
}

/* ---- left rail items ---- */
.wiki-nav-section {
  margin-bottom: 14px;
}
.wiki-nav-head {
  font-size: 9px;
  letter-spacing: 0.15em;
  color: #a3aeb9;
  padding: 8px 8px 5px;
}
.wiki-nav-item {
  display: block;
  padding: 5px 9px;
  margin-bottom: 1px;
  font-size: 12.5px;
  line-height: 1.35;
  color: #4a5560;
  border-radius: 6px;
  border-left: 2px solid transparent;
  cursor: pointer;
  user-select: none;
}
.wiki-nav-item:hover {
  background: #eef2f6;
  color: #0f4c81;
}
.wiki-nav-item.active {
  background: #e8f0fb;
  color: #0f4c81;
  font-weight: 600;
  border-left-color: #0366d6;
}
.wiki-nav-sec {
  display: block;
  font-size: 9.5px;
  letter-spacing: 0.06em;
  color: #a3aeb9;
  font-weight: 400;
}
.wiki-nav-empty {
  padding: 4px 9px;
  font-size: 12px;
  color: #a3aeb9;
}

/* ---- article typography ---- */
.wiki-kicker {
  font-size: 9.5px;
  letter-spacing: 0.16em;
  color: #a3aeb9;
  margin-bottom: 6px;
}
.wiki-content h2 {
  font-size: 27px;
  line-height: 1.2;
  font-weight: 700;
  color: #16202a;
  margin-bottom: 10px;
  letter-spacing: -0.012em;
}
.wiki-content h3 {
  font-size: 16px;
  font-weight: 700;
  color: #16202a;
  margin: 30px 0 8px;
  padding-top: 12px;
  border-top: 1px solid #eef1f4;
}
.wiki-content h4 {
  font-size: 13.5px;
  font-weight: 700;
  color: #3b4855;
  margin: 20px 0 4px;
  letter-spacing: 0.01em;
}
.wiki-lede {
  font-size: 16.5px;
  line-height: 1.55;
  color: #55606c;
  margin-bottom: 18px;
}
.wiki-content p {
  margin: 11px 0;
}
.wiki-content ul,
.wiki-content ol {
  margin: 11px 0 11px 22px;
}
.wiki-content li {
  margin: 5px 0;
}
.wiki-content strong {
  color: #16202a;
  font-weight: 650;
}
.wiki-content em {
  color: #3b4855;
}
.wiki-content code {
  font-family: "Courier New", Courier, monospace;
  font-size: 0.9em;
  background: #f2f5f8;
  border: 1px solid #e4e9ee;
  border-radius: 4px;
  padding: 1px 5px;
  color: #0f4c81;
  white-space: nowrap;
}
.wiki-pre {
  font-family: "Courier New", Courier, monospace;
  font-size: 12.5px;
  line-height: 1.5;
  background: #f7f9fb;
  border: 1px solid #e4e9ee;
  border-left: 3px solid #c3ccd5;
  border-radius: 7px;
  padding: 13px 16px;
  margin: 15px 0;
  overflow-x: auto;
  color: #2b3a44;
  white-space: pre;
  scrollbar-width: none;
}
.wiki-pre::-webkit-scrollbar {
  height: 0;
  display: none;
}
.wiki-note {
  margin: 15px 0;
  padding: 11px 15px;
  background: #fbf7ff;
  border-left: 3px solid #8957e5;
  border-radius: 0 7px 7px 0;
  color: #3b4855;
  font-size: 14.5px;
}
.wiki-table {
  border-collapse: collapse;
  margin: 15px 0;
  font-size: 13.5px;
  width: 100%;
}
.wiki-table th {
  text-align: left;
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #8a97a3;
  font-weight: 600;
  padding: 5px 11px 5px 0;
  border-bottom: 1px solid var(--border-color);
}
.wiki-table td {
  padding: 6px 11px 6px 0;
  border-bottom: 1px solid #f0f3f6;
  vertical-align: top;
  color: #3b4855;
}
.wiki-link,
.wiki-link-demo {
  color: #0366d6;
  cursor: pointer;
  border-bottom: 1px solid rgba(3, 102, 214, 0.28);
}
.wiki-link:hover {
  background: rgba(3, 102, 214, 0.09);
  border-bottom-color: #0366d6;
}

/* ---- key/value strip at the top of a part article ---- */
.wiki-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1px;
  background: var(--border-color);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  overflow: hidden;
  margin: 16px 0 22px;
}
.wiki-fact {
  background: #fbfcfd;
  padding: 9px 13px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.wiki-fact .k {
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #a3aeb9;
}
.wiki-fact .v {
  font-size: 13.5px;
  color: #16202a;
}

/* ---- see also ---- */
.wiki-see {
  margin-top: 34px;
  padding-top: 14px;
  border-top: 1px solid var(--border-color);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
}
.wiki-see-head {
  font-size: 9.5px;
  letter-spacing: 0.15em;
  color: #a3aeb9;
}
.wiki-see .wiki-link {
  font-size: 13px;
}

/* ---- footer key hints ---- */
.wiki-foot {
  flex: 0 0 auto;
  display: flex;
  gap: 18px;
  align-items: center;
  padding: 8px 18px;
  border-top: 1px solid var(--border-color);
  background: #fbfcfd;
  font-size: 10.5px;
  letter-spacing: 0.05em;
  color: #a3aeb9;
}
.wiki-foot b {
  color: #4a5560;
  font-family: "Courier New", monospace;
}
.wiki-foot-right {
  margin-left: auto;
}
.wiki-link-demo {
  cursor: default;
}

/* the "read the manual" button on a component's inspector popup */
#transistor-modal .wiki-jump {
  background: #ffffff;
  color: #0366d6;
  border: 1px solid rgba(3, 102, 214, 0.4);
}

/* The action row used to be three inline buttons whose widths were whatever
   their labels happened to measure — "Acknowledge" next to "Set exact value
   (E)" next to "Read the manual", ragged and one label away from wrapping.
   The two navigational buttons now share a row at equal flex width, so the
   block stays symmetrical no matter what the labels say, and the dismiss
   sits full-width beneath them where a dismiss belongs. */
#transistor-modal .modal-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 14px;
  border-top: 1px solid var(--border-color);
}
#transistor-modal .modal-actions-nav {
  display: flex;
  gap: 8px;
}
#transistor-modal .modal-actions-nav button {
  flex: 1 1 0;
  min-width: 0;
}
#transistor-modal .modal-actions button {
  padding: 9px 12px;
  font-size: 12.5px;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#transistor-modal .modal-dismiss {
  width: 100%;
}


/* =========================================================================
   TIMEBASE PANEL
   Sits under the toolbar in the canvas overlay. Same frosted, low-chrome
   language as #hud and #toolbar so it reads as part of the instrument
   rather than as a dialog.
   ========================================================================= */
#timebase {
  position: absolute;
  top: 58px;
  right: 12px;
  z-index: 6;
  width: 214px;
  padding: 8px 10px 9px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(110, 130, 150, 0.28);
  box-shadow: 0 6px 18px rgba(20, 30, 40, 0.1);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px;
  color: #35424e;
  user-select: none;
}
#timebase .tb-head {
  font-size: 9px;
  letter-spacing: 0.14em;
  color: #7d8b98;
  margin-bottom: 6px;
}
#timebase .tb-row {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 4px;
}
#timebase .tb-lab {
  flex: 1;
  color: #7d8b98;
}
#timebase .tb-val {
  min-width: 44px;
  text-align: center;
  font-weight: 700;
  color: #1f2b36;
}
#timebase .tb-btn {
  min-width: 22px;
  height: 20px;
  padding: 0 5px;
  border-radius: 5px;
  border: 1px solid rgba(110, 130, 150, 0.34);
  background: rgba(255, 255, 255, 0.7);
  color: #35424e;
  font: inherit;
  font-size: 10px;
  line-height: 1;
  cursor: pointer;
  transition:
    background 0.12s ease,
    border-color 0.12s ease;
}
#timebase .tb-btn:hover {
  background: #fff;
  border-color: rgba(50, 130, 184, 0.6);
}
#timebase .tb-btn.tb-wide {
  flex: 1;
  letter-spacing: 0.08em;
}
#timebase .tb-btn.tb-on {
  background: #3282b8;
  border-color: #3282b8;
  color: #fff;
}
#timebase .tb-readout {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid rgba(110, 130, 150, 0.22);
}
#timebase .tb-line {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  line-height: 1.55;
}
#timebase .tb-line span {
  color: #7d8b98;
}
#timebase .tb-line b {
  color: #1f2b36;
  font-weight: 700;
  text-align: right;
}
#timebase .tb-warn {
  color: #d3552b !important;
}

/* =========================================================================
   SHARE DIALOG — Stage 1
   ========================================================================= */
.dialog-note {
  font-size: 12px;
  line-height: 1.5;
  color: #57606a;
  margin-bottom: 12px;
}
.share-url {
  width: 100%;
  font:
    12px/1.5 ui-monospace,
    "SF Mono",
    Menlo,
    monospace;
  padding: 10px;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  background: #f6f8fa;
  color: #24292e;
  resize: vertical;
  word-break: break-all;
}
.share-url:focus {
  outline: none;
  border-color: #0366d6;
  box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.14);
}
.share-verdict {
  margin-top: 10px;
  padding: 9px 11px;
  border-radius: 8px;
  font-size: 12px;
  line-height: 1.5;
  border: 1px solid var(--border-color);
  background: #f6f8fa;
  color: #57606a;
}
.share-verdict .share-sub {
  color: #8a97a3;
}
.share-verdict.share-safe {
  border-color: #b7e2c4;
  background: #e9f8ee;
  color: #16603a;
}
.share-verdict.share-ok {
  border-color: #bcd9f5;
  background: #eaf3fd;
  color: #0a4c8b;
}
.share-verdict.share-risky {
  border-color: #f0dbA0;
  background: #fdf7e3;
  color: #7a5c00;
}
.share-verdict.share-over {
  border-color: #f3c2c7;
  background: #fdecee;
  color: #97121f;
}
.share-opt {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  margin-top: 12px;
  font-size: 12px;
  line-height: 1.5;
  color: #57606a;
  cursor: pointer;
}
.share-opt input {
  margin-top: 2px;
  width: 14px;
  height: 14px;
  accent-color: #0366d6;
  flex: 0 0 auto;
  cursor: pointer;
}

/* =========================================================================
   READ-ONLY VIEWER — ?ro=1
   -------------------------------------------------------------------------
   A first-time visitor, usually on a phone, following a link from a caption.
   Everything that edits the board is gone; everything that OPERATES it stays,
   because a circuit you cannot flip a switch on is a screenshot.
   ========================================================================= */
body.read-only #toolbar,
body.read-only #inventory-panel,
body.read-only #tip,
body.read-only #terminal-resizer,
/* TIMEBASE is an operator instrument with live controls — scale, steps,
   pause. In a viewer those buttons are the one piece of editor chrome left
   on screen, and its readout answers a question nobody following a link from
   a caption is asking. */
body.read-only #timebase {
  display: none !important;
}
body.read-only #terminal-log {
  flex: 5;
}
body.read-only #terminal-state {
  flex: 4;
  border-right: 0;
}
body.read-only #canvas-wrapper {
  flex: 7;
}
body.read-only canvas {
  cursor: default;
}

/* A real flex item at the end of #app-container's column, not an overlay:
   absolutely positioning it against the viewport laid it straight over the
   bottom of the terminal and cut both panes off mid-line. */
#ro-bar {
  order: 99;
  flex: 0 0 auto;
  z-index: 120;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 14px;
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(6px);
  border-top: 1px solid var(--border-color);
  font-size: 12px;
  color: #57606a;
}
#ro-bar[hidden] {
  display: none;
}
#ro-title {
  font-weight: 700;
  color: #24292e;
}
#ro-bar .ro-sep {
  flex: 1;
}
#ro-bar a {
  color: #0366d6;
  text-decoration: none;
  font-weight: 600;
  padding: 4px 9px;
  border-radius: 6px;
  border: 1px solid transparent;
}
#ro-bar a:hover {
  background: #eaf3fd;
  border-color: #bcd9f5;
}
#ro-snow {
  color: #57606a !important;
}

/* Phone: the board is the whole point, so give it the screen. The log and
   the state panel are a desktop luxury at 390px wide, and the 3-second
   first-paint budget does not survive rendering them. */
@media (max-width: 720px) {
  body.read-only #terminal-container {
    display: none;
  }
  /* The zoom HUD and the TIMEBASE panel are operator instruments. On a
     390px-wide phone the timebase alone covers a quarter of the board, and
     the visitor came to see a circuit, not a solver readout. */
  body.read-only #hud,
  body.read-only #timebase {
    display: none;
  }
  body.read-only #canvas-wrapper {
    flex: 1;
  }
  #ro-bar {
    font-size: 13px;
    padding: 10px 12px;
    padding-bottom: max(10px, env(safe-area-inset-bottom));
  }
  #ro-bar a {
    padding: 7px 10px;
  }
}

/* =========================================================================
   PHONE — html.phone, set by mobile.js (and by the inline probe in
   index.html one frame earlier)
   -------------------------------------------------------------------------
   Not a breakpoint and not tied to ?ro=1: on a phone this IS the app. There
   is no gesture on a touchscreen that drags a part out of a toolbox, so an
   editor here is a wall, not a feature. What is left is the board — pan,
   zoom, and tapping a part to operate it — plus one line of chrome saying
   what you are looking at and who made it.

   These rules repeat what body.read-only already does rather than depending
   on it, so the viewer layout is correct in the first painted frame, before
   any script has decided anything.
   ========================================================================= */
.phone #toolbar,
.phone #inventory-panel,
.phone #tip,
.phone #terminal-resizer,
.phone #terminal-container,
.phone #timebase,
.phone #hud,
/* The editor link is the one control on the bar that leads somewhere a
   phone cannot follow. The credit and the circuit's name stay. */
.phone #ro-edit,
/* Nothing can open these here, but a stray hash or a restored scroll
   position should not be able to either. */
.phone #save-dialog,
.phone #load-dialog,
.phone #share-dialog {
  display: none !important;
}

.phone #canvas-wrapper {
  flex: 1;
  min-height: 0;
}

.phone canvas {
  cursor: default;
}

/* The bar is a flex item at the end of the column, so its height comes out
   of the board's rather than sitting on top of it. padding-bottom clears the
   home indicator — env() only resolves to a real number because of
   viewport-fit=cover in index.html's viewport meta. */
.phone #ro-bar {
  font-size: 13px;
  padding: 10px 12px;
  padding-bottom: max(10px, env(safe-area-inset-bottom));
  gap: 10px;
}
.phone #ro-bar a {
  padding: 7px 10px;
}
/* A long episode title must shorten itself rather than push the credit off
   the end of the bar. */
#ro-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.phone #ro-snow {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* =========================================================================
   TIMEBASE minimise / restore
   -------------------------------------------------------------------------
   The panel sits over the top-right of the board. Hiding it must leave a
   handle behind — a hidden panel with no way back is a one-way door.
   ========================================================================= */
.tb-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.tb-min {
  width: 18px;
  height: 18px;
  line-height: 1;
  padding: 0;
  border: 1px solid var(--border-color);
  border-radius: 5px;
  background: #ffffff;
  color: #6b7885;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.tb-min:hover {
  background: #eef2f6;
  color: #24292e;
  border-color: #b7c3ce;
}

body.timebase-hidden #timebase {
  display: none;
}

/* The bookmark. Only exists while the panel is hidden. */
#timebase-tab {
  position: absolute;
  /* Level with where the panel itself starts (top:58px), so the bookmark
     points at the thing it restores — and clear of the Save/Load/Share
     toolbar, which also lives in the top-right corner. */
  top: 58px;
  right: 0;
  z-index: 60;
  display: none;
  align-items: center;
  padding: 9px 9px 9px 11px;
  border: 1px solid var(--border-color);
  border-right: 0;
  border-radius: 9px 0 0 9px;
  background: rgba(255, 255, 255, 0.96);
  box-shadow: -2px 2px 10px rgba(15, 25, 40, 0.1);
  cursor: grab;
  user-select: none;
  touch-action: none;
  transition:
    transform 0.12s ease,
    box-shadow 0.12s ease,
    background 0.12s ease;
}
body.timebase-hidden #timebase-tab {
  display: flex;
}
#timebase-tab:hover {
  background: #ffffff;
  box-shadow: -3px 3px 14px rgba(15, 25, 40, 0.16);
  transform: translateX(-3px);
}
#timebase-tab.pulling {
  cursor: grabbing;
  transition: none;
}
#timebase-tab span {
  writing-mode: vertical-rl;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: #6b7885;
  pointer-events: none;
}
/* The studio frame and the read-only viewer hide the timebase entirely, so
   the handle must go with it — otherwise a bookmark for an invisible panel
   ends up in the shot. */
body.studio #timebase-tab,
body.read-only #timebase-tab {
  display: none !important;
}

/* =========================================================================
   VALUE EDITOR — hover a part and press E (or Shift+click it) to type an
   exact resistance / capacitance / voltage. Shares the dashed-box panel's
   visual language on purpose: same chrome, same actions row, so it reads
   as the same class of tool rather than a new dialect.
   ========================================================================= */
.value-editor-panel {
  position: fixed;
  z-index: 160;
  background: #ffffff;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 12px;
  width: 218px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.2);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.value-editor-head {
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #586069;
  border-bottom: 1px solid var(--border-color);
  padding-bottom: 6px;
  margin-bottom: 10px;
}
.value-editor-row {
  margin-bottom: 10px;
}
.value-editor-row label {
  display: block;
  font-size: 10.5px;
  color: #586069;
  margin-bottom: 4px;
  letter-spacing: 0.03em;
}
.value-editor-row .ve-unit {
  color: #0366d6;
  font-weight: 700;
}
.value-editor-row input {
  width: 100%;
  box-sizing: border-box;
  padding: 5px 7px;
  border: 1.5px solid #d1d5da;
  border-radius: 4px;
  font:
    700 14px "Courier New",
    monospace;
  color: #24292e;
  outline: none;
}
.value-editor-row input:focus {
  border-color: #0366d6;
  box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.14);
}
.value-editor-row .ve-hint {
  margin-top: 3px;
  font-size: 10px;
  color: #8a949e;
  font-family: "Courier New", monospace;
}
.value-editor-msg {
  min-height: 14px;
  font-size: 10.5px;
  margin-bottom: 8px;
  color: #586069;
  font-family: "Courier New", monospace;
}
.value-editor-msg.ok {
  color: #2f9e44;
}
.value-editor-msg.warn {
  color: #b8860b;
}
.value-editor-msg.bad {
  color: #e5484d;
}

/* =========================================================================
   FIELD MANUAL — RESPONSIVE
   -------------------------------------------------------------------------
   The manual was authored for a 1180 x 860 desktop panel: a fixed 244px rail
   beside a scrolling article, and a footer of keyboard hints. None of that
   survives a 390px phone, and — since the phone build is where most first
   contact with the manual happens — none of it could be left as it was.

   Three states, in order of increasing constraint:

     >= 900px   the original two-column reading layout, untouched.
     <  900px   ONE column. The rail becomes a left drawer behind a
                "Contents" button, the header stacks its search field onto a
                second row, and the keyboard-hint footer (meaningless without
                a keyboard) is dropped for a back button in the header.
     <  620px   full-bleed: no radius, no margin, safe-area padding, and
                16px form text so iOS does not zoom the whole panel when the
                search field takes focus.

   Everything here is additive and lives after the base rules on purpose:
   the desktop layout is literally the same cascade it always was, so a
   regression at 1440px is not possible from this block alone.
   ========================================================================= */

/* The drawer is positioned against the body, so the body has to be the
   containing block. Harmless at every width. */
.wiki-body {
  position: relative;
}

/* Scrim behind the open drawer. Present in the DOM at all widths, inert
   until the drawer layout is active. */
.wiki-nav-scrim {
  display: none;
}

/* The two header buttons that only exist below the breakpoint. Declared
   hidden here so they never flash on a desktop first paint. */
.wiki-menu,
.wiki-back {
  display: none;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 34px;
  min-width: 34px;
  padding: 0 10px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #4a5560;
  background: #ffffff;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.wiki-menu:active,
.wiki-back:active {
  background: #eef2f6;
}
.wiki-menu-bars {
  display: block;
  width: 14px;
  height: 10px;
  border-top: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  position: relative;
}
.wiki-menu-bars::after {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  width: 14px;
  border-top: 2px solid currentColor;
}

/* A wide table is the one piece of article content that cannot be made to
   fit — a truth table has the columns it has. It scrolls inside its own box
   rather than widening the article and taking the whole page with it. */
.wiki-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin: 15px 0;
}
.wiki-table-wrap::-webkit-scrollbar {
  height: 0;
  display: none;
}
.wiki-table-wrap .wiki-table {
  margin: 0;
  min-width: 100%;
}

/* Panel height: 92vh is the LARGE viewport on iOS, which is the same lie
   that put the read-only footer under Safari's toolbar. Each line only
   overrides the one before it where the browser understands the unit. */
.wiki-panel {
  max-height: 100%;
}
@supports (height: 100dvh) {
  .wiki-panel {
    height: min(860px, 92dvh);
  }
}

@media (max-width: 899px) {
  .wiki-panel {
    width: 100%;
    height: 100%;
    height: var(--app-h, 100dvh);
    max-width: none;
    border-radius: 0;
  }

  /* ---- header stacks: [≡] [← ] brand ......... [×] / [ search ] ---- */
  .wiki-head {
    flex-wrap: wrap;
    gap: 8px 10px;
    padding: 10px 12px;
    padding-top: max(10px, env(safe-area-inset-top));
  }
  .wiki-menu {
    display: inline-flex;
    order: 1;
  }
  .wiki-back {
    order: 2;
  }
  .wiki-panel.has-history .wiki-back {
    display: inline-flex;
  }
  .wiki-brand {
    order: 3;
    flex: 1 1 auto;
  }
  .wiki-close {
    order: 4;
    width: 34px;
    height: 34px;
    border-color: var(--border-color);
    background: #ffffff;
  }
  #wiki-search {
    order: 5;
    flex: 1 0 100%;
    width: auto;
    max-width: none;
    margin-left: 0;
    font-size: 16px; /* < 16px makes iOS zoom the panel on focus */
    padding: 9px 12px;
  }
  .wiki-title {
    font-size: 12px;
  }
  .wiki-sub {
    font-size: 10px;
  }

  /* ---- the rail becomes a drawer ---- */
  .wiki-nav {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 3;
    flex: 0 0 auto;
    width: min(310px, 84%);
    padding: 10px 8px calc(28px + env(safe-area-inset-bottom)) 10px;
    background: #ffffff;
    box-shadow: 6px 0 28px rgba(15, 25, 40, 0.18);
    transform: translateX(-102%);
    transition: transform 0.22s ease;
    overscroll-behavior: contain;
  }
  .wiki-panel.nav-open .wiki-nav {
    transform: none;
  }
  .wiki-nav-scrim {
    display: block;
    position: absolute;
    inset: 0;
    z-index: 2;
    background: rgba(16, 24, 34, 0.34);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.22s ease;
  }
  .wiki-panel.nav-open .wiki-nav-scrim {
    opacity: 1;
    pointer-events: auto;
  }
  /* Thumb-sized rows. A 5px-padded 12.5px link is a desktop affordance. */
  .wiki-nav-item {
    padding: 10px 11px;
    font-size: 14px;
    margin-bottom: 2px;
  }
  .wiki-nav-head {
    font-size: 10px;
    padding: 10px 11px 6px;
  }

  /* ---- the article gets the whole width ---- */
  .wiki-content {
    padding: 18px 18px calc(56px + env(safe-area-inset-bottom));
    font-size: 16px;
    line-height: 1.68;
    /* A long unbroken part number or URL must not widen the column. */
    overflow-wrap: break-word;
  }
  .wiki-content h2 {
    font-size: 23px;
  }
  .wiki-lede {
    font-size: 16px;
  }
  .wiki-content h3 {
    margin-top: 26px;
    font-size: 15.5px;
  }
  /* Inline code is nowrap by design (a value should never break across
     lines) — but on a narrow column that is what pushes the page sideways.
     Allow it to break here, and only here. */
  .wiki-content code {
    white-space: normal;
    overflow-wrap: break-word;
  }
  .wiki-pre {
    font-size: 11.5px;
    padding: 11px 12px;
  }
  .wiki-facts {
    grid-template-columns: 1fr;
  }
  .wiki-content ul,
  .wiki-content ol {
    margin-left: 18px;
  }

  /* Keyboard hints on a device with no keyboard. The back button in the
     header replaces the one hint that still meant something. */
  .wiki-foot {
    display: none;
  }
}

@media (max-width: 619px) {
  .wiki-scrim {
    /* Nothing shows behind a full-bleed panel; skip the blur, which is the
       single most expensive thing on the page on a mid-range Android. */
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .wiki-sub {
    display: none;
  }
  .wiki-content {
    padding-left: 15px;
    padding-right: 15px;
  }
}

/* Landscape phone: 390px of height, most of it spent on chrome. Claw back
   the header padding and the lede's air. */
@media (max-height: 460px) and (pointer: coarse) {
  .wiki-head {
    padding-top: 6px;
    padding-bottom: 6px;
  }
  .wiki-sub {
    display: none;
  }
  .wiki-content {
    padding-top: 12px;
  }
}

/* =========================================================================
   INSPECTOR MODAL — RESPONSIVE
   -------------------------------------------------------------------------
   width: 420px on a 390px phone is 30px of the popup off the side of the
   screen, and the popup is the phone's ONLY route into the manual (tap a
   part, then "Read the manual"). It had to be fixed before that route could
   be claimed to work.
   ========================================================================= */
#transistor-modal {
  width: min(420px, calc(100vw - 24px));
  max-height: calc(100% - 24px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
@media (max-width: 619px) {
  #transistor-modal {
    padding: 16px;
  }
  #transistor-modal .state-grid {
    grid-template-columns: 1fr;
    gap: 6px;
  }
  #transistor-modal button {
    padding: 11px 16px;
    font-size: 14px;
  }
  #transistor-modal .modal-actions-nav {
    flex-direction: column;
  }
}

/* =========================================================================
   MANUAL BUTTON
   -------------------------------------------------------------------------
   Tab is not a key a phone has, and it is not a key most first-time desktop
   visitors will guess. The manual — which is half the product, and all of
   the sourcing surface — was reachable by an undiscoverable shortcut only.
   Two entry points now: a labelled button in the editor toolbar, and a link
   on the read-only bar, which is the whole of the chrome on a phone.
   ========================================================================= */
#btn-manual {
  font-weight: 600;
}
.phone #ro-manual,
body.read-only #ro-manual {
  display: inline-block;
}
#ro-manual {
  font-weight: 600;
}
/* =========================================================================
   SOURCING BLOCK
   -------------------------------------------------------------------------
   Sits at the foot of a part article and only ever appears when a real part
   matched the reader's board. It is deliberately the quietest thing on the
   page: no coloured pills, no badges, no logos, one accent (the Order
   button) and otherwise the same greys the manual already uses. A listing
   that looks like an advertisement is read as one and skipped — this reads
   as the last row of the specification table, which is what it is.

   Mobile-first. Single column stack under 700px, three tracks above it.
   Nothing is positioned absolutely and nothing has a fixed width, so it
   survives 320px.
   ========================================================================= */
.wiki-sourcing {
  margin: 42px 0 8px;
  padding-top: 22px;
  border-top: 1px solid #e8ecf1;
}
.src-skel {
  height: 84px;
  border-radius: 12px;
  background: linear-gradient(90deg, #f6f8fa 25%, #eef2f6 37%, #f6f8fa 63%);
  background-size: 400% 100%;
  animation: src-shimmer 1.4s ease infinite;
}
@keyframes src-shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .src-skel { animation: none; }
}

/* ---- header ---- */
.wiki-content h3.src-h {
  font-size: 21px;
  font-weight: 650;
  letter-spacing: -0.014em;
  color: #16202a;
  margin: 0 0 5px;
  padding-top: 0;
  border-top: 0;
}
.src-sub {
  font-size: 13.5px;
  color: #8a97a3;
  margin-bottom: 16px;
}
.src-sub b {
  color: #4a5560;
  font-weight: 600;
}
.src-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: -6px 0 16px;
}
.src-chip {
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 6px 13px;
  min-height: 32px;
  color: #4a5560;
  background: #ffffff;
  border: 1px solid var(--border-color);
  border-radius: 999px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.src-chip.on {
  color: #ffffff;
  background: #16202a;
  border-color: #16202a;
}

/* ---- the one line high in the article ---- */
.src-teaser {
  display: inline-block;
  margin: 2px 0 16px;
  font-size: 13px;
  color: #8a97a3;
  text-decoration: none;
  border-bottom: 1px solid #e0e5ea;
  cursor: pointer;
}
.src-teaser::after {
  content: " \2193";
  color: #b6bfc8;
}
.src-teaser:hover {
  color: #4a5560;
  border-bottom-color: #b6bfc8;
}
.src-teaser[hidden] {
  display: none;
}

/* ---- cards ---- */
.src-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.src-card {
  display: grid;
  grid-template-columns: 46px 1fr;
  gap: 14px;
  padding: 15px;
  background: #ffffff;
  border: 1px solid #e8ecf1;
  border-radius: 12px;
  transition: border-color 0.14s ease;
}
.src-card:hover {
  border-color: #d3dbe3;
}

/* ---- tiles: each drawn from the part's own facts ---- */
.src-tile {
  width: 46px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  background: hsl(var(--h) 45% 96.5%);
  border: 1px solid hsl(var(--h) 35% 90%);
}
.src-tile span {
  font-size: 12px;
  font-weight: 700;
  color: hsl(var(--h) 40% 36%);
}
/* An LED shows its die colour, because that is the only spec that matters
   at a glance and the part is literally that colour in your hand. */
.src-tile-led {
  background: #fbfcfd;
  border-color: #e8ecf1;
}
.src-tile-led span {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--led);
  box-shadow: 0 0 0 4px rgba(120, 140, 160, 0.14);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--led) 18%, transparent);
  border: 1px solid rgba(20, 30, 40, 0.14);
}
/* A resistor wears its actual colour code — the same bands printed on the
   part the student would receive. */
.src-tile-res {
  background: #fbfcfd;
  border-color: #e8ecf1;
}
.src-res-body {
  position: relative;
  width: 32px;
  height: 15px;
  border-radius: 4px;
  background: linear-gradient(180deg, #f0e2c4 0%, #dfcda6 100%);
  border: 1px solid #cbb891;
  display: flex;
  align-items: stretch;
  gap: 2px;
  padding: 0 4px;
}
.src-res-body i {
  display: block;
  width: 2.5px;
  border-radius: 0.5px;
}

/* ---- card body ---- */
.src-main {
  min-width: 0;
}
.src-id {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 3px 7px;
  margin-bottom: 3px;
}
.src-mfr {
  font-size: 13px;
  color: #8a97a3;
}
.src-mpn {
  font-size: 15px;
  font-weight: 650;
  color: #16202a;
  letter-spacing: -0.008em;
  overflow-wrap: anywhere;
}
.src-spec {
  font-size: 13px;
  color: #3b4855;
  margin-bottom: 4px;
}
.src-avail {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: #8a97a3;
  margin-bottom: 8px;
}
.src-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #b6bfc8;
  flex: 0 0 auto;
}
.src-dot.in { background: #1a7f37; }
.src-dot.low { background: #b8860b; }
.src-dot.back { background: #cf6b22; }

.wiki-content p.src-blurb {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: #8a97a3;
}

.src-more {
  margin-top: 9px;
}
.src-more summary {
  display: inline-block;
  font-size: 12px;
  color: #6b7885;
  cursor: pointer;
  list-style: none;
  padding: 3px 0;
}
.src-more summary::-webkit-details-marker { display: none; }
.src-more summary::before { content: "\25B8  "; color: #b6bfc8; }
.src-more[open] summary::before { content: "\25BE  "; }
.src-dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 16px;
  margin-top: 6px;
  padding: 12px 14px;
  background: #fafbfc;
  border-radius: 9px;
  font-size: 12px;
}
.src-dt { color: #a3aeb9; }
.src-dd { color: #3b4855; }
.wiki-content ul.src-notes {
  margin: 8px 0 0 16px;
  font-size: 11.5px;
  color: #8a97a3;
}
.src-notes li { margin: 2px 0; }
.src-ds {
  display: inline-block;
  margin-top: 9px;
  font-size: 12px;
  color: #0366d6;
  text-decoration: none;
}
.src-ds:hover { text-decoration: underline; }

/* ---- buy column ---- */
.src-buy {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding-top: 13px;
  border-top: 1px solid #f2f5f8;
}
.src-line {
  display: flex;
  align-items: center;
  gap: 11px;
  margin-right: auto;
}
.src-qty {
  display: inline-flex;
  align-items: center;
  border: 1px solid #e2e7ec;
  border-radius: 8px;
  overflow: hidden;
  background: #ffffff;
}
.src-step {
  width: 30px;
  height: 32px;
  font: inherit;
  font-size: 15px;
  color: #6b7885;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.src-step:active { background: #f2f5f8; }
.src-qty-in {
  width: 34px;
  height: 32px;
  border: 0;
  text-align: center;
  font: 600 13px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  color: #16202a;
  outline: none;
  -moz-appearance: textfield;
  background: transparent;
}
.src-qty-in::-webkit-outer-spin-button,
.src-qty-in::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.src-amount {
  font-size: 16px;
  font-weight: 650;
  color: #16202a;
  letter-spacing: -0.01em;
}
.src-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 0 22px;
  font-size: 13.5px;
  font-weight: 600;
  color: #ffffff;
  background: #16202a;
  border-radius: 999px;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.src-cta:hover { background: #0366d6; }

/* ---- the one honest line, when there is anything to say ---- */
.src-foot {
  margin-top: 14px;
  font-size: 11px;
  color: #b6bfc8;
}

/* ---- wide enough for the three-track card ---- */
@media (min-width: 700px) {
  .src-card {
    grid-template-columns: 46px 1fr 150px;
    gap: 16px;
  }
  .src-buy {
    grid-column: 3;
    grid-row: 1;
    flex-direction: column;
    align-items: flex-end;
    /* Top-aligned, not centred: opening the specification drawer makes the
       card tall, and a price that drifts to the middle of a long card reads
       as unmoored. Held level with the part name, it stays where the eye
       left it. */
    justify-content: flex-start;
    gap: 10px;
    padding-top: 2px;
    border-top: 0;
  }
  .src-line {
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    margin-right: 0;
  }
  .src-cta { width: 100%; }
}

/* =========================================================================
   POLARISED PARTS IN THE TOOLBOX
   -------------------------------------------------------------------------
   A part with a right way round gets a small +/− badge on its slot. It is a
   flag, not an explanation — hovering the slot gives the full line, and the
   part itself labels its own terminals once it is on the board. See
   components/polarity.js.
   ========================================================================= */
.slot.polarised-slot {
  position: relative;
}
.slot.polarised-slot::after {
  content: "+\2212";
  position: absolute;
  top: 3px;
  right: 4px;
  font: 700 8px/1 ui-monospace, "SF Mono", Menlo, monospace;
  letter-spacing: 0.5px;
  padding: 2px 3px;
  border-radius: 3px;
  color: #e5484d;
  background: rgba(229, 72, 77, 0.09);
  border: 1px solid rgba(229, 72, 77, 0.28);
  pointer-events: none;
}
