/* DotGame — dark UI optimized for stylus + canvas. v0.1 */
:root {
  --bg: #0e1116;
  --bg-elev: #161a22;
  --surface: #1d222c;
  --surface-2: #262c38;
  --text: #e6edf3;
  --text-dim: #8b96a8;
  --text-muted: #5c6573;
  --accent: #79c0ff;
  --accent-warm: #f0a35e;
  --pin: #ff4d4d;
  --pin1: #ffd54d;
  --grid-dot: #2d3340;
  --grid-dot-bold: #4a5568;
  --rect: #4ec99a;
  --border: #2a313e;
  --danger: #ff7676;
  --radius: 8px;
  --radius-sm: 4px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bot: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; -webkit-user-select: none; user-select: none; }
html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 14px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  height: 100vh;
}

/* v0.6.26: the app-shell is the rigid page. Lift bar translates this as
   a unit so the whole UI (topbar + panels + canvas + status + foot-dock)
   travels together — no stretching, grid stays proportional. */
#app-shell {
  height: 100vh;
  display: flex;
  flex-direction: column;
  transition: transform 0.04s linear;
  will-change: transform;
}

button { font: inherit; color: inherit; cursor: pointer; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 6px 10px; }
button:active { background: var(--surface-2); }
button.primary { background: var(--accent); color: #0a1018; border-color: var(--accent); font-weight: 600; }
button.primary:active { background: #5cb0ee; }

input, select {
  font: inherit;
  color: var(--text);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 4px 6px;
  width: 56px;
  text-align: center;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* ----- Top bar ----- */
/* v0.6.44: ensure at least ~28px of headroom from the system status bar
   (clock / battery / signal icons). The safe-area-inset-top env var is
   sometimes 0 on Android even when there's a status bar above us, so
   max() with a fallback prevents the topbar from sliding under the
   system icons. */
#topbar {
  padding: calc(max(var(--safe-top), 28px) + 6px) 8px 6px;
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex-shrink: 0;
}
#topbar-title {
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.5px;
  color: var(--text-dim);
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}
/* v0.6.30: component name shown next to app name when one is loaded.
   Brighter color than the app name so it pops as "what you're editing." */
#topbar-component {
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  font-family: monospace;
}
#topbar-component:empty { display: none; }
#topbar-component::before { content: "▸ "; color: var(--text-muted); font-weight: normal; }
/* v0.6.43: project name shown in Wire Mode (set by app.js). Uses a warmer
   accent so it visually differs from the component name. */
#topbar-project {
  color: var(--accent-warm);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  font-family: monospace;
}
#topbar-project:empty { display: none; }
#topbar-project::before { content: "📁 "; }
#topbar-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.ctrl { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text-dim); }
.ctrl span { font-size: 11px; }
.ctrl .x { color: var(--text-muted); font-size: 12px; }

/* ----- Canvas ----- */
#canvas-wrap {
  flex: 1;
  position: relative;
  overflow: hidden;
  background: #0a0d12;
  touch-action: none;
}
#canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

/* ----- Bottom bar ----- */
#botbar {
  background: var(--bg-elev);
  border-top: 1px solid var(--border);
  padding: 6px 8px calc(var(--safe-bot) + 6px);
  flex-shrink: 0;
  font-size: 11.5px;
}
#status {
  display: flex;
  gap: 12px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
#status span { white-space: nowrap; }
#pin-count, #rotation-label { color: var(--text); font-weight: 600; }
#next-pin { color: var(--pin1); }
#hint { color: var(--text-muted); font-size: 10.5px; margin-top: 3px; line-height: 1.3; }

/* ----- Version badge ----- */
#version-badge {
  position: fixed;
  bottom: 2px;
  right: 4px;
  font-size: 9px;
  color: var(--text-muted);
  pointer-events: none;
  font-family: monospace;
  opacity: 0.6;
}

/* ----- Nudge panel — sits in flex flow between topbar and canvas -----
   v0.7.16: compacted hard. The original panel ate ~70% of the screen,
   leaving no canvas to see the pins you're nudging. Tighter padding,
   shorter buttons, smaller gaps so the canvas keeps the majority. */
