/* Pipe Fitter - application layout and control styling.
   Design tokens and component classes come from dark.css; this sheet holds
   the app shell, the range-input skin, and the viewer overlays. */

html, body {
  margin: 0;
  height: 100%;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
}
a { color: var(--color-accent-300); text-decoration: none; }
a:hover { color: var(--color-accent-200); }
::selection { background: var(--color-accent-800); }

/* ── Range inputs ─────────────────────────────────────────────────────────── */
input[type=range] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 2px; margin: 0;
  background: var(--color-neutral-800); border-radius: 2px; outline: none;
}
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--color-bg); border: 2px solid var(--color-accent);
  cursor: ew-resize;
}
input[type=range]::-webkit-slider-thumb:hover { background: var(--color-accent-800); }
input[type=range]::-moz-range-thumb {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--color-bg); border: 2px solid var(--color-accent);
  cursor: ew-resize;
}
input[type=range]:focus-visible::-webkit-slider-thumb {
  outline: 2px solid var(--color-accent); outline-offset: 2px;
}

/* ── App shell ────────────────────────────────────────────────────────────── */
.app {
  height: 100vh;
  display: flex; flex-direction: column;
  overflow: hidden;
  background: var(--color-bg);
}

/* ── Header ───────────────────────────────────────────────────────────────── */
.topbar {
  display: flex; align-items: center; gap: var(--space-8);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--color-neutral-900);
  flex: 0 0 auto;
}
.brand {
  display: flex; flex-direction: column; gap: 1px;
  min-width: 0; flex: 1 1 auto; overflow: hidden; white-space: nowrap;
}
.brand-title {
  display: flex; align-items: baseline; gap: var(--space-3);
  white-space: nowrap; min-width: 0; overflow: hidden;
}
.brand-name {
  font-family: var(--font-heading); font-weight: 500;
  font-size: 15px; letter-spacing: 0.02em;
}
.brand-sub { font-size: 11px; color: var(--color-neutral-600); }
.brand-summary {
  font-family: 'JetBrains Mono', monospace; font-size: 11px;
  color: var(--color-neutral-700); letter-spacing: 0.04em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.units-switch {
  display: flex; gap: var(--space-1); padding: var(--space-1);
  border: 1px solid var(--color-neutral-900); border-radius: var(--radius-md);
  flex: 0 0 auto;
}
.units-switch .btn {
  padding: 4px 9px; font-size: 11px;
  border-radius: var(--radius-sm); white-space: nowrap;
}

.actions { display: flex; align-items: center; gap: var(--space-3); flex: 0 0 auto; }
.actions .btn { white-space: nowrap; flex: 0 0 auto; font-size: 12px; }
.actions .btn-undo, .actions .btn-redo { padding: 6px 11px; }
.actions .menu-trigger { padding: 6px 12px; }
.actions .btn-help {
  width: 28px; padding: 6px 0; font-size: 13px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}
/* Undo/Redo collapsed to gapped circle-arrow icons on narrow screens. */
.actions .btn-icon {
  width: 28px; padding: 6px 0; font-size: 16px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}

/* Once the panel is forced below the viewer (width < 900), the topbar gets
   crowded, so tuck the mm/in toggle tighter against its neighbors. */
@media (max-width: 899px) {
  .units-switch { margin-left: -32px; margin-right: -12px; }
}
/* Below this the brand and the controls can't share a row without the
   (negatively-margined) unit toggle overlapping the title, so wrap the brand
   onto its own line above the controls and drop the now-pointless negative
   margins (which would otherwise hang the toggle off the row's left edge). */
@media (max-width: 790px) {
  /* Brand wraps to its own line; the tighter column-gap keeps every control
     button (toggle + actions) together on the single line below it. */
  .topbar { flex-wrap: wrap; row-gap: 8px; column-gap: 12px; justify-content: flex-end; }
  .brand { flex-basis: 100%; }
  .units-switch { margin: 0; }
}
/* Phone widths (e.g. iPhone 12 Pro, 390px): shrink padding, gaps, and the
   menu-trigger buttons further so the control row still fits on one line. */
@media (max-width: 480px) {
  .topbar { padding-left: 8px; padding-right: 8px; column-gap: 6px; }
  .units-switch .btn { padding: 4px 7px; }
  .actions { gap: 5px; }
  .actions .menu-trigger { padding: 6px 8px; }
}

/* ── Download hover menus ─────────────────────────────────────────────────── */
.menu { position: relative; flex: 0 0 auto; }
.menu-trigger { white-space: nowrap; }
.menu-list {
  position: absolute; top: 100%; right: 0; z-index: 40;
  display: none; flex-direction: column; min-width: 100%;
  margin-top: 4px; padding: 4px; gap: 2px;
  background: var(--color-surface);
  border: 1px solid var(--color-neutral-800);
  border-radius: var(--radius-md); box-shadow: var(--shadow-md);
}
/* A transparent bridge over the 4px gap keeps hover continuous. */
.menu-list::before { content: ''; position: absolute; left: 0; right: 0; top: -4px; height: 4px; }
.menu:hover .menu-list, .menu:focus-within .menu-list { display: flex; }
.menu-heading {
  padding: 6px 10px 2px; font-family: var(--font-body);
  font-size: 10px; font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--color-neutral-500);
}
/* A heading that follows items is the 2nd group (3MF) - space it off from the first. */
.menu-item + .menu-heading { margin-top: 4px; }
.menu-item {
  display: block; width: 100%; text-align: left; white-space: nowrap;
  padding: 6px 10px; font-family: var(--font-body); font-size: 12px;
  color: var(--color-neutral-200); background: none; border: 0;
  border-radius: var(--radius-sm); cursor: pointer;
}
.menu-item:hover, .menu-item:focus-visible {
  background: color-mix(in srgb, var(--color-accent) 14%, transparent);
  color: var(--color-accent-100); outline: none;
}
.menu-item.is-active { color: var(--color-accent-200); }
.menu-item.is-active::after { content: '✓'; float: right; margin-left: 14px; opacity: 0.85; }
/* Wide enough that the longest option plus its ✓ stays on one line. */
.menu-render .menu-list { min-width: 132px; }

