/* Greyscale only. Every colour here is a neutral: R, G and B are always equal,
   so nothing carries a hue. Dark theme is fixed, not system-dependent. */

:root {
  color-scheme: dark;

  --bg: #131313;
  /* Kept in sync by hand with the stroke colour baked into the #stage
     data-URI below; a var() cannot reach inside that URL. Holds the same
     5-step gap over --bg that it had at the older, darker values. */
  --plus: #181818;

  --panel: #1c1c1c;
  --panel-2: #232323;
  --well: #0a0a0a;

  /* Field labels sit just above the card in value. Must stay lighter than
     --panel, but well below --ink so the values still read first. */
  --label: #5a5a5a;

  /* The deliberate exceptions to the greyscale rule. Orange marks buildings
     in the machine view, and on anything else it's a warning: shortfalls and
     the like. Green marks outputs, the things the plan is for. */
  --warn: #e08b3d;
  --machine: 224, 139, 61;   /* as r, g, b so tints can share it */
  --output: 76, 190, 122;
  /* The outline round the open tab and along the toolbar. */
  --tab-line: #3c3c3c;
  /* The header: the one broad field of colour, a dark orange. */
  --header: #4d2a10;
  --header-edge: #6b3b17;

  --edge: #2e2e2e;
  --edge-hi: #4a4a4a;
  --edge-focus: #8a8a8a;

  --ink: #e8e8e8;
  --ink-dim: #9a9a9a;
  --ink-faint: #6a6a6a;
  --ink-ghost: #4a4a4a;

  --bright: #ededed;
  --bright-ink: #101010;

  /* Connectors: barely there until they matter. */
  --port: #232323;
  --port-live: #f4f4f4;
  --wire: #cfcfcf;

  --radius: 10px;
  --thumb-radius: 8px;
  --bar-h: 132px;   /* everything above the canvas; JS keeps it measured */
  --plan-w: min(372px, 44vw);  /* the plan column, right of the canvas */
  --cell: 44px;

  /* Thickness of the rail that runs down the sides and along the bottom, and
     the radius of the canvas corners that sit inside it. */
  --frame: 13px;
  --inner-radius: 12px;

  --font: "Space Grotesk", "Segoe UI", system-ui, sans-serif;
}

* { box-sizing: border-box; }

/* Class-level `display` beats the UA rule for [hidden], which would otherwise
   leave the empty-state and status overlays permanently visible. */
[hidden] { display: none !important; }

/* The header colour also paints the body, so it continues down both sides and
   across the bottom as a thin rail. The canvas is inset into that frame and
   rounded, which is what produces the rounded inner corners. */
html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  background: var(--panel);
  color: var(--ink);
  font: 14px/1.45 var(--font);
}

/* ---------- top bar ---------- */

/* No bottom rule: the header runs continuously into the side rails.
   Height is content-driven — the controls wrap on a narrow window — and JS
   mirrors the measured height into --bar-h so the canvas always starts below
   it instead of being overlapped. */
.top { position: relative; z-index: 20; }

.bar {
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 3px calc(var(--frame) + 6px);
  background: var(--header);
  border-bottom: 1px solid var(--header-edge);
  position: relative;
  z-index: 20;
}

.bar-left { display: flex; align-items: center; gap: 22px; min-width: 0; }
.brand { display: flex; align-items: baseline; gap: 8px; white-space: nowrap; }
.brand .mark {
  width: 10px; height: 10px; border-radius: 2px;
  background: var(--ink-dim);
  transform: rotate(45deg);
  align-self: center;
}
.brand strong { letter-spacing: 0.08em; font-size: 15px; }
.brand .sub { color: var(--ink-faint); font-size: 15px; }

/* Same borderless treatment as the card fields, scaled up for the header.
   A rule and a wide gutter hold it clear of the GCL wordmark so the two don't
   read as one run of text. */
.board-name {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding-left: 22px;
  border-left: 1px solid var(--edge);
}
.bn-label {
  flex: 0 0 auto;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--label);
  white-space: nowrap;
  user-select: none;
}
#board-name {
  min-width: 0;
  width: 230px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 5px;
  color: var(--ink);
  font: inherit;
  font-size: 17px;
  font-weight: 600;
  padding: 5px 8px;
  transition: background-color .16s ease;
}
#board-name::placeholder { color: var(--ink-ghost); }
#board-name:hover { background: rgba(255, 255, 255, .034); }
#board-name:focus { outline: none; background: rgba(255, 255, 255, .075); }

.bar-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.group { display: flex; gap: 4px; }

.btn {
  background: var(--panel-2);
  color: var(--ink);
  border: 1px solid var(--edge);
  border-radius: 7px;
  padding: 6px 11px;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { border-color: var(--edge-hi); background: #2c2c2c; }
.btn:active { transform: translateY(1px); }
.btn.primary {
  background: var(--bright);
  color: var(--bright-ink);
  border-color: var(--bright);
  font-weight: 600;
}
.btn.primary:hover { background: #fff; border-color: #fff; }
.btn.danger:hover { border-color: var(--edge-focus); color: #fff; }
.btn.icon { width: 30px; padding: 6px 0; text-align: center; }

/* ---------- factory tabs ---------- */

/* Browser-style tabs over the canvas's left edge; the open one joins the
   toolbar beneath it. */
.tabs {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  min-height: 34px;
  padding: 4px var(--frame) 0;
  margin-bottom: -1px;
  position: relative;
  z-index: 1;
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  flex: 0 1 auto;
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  max-width: 220px;
  height: 30px;
  padding: 0 6px 0 14px;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  color: var(--ink-faint);
  font-size: 12.5px;
  cursor: pointer;
  user-select: none;
  transition: background-color .14s ease, color .14s ease;
}
.tab:hover { color: var(--ink-dim); background: rgba(255, 255, 255, .03); }
.tab.on {
  color: var(--ink);
  font-weight: 600;
  background: var(--panel-2);
  border-color: var(--edge);
  /* Covers the toolbar's top rule, so tab and toolbar read as one. */
  box-shadow: 0 1px 0 var(--panel-2);
}
.tab-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tab-input {
  width: 150px;
  min-width: 0;
  padding: 2px 5px;
  border: 1px solid var(--edge-hi);
  border-radius: 4px;
  background: rgba(255, 255, 255, .06);
  color: var(--ink);
  font: inherit;
  outline: none;
}
.tab-x {
  flex: 0 0 auto;
  width: 14px; height: 14px;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
}
.tab:hover .tab-x, .tab.on .tab-x { opacity: 1; }
.tab-x:hover { background: rgba(255, 255, 255, .08); color: var(--ink); }
.tab-add {
  flex: 0 0 auto;
  align-self: center;
  width: 26px; height: 26px;
  margin-left: 4px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}
.tab-add:hover { background: rgba(255, 255, 255, .06); color: var(--ink); }

/* ---------- toolbar ---------- */

/* A thin strip right across the app: controls for the open factory. */
.toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 5px calc(var(--frame) + 4px);
  background: var(--panel-2);
  border-top: 1px solid var(--edge);
  border-bottom: 1px solid var(--edge);
}
.toolbar .seg { margin: 0; padding: 2px; }
.toolbar .bar-seg .seg-btn { padding: 3px 11px; font-size: 12.5px; }
.tb-sep { width: 1px; height: 18px; background: var(--edge); }
.tb-space { flex: 1 1 auto; }
.tb-btn {
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--ink-dim);
  font: inherit;
  font-size: 12.5px;
  padding: 3px 10px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .14s ease, color .14s ease;
}
.tb-btn:hover { background: rgba(255, 255, 255, .06); color: var(--ink); }
.tb-btn:active { transform: translateY(1px); }
.tb-btn.icon { width: 28px; padding: 3px 0; text-align: center; }
.tb-btn.danger:hover { color: var(--warn); }
#zoom-fit { min-width: 52px; font-variant-numeric: tabular-nums; }

/* The save's name and its menu. */
.save-pick { gap: 6px; }
.save-pick #save-name { width: 200px; }

/* ---------- canvas ---------- */

/* A plus mark at every grid intersection, tiled. The background-position and
   background-size are driven from JS so the field pans and zooms with the
   nodes rather than sitting still underneath them. */
#stage {
  position: absolute;
  inset: calc(var(--bar-h) + 8px) var(--plan-w) var(--frame) var(--frame);
  border-radius: var(--inner-radius);
  overflow: hidden;
  cursor: grab;
  background-color: var(--bg);
  /* Hairline where the frame meets the canvas. An inset shadow rather than a
     border, so it adds no layout box and the world origin stays put. */
  box-shadow: inset 0 0 0 1px var(--edge);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='44'%3E%3Cpath d='M22 18.5v7M18.5 22h7' stroke='%23181818' stroke-width='1.75' stroke-linecap='round'/%3E%3C/svg%3E");
  background-size: var(--cell) var(--cell);
  background-repeat: repeat;
}
#stage.panning { cursor: grabbing; }

#world {
  position: absolute;
  top: 0; left: 0;
  width: 0; height: 0;
  transform-origin: 0 0;
}