#nudge-panel {
  background: var(--bg-elev);
  border-bottom: 1px solid var(--accent);
  padding: 3px 6px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 11px;
}
#nudge-panel[hidden] { display: none; }
#nudge-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
#nudge-target {
  color: var(--accent);
  font-weight: 600;
  font-size: 11px;
}
#nudge-close {
  width: 24px;
  height: 24px;
  font-size: 13px;
  padding: 0;
}
/* v0.7.16: position readout folds into the header row to save a line. */
#nudge-pos {
  font-family: monospace;
  font-size: 10px;
  color: var(--text-dim);
  display: flex;
  gap: 6px;
  align-items: center;
}
#nudge-pos .lbl { color: var(--text-muted); }
#nudge-pos-display { color: var(--text); }
.nudge-row {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}
.nudge-row .ctrl { font-size: 10px; }
.nudge-row .ctrl input { width: 52px; padding: 3px 4px; }
.nudge-row button {
  flex: 1 1 0;
  min-width: 48px;
  font-size: 11px;
  padding: 5px 3px;
  font-family: monospace;
}
.scope-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  color: var(--text-dim);
  padding: 3px 5px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.scope-toggle input { display: none; }
.scope-toggle:has(input:checked) {
  background: var(--surface-2);
  color: var(--accent);
  border-color: var(--accent);
}
#btn-nudge.active {
  background: var(--accent);
  color: #0a1018;
  border-color: var(--accent);
}
#nudge-mode-label {
  background: var(--accent);
  color: #0a1018;
  padding: 1px 6px;
  border-radius: 3px;
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.5px;
}

/* ----- Calibration overlay ----- */
#cal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
}
#cal-overlay[hidden] { display: none; }
#cal-panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px;
  max-width: 100%;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow: hidden;
}
#cal-panel h2 {
  margin: 0;
  font-size: 16px;
  color: var(--text);
}
.cal-help {
  margin: 0;
  color: var(--text-dim);
  font-size: 12px;
}
.cal-help span { color: var(--accent); font-weight: 600; font-variant-numeric: tabular-nums; }
.cal-targets {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
}
.cal-target {
  text-align: left;
  font-size: 12px;
  padding: 8px;
  color: var(--text);
  background: var(--surface);
}
.cal-target.active {
  background: var(--surface-2);
  border-color: var(--accent);
  color: var(--accent);
}
.cal-target small {
  color: var(--text-muted);
  font-size: 10px;
  font-weight: normal;
}
#cal-canvas-wrap {
  flex: 1;
  position: relative;
  background: #0a0d12;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  touch-action: none;
}
#cal-canvas { position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; }
.cal-slider-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.cal-slider-row input[type="range"] {
  flex: 1;
  width: auto;
  padding: 0;
  border: none;
  background: transparent;
}
#cal-minus, #cal-plus {
  width: 36px;
  height: 36px;
  font-size: 18px;
}
.cal-actions {
  display: flex;
  gap: 6px;
  justify-content: flex-end;
}
.cal-actions button { padding: 8px 14px; }

/* ----- Modal toast ----- */
.toast {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 12px 16px;
  border-radius: var(--radius);
  z-index: 100;
  max-width: 80vw;
  font-size: 13px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
  animation: toast-in 0.15s ease-out;
}
.toast.error { border-color: var(--danger); color: var(--danger); }
.toast.success { border-color: var(--accent); color: var(--accent); }

/* v0.9.3: transient bottom toast — non-blocking action feedback that
   auto-dismisses. Sits above the bottom edge, fades + slides in. */