/* ── Help modal ───────────────────────────────────────────────────────────── */
.help-backdrop {
  position: fixed; inset: 0; z-index: 50;
  display: grid; place-items: center; padding: var(--space-8);
  background: color-mix(in srgb, var(--color-neutral-900) 55%, transparent);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.help-backdrop[hidden] { display: none; }
.help-dialog {
  position: relative;
  width: min(560px, 100%); max-height: 80vh; overflow: auto;
  padding: var(--space-8) 28px;
  background: var(--color-surface);
  border: 1px solid var(--color-neutral-800);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.help-dialog::-webkit-scrollbar { width: 9px; }
.help-dialog::-webkit-scrollbar-thumb { background: var(--color-neutral-800); border-radius: 5px; }
.help-close {
  position: absolute; top: var(--space-4); right: var(--space-4);
  width: 26px; height: 26px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--color-neutral-500); font-size: 13px; cursor: pointer;
}
.help-close:hover { background: color-mix(in srgb, var(--color-text) 8%, transparent); color: var(--color-neutral-200); }

/* Rendered markdown, themed to match the app */
.markdown { color: var(--color-neutral-300); font-size: 14px; line-height: 1.6; }
.markdown > :first-child { margin-top: 0; }
.markdown > :last-child { margin-bottom: 0; }
.markdown h1 {
  font-family: var(--font-heading); font-weight: 500; font-size: 20px;
  letter-spacing: 0.01em; color: var(--color-neutral-100); margin: 0 0 12px;
}
.markdown h2 {
  font-family: var(--font-heading); font-weight: 500; font-size: 16px;
  color: var(--color-neutral-200); margin: 18px 0 8px;
}
.markdown h3 {
  font-family: var(--font-heading); font-weight: 500; font-size: 14px;
  color: var(--color-neutral-200); margin: 14px 0 6px;
}
.markdown p { margin: 0 0 10px; }
.markdown ul, .markdown ol { margin: 0 0 10px; padding-left: 20px; }
.markdown li { margin: 2px 0; }
.markdown a { color: var(--color-accent-300); }
.markdown a:hover { color: var(--color-accent-200); }
.markdown strong { color: var(--color-neutral-100); font-weight: 600; }
.markdown code {
  font-family: 'JetBrains Mono', monospace; font-size: 0.9em;
  background: color-mix(in srgb, var(--color-text) 8%, transparent);
  padding: 1px 5px; border-radius: 4px; color: var(--color-neutral-200);
}
.markdown blockquote {
  margin: 0 0 10px; padding-left: 12px;
  border-left: 2px solid var(--color-neutral-700); color: var(--color-neutral-400);
}
.markdown hr { border: 0; height: 1px; background: var(--color-neutral-800); margin: 16px 0; }

/* ── Body split ───────────────────────────────────────────────────────────── */
.body { flex: 1 1 auto; display: flex; min-height: 0; }

/* ── Control panel ────────────────────────────────────────────────────────── */
.pnl {
  flex: 0 0 auto; overflow: auto;
  border: 1px solid var(--color-neutral-900);
  background: linear-gradient(180deg, var(--color-panel), var(--color-bg));
}
.pnl::-webkit-scrollbar { width: 9px; }
.pnl::-webkit-scrollbar-thumb { background: var(--color-neutral-800); border-radius: 5px; }
/* Collapse/Expand-all bar, pinned to the top of the scrolling panel so it stays
   visible. Opaque background covers group content scrolling underneath. Hidden
   in the bottom layout (set from applyLayout). */
.panel-toolbar {
  position: sticky; top: 0; z-index: 5;
  display: flex; gap: 8px;
  padding: 10px var(--space-6);
  background: var(--color-panel);
  border-bottom: 1px solid var(--color-neutral-900);
}
.panel-toolbar .btn { flex: 1 1 0; padding: 5px 8px; font-size: 11px; }
/* The side-swap arrow is an icon, so it keeps its width instead of taking a
   third of the bar. `order` puts it past the two buttons when the panel is on
   the left, and ahead of them when it's on the right (set from applyLayout). */
.panel-toolbar .panel-side {
  flex: 0 0 auto; padding: 5px 9px; font-size: 13px; line-height: 1;
  color: var(--color-neutral-500);
}
.panel-toolbar .panel-side:hover { color: var(--color-text); }
/* Extra top padding clears the "+ Pipe ↑" button, which straddles the first
   block's top border and pokes up out of the grid. */
.panel-grid { display: grid; gap: var(--space-8); padding: var(--space-6) var(--space-2) var(--space-2); }

/* One pipe's cards, boxed together with the header that folds the whole part
   away - so a chain reads as separate parts rather than one long list. */
.pipe-block {
  position: relative;
  display: flex; flex-direction: column; gap: var(--space-8); min-width: 0;
  padding: var(--space-6) var(--space-3) var(--space-6);
  border: 1px solid var(--color-neutral-800); border-radius: var(--radius-md);
}
/* The two "+ Pipe" joins straddle the block's edge - near-end on the top border,
   far-end on the bottom - so they read as attaching to the pipe box. An opaque
   fill (matching the panel) masks the border line running behind them. */
.pipe-join, .pipe-foot {
  position: absolute; right: var(--space-3); z-index: 1;
}
.pipe-join { top: 0; transform: translateY(-50%); }
.pipe-foot { bottom: 0; transform: translateY(50%); }
.pipe-join, .pipe-foot-add { background: var(--color-panel); }
.pipe-join:hover, .pipe-foot-add:hover { background: color-mix(in srgb, var(--color-text) 7%, var(--color-panel)); }
.pipe-join:active, .pipe-foot-add:active { background: color-mix(in srgb, var(--color-text) 14%, var(--color-panel)); }
/* The join arrow lives here, not in the label, so it can flip between layouts
   without rebuilding the panel: stacked ↑/↓ beside the viewer, ←/→ when the
   panel is docked below in a left-to-right row of pipes. */
.pipe-join::after { content: '↑'; }
.pipe-foot-add::after { content: '↓'; }
.pnl.is-below .pipe-join::after { content: '←'; }
.pnl.is-below .pipe-foot-add::after { content: '→'; }
/* Docked, "add before" attaches to the left end of the row, so it moves to the
   left of the box. */
.pnl.is-below .pipe-join { left: var(--space-3); right: auto; }
.pipe-block.collapsed > .group { display: none; }
/* Folded away, the box hugs its header instead of leaving the body's gap. */
.pipe-block.collapsed { padding-bottom: var(--space-4); }
.pipe-block.collapsed .pipe-head .group-caret { transform: rotate(-90deg); }
/* Join-a-pipe row below the last section. It rides the block's bottom border
   (like the "+ Pipe" join on the top border), so it stays put when the pipe is
   folded down to its header rather than folding away with the body. */
.pipe-foot { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2); }
.pipe-foot-add { padding: 3px 10px; font-size: 11px; border-radius: var(--radius-sm); }
.pipe-head { padding-bottom: 0; }
/* Docked below the viewer (narrow/mobile), a whole pipe can't be folded away -
   only its sections and bends collapse. Drop the header's caret, disable its
   toggle, and force open any pipe that was folded in a side layout. */