/* The container stays click-through so the canvas can still be panned from
   the middle; only the controls inside take pointer events. */
.empty-hint {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  color: var(--ink-faint);
  pointer-events: none;
  margin: 0;
  width: min(560px, calc(100% - 48px));
}
.eh-lead { margin: 0 0 16px; font-size: 13.5px; }
.eh-tip { margin: 16px 0 0; font-size: 12px; color: var(--ink-ghost); }
.eh-link {
  pointer-events: auto;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--ink-dim);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  transition: color .16s ease;
}
.eh-link:hover { color: var(--ink); }

.tpl-grid {
  pointer-events: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.tpl {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px 12px 13px;
  min-height: 74px;
  justify-content: center;
  border: 1px solid var(--edge);
  border-radius: 9px;
  background: rgba(255, 255, 255, .022);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color .16s ease, border-color .16s ease;
}
.tpl:hover { background: rgba(255, 255, 255, .06); border-color: var(--edge-hi); }
.tpl-name { font-size: 13px; font-weight: 600; }
.tpl-note {
  font-size: 11.5px;
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* An unfilled slot is visible but inert, so the grid keeps its shape. */
.tpl.empty {
  cursor: default;
  border-style: dashed;
  background: none;
  opacity: .5;
}
.tpl.empty:hover { background: none; border-color: var(--edge); }
.tpl.empty .tpl-name { color: var(--ink-faint); font-weight: 500; }

@media (max-width: 620px) {
  .tpl-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- marquee ---------- */

/* Ctrl/Shift-drag on the canvas. Drawn in stage coordinates, above the nodes
   but inert — it selects nothing yet. */
#marquee {
  position: absolute;
  display: none;
  z-index: 40;
  border: 1px solid rgba(255, 255, 255, .5);
  background: rgba(255, 255, 255, .06);
  border-radius: 2px;
  pointer-events: none;
}
#marquee.on { display: block; }

/* ---------- context menu ---------- */

.ctx {
  position: fixed;
  z-index: 60;
  min-width: 160px;
  padding: 5px;
  display: flex;
  flex-direction: column;
  background: var(--panel-2);
  border: 1px solid var(--edge);
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .68);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-5px) scale(.98);
  transform-origin: top left;
  transition: opacity .12s ease, transform .12s ease, visibility .12s,
              filter .16s ease;
}
/* Recedes while a popup of its own is open, so the popup reads as the thing
   being answered. The popup is a sibling, so it stays at full strength. */
.ctx.dimmed { filter: brightness(.7); }
.ctx.show {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}
.ctx button {
  display: flex;
  align-items: center;
  background: none;
  border: none;
  border-radius: 5px;
  color: var(--ink-dim);
  font: inherit;
  font-size: 12.5px;
  text-align: left;
  padding: 7px 9px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .12s ease, color .12s ease;
}
.ctx button:hover { background: rgba(255, 255, 255, .07); color: var(--ink); }
/* Picker menus get a marker column showing the current value. Scoped to
   .picker so ordinary command menus aren't indented by the empty slot. */
.ctx.picker button::before {
  content: '';
  width: 4px; height: 4px;
  border-radius: 50%;
  margin-right: 8px;
  flex: 0 0 auto;
}
.ctx.picker button.on { color: var(--ink); font-weight: 600; }
.ctx.picker button.on::before { background: currentColor; }
.ctx button.danger:hover { color: #fff; }
.ctx .sep { height: 1px; background: var(--edge); margin: 4px 3px; }

/* ---------- connectors and wires ---------- */

/* The SVG is a 1px anchor at the world origin with clipping switched off, so
   paths can be drawn straight in world coordinates at any offset. */
#wires {
  position: absolute;
  left: 0; top: 0;
  width: 1px; height: 1px;
  overflow: visible;
  pointer-events: none;
  z-index: 0;
}
.wire {
  fill: none;
  stroke: var(--wire);
  stroke-width: 2;
  stroke-linecap: round;
}
.wire-pending {
  stroke: var(--port-live);
  stroke-dasharray: 5 4;
}
/* A wire dropped on nothing dissolves rather than blinking out. */
.wire-fade { transition: opacity .18s ease; }
.wire-fade.gone { opacity: 0; }

/* One shared confirmation, positioned from JS beneath whichever control asked
   for it — a card's Delete, a context-menu row, or the header's Clear. Kept in
   the DOM and animated with opacity/transform; display:none would skip the
   transition. Sits above the context menu so it can overlay a menu row. */