#vs-toast {
  position: fixed;
  left: 50%;
  bottom: 18%;
  transform: translate(-50%, 12px);
  background: var(--surface-2, #262c38);
  color: var(--text, #e6edf3);
  border: 1px solid var(--border, #2a313e);
  padding: 9px 16px;
  border-radius: 18px;
  z-index: 2000;
  max-width: 84vw;
  font-size: 13px;
  font-weight: 600;
  text-align: center;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
#vs-toast.show { opacity: 1; transform: translate(-50%, 0); }
#vs-toast.success { border-color: var(--accent, #79c0ff); }
#vs-toast.error { border-color: var(--danger, #ff7676); color: var(--danger, #ff7676); }

/* v0.9.8: "Add a part" bar at the top of the Library — makes the two ways
   to add a part (make one / import one) obvious and prominent. */
#lib-add-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  margin: 0 0 8px;
  background: var(--bg-elev, #161b22);
  border: 1px solid var(--border, #2a313e);
  border-radius: 8px;
  flex-wrap: wrap;
}
#lib-add-label { font-size: 12px; color: var(--text-dim, #9aa6b2); font-weight: 600; }
#lib-make-part, #lib-import-jump {
  font-size: 13px;
  padding: 7px 14px;
  border: none;
  border-radius: 6px;
  font-weight: 700;
  flex: 1 1 auto;
}
#lib-make-part { background: var(--accent, #79c0ff); color: #0a1018; }
#lib-import-jump { background: var(--surface-2, #262c38); color: var(--text, #e6edf3); border: 1px solid var(--border, #2a313e); }
#lib-import-row.flash-hl {
  outline: 2px solid var(--accent, #79c0ff);
  outline-offset: 3px;
  border-radius: 6px;
  transition: outline-color 0.3s ease;
}

/* v0.9.4: Board Mode print popover — collapsed print actions + IP/Port.
   Sits inline in the flex flow (pushes canvas down only while open). */
#board-print-menu, #board-check-menu, #board-size-menu {
  background: var(--bg, #0e1116);
  border: 1px solid var(--accent-warm, #f0a35e);
  border-radius: 8px;
  padding: 6px;
  margin-top: 4px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
#board-print-menu[hidden], #board-check-menu[hidden], #board-size-menu[hidden] { display: none; }
/* v0.9.5: the ruler-fields span had inline display:inline-flex which
   overrode the [hidden] attribute — force it off so the row truly
   collapses when no ruler is active. */
#board-ruler-fields[hidden] { display: none !important; }
/* v0.9.5: 🩺 Check button turns warm/red when there are issues. */
#board-check-toggle.has-issues {
  background: var(--danger, #ff7676);
  color: #0a0d12;
  border-color: var(--danger, #ff7676);
  font-weight: 700;
}
/* v0.9.5: keep the board status hint to a single clipped line. */
#board-status {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
@keyframes toast-in {
  from { opacity: 0; transform: translate(-50%, -40%); }
  to { opacity: 1; transform: translate(-50%, -50%); }
}

/* ---- Paint mode panel (v0.5.1) ---- */
/* Mirrors the nudge-panel layout so both modes feel like the same family. */
#paint-panel {
  background: var(--bg-elev);
  border-bottom: 1px solid var(--accent);
  padding: 6px 8px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
}
#paint-panel[hidden] { display: none; }
#paint-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--text-dim);
  font-size: 11px;
}
#paint-close {
  width: 28px;
  height: 28px;
  font-size: 14px;
  padding: 0;
}
#paint-swatches {
  /* 26 letter swatches + erase. Grid keeps them aligned and lets us pack
     ~9 per row on a typical phone width without each square shrinking to
     unreadable. minmax() floor of 32px protects readability on narrow
     screens; auto-fill spreads the rest. */
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(32px, 1fr));
  gap: 4px;
}
.swatch {
  height: 32px;
  border: 2px solid transparent;
  border-radius: 5px;
  color: #fff;
  /* Letter on the swatch — outlined so it stays readable over light AND
     dark palette colors without a per-swatch foreground choice. */
  text-shadow: 0 0 2px #000, 0 0 2px #000;
  font-weight: 800;
  font-size: 14px;
  cursor: pointer;
  padding: 0;
  /* Background is set inline per swatch from the palette in render.js */
}
.swatch.swatch-erase {
  background: #2d3340;
  color: #8b96a8;
  font-size: 10px;
  font-weight: 600;
}
.swatch.active {
  /* "Loaded brush" indicator — a bright ring jason can spot at a glance.
     Picked white so it works over any palette color. */
  border-color: #fff;
  box-shadow: 0 0 0 1px #0a0d12, 0 0 6px rgba(255,255,255,0.5);
}
#btn-paint.active {
  background: var(--accent);
  color: #0a0d12;
}