.pnl.is-below .pipe-head .group-caret { display: none; }
.pnl.is-below .pipe-head .group-toggle { pointer-events: none; }
.pnl.is-below .pipe-block.collapsed > .group { display: flex; }
.pnl.is-below .pipe-block.collapsed { padding-bottom: var(--space-6); }
.pipe-head .group-title { font-size: 14px; color: var(--color-neutral-200); }
.pipe-head .group-rule { background: linear-gradient(90deg, var(--color-neutral-700), transparent); }

.group { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.group-head {
  display: flex; align-items: center; gap: var(--space-3); padding-bottom: var(--space-2);
}
.group-toggle {
  display: flex; align-items: center; gap: var(--space-3); min-width: 0;
  padding: 0; margin: 0; border: 0; background: none;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.group-caret {
  font-size: 9px; line-height: 1; color: var(--color-neutral-600);
  transition: transform 0.12s ease;
}
.group.collapsed .group-caret { transform: rotate(-90deg); }
.group-toggle:hover .group-title { color: var(--color-neutral-100); }
.group-toggle:hover .group-caret { color: var(--color-neutral-400); }
.group-body { display: flex; flex-direction: column; gap: var(--space-1); }
.group.collapsed .group-body { display: none; }
.group-tag {
  font-family: 'JetBrains Mono', monospace; font-size: 11px;
  color: var(--color-accent); letter-spacing: 0.1em;
}
.group-title {
  font-family: var(--font-heading); font-weight: 500;
  font-size: 13px; color: var(--color-neutral-300);
}
.group-rule {
  flex: 1 1 auto; height: 1px;
  background: linear-gradient(90deg, var(--color-neutral-800), transparent);
}
.group-mirror {
  padding: 2px 7px; font-size: 11px;
  white-space: nowrap; border-radius: var(--radius-sm);
}
/* Per-pipe show/hide eye: a square icon button holding an inline SVG. Dimmed
   when the pipe is hidden, so its state reads even without hovering. */
.group-eye {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 2px 6px; flex: 0 0 auto;
}
/* Sized to the text line-box of the sibling buttons (1.2em of the shared 11px
   font) so the eye button ends up exactly as tall as the close button. */
.group-eye svg { display: block; width: 1.2em; height: 1.2em; }
.group-eye.is-hidden { color: var(--color-neutral-500); opacity: 0.85; }

.presets {
  display: flex; flex-wrap: wrap; gap: var(--space-2); padding: 2px 0 6px;
}
.presets .btn {
  padding: 3px 10px; font-size: 11px; border-radius: var(--radius-sm);
}

/* Heading inside a card, separating two blocks of controls - the two end
   treatments a single-section pipe carries. */
.field-subhead {
  display: flex; align-items: center; gap: 8px;
  margin-top: var(--space-2); padding-bottom: 2px;
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--color-accent);
}
.field-subhead::after {
  content: ''; flex: 1 1 auto; height: 1px;
  background: linear-gradient(90deg, var(--color-neutral-800), transparent);
}
.group-body > .field-subhead:first-child { margin-top: 0; }

.field-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: 2px 0 4px; }
.field-action { padding: 3px 9px; font-size: 11px; white-space: nowrap; }
.field-readout {
  font-family: 'JetBrains Mono', monospace; font-size: 10px;
  color: var(--color-neutral-500); text-align: right; padding: 0 0 2px;
}
.field-toggle {
  display: flex; align-items: center; gap: 8px; padding: 4px 0; cursor: pointer;
  font-size: 11px; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--color-neutral-500);
}
.field-toggle input {
  width: 14px; height: 14px; margin: 0; cursor: pointer;
  accent-color: var(--color-accent);
}
.field-toggle span { margin-top: 3px; }