.confirm {
  position: fixed;
  z-index: 70;
  display: flex;
  align-items: center;
  gap: 2px;
  white-space: nowrap;
  background: var(--panel-2);
  border: 1px solid var(--edge);
  border-radius: 6px;
  padding: 1px 5px;
  box-shadow: 0 8px 22px rgba(0, 0, 0, .65);
  font-size: 11.5px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity .15s ease, transform .15s ease, visibility .15s;
}
.confirm.show {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.confirm-q { color: var(--ink-dim); padding-right: 2px; }
.link-btn {
  background: none; border: none; padding: 0;
  color: var(--ink-faint); font: inherit; font-size: 11.5px;
  cursor: pointer;
  transition: color .16s ease;
}
.link-btn:hover { color: var(--ink); }

/* Outside any toolbar, so it needs its own hit padding. */
.confirm .link-btn { padding: 6px 6px; line-height: 1; }
.confirm .confirm-yes:hover { color: #fff; }

/* #stage no longer needs a hard-coded top here: --bar-h tracks the real
   header height, however many rows it has wrapped onto. */
@media (max-width: 720px) {
  .bar { padding: 7px var(--frame); }
  .bar-actions { gap: 6px; }
}

/* Undo/redo go flat when there's nothing left on their stack. */
.btn:disabled {
  opacity: .32;
  cursor: default;
}
.btn:disabled:hover {
  background: var(--panel-2);
  border-color: var(--edge);
}
/* ---------- summary panel ---------- */

/* The plan's own column, on the app's frame to the right of the canvas. */
.summary {
  position: fixed;
  top: calc(var(--bar-h) + 8px);
  right: 0;
  bottom: 0;
  width: var(--plan-w);
  z-index: 10;
  display: flex;
  flex-direction: column;
  padding: 0 calc(var(--frame) - 8px) 0 6px;
  overflow: hidden;
}

.sum-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px 10px;
}
.sum-head strong { font-size: 14px; letter-spacing: .02em; }

.sum-totals {
  display: flex;
  gap: 6px;
  padding: 0 14px 12px;
}
.sum-stat {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
  border-radius: 7px;
  background: rgba(255, 255, 255, .034);
}
.sum-k {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--ink-faint);
}
.sum-v {
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
#sum-total { color: var(--bright); }

/* Segmented control for the grouping. Same borderless language as the fields:
   a pale panel marks the active choice rather than an outline. */
.seg {
  display: flex;
  gap: 2px;
  margin: 0 14px 10px;
  padding: 3px;
  border-radius: 8px;
  background: rgba(255, 255, 255, .034);
}
.seg-btn {
  flex: 1 1 0;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: 12px;
  padding: 5px 0;
  cursor: pointer;
  transition: background-color .16s ease, color .16s ease;
}
.seg-btn:hover { color: var(--ink-dim); }
.seg-btn.on { background: rgba(255, 255, 255, .1); color: var(--ink); font-weight: 600; }

.sum-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0 8px 8px;
}
.sum-list::-webkit-scrollbar { width: 9px; }
.sum-list::-webkit-scrollbar-thumb {
  background: var(--edge);
  border-radius: 20px;
  border: 3px solid var(--panel);
}
.sum-list::-webkit-scrollbar-thumb:hover { background: var(--edge-hi); }

.sum-group { margin-bottom: 10px; }
.sum-group-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 6px 5px;
  border-bottom: 1px solid var(--edge);
  margin-bottom: 3px;
}
.sum-group-name {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sum-group-count { font-size: 11px; color: var(--ink-ghost); }
.sum-group-sub {
  margin-left: auto;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-dim);
}

/* One row per part. Clicking it takes you to that block on the canvas. */
.sum-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  border: none;
  background: none;
  border-radius: 5px;
  padding: 5px 6px;
  font: inherit;
  font-size: 12.5px;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: background-color .14s ease;
}
.sum-row:hover { background: rgba(255, 255, 255, .05); }
.sum-row-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sum-row-name.untitled { color: var(--ink-ghost); font-style: italic; }
.sum-row-qty {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.sum-row-price {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  color: var(--ink-dim);
}
.sum-row-price.none { color: var(--ink-ghost); }

.sum-empty {
  padding: 22px 10px;
  text-align: center;
  color: var(--ink-faint);
  font-size: 12.5px;
}

.sum-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 9px 14px 11px;
  border-top: 1px solid var(--edge);
}
.sum-exports { display: flex; gap: 2px; }
.sum-exports .link-btn {
  padding: 5px 7px;
  border-radius: 5px;
  transition: background-color .14s ease, color .16s ease;
}
.sum-exports .link-btn:hover { background: rgba(255, 255, 255, .06); }

/* Brief pulse when a panel row sends you to its node. */
.node.flash {
  border-color: var(--edge-focus);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .13), 0 16px 40px rgba(0, 0, 0, .7);
}

@media (max-width: 560px) {
  .summary { width: auto; left: var(--frame); }
}

/* Quiet status text in the panel footer. */
.recheck-note {
  font-size: 11px;
  color: var(--ink-faint);
  align-self: center;
  margin-right: 4px;
}
.recheck-note.warn { color: var(--warn); }

/* ---------- flow lines ---------- */

/* Pipes read as a hollow double line, belts as a solid one, so fluids are
   told apart without spending a colour on them. */
.wire.pipe { stroke-width: 6; stroke: #6a6a6a; }
.wire.pipe-core { stroke-width: 2.4; stroke: var(--bg); }
.wire-end { fill: var(--port-live); }

/* Hovering a node brings its own lines forward and lets the rest recede. */
.wire, .wire-end, .flow-label { transition: opacity .14s ease; }
#world.focusing .wire:not(.hot),
#world.focusing .wire-end:not(.hot),
#world.focusing .flow-label:not(.hot) { opacity: .18; }

#labels {
  position: absolute;
  left: 0; top: 0;
  width: 0; height: 0;
  z-index: 1;
  pointer-events: none;
}
.flow-label {
  position: absolute;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  padding: 1px 7px 2px;
  border-radius: 20px;
  background: var(--bg);
  border: 1px solid var(--edge);
  color: var(--ink-dim);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
}
.flow-label b { color: var(--ink); font-weight: 600; }
.flow-label .fl-item { color: var(--ink-faint); margin-left: 4px; }

/* ---------- nodes ---------- */

/* Same surface as a GCL card: panel fill, hairline edge, deep shadow. */
.node {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 9px 11px 10px;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .5);
  touch-action: none;
  cursor: grab;
  user-select: none;
}
.node:hover { border-color: var(--edge-hi); }
.node.dragging {
  z-index: 5;
  cursor: grabbing;
  box-shadow: 0 16px 40px rgba(0, 0, 0, .7);
  border-color: var(--edge-focus);
}
/* A node you've moved by hand keeps its place through re-solves; the corner
   dot says so. */
.node.pinned::after {
  content: "";
  position: absolute;
  top: 5px; right: 5px;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--ink-ghost);
}

.n-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.n-title {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.n-rate {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--bright);
}
.n-rate small { font-size: 10.5px; font-weight: 500; color: var(--ink-faint); margin-left: 1px; }

/* The machine line doubles as the recipe picker, drawn like GCL's part-type
   button: a label with a caret that only shows a panel under the cursor. */