/* ---- Rapid Label panel (v0.6.7) ---- */
/* Sits in the flex flow above the canvas. The pin tag shows which pin you
   tapped, the input is wide enough for ~12 char signal names, the ↵
   button is a thumb-tap alternative to the keyboard Enter key. */
#label-panel {
  background: var(--bg-elev);
  border-bottom: 1px solid var(--accent);
  padding: 6px 8px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
}
#label-panel[hidden] { display: none; }
#label-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--text-dim);
  font-size: 11px;
}
#label-close {
  width: 28px;
  height: 28px;
  font-size: 14px;
  padding: 0;
}
#label-input-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
#label-pin-num {
  width: 56px;
  font-family: monospace;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
  padding: 10px 4px;
  background: var(--bg);
  color: var(--accent);
  border: 1px solid var(--border);
  border-radius: 6px;
  /* Hide spinner arrows — looks cleaner, big-tap on the field is enough */
  -moz-appearance: textfield;
}
#label-pin-num::-webkit-outer-spin-button,
#label-pin-num::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
#label-pin-num:disabled {
  color: var(--text-dim);
}
#label-input {
  flex: 1 1 auto;
  font-family: monospace;
  font-size: 16px; /* >= 16px so iOS Safari does not zoom on focus */
  padding: 10px 8px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
}
#label-input:disabled {
  color: var(--text-dim);
  font-style: italic;
}
#label-next {
  padding: 8px 14px;
  font-size: 16px;
  font-weight: 700;
}
#label-lock {
  padding: 8px 8px;
  font-size: 16px;
  width: 40px;
}
#label-lock:disabled { opacity: 0.4; }
#btn-label.active {
  background: var(--accent);
  color: #0a0d12;
}

/* ---- Wire Mode panel (v0.6) ---- */
/* Same flex-flow trick as nudge/paint panels — pushes canvas down rather
   than overlaying it, so all pads stay visible. */
#wire-panel {
  background: var(--bg-elev);
  border-bottom: 1px solid var(--accent);
  padding: 6px 8px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
}
#wire-panel[hidden] { display: none; }
#wire-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
#wire-status {
  color: var(--accent);
  font-weight: 600;
  font-size: 12px;
  font-family: monospace;
}
#wire-close {
  width: 28px;
  height: 28px;
  font-size: 14px;
  padding: 0;
}
.wire-row {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
}
/* v0.9.7: every Wire/Board toolbar button is the SAME rectangle — uniform
   height, equal width share within a row, centered label. Packs the row
   evenly instead of ragged mixed-width buttons. */
.wire-row button {
  flex: 1 1 0;
  min-width: 48px;
  height: 40px;
  font-size: 11px;
  line-height: 1.1;
  padding: 4px 4px;
  font-family: monospace;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  box-sizing: border-box;
}
#btn-level.active {
  background: var(--accent);
  color: #0a0d12;
}

/* Project manager modal (v0.6.21). Reuses Library overlay scrim + panel
   styles. lib-row card layout works as-is for projects. */