.field { display: grid; gap: 4px; padding: 4px 0; }
.field > label {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--space-3); margin: 0;
}
.field-name {
  font-size: 11px; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--color-neutral-500);
}
.field-hint {
  font-family: 'JetBrains Mono', monospace; font-size: 10px;
  color: var(--color-neutral-700);
}
.field-enum { width: 100%; min-height: 30px; padding: 4px 7px; font-size: 13px; }
.field-num {
  display: grid; grid-template-columns: 1fr 56px; gap: var(--space-4); align-items: center;
}
.field-num-input {
  width: 100%; min-height: 28px; padding: 3px 5px;
  font-family: 'JetBrains Mono', monospace; font-size: 12px; text-align: right;
}

/* ── Viewer ───────────────────────────────────────────────────────────────── */
.viewer {
  flex: 1 1 auto; position: relative; min-width: 0; min-height: 0;
  overflow: hidden;
  background: radial-gradient(120% 90% at 50% 15%, var(--color-glow) 0%, var(--color-bg) 70%);
}
/* touch-action: none stops the browser from claiming a touch-drag as a page
   scroll/gesture mid-orbit (which fires pointercancel and freezes the drag). */
.stage { position: absolute; inset: 0; cursor: grab; z-index: 1; touch-action: none; }
.stage canvas { display: block; touch-action: none; }