.n-recipe {
  align-self: flex-start;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: -5px;
  padding: 2px 5px;
  background: none;
  border: 1px solid transparent;
  border-radius: 3px;
  color: var(--label);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .02em;
  cursor: pointer;
  transition: background-color .16s ease, color .16s ease;
}
.n-recipe::after {
  content: "";
  width: 0; height: 0;
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  border-top: 4px solid currentColor;
  opacity: .75;
}
.n-recipe:hover { background: rgba(255, 255, 255, .034); color: var(--ink-dim); }
.n-recipe:disabled { cursor: inherit; }
.n-recipe:disabled::after { display: none; }
.n-recipe:disabled:hover { background: none; color: var(--label); }
.n-machine b { color: var(--ink-dim); font-weight: 600; font-variant-numeric: tabular-nums; }

.n-alt {
  font-size: 11.5px;
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.n-alt.is-alt::before {
  content: "ALT";
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .08em;
  margin-right: 6px;
  padding: 0 4px;
  border-radius: 3px;
  border: 1px solid var(--edge-hi);
  color: var(--ink-dim);
  vertical-align: 1px;
}

.n-notes:empty { display: none; }
.n-notes {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.n-notes .warn { color: var(--warn); }

/* Same idea as GCL's status chip, sat on the node's top edge. */
.n-badge {
  position: absolute;
  top: -9px; left: 10px;
  padding: 1px 8px;
  border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, .22);
  background: #2a2a2a;
  color: #f2f2f2;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Raw inputs sit a step back from the machines that use them. */
.node.raw { background: var(--panel-2); border-style: dashed; }
.node.raw .n-title { color: var(--ink-dim); }
.node.short { border-color: rgba(224, 139, 61, .55); }
.node.short .n-machine { color: var(--warn); }

/* Solver trouble, above the canvas rather than in any one node. */
.solve-error {
  position: absolute;
  left: 50%; top: 14px;
  transform: translateX(-50%);
  z-index: 25;
  max-width: min(560px, calc(100% - 32px));
  padding: 8px 12px;
  border-left: 2px solid var(--warn);
  background: var(--panel);
  color: var(--warn);
  font-size: 12.5px;
  box-shadow: 0 8px 22px rgba(0, 0, 0, .55);
}

/* ---------- context menu extras ---------- */

.ctx { max-height: calc(100vh - 16px); overflow-y: auto; }

/* Rows that carry a second, quieter line (a recipe's ingredients). */
.ctx button.two-line {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0;
  row-gap: 1px;
  align-items: center;
}
.ctx button.two-line .ctx-main { grid-column: 2; }
.ctx button.two-line .ctx-note { grid-column: 2; }
.ctx.picker button.two-line::before { grid-row: 1 / span 2; }
.ctx .ctx-note {
  font-size: 11px;
  color: var(--ink-faint);
  font-weight: 400;
  white-space: nowrap;
}
.ctx .ctx-tag {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .08em;
  margin-left: 7px;
  padding: 0 4px;
  border-radius: 3px;
  border: 1px solid var(--edge-hi);
  color: var(--ink-dim);
  vertical-align: 1px;
}
.ctx .ctx-head {
  padding: 5px 9px 3px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--ink-ghost);
}

/* ---------- item search ---------- */

.item-pop { width: 280px; padding: 6px; gap: 4px; overflow: hidden; }
.item-pop .ip-input, .alt-search {
  background: rgba(255, 255, 255, .055);
  border: 1px solid var(--edge);
  border-radius: 5px;
  color: var(--ink);
  font: inherit;
  font-size: 12.5px;
  padding: 6px 8px;
  outline: none;
  transition: border-color .14s ease;
}
.item-pop .ip-input::placeholder, .alt-search::placeholder { color: var(--ink-ghost); }
.item-pop .ip-input:focus, .alt-search:focus { border-color: var(--edge-hi); }
.ip-list { max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; }
.ip-list button.sel { background: rgba(255, 255, 255, .07); color: var(--ink); }
.ip-empty { padding: 8px 9px; font-size: 12px; color: var(--ink-ghost); }

/* ---------- plan panel ---------- */

.target-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 2px 0;
}
.t-item {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 1px solid transparent;
  border-radius: 5px;
  padding: 5px 6px;
  color: var(--ink);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background-color .14s ease;
}
.t-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.t-item::after {
  content: "";
  flex: 0 0 auto;
  width: 0; height: 0;
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  border-top: 4px solid var(--ink-faint);
}
.t-item:hover { background: rgba(255, 255, 255, .05); }
.t-rate {
  flex: 0 0 64px;
  width: 64px;
  background: rgba(255, 255, 255, .034);
  border: 1px solid transparent;
  border-radius: 5px;
  color: var(--bright);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
  padding: 4px 6px;
  transition: background-color .16s ease;
}
.t-rate:hover { background: rgba(255, 255, 255, .06); }
.t-rate:focus { outline: none; background: rgba(255, 255, 255, .085); }
.t-rate.bad { border-color: var(--warn); }
/* A max output's figure is the solver's answer, not something to type. */
.t-rate:disabled { background: none; color: var(--ink-dim); cursor: default; }

/* The unit doubles as the rate/max switch. */
.t-unit {
  flex: 0 0 auto;
  min-width: 44px;
  padding: 4px 6px;
  border: 1px solid transparent;
  border-radius: 5px;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: 11px;
  text-align: left;
  cursor: pointer;
  transition: background-color .14s ease, color .14s ease, border-color .14s ease;
}
.t-unit:hover { background: rgba(255, 255, 255, .05); color: var(--ink); }
.t-unit.on {
  border-color: var(--edge-hi);
  color: var(--ink);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-size: 10px;
  text-align: center;
}
.t-del {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  border: none;
  background: none;
  border-radius: 5px;
  color: var(--ink-ghost);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: background-color .14s ease, color .14s ease;
}
.t-del:hover { background: rgba(255, 255, 255, .06); color: var(--ink); }

.add-target {
  margin: 4px 0 0;
  padding: 6px;
  border: 1px dashed var(--edge);
  border-radius: 6px;
  background: none;
  width: 100%;
  color: var(--ink-faint);
  font: inherit;
  font-size: 12px;
  text-align: left;
  cursor: pointer;
  transition: border-color .14s ease, color .14s ease;
}
.add-target:hover { border-color: var(--edge-hi); color: var(--ink); }

.sum-row .sum-row-note {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--ink-ghost);
  font-variant-numeric: tabular-nums;
}
.sum-row .sum-row-price.warn { color: var(--warn); }
.sum-foot .recheck-note { margin-right: 0; text-align: right; }

/* ---------- view and clock switches ---------- */

.bar-seg { margin: 0; }
.bar-seg .seg-btn { flex: 0 0 auto; padding: 5px 11px; font-size: 12.5px; }
.panel-seg { margin: 4px 0 0; }

/* ---------- outputs ---------- */