#proj-overlay {
  position: fixed; inset: 0; z-index: 1100;
  background: rgba(10,13,18,0.85);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 20px 12px; overflow-y: auto;
}
#proj-overlay[hidden] { display: none; }
#proj-panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  width: 100%; max-width: 480px;
  display: flex; flex-direction: column; gap: 10px;
}
#proj-panel h2 { margin: 0; font-size: 16px; color: var(--accent); }
#proj-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
#proj-search-row { display: flex; gap: 4px; }
#proj-search {
  flex: 1 1 auto;
  font-size: 14px; padding: 8px 10px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
}
#proj-search-clear { width: 36px; padding: 0; }
#proj-list {
  display: flex; flex-direction: column; gap: 6px;
  max-height: 50vh; overflow-y: auto;
}
.proj-current { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.proj-active-tag {
  color: var(--accent);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
}
.proj-thumb { width: 100px !important; }
#proj-import-row textarea {
  width: 100%;
  font-family: monospace; font-size: 11px;
  padding: 6px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  resize: vertical;
}

#wire-tool.active {
  background: var(--accent);
  color: #0a0d12;
}
#wire-snap.active {
  background: var(--accent);
  color: #0a0d12;
}

/* ---- Component Maker overlay (v0.6.1) ---- */
/* Same modal pattern as the calibration overlay - opaque scrim + centered
   panel. Form fields are big-tap-friendly with row labels. */
#comp-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 13, 18, 0.85);
  z-index: 1000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 20px 12px;
  overflow-y: auto;
}
#comp-overlay[hidden] { display: none; }
#comp-panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 14px 12px;
  width: 100%;
  max-width: 440px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#comp-panel h2 {
  margin: 0;
  font-size: 16px;
  color: var(--accent);
}
.comp-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.comp-row .ctrl {
  flex: 1 1 100px;
}
.comp-row .ctrl > span {
  font-size: 11px;
  color: var(--text-dim);
  display: block;
  margin-bottom: 2px;
}
.comp-row .ctrl input,
.comp-row .ctrl select {
  width: 100%;
  font-size: 14px;
  padding: 8px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.comp-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 4px;
}
.comp-actions button {
  padding: 10px 16px;
  font-size: 13px;
}

/* ---- Library modal (v0.6.2) ---- */
/* Reuses comp-overlay's scrim style; the panel is a tall list with rows */
#lib-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 13, 18, 0.85);
  z-index: 1000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 20px 12px;
  overflow-y: auto;
}
#lib-overlay[hidden] { display: none; }
#lib-panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 14px 12px;
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#lib-panel h2 {
  margin: 0;
  font-size: 16px;
  color: var(--accent);
}
#lib-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
#lib-x {
  width: 32px;
  height: 32px;
  font-size: 14px;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  border-radius: 6px;
  border: 1px solid var(--border);
}
#lib-x:hover, #lib-x:active {
  background: var(--bg-elev);
  color: var(--accent);
}
/* Search bar (v0.6.18). Lives above the chip row, filters live. */
#lib-search-row {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}
#lib-search {
  flex: 1 1 auto;
  font-size: 14px;
  padding: 8px 10px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  /* Hide the default browser clear control - we provide our own button */
  -webkit-appearance: none;
}
#lib-search-clear {
  width: 36px;
  font-size: 13px;
  padding: 0;
}
.lib-cat-tag {
  display: inline-block;
  margin-top: 2px;
  padding: 1px 4px;
  border-radius: 3px;
  cursor: pointer;
  color: var(--text-dim);
}
.lib-cat-tag:hover, .lib-cat-tag:active {
  background: rgba(78, 201, 154, 0.10);
  color: var(--accent);
}
.lib-cat-edit {
  font-size: 10px;
  margin-left: 4px;
  opacity: 0.7;
}

/* Category filter chips (v0.6.17). Horizontal scroll on narrow screens. */
#lib-filter-row {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding-bottom: 4px;
  flex-shrink: 0;
}
.lib-chip {
  font-size: 11px;
  padding: 6px 10px;
  border-radius: 999px;
  background: var(--bg);
  color: var(--text-dim);
  border: 1px solid var(--border);
  flex-shrink: 0;
  white-space: nowrap;
}
.lib-chip.active {
  background: var(--accent);
  color: #0a0d12;
  border-color: var(--accent);
}

/* AI Review prompt overlay (v0.6.29). Same scrim style as save-overlay.
   Textarea is monospace for prompt clarity. */