.overlay { position: absolute; z-index: 3; }
.overlay-tl {
  top: var(--space-6); left: var(--space-6);
  display: flex; flex-direction: column; gap: var(--space-2); pointer-events: none;
}
.overlay-kicker {
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--color-neutral-600);
}
.overlay-bbox {
  font-family: 'JetBrains Mono', monospace; font-size: 13px;
  color: var(--color-neutral-200);
}
.overlay-mesh {
  font-family: 'JetBrains Mono', monospace; font-size: 11px;
  color: var(--color-neutral-700);
}
.overlay-tr {
  top: var(--space-6); right: var(--space-6);
  display: flex; flex-direction: column; gap: var(--space-2);
  align-items: flex-end; max-width: 300px;
}
.note {
  font-size: 11px; line-height: 1.35; text-align: right;
  color: var(--color-accent-300); background: var(--color-accent-900);
  border: 1px solid var(--color-accent-800); border-radius: var(--radius-sm);
  padding: 4px 8px;
}
/* Only a note reporting something taken away carries a ✕ - a clamp note has no
   business being dismissed, since its limit is still in force. */
.note-dismissible { display: flex; align-items: flex-start; gap: 6px; }
.note-close {
  flex: none; margin: 0 -3px 0 0; padding: 0 3px;
  background: none; border: 0; border-radius: var(--radius-sm);
  color: inherit; font: inherit; line-height: inherit; opacity: 0.6; cursor: pointer;
}
.note-close:hover { opacity: 1; background: var(--color-accent-800); }
.overlay-br {
  bottom: var(--space-6); right: var(--space-6);
  display: flex; flex-direction: row; align-items: flex-end; gap: var(--space-4);
}
/* Warnings sit under the camera controls in the top-right stack. */
.overlay-tr .notes:empty { display: none; }
.overlay-tr .notes {
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-2);
  margin-top: var(--space-3);
}
.coffee { display: block; line-height: 0; }
.coffee img { display: block; width: 109px; height: 30px; }
.copyright {
  font-family: 'JetBrains Mono', monospace; font-size: 10px;
  color: var(--color-neutral-700); white-space: nowrap;
  /* Bottom-aligned with the coffee button and given its height, so the text
     centers against the button rather than the taller controls stack. */
  align-self: flex-end; height: 30px; line-height: 30px;
}
.br-controls {
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-3);
}
.br-controls .hint {
  font-family: 'JetBrains Mono', monospace; font-size: 10px;
  color: var(--color-neutral-700); text-align: right; line-height: 1.5;
}
.br-controls .btn-reset {
  padding: 4px 9px; font-size: 11px; white-space: nowrap;
  background: color-mix(in srgb, var(--color-bg) 78%, transparent);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
.view-presets { display: flex; align-items: center; gap: 6px; }
/* Vertical rule separating the view presets from the Reset button. */
.view-divider {
  align-self: stretch; width: 1px; margin: 2px 3px;
  background: var(--color-neutral-800);
}
/* On narrow screens the preset views (and their divider) drop out, leaving just
   Reset view. */
@media (max-width: 480px) {
  .view-presets .view-btn, .view-divider { display: none; }
}
.br-controls .view-btn {
  padding: 4px 9px; font-size: 11px; white-space: nowrap;
  background: color-mix(in srgb, var(--color-bg) 78%, transparent);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}

/* ── Schematic card ───────────────────────────────────────────────────────── */
.schematic {
  position: absolute; bottom: var(--space-6); left: var(--space-6); margin: 0;
  width: 352px; z-index: 2;
  border: 1px solid var(--color-neutral-800); border-radius: var(--radius-md);
  background: var(--color-card); box-shadow: var(--shadow-md); overflow: hidden;
}
/* The title bar doubles as the card's drag handle (see bindSchematicDrag).
   touch-action: none keeps a touch-drag from being claimed as a page gesture,
   for the same reason it's set on the canvases above. */
.schematic-cap {
  display: flex; justify-content: space-between; align-items: center;
  padding: 6px 9px; border-bottom: 1px solid var(--color-neutral-900);
  font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-neutral-600);
  cursor: move; user-select: none; touch-action: none;
}
.schematic.dragging { box-shadow: var(--shadow-lg); }
/* Expanded, the card is the whole viewer - nowhere to drag it to. */
.viewer.swapped .schematic-cap { cursor: default; }
.schematic-expand {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0;
  background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--color-neutral-500); font-size: 12px; line-height: 1; cursor: pointer;
}
.schematic-expand:hover { color: var(--color-neutral-200); background: color-mix(in srgb, var(--color-text) 8%, transparent); }
.schematic-expand.is-swapped { color: var(--color-accent-400); }
.schematic-canvas { display: block; width: 100%; height: 226px; cursor: grab; touch-action: none; }
/* Floating reset-view control, top-left over the drawing. Sits just below the
   caption. The column is a layout box only - it spans the drawing's width, so
   it must not swallow the drags and wheel-zoom aimed at the canvas beneath. */