/* The end of the line, and the point of the plan: tinted green. */
.node.output {
  background: rgba(var(--output), .09);
  border-color: rgba(var(--output), .55);
}
.node.output:hover { border-color: rgba(var(--output), .8); }
.node.output .n-head { margin-top: 2px; }
.node.output .n-title { color: #bff0d2; }
.node.output .n-rate { color: #93e5b3; }
.node.output .n-badge {
  background: #1d3627;
  border-color: rgba(var(--output), .6);
  color: #93e5b3;
}

/* Machine view: an unused byproduct's belt ends here. */
.node.spare { border-style: dashed; background: var(--panel-2); }
.node.spare .n-title { color: var(--ink-dim); }

/* ---------- machine view ---------- */

/* The build at 8 px to the metre. Nothing in it moves, so nothing looks
   grabbable; dragging anywhere pans. */
#world.machines .node { cursor: inherit; }

.sub-head { margin-top: 10px; }

/* Where things start and end: not buildings, so kept compact. */
.node.endpoint { padding: 7px 9px 8px; gap: 2px; }
.node.endpoint .n-title { font-size: 12.5px; }
.node.endpoint .n-rate { font-size: 12px; }
.node.endpoint .n-recipe { font-size: 11.5px; }

/* Belts and pipes, about a metre wide, over a dark casing so a belt that
   crosses another reads as passing over it. */
.belt-casing {
  fill: none;
  stroke: var(--bg);
  stroke-width: 10;
  stroke-linejoin: round;
}
.belt {
  fill: none;
  stroke: #cdcdcd;
  stroke-width: 6;
  stroke-linejoin: round;
}
.belt.pipe { stroke: #a9a9a9; stroke-width: 8; }
.belt.pipe-core { stroke: var(--bg); stroke-width: 3.5; }

/* One building, top-down at its in-game footprint, tinted orange. Belts run
   left to right through it, so its length is across and its width is down. */
.machine {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 2px 5px;
  background: rgb(47, 35, 24);
  border: 1px solid rgba(var(--machine), .7);
  border-radius: 3px;
  overflow: hidden;
  line-height: 1.15;
}
.machine span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.m-name { font-size: 10px; font-weight: 600; color: #f6cfa4; }
.m-product { font-size: 9.5px; color: #e3b98c; }
.m-sub { font-size: 9.5px; color: #c49468; font-variant-numeric: tabular-nums; }
/* Underclocked buildings read quieter than ones at full speed. */
.machine.under { background: rgb(38, 30, 23); border-color: rgba(var(--machine), .45); }
.machine.under .m-sub { color: #a27e5c; }

/* Conveyor and pipe ports on the building's ends. */
.m-port {
  position: absolute;
  width: 6px; height: 6px;
  margin-top: -3px;
  border-radius: 1px;
  background: #f6cfa4;
}
.m-port.in { left: -1px; }
.m-port.out { right: -1px; }
.m-port.fluid {
  background: var(--bg);
  border: 1.5px solid #f6cfa4;
  border-radius: 50%;
}

/* Splitters (S) and mergers (M) at their real 4 m, and pipeline junctions
   doing either job at their 2.4 m, round. */
.part {
  position: absolute;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 3px;
  background: #2b2b2b;
  border: 1px solid #a0a0a0;
  color: var(--bright);
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  user-select: none;
}
.part.junction { border-radius: 50%; font-size: 10px; }

/* The slowest belt or pipe tier that carries a belt. */
.flow-label .fl-tier {
  margin-left: 5px;
  padding-left: 5px;
  border-left: 1px solid var(--edge-hi);
  color: var(--ink-faint);
}
.flow-label .fl-tier.warn { color: var(--warn); }
#world.machines .flow-label { z-index: 4; font-size: 10.5px; padding: 0 6px 1px; color: #c4c4c4; }
#world.machines .flow-label .fl-tier { color: #a8a8a8; }
#world.machines .flow-label .fl-tier.warn { color: var(--warn); }
#world.machines .flow-label .fl-item { color: #a8a8a8; }
#world.machines #labels { z-index: 4; }

/* ---------- storage ---------- */

/* Outputs end in real storage, tinted green like outputs elsewhere; spare
   byproducts go to an AWESOME Sink, left grey. */
.machine.storage.output {
  background: rgb(22, 42, 31);
  border-color: rgba(var(--output), .7);
}
.machine.storage.output .m-name { color: #bff0d2; }
.machine.storage.output .m-product { color: #93e5b3; }
.machine.storage.output .m-sub { color: #7fc79c; }
.machine.storage.output .m-port { background: #bff0d2; }
.machine.storage.output .m-port.fluid { background: var(--bg); border-color: #bff0d2; }
.machine.storage.spare {
  background: #242424;
  border-color: #6a6a6a;
  border-style: dashed;
}
.machine.storage.spare .m-name { color: var(--ink-dim); }
.machine.storage.spare .m-product,
.machine.storage.spare .m-sub { color: var(--ink-faint); }
.machine.storage.spare .m-port { background: var(--ink-dim); }

/* ---------- recipe picker ---------- */

.opt-note {
  margin: 8px 2px 0;
  font-size: 11.5px;
  color: var(--ink-faint);
  line-height: 1.4;
}
.opt-note:empty { display: none; }
.sum-group-head .link-btn { margin-left: auto; font-size: 11px; }
.sum-group-head .link-btn + .link-btn { margin-left: 10px; }

/* ---------- panel sections ---------- */

/* Related settings share a rounded box, so the panel reads as a few groups
   rather than one long run of controls. */
.panel-box {
  margin: 4px 0 12px;
  padding: 8px 10px 10px;
  border: 1px solid var(--edge);
  border-radius: 10px;
  background: rgba(255, 255, 255, .02);
}
.panel-box .sum-group-head {
  border-bottom: none;
  margin-bottom: 0;
  padding: 2px 2px 5px;
}
.panel-box .sub-head { margin-top: 10px; }
.panel-box .panel-seg { margin: 0; }

/* Inputs, Outputs and Machines fold away from their heading. */
.fold-head {
  width: 100%;
  background: none;
  border: none;
  border-bottom: 1px solid var(--edge);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: 0;
}
.fold-head:hover .sum-group-name { color: var(--ink); }
.fold-head::before {
  content: "";
  flex: 0 0 auto;
  align-self: center;
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid var(--ink-faint);
  transition: transform .15s ease;
}
.folded > .fold-head::before { transform: rotate(-90deg); }
.folded > .fold-body { display: none; }
.folded > .fold-head { margin-bottom: 0; }

/* Miners and extractors: inputs, so grey like inputs elsewhere, not orange. */
.machine.extractor { background: #262626; border-color: #7a7a7a; }
.machine.extractor.under { background: #212121; border-color: #5c5c5c; }
.machine.extractor .m-name { color: var(--ink); }
.machine.extractor .m-product { color: var(--ink-dim); }
.machine.extractor .m-sub { color: var(--ink-faint); }
.machine.extractor .m-port { background: var(--ink-dim); }
.machine.extractor .m-port.fluid { background: var(--bg); border-color: var(--ink-dim); }

/* ---------- boxed panel sections ---------- */

.panel-box:empty { display: none; }
.panel-box > .sum-group { margin: 0; }
.panel-box > .sum-group + .sum-group { margin-top: 10px; }

/* Buildings the user has are ticked; unticking re-plans without them. */
.sum-row.check-row::before {
  content: "";
  flex: 0 0 auto;
  align-self: center;
  width: 10px; height: 10px;
  border: 1.5px solid var(--edge-hi);
  border-radius: 3px;
}
.sum-row.check-row:not(.on) .sum-row-name { color: var(--ink-faint); text-decoration: line-through; }
.sum-row.check-row.idle.on .sum-row-name { color: var(--ink-dim); }
.sum-row.extra-row { padding-left: 24px; }

/* ---------- canvas overlays ---------- */

/* Machine view: nothing here moves by hand. */
.view-note {
  position: absolute;
  top: 14px; left: 14px;
  z-index: 24;
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--ink-dim);
  font-size: 12px;
  pointer-events: none;
  text-shadow: 0 0 6px var(--bg), 0 0 2px var(--bg);
}
.view-note svg { flex: 0 0 auto; color: var(--warn); }

/* Display options, top right of whatever the plan panel leaves showing. */
.view-opts {
  position: absolute;
  top: 14px; right: 14px;
  z-index: 26;
  transition: right .2s ease;
}
.view-opts .btn.icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  padding: 0;
  box-shadow: 0 8px 22px rgba(0, 0, 0, .45);
}
.vo-menu {
  position: absolute;
  top: calc(100% + 6px); right: 0;
  width: 250px;
  padding: 5px;
  border: 1px solid var(--edge);
  border-radius: 9px;
  background: var(--panel);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .6);
}
.vo-row {
  display: grid;
  grid-template-columns: 16px 1fr;
  column-gap: 8px;
  align-items: center;
  width: 100%;
  padding: 6px 8px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--ink-dim);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.vo-row:hover { background: rgba(255, 255, 255, .05); }
.vo-row::before {
  content: "";
  grid-row: 1 / span 2;
  width: 10px; height: 10px;
  border: 1.5px solid var(--edge-hi);
  border-radius: 3px;
}
.vo-main { grid-column: 2; font-size: 12.5px; }
.vo-row.on .vo-main { color: var(--ink); font-weight: 600; }
.vo-note { grid-column: 2; font-size: 11px; color: var(--ink-faint); }

/* ---------- label options ---------- */

#stage.hide-rates .flow-label { display: none; }
#stage.hide-products .machine:not(.storage) .m-product { display: none; }

.nm-short { display: none; }
#stage.short-names .nm-full { display: none; }
#stage.short-names .nm-short { display: inline; }
/* Two letters have room to be read from further out. */
#stage.short-names .m-name .nm-short { font-size: 17px; font-weight: 700; letter-spacing: .04em; line-height: 1.05; }
#stage.short-names .n-machine .nm-short { font-size: 13.5px; font-weight: 700; letter-spacing: .04em; }
#stage.short-names .storage .m-product .nm-short { font-weight: 600; letter-spacing: .04em; }

/* Overclocked buildings read a touch hotter than ones at 100%. */
.machine.over { border-color: rgba(var(--machine), .95); }

/* ---------- tick boxes ---------- */

/* Every on/off row: an outlined box, with a tick in it when on. */
.sum-row.check-row::before,
.vo-row::before {
  width: 12px; height: 12px;
  border-radius: 3px;
}
.sum-row.check-row.on::before,
.vo-row.on::before {
  border-color: var(--bright);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.6 6.3l2.2 2.2 4.6-4.9' fill='none' stroke='%23ededed' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 12px no-repeat;
}

/* ---------- alternates list ---------- */

/* The heading folds from its name; All and None sit beside it. */
.fold-head.fold-inline {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  padding: 0;
  border-bottom: none;
}
.folded .fold-inline::before { transform: rotate(-90deg); }
.alt-fold .fold-body { margin-top: 6px; }
.alt-search { width: 100%; margin-bottom: 4px; }
.alt-list { max-height: 300px; overflow-y: auto; }
.alt-list .sum-row { align-items: center; }
.alt-check .sum-row-name { display: flex; flex-direction: column; gap: 1px; }
.sum-row.alt-check:not(.on) .sum-row-name { text-decoration: none; }
.ac-main { overflow: hidden; text-overflow: ellipsis; }
.alt-check.on .ac-main { color: var(--ink); font-weight: 600; }
.ac-note { font-size: 11px; color: var(--ink-faint); overflow: hidden; text-overflow: ellipsis; }

/* Four ways to clock, two to a row. */
#clock-seg { flex-wrap: wrap; }
#clock-seg .seg-btn { flex: 1 1 calc(50% - 2px); }

/* ---------- boxed panel sections: headings centred ---------- */

/* Even padding above and below, so a folded box is just its heading with
   the name sitting in the middle. */
.panel-box { padding: 10px 12px; }
.panel-box .sum-group-head {
  align-items: center;
  min-height: 18px;
  padding: 0 2px;
  margin-bottom: 8px;
}
.panel-box .sub-head { margin-top: 12px; }
.panel-box .folded > .fold-head,
.panel-box.folded > .fold-head { margin-bottom: 0; }
.alt-fold .sum-group-head { margin-bottom: 0; }
.alt-fold .fold-body { margin-top: 8px; }
.panel-box .sum-group-name { line-height: 18px; }
.panel-box .sum-group-count { line-height: 18px; }

/* ---------- clock speeds option ---------- */

#stage.hide-clocks .m-clock { display: none; }

/* ---------- header on orange ---------- */

.bar .brand strong { color: #fff3e6; }
.bar .brand .sub { color: rgba(255, 226, 199, .55); }
.bar .brand .mark { background: #f2a25c; }
.bar .board-name { border-left-color: rgba(255, 220, 190, .18); }
.bar .bn-label { color: rgba(255, 226, 199, .5); }

/* The save's name, set like the old plan name: big, borderless, a soft
   panel behind it on hover and while typing. */
#save-name {
  min-width: 0;
  width: 220px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  color: #fff3e6;
  font: inherit;
  font-size: 17px;
  font-weight: 600;
  padding: 5px 8px;
  transition: background-color .16s ease;
}
#save-name::placeholder { color: rgba(255, 226, 199, .35); }
#save-name:hover { background: rgba(0, 0, 0, .14); }
#save-name:focus { outline: none; background: rgba(0, 0, 0, .24); }

/* Save, browse, import, export: quiet icon buttons on the orange. */
.save-tools { display: flex; align-items: center; gap: 2px; margin-left: 2px; }
.hbtn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  padding: 0;
  border: none;
  border-radius: 7px;
  background: none;
  color: rgba(255, 226, 199, .72);
  cursor: pointer;
  transition: background-color .14s ease, color .14s ease;
}
.hbtn:hover, .hbtn.open { background: rgba(0, 0, 0, .2); color: #fff3e6; }
.hbtn:active { transform: translateY(1px); }
#save-now { color: rgba(255, 226, 199, .38); }
#save-now .save-tick { opacity: 0; transition: opacity .16s ease; }
#save-now.saved { color: rgb(var(--output)); }
#save-now.saved .save-tick { opacity: 1; }
#save-now:hover { color: rgba(255, 226, 199, .8); }
#save-now.saved:hover { color: rgb(118, 216, 158); }

/* ---------- tabs strip stays grey ---------- */

.tabs { background: var(--panel); }

/* ---------- toolbar ---------- */

.tb-btn:disabled { opacity: .32; cursor: default; }
.tb-btn:disabled:hover { background: none; color: var(--ink-dim); }
.tb-btn:disabled:active { transform: none; }
.seg.disabled { opacity: .38; }
.seg.disabled .seg-btn { cursor: default; }
.seg.disabled .seg-btn:hover { color: var(--ink-faint); }
.seg.disabled .seg-btn.on:hover { color: var(--ink); }

/* ---------- browse saves ---------- */

.save-pop { width: 290px; padding: 6px; }
.sp-head { display: flex; align-items: center; padding: 3px 6px 6px; }
.sp-head strong { font-size: 12.5px; }
.sp-head .link-btn { margin-left: auto; font-size: 12px; }
.sp-list { max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; gap: 1px; }
.sp-row { display: flex; align-items: center; border-radius: 6px; }
.sp-row:hover { background: rgba(255, 255, 255, .05); }
.sp-row.on { background: rgba(255, 255, 255, .07); }
.ctx .sp-open {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  padding: 6px 8px;
  background: none;
}
.ctx .sp-open:hover { background: none; }
.sp-name { font-size: 12.5px; color: var(--ink); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-row.on .sp-name { font-weight: 600; }
.sp-note { font-size: 11px; color: var(--ink-faint); }
.ctx .sp-del {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  justify-content: center;
  padding: 0;
  margin-right: 3px;
  color: var(--ink-faint);
  opacity: .45;
}
.sp-row:hover .sp-del, .sp-del:focus-visible { opacity: 1; }
.ctx .sp-del:hover { color: var(--warn); background: rgba(255, 255, 255, .06); }

/* ---------- round 7 ---------- */

/* A thinner header: a smaller name and buttons to match. */
.bar .brand strong, .bar .brand .sub { font-size: 14px; }
.bar .bn-label { font-size: 15px; }
#save-name { font-size: 15px; padding: 3px 8px; }
.hbtn { width: 28px; height: 28px; }

/* The name's field is as wide as the name; this measures it. */
.save-name-fit {
  position: absolute;
  visibility: hidden;
  white-space: pre;
  font-size: 15px;
  font-weight: 600;
  pointer-events: none;
}

/* The save's buttons as one pill, tucked right after the name. */
.save-tools {
  gap: 0;
  margin-left: 0;
  padding: 2px;
  border-radius: 9px;
  background: rgba(0, 0, 0, .16);
  box-shadow: inset 0 0 0 1px rgba(255, 220, 190, .08);
}

/* Chrome-style dividers between tabs, dropped beside the open tab and the
   one under the pointer. */
.tab { position: relative; }
.tab::after {
  content: "";
  position: absolute;
  right: -2px;
  top: 8px;
  bottom: 8px;
  width: 1px;
  background: var(--edge-hi);
}
.tab:hover::after,
.tab:has(+ .tab.on)::after,
.tab:has(+ .tab:hover)::after { display: none; }

/* "View" heads the controls that change how the factory is shown. */
.tb-label {
  font-size: 12px;
  color: var(--ink-faint);
  margin-right: 6px;
}

/* Room for everything on one row at ordinary widths. */
.toolbar { gap: 6px; }
.tb-btn { padding: 3px 8px; }
.toolbar .bar-seg .seg-btn { padding: 3px 10px; }

/* ---------- round 8 ---------- */

/* The open tab flares out where it meets the toolbar, as in Chrome: its side
   line curves out into the toolbar's top line. Each corner is a small
   drawing laid over the bottom of the tab's border, filled with the
   toolbar's grey and stroked like the border (#232323 is --panel-2, #3c3c3c
   is --tab-line; a var() can't reach inside the image). */
.tabs .tab.on { z-index: 1; }
.tabs .tab.on::before,
.tabs .tab.on::after,
.tabs .tab.on:hover::after {
  content: "";
  display: block;
  position: absolute;
  top: auto;
  bottom: 0;
  left: -9px;
  right: auto;
  width: 9px;
  height: 9px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='9' viewBox='0 0 9 9'%3E%3Cpath d='M0.5 8.5A8 8 0 0 0 8.5 0.5L9 0.5L9 9L0.5 9Z' fill='%23232323'/%3E%3Cpath d='M0.5 8.5A8 8 0 0 0 8.5 0.5' fill='none' stroke='%233c3c3c' stroke-width='1'/%3E%3C/svg%3E") 0 0 / 9px 9px no-repeat;
  pointer-events: none;
}
.tabs .tab.on::after,
.tabs .tab.on:hover::after {
  left: auto;
  right: -9px;
  transform: scaleX(-1);
}

/* A tab being dragged rides above the rest. */
.tab.dragging { z-index: 2; background: var(--panel-2); color: var(--ink-dim); cursor: grabbing; }
.tab.dragging::after { display: none; }

/* A resource block's tall, thin + for another node, down its left side. */
.n-add {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -22px;
  width: 15px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--edge-hi);
  border-radius: 6px;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  transition: background-color .14s ease, color .14s ease, border-color .14s ease;
}
.n-add:hover {
  border-style: solid;
  border-color: var(--edge-focus);
  background: rgba(255, 255, 255, .05);
  color: var(--ink);
}

/* ---------- round 9 ---------- */

/* Quieter half of a label: "(Default)", "details". */
.seg-btn .dim { color: var(--ink-ghost); font-weight: 400; }
.seg-btn.on .dim { color: var(--ink-faint); }

/* The plan column runs the full height under the header; the tabs and the
   toolbar stop where the canvas does. */
.tabs, .toolbar { margin-right: var(--plan-w); }
.toolbar { border-right: 1px solid var(--edge); border-top-right-radius: 0; }
.summary { top: calc(var(--head-h, 44px) + 6px); }

/* The toolbar now stops at the canvas, so it's a little more compact: one
   row down to about 1280 px wide. */
.toolbar { gap: 5px; }
.tb-btn { padding: 3px 7px; }
.tb-btn.icon { width: 24px; }
#zoom-fit { min-width: 44px; }
.toolbar .bar-seg .seg-btn { padding: 3px 8px; }

/* ---------- round 10 ---------- */

/* The toolbar's outline, visible against the tab strip, and the open tab
   drawn in the same line. Its far end is rounded like the canvas. */
.tab.on { border-color: var(--tab-line); }
.toolbar {
  border-top: 1px solid var(--tab-line);
  border-bottom: 1px solid var(--tab-line);
  border-right: 1px solid var(--tab-line);
  border-top-right-radius: var(--inner-radius);
  border-bottom-right-radius: var(--inner-radius);
}

/* The plan panel: a rounded panel of its own, cornered like the canvas and
   the same distance from it as the canvas is from the window's edge. */
.summary {
  top: calc(var(--head-h, 44px) + 8px);
  right: var(--frame);
  bottom: var(--frame);
  width: calc(var(--plan-w) - var(--frame) * 2);
  padding: 0 4px;
  background: var(--bg);
  border: 1px solid var(--edge);
  border-radius: var(--inner-radius);
}

/* Its pages: plain text tabs, underlined when open. */
.ptabs {
  display: flex;
  gap: 18px;
  padding: 0 12px;
  margin: 0 4px 12px;
  border-bottom: 1px solid var(--edge);
}
.ptab {
  position: relative;
  padding: 12px 0 10px;
  border: none;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  transition: color .14s ease;
}
.ptab:hover { color: var(--ink-dim); }
.ptab.on { color: var(--ink); }
.ptab.on::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: var(--bright);
}
.ptab-page {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.ptab-soon {
  margin: 40px 16px;
  text-align: center;
  color: var(--ink-faint);
  font-size: 12.5px;
}

/* ---------- round 11 ---------- */

/* The tab strip is see-through, so the toolbar's top line shows along its
   whole length (the strip overlaps it by a pixel to meet the open tab). */
.tabs { background: none; }

/* A lighter plan panel. */
.summary { background: var(--panel-2); }

/* Overview and Power. */
.sum-row.quiet .sum-row-name,
.sum-row.quiet .sum-row-price { color: var(--ink-faint); }
.sum-row.total-row { border-top: 1px solid var(--edge); border-radius: 0 0 5px 5px; margin-top: 3px; padding-top: 7px; }
.sum-row.total-row .sum-row-name,
.sum-row.total-row .sum-row-price { color: var(--ink); font-weight: 600; }
.sum-row.draw-row { position: relative; flex-wrap: wrap; padding-bottom: 8px; }
.draw-bar {
  position: absolute;
  left: 6px;
  bottom: 3px;
  max-width: calc(100% - 12px);
  height: 2px;
  border-radius: 2px;
  background: rgba(var(--machine), .6);
}

/* The wrapper round the header, tabs and toolbar spans the window but is
   empty beside the tabs and toolbar, over the plan panel. Presses there go
   through to the panel; only the wrapper's contents catch them. */
.top { pointer-events: none; }
.top > * { pointer-events: auto; }

/* ---------- round 12 ---------- */

/* The canvas sits as far below the toolbar as it does from the window's side. */
#stage { top: calc(var(--bar-h) + var(--frame)); }

/* Selected nodes: a bright outline and a soft ring. */
.node.selected {
  border-color: var(--bright);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .14), 0 6px 20px rgba(0, 0, 0, .5);
}
.node.output.selected { border-color: rgb(var(--output)); box-shadow: 0 0 0 3px rgba(var(--output), .22), 0 6px 20px rgba(0, 0, 0, .5); }

/* A menu option that doesn't apply to what's selected. */
.ctx button:disabled { opacity: .38; cursor: default; }
.ctx button:disabled:hover { background: none; color: var(--ink-dim); }

/* ---------- round 13 ---------- */

/* Selected: a solid white line just outside the node's own border. */
.node.selected,
.node.output.selected {
  border-color: var(--edge);
  outline: 2px solid #fff;
  outline-offset: 2px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .5);
}

/* The support button, top right of the header. */
.bar-right { margin-left: auto; display: flex; align-items: center; }
#support { color: #ffd3b0; }
#support:hover { color: #fff; }

/* ---------- round 14 ---------- */

/* "Support me" and its icon, one button. */
.hbtn.support-btn { width: auto; gap: 7px; padding: 0 8px 0 10px; }
.support-text { font-size: 13px; font-weight: 600; }

/* The version picker, last in the save's pill. */
.hbtn.version-btn { width: auto; gap: 4px; padding: 0 8px; font: inherit; font-size: 12.5px; font-weight: 600; }

/* Another resource node: a thin + along the bottom of the lowest block. */
.n-add {
  top: calc(100% + 6px);
  bottom: auto;
  left: 0;
  right: 0;
  width: auto;
  height: 14px;
  font-size: 12px;
}

/* ---------- round 15 ---------- */

/* The resource +: a little taller. */
.n-add { height: 20px; font-size: 13px; }

/* Straight lines' arrowheads, faded with their lines. */
.wire-arrow { fill: var(--wire); transition: opacity .14s ease; }
.wire-arrow.pipe { fill: #6a6a6a; }
#world.focusing .wire-arrow:not(.hot) { opacity: .18; }

/* Curved or straight, at the top of the display options. */
.vo-seg-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px 8px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--edge);
}
.vo-seg-row .vo-main { color: var(--ink-dim); }
.vo-seg { margin: 0 0 0 auto; }
.vo-seg .seg-btn { flex: 0 0 auto; padding: 4px 12px; }

/* ---------- round 16 ---------- */

/* Straight lines: thinner, so the arrows lead. */
.wire.thin { stroke-width: 1.25; }
.wire.pipe.thin { stroke-width: 4; }
.wire.pipe-core.thin { stroke-width: 1.6; }

/* The hovered node's figures: just text, bottom left, over a soft blur of
   whatever is behind. */
.hover-info {
  position: absolute;
  left: 16px;
  bottom: 14px;
  z-index: 24;
  max-width: min(460px, calc(100% - 32px));
  padding: 6px 8px;
  border-radius: 8px;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  pointer-events: none;
  color: var(--ink-dim);
  font-size: 12.5px;
  line-height: 1.45;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
}
.hi-line { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hi-title { color: var(--ink); font-size: 14px; font-weight: 600; margin-bottom: 1px; }

/* ---------- round 17 ---------- */

/* Steps in the Items view, and buildings in the Machines view: the same
   quiet weight as the grey cards, tinted orange. */
.node:not(.raw):not(.output):not(.spare) {
  background: #221810;
  border-color: #422d1a;
}
.node:not(.raw):not(.output):not(.spare):hover { border-color: #684628; }
.node.selected:not(.raw):not(.output):not(.spare) { border-color: #422d1a; }

.machine { background: #221810; border-color: #422d1a; }
.machine.under { background: #1c140d; border-color: #37261a; }
.machine.over { border-color: #684628; }

/* Panel heading icons. */
.sg-icon {
  flex: 0 0 auto;
  align-self: center;
  display: flex;
  color: var(--ink-faint);
  margin-right: -2px;
}
.fold-inline .sg-icon { margin-right: -2px; }
.machine.extractor.over { border-color: #9a9a9a; }

/* Steps in the Items view a shade lighter than the machines, so the cards
   read clearly on the canvas. */
.node:not(.raw):not(.output):not(.spare) { background: #2c2015; border-color: #4f3721; }
.node:not(.raw):not(.output):not(.spare):hover { border-color: #775333; }
.node.selected:not(.raw):not(.output):not(.spare) { border-color: #4f3721; }