#review-overlay {
  position: fixed; inset: 0; z-index: 1100;
  background: rgba(10,13,18,0.85);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 20px 12px; overflow-y: auto;
}
#review-overlay[hidden] { display: none; }
#review-panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  width: 100%; max-width: 480px;
  display: flex; flex-direction: column; gap: 10px;
}
#review-panel h2 { margin: 0; font-size: 16px; color: var(--accent); }
#review-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
#review-x { width: 32px; height: 32px; padding: 0; font-size: 14px; }
#review-prompt {
  width: 100%;
  font-family: monospace;
  font-size: 11px;
  padding: 8px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  resize: vertical;
  min-height: 180px;
}
#review-overlay .comp-row .ctrl input {
  width: 100%;
  font-size: 14px;
  padding: 8px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
}
#review-overlay .comp-row .ctrl > span {
  font-size: 11px;
  color: var(--text-dim);
  display: block;
  margin-bottom: 2px;
}

/* Save-to-Library overlay (v0.6.17). Reuses the comp-overlay scrim style. */
#save-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 13, 18, 0.85);
  z-index: 1100;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 20px 12px;
  overflow-y: auto;
}
#save-overlay[hidden] { display: none; }
#save-panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  width: 100%;
  max-width: 440px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#save-panel h2 {
  margin: 0;
  font-size: 16px;
  color: var(--accent);
}

#lib-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 50vh;
  overflow-y: auto;
}
.lib-empty {
  color: var(--text-dim);
  font-size: 12px;
  font-style: italic;
  padding: 8px 4px;
}
/* Card-style library row (v0.6.15): thumbnail on the LEFT, meta in the
   MIDDLE with breathing room, action buttons stacked VERTICALLY on the
   RIGHT. Replaces the v0.6.14 horizontal-actions layout that squeezed
   the name to one letter per line on narrow phones. */
.lib-row {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px;
  /* Card height matches the 60px thumbnail + padding. Action buttons
     shrink to fill that height equally (4 buttons / ~16px each). */
}
.lib-thumb {
  flex-shrink: 0;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 4px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  align-self: center;
}
.lib-meta {
  flex: 1 1 auto;
  font-size: 12px;
  color: var(--text);
  min-width: 0;
  overflow-wrap: anywhere;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
}
.lib-meta strong {
  display: block;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.2;
}
.lib-meta small { color: var(--text-dim); font-size: 11px; }
.lib-actions {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex-shrink: 0;
  align-self: stretch;
  justify-content: stretch;
  min-width: 64px;
}
.lib-actions button {
  flex: 1 1 0;     /* equal-height share of the 4-button stack */
  font-size: 10px;
  padding: 2px 6px;
  width: 100%;
  line-height: 1;
  min-height: 0;
}
.lib-del { color: #ff7a7a; }
#lib-import-row textarea {
  width: 100%;
  font-family: monospace;
  font-size: 11px;
  padding: 6px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  resize: vertical;
}

/* v0.6.24's keyboard-aware compact mode was removed in v0.6.26 — the
   automatic shrinking caused visible "jump" effects when the keyboard
   showed/hid. The lift bar now handles vertical positioning manually,
   user-controlled, no reflow. */

/* v0.6.31: mode-aware UI. The Wire Mode workspace needs as much canvas
   as we can give it; the Component-Mode controls aren't relevant there.
   Toggle body.mode-comp / body.mode-wire from JS based on state.level. */
body.mode-wire [data-mode="comp"] { display: none !important; }
body.mode-comp [data-mode="wire"] { display: none !important; }
/* v0.7.0: Board Mode hides Component-Mode only AND most Wire-Mode-only
   controls (since Board Mode shows the layout, not the schematic). */