.schematic-overlay {
  position: absolute; top: 40px; left: 10px; z-index: 3;
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  pointer-events: none;
}
.schematic-overlay > * { pointer-events: auto; }
.viewer.swapped .schematic-overlay { z-index: 6; }

/* Toggled visible from JS only when the diagram is zoomed or panned. */
.schematic-reset {
  padding: 4px 9px; font-size: 11px; white-space: nowrap;
  background: color-mix(in srgb, var(--color-bg) 78%, transparent);
  border-color: var(--color-neutral-800);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
.schematic-reset[hidden] { display: none; }

/* Steps the drawing through All Pipes → Pipe 1 → Pipe 2 …, so one part of a
   chain can be read on its own. Only present when there are several. */
.pipe-switch {
  display: flex; align-items: center; gap: 1px;
  padding: 1px 2px;
  font-size: 11px; color: var(--color-neutral-300);
  background: color-mix(in srgb, var(--color-bg) 78%, transparent);
  border: 1px solid var(--color-neutral-800); border-radius: var(--radius-sm);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  user-select: none;
}
.pipe-switch[hidden] { display: none; }
.pipe-switch-label { min-width: 62px; text-align: center; white-space: nowrap; }
.pipe-switch-arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0;
  background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--color-neutral-500); font-size: 14px; line-height: 1; cursor: pointer;
}
.pipe-switch-arrow:hover { color: var(--color-neutral-100); background: color-mix(in srgb, var(--color-text) 10%, transparent); }
/* At either end of the run the arrow goes, but keeps its slot so the label
   doesn't shift as you step through. */
.pipe-switch-arrow.is-off { visibility: hidden; }

/* Whenever the panel is docked below (the `panel-below` class, set from
   applyLayout at the same breakpoint), the docked card collapses to just its
   caption (title + expand button); expanding it still shows the full drawing. */
.viewer.panel-below:not(.swapped) .schematic { width: auto; }
.viewer.panel-below:not(.swapped) .schematic-cap { border-bottom: 0; gap: 14px; }
.viewer.panel-below:not(.swapped) .schematic-canvas,
.viewer.panel-below:not(.swapped) .schematic-reset { display: none; }
/* Lifted above the copyright/coffee row only when JS detects the docked card
   would otherwise overlap it (see updateSchematicPlacement). */
.viewer:not(.swapped) .schematic.raised { bottom: 55px; }

/* ── Swapped: diagram fills the viewer, 3D render is hidden ─────────────────── */
.viewer.swapped .schematic {
  inset: 0; width: auto; z-index: 4;
  border: 0; border-radius: 0; box-shadow: none;
  display: flex; flex-direction: column;
}
/* min-height: 0 lets the canvas shrink to the flex area instead of its intrinsic
   size. The drawing reserves space for the floating coffee button itself (the
   bottomInset passed to drawDiagram), so the content clears it. */
.viewer.swapped .schematic-canvas { flex: 1 1 auto; min-height: 0; height: auto; }
.viewer.swapped .stage { display: none; }
/* Let the coffee button float over the diagram; the 3D-view controls
   (reset / orbit hint) don't apply while the 3D view is hidden. */
.viewer.swapped .overlay-br { z-index: 5; }
.viewer.swapped .br-controls { display: none; }