body.mode-board [data-mode="comp"] { display: none !important; }
body.mode-board #wire-panel { display: none !important; }
body.mode-board #botbar { display: none; }
body.mode-board #foot-dock { display: none; }
body.mode-board #lift-bar { display: none; }
/* Board panel styling mirrors wire panel */
#board-panel {
  background: var(--bg-elev);
  border-bottom: 1px solid var(--accent-warm);
  padding: 6px 8px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
}
#board-panel[hidden] { display: none; }
#board-panel .wire-row button {
  flex: 1 1 0;
  min-width: 0;
  height: 32px;
  padding: 0 4px;
  font-size: 12px;
  white-space: nowrap;
  /* v0.8.1: clip overflow + ellipsis so labels can never pour out of the
     button box. Combined with fewer-buttons-per-row this keeps them legible. */
  overflow: hidden;
  text-overflow: ellipsis;
}
/* v0.8.1/4: active state for the in-place pad-edit + snap toggles. */
#board-pad-edit.active,
#board-pad-snap.active {
  background: var(--accent-warm);
  color: #0a0d12;
  border-color: var(--accent-warm);
}
#board-pad-undo:disabled { opacity: 0.35; }
/* v0.8.2: zoom +/- are icon-only - give them a narrow FIXED width so the
   labeled buttons (Fit, 1:1, Pads, Exit) get the rest of the row and show
   their full text instead of getting ellipsis-clipped. */
.board-icon-btn {
  flex: 0 0 34px !important;
  font-size: 15px;
  padding: 0 !important;
}
#board-panel .ctrl input { width: 64px; }
#btn-board.active {
  background: var(--accent-warm);
  color: #0a0d12;
  border-color: var(--accent-warm);
}

/* Hide the Component-Mode status row + hint in Wire Mode — those refer
   to pin count / next pin / drawing hints which don't apply. */
body.mode-wire #botbar { display: none; }
/* Hide the foot-dock placeholder in Wire Mode so the canvas claims that
   space too. The dock returns when there's something useful to put in it. */
body.mode-wire #foot-dock { display: none; }
/* v0.6.44: lift bar is irrelevant in Wire Mode - the topbar stays put
   and the wire toolbar lives directly under it, so there's nothing to
   push out of the way. Hide it to reclaim the right-edge real estate. */
body.mode-wire #lift-bar { display: none; }
/* v0.7.18: nudge mode collapses the topbar's big button grid - in nudge
   mode the nudge panel IS the toolset, so Pitch/Shape/Board/New/1:1/grid/
   Paint/Label/Wire/Board/Projects/Save/ToProject/Open/share/Review/Send
   are all irrelevant. Hiding them reclaims ~450px so the canvas + footer
   get the screen. The "DotGame ▸ esp32-s3" title stays so jason still
   sees what he is editing. The lift bar STAYS available for fine scroll. */
body.mode-nudge #topbar-controls { display: none; }
body.mode-nudge #topbar { padding-bottom: 4px; }

/* v0.6.33-35: compact wire toolbar - two rows of buttons. Most flex:1 to
   share evenly. Undo/Redo are narrower fixed-width icons. */
#wire-row-ops button,
#wire-row-view button {
  flex: 1 1 0;
  min-width: 0;
  height: 32px;
  padding: 0 4px;
  font-size: 12px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  line-height: 1;
  white-space: nowrap;
}
/* Undo/Redo: narrow square buttons so the rest of the row keeps text labels. */
#wire-undo, #wire-redo {
  flex: 0 0 30px;
  font-size: 16px;
  padding: 0;
}
#wire-undo:disabled, #wire-redo:disabled { opacity: 0.35; }

/* v0.6.35: wire color picker. Inline horizontal row of letter swatches,
   visible only when a wire is selected. Compact — 22px tall row to keep
   the canvas the dominant element. */
#wire-color-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 0 0;
}
#wire-color-row[hidden] { display: none; }
#wire-color-label { font-size: 10px; color: var(--text-dim); flex: 0 0 auto; }
#wire-color-swatches {
  display: flex;
  gap: 2px;
  flex: 1 1 auto;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.wire-swatch {
  flex: 0 0 22px;
  height: 22px;
  border: 1px solid transparent;
  border-radius: 4px;
  color: #fff;
  text-shadow: 0 0 2px #000, 0 0 2px #000;
  font-weight: 800;
  font-size: 11px;
  cursor: pointer;
  padding: 0;
}
.wire-swatch.swatch-erase {
  background: #2d3340;
  color: #8b96a8;
  font-size: 9px;
  font-weight: 600;
}
.wire-swatch.active {
  border-color: #fff;
  box-shadow: 0 0 0 1px #0a0d12, 0 0 4px rgba(255,255,255,0.5);
}
/* In Wire Mode topbar collapses to a single row of just the universal
   controls (Wire toggle, Projects, Share, Send, component name). */
body.mode-wire #topbar-controls { gap: 4px; flex-wrap: wrap; }
body.mode-wire #topbar { padding: 4px 6px; gap: 2px; }
/* v0.8.3: compact the board-mode topbar buttons so Wire / Board / Projects
   / share / Send all fit on ONE row (Send was wrapping to its own line). */
body.mode-board #topbar-controls { gap: 4px; }
body.mode-board #topbar-controls button {
  font-size: 12px;
  padding: 5px 8px;
}
/* v0.6.26: removed all body.kbd-up auto-positioning. The lift bar (below)
   is now the sole mechanism for repositioning the UI vertically. No more
   automatic reflows on keyboard show/hide, so no more "jumping". */

/* ---- Foot dock (v0.6.26) ---- */
/* Sits BELOW the status bar at the bottom of #app-shell. Empty placeholder
   for now — jason wants quick-access controls here later. When the user
   drags the lift thumb down, the whole shell translates up uniformly, so
   the foot-dock rides up along with the canvas + status, keeping the
   grid's aspect ratio intact. */
#foot-dock {
  flex-shrink: 0;
  background: var(--bg-elev);
  border-top: 1px solid var(--border);
  min-height: 36px;
  padding: 4px 8px;
  display: flex;
  align-items: center;
  gap: 6px;
}
#foot-dock-spacer {
  flex: 1 1 auto;
  height: 100%;
  color: var(--text-muted);
  font-size: 10px;
  font-style: italic;
  text-align: center;
}

/* ---- Lift bar (v0.6.25/26) ---- */
/* A draggable vertical thumb on the right edge of the screen. As the user
   drags it down, the WHOLE #app-shell translates up uniformly (transform
   translateY). Canvas keeps its size, grid keeps proportion, foot-dock
   rides up with everything. Position persists across keyboard cycles. */
#lift-bar {
  position: fixed;
  top: 8%;
  right: 2px;
  width: 16px;       /* v0.6.43: shrunk from 22px to give the color picker more room */
  height: 70%;
  background: rgba(78, 192, 255, 0.06);
  border: 1px solid rgba(78, 192, 255, 0.15);
  border-radius: 8px;
  z-index: 200;
  touch-action: none;
  pointer-events: auto;
}
#lift-thumb {
  position: absolute;
  left: 1px;
  right: 1px;
  height: 44px;       /* v0.6.43: matches narrower bar */
  top: 0;
  background: rgba(78, 192, 255, 0.55);
  border: 1px solid rgba(78, 192, 255, 0.9);
  border-radius: 8px;
  cursor: grab;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  /* center triple-line grip indicator */
  background-image: linear-gradient(
    to bottom,
    transparent calc(50% - 8px),
    rgba(255, 255, 255, 0.55) calc(50% - 8px),
    rgba(255, 255, 255, 0.55) calc(50% - 7px),
    transparent calc(50% - 7px),
    transparent calc(50% - 2px),
    rgba(255, 255, 255, 0.55) calc(50% - 2px),
    rgba(255, 255, 255, 0.55) calc(50% - 1px),
    transparent calc(50% - 1px),
    transparent calc(50% + 4px),
    rgba(255, 255, 255, 0.55) calc(50% + 4px),
    rgba(255, 255, 255, 0.55) calc(50% + 5px),
    transparent calc(50% + 5px)
  );
}
#lift-thumb:active,
#lift-thumb.dragging {
  cursor: grabbing;
  background-color: rgba(78, 192, 255, 0.85);
}
