/* GEN2 Assembly Instructions viewer — brand palette matches the planner */
:root {
  --accent: #ff8a40;
  --ink: #23262b;
  --ink-soft: #5b6069;
  --panel: rgba(255, 255, 255, 0.92);
  --panel-border: #e3e5e9;
  --bg: #eef0f3;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body, #app { height: 100%; }
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  background: var(--bg);
  overflow: hidden;
}

#app { display: flex; flex-direction: column; }

#topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px;
  background: #fff; border-bottom: 1px solid var(--panel-border);
}
#kit-title { font-weight: 700; font-size: 15px; }
/* auto margin keeps the counter on the right exactly as before now that the
   theme pill sits after it (space-between alone would center it) */
#step-counter { font-size: 13px; color: var(--ink-soft); margin-left: auto; }
/* the dark-mode switch — a small sun/moon slider (state = aria-checked, set
   by main.js; same component as the planner's hero-bar switch) */
#btn-theme {
  position: relative; flex: none; margin-left: 10px;
  width: 46px; height: 24px; padding: 0;
  border: 1px solid var(--panel-border); border-radius: 999px;
  background: #fff; cursor: pointer;
}
#btn-theme:hover { border-color: var(--accent); }
#btn-theme .tt-sun, #btn-theme .tt-moon {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 13px; height: 13px; color: var(--ink-soft); pointer-events: none;
}
#btn-theme .tt-sun { left: 5px; }
#btn-theme .tt-moon { right: 5px; }
#btn-theme .tt-knob {
  position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: 50%;
  background: #d7d9e0;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
  transition: transform 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}
#btn-theme[aria-checked="true"] .tt-knob {
  transform: translateX(22px);
  background: #303469;
  box-shadow: 0 0 8px rgba(56, 220, 255, 0.55);
}
/* render-quality cycle pill, beside the light/dark switch — both are "how the
   stage looks". Fixed width so High/Balanced/Fast don't reflow the topbar. */
#btn-quality {
  flex: none; margin-left: 8px; min-width: 74px;
  padding: 4px 9px; font: inherit; font-size: 12px; font-weight: 700;
  color: var(--ink-soft); background: #fff;
  border: 1px solid var(--panel-border); border-radius: 999px; cursor: pointer;
}
#btn-quality:hover { border-color: var(--accent); color: var(--ink); }
/* the tier is legible at a glance without reading the word */
#btn-quality[data-q="veryhigh"], #btn-quality[data-q="high"] { color: var(--accent); }
#btn-quality[data-q="fast"] { opacity: 0.75; }
@media (max-width: 560px) { #btn-quality { display: none; } }
/* Feedback & support: the quality pill's look; it stays on a phone, where the quality pill hides */
#btn-feedback {
  flex: none; margin-left: 8px; padding: 4px 11px; font: inherit; font-size: 12px; font-weight: 700;
  color: var(--ink-soft); background: #fff; border: 1px solid var(--panel-border); border-radius: 999px; cursor: pointer;
}
#btn-feedback:hover { color: var(--accent); border-color: var(--accent); }

/* the picker's honesty line — only when the showcase (dark) stage is up */
.fm-accuracy { display: none; font-size: 11.5px; color: var(--ink-soft); margin: 6px 2px 2px; }
body.stage-dark .fm-accuracy { display: block; }

#stage-wrap { position: relative; flex: 1; min-height: 0; }
#stage { width: 100%; height: 100%; display: block; touch-action: none; }

#note-panel {
  position: absolute; top: 12px; left: 12px; right: 12px;
  max-width: 480px;
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--panel); border: 1px solid var(--panel-border);
  border-left: 4px solid var(--accent);
  border-radius: 10px; padding: 10px 14px;
  backdrop-filter: blur(4px);
  pointer-events: none;
}
#step-num {
  flex: none; width: 34px; height: 34px; margin-top: 1px;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: #fff;
  border-radius: 50%; font-weight: 800; font-size: 16px;
}
.note-body { min-width: 0; }
#step-title { font-weight: 700; font-size: 15px; margin-bottom: 2px; }
#step-note { font-size: 13px; color: var(--ink-soft); line-height: 1.45; }
/* collapse the step text to a small badge pill — reclaims the canvas while
   recoloring/inspecting; the header's "Step x / y" keeps the context */
/* big enough to FIND — the 24px ghost chevron was invisible next to the text.
   Expanded = ✕ (dismiss the text), collapsed = ▸ (bring it back). */
#note-collapse {
  pointer-events: auto; /* the panel itself is pointer-events: none */
  flex: none; align-self: flex-start;
  display: flex; align-items: center; justify-content: center;
  font: inherit; font-size: 22px; line-height: 1;
  width: 36px; height: 36px; margin: 0 -4px 0 0;
  border: none; background: rgba(0,0,0,.05); color: var(--ink-soft);
  border-radius: 50%; cursor: pointer;
}
#note-collapse:hover { color: var(--accent); background: rgba(0,0,0,.09); }
#note-panel.collapsed { right: auto; } /* shrink to the badge + chevron */
#note-panel.collapsed .note-body { display: none; }

#pointer-line {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none;
}
#pointer-line line { stroke: var(--ink); stroke-width: 1.5; opacity: 0.55; }

#checklist-panel {
  position: absolute; top: 76px; right: 12px;
  width: 250px; max-height: calc(100% - 140px); overflow-y: auto;
  background: var(--panel); border: 1px solid var(--panel-border);
  border-radius: 10px; padding: 10px 12px;
  backdrop-filter: blur(4px);
}
.checklist-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-weight: 700; font-size: 13px; margin-bottom: 8px;
}
#checklist-close {
  font: inherit; font-size: 16px; line-height: 1;
  border: none; background: none; color: var(--ink-soft);
  cursor: pointer; padding: 0 2px;
}
#checklist-close:hover { color: var(--ink); }
#checklist-tab {
  position: absolute; top: 76px; right: 12px;
  font: inherit; font-size: 12.5px; font-weight: 700;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--panel-border); border-right: 3px solid var(--accent);
  border-radius: 999px; padding: 7px 14px;
  backdrop-filter: blur(4px);
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0,0,0,.08);
}
#checklist-tab:hover { border-color: var(--accent); }
.checklist-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; padding: 4px 0;
  border-top: 1px solid var(--panel-border);
}
.checklist-row .chip { width: 15px; height: 15px; border-radius: 4px; flex: none; border: 1px solid rgba(0,0,0,.15); margin-top: 2px; padding: 0; cursor: pointer; }
.checklist-row .chip:hover { outline: 2px solid var(--accent); outline-offset: 1px; }
/* purchased hardware: the chip is a plain color dot, not a filament picker */
.checklist-row .chip.locked { cursor: default; }
.checklist-row .chip.locked:hover { outline: none; }
/* section headers inside the parts/options panel — one look for all three
   (⚙ Build options · 🎨 Filament colors · 🧩 Parts to print) */
.section-head { font-size: 11.5px; font-weight: 800; color: var(--ink-soft); letter-spacing: .01em; margin-bottom: 7px; }
#parts-head { margin: 2px 0 8px; }
/* the shared "needs bought hardware" wrench, inline in text — sized in em so it
   tracks whatever it sits beside, and currentColor so it never fights the theme */
/* 1.25em, not 1em: the cropped viewBox means the box IS the wrench, with none
   of the internal padding an emoji carries — at a matched em they looked
   mismatched, this sits level with the 🧩 beside it */
.hw-ico { width: 1.25em; height: 1.25em; vertical-align: -0.28em; fill: currentColor; }
#build-options { margin-bottom: 8px; padding-bottom: 10px; border-bottom: 1px solid var(--panel-border); }
.opt-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.opt-label { font-size: 12px; font-weight: 600; }
/* one-line honesty/explainer under an option row (build plate: the effect is a
   simulation, and the real thing varies with light and angle) */
.opt-note { font-size: 11px; color: var(--ink-soft); margin: -2px 0 8px; line-height: 1.35; }
.opt-seg { display: inline-flex; border: 1px solid var(--panel-border); border-radius: 8px; overflow: hidden; }
.opt-seg button { font: inherit; font-size: 11px; font-weight: 700; padding: 5px 10px; border: none; background: #fff; color: var(--ink-soft); cursor: pointer; }
.opt-seg button + button { border-left: 1px solid var(--panel-border); }
.opt-seg button.on { background: var(--accent); color: #fff; }
/* choices too long to sit beside their label - the three build plates, whose names match the planner's - stack under it:
   side by side they need ~245 px and the desktop panel's options are 209 px wide, so "Powder-coated" broke at its hyphen
   and "Holographic" ran past the panel's edge (measured, integration/scripts/p38/p38b.mjs) */
.opt-row.opt-stack { flex-direction: column; align-items: stretch; gap: 4px; }
.opt-row.opt-stack .opt-seg { flex-direction: column; }
.opt-row.opt-stack .opt-seg button { text-align: left; white-space: nowrap; }
.opt-row.opt-stack .opt-seg button + button { border-left: none; border-top: 1px solid var(--panel-border); }
.opt-cycle button { color: var(--accent); padding: 5px 8px; }
.opt-cycle-name { font-size: 11px; font-weight: 700; padding: 0 6px; align-self: center; min-width: 70px; text-align: center; }
.opt-reset { width: 100%; font: inherit; font-size: 11.5px; font-weight: 700; margin-top: 4px; padding: 6px; border: 1px solid var(--panel-border); background: none; color: var(--ink-soft); border-radius: 7px; cursor: pointer; }
.opt-reset:hover { border-color: var(--accent); color: var(--accent); }
#preset-bar { margin-bottom: 8px; padding-bottom: 10px; border-bottom: 1px solid var(--panel-border); }
.preset-label { font-size: 11px; font-weight: 700; color: var(--ink-soft); margin-bottom: 6px; }
/* the preset block collapses so a growing preset library never crowds the
   panel — the head doubles as the toggle and names the active palette */
#preset-head {
  display: flex; align-items: center; gap: 6px; width: 100%;
  font: inherit; font-size: 11.5px; font-weight: 800; color: var(--ink-soft);
  letter-spacing: .01em; margin-bottom: 7px;
  background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
}
#preset-head.collapsed { margin-bottom: 0; }
#preset-head .chev { margin-left: auto; font-size: 10px; transition: transform .18s; }
#preset-head.collapsed .chev { transform: rotate(-90deg); }
#preset-active { font-weight: 600; opacity: .85; }
#preset-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.preset-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font: inherit; font-size: 11px; font-weight: 600; color: var(--ink);
  border: 1px solid var(--panel-border); background: none;
  border-radius: 999px; padding: 3px 9px 3px 4px; cursor: pointer;
}
.preset-chip:hover { border-color: var(--accent); color: var(--accent); }
.preset-chip.on { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
/* the user's own hand-built palette — presets never overwrite it */
.preset-chip.mine::before { content: "★"; color: var(--accent); font-size: 10px; margin-right: -1px; }
.preset-sw { display: inline-flex; }
.preset-sw i { width: 11px; height: 11px; border-radius: 50%; display: block; margin-left: -3px; border: 1.5px solid var(--panel); }
.preset-sw i:first-child { margin-left: 0; }
#preset-io { display: flex; gap: 6px; margin-top: 8px; }

#checklist-actions {
  display: flex; gap: 6px; margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--panel-border);
}
.bom-btn {
  flex: 1; font: inherit; font-size: 11.5px; font-weight: 700;
  border: 1px solid var(--panel-border); background: none; color: var(--ink);
  border-radius: 7px; padding: 6px 8px; cursor: pointer; white-space: nowrap;
}
.bom-btn:hover { border-color: var(--accent); color: var(--accent); }
.checklist-row .qty { margin-left: auto; font-weight: 700; color: var(--ink-soft); align-self: flex-start; }
.checklist-row { align-items: flex-start; }
.cl-mid { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* optional per-row note: an alternative or condition the label can't carry */
.cl-note { font-size: .78rem; color: var(--ink-soft); line-height: 1.35; }
/* the requirement tier, one chip per non-core row: option (named cause) in
   the accent, enhancement muted. Core rows with a basis get the same muted
   treatment - their variant is information, not a warning. */
.cl-req { display: inline-block; margin-top: 2px; font-size: .72rem; line-height: 1.3;
  padding: 1px 7px; border-radius: 999px; letter-spacing: .01em; }
.cl-req.option { color: var(--accent); background: rgba(255,138,64,0.12); }
.cl-req.enhancement, .cl-req.core { color: var(--ink-soft); background: rgba(0,0,0,0.06); }
body.stage-dark .cl-req.enhancement, body.stage-dark .cl-req.core { background: rgba(255,255,255,0.08); }

.dl-link {
  display: inline-block; font-size: 11px; font-weight: 700;
  color: var(--accent); text-decoration: none;
  border: 1px solid var(--panel-border); border-radius: 999px;
  padding: 1px 8px; margin-right: 4px;
}
.dl-link:hover { border-color: var(--accent); }
/* One store button per row + a ▾ for the others, so the row stays the same
   width however many stores exist. */
.dl-more { position: relative; display: inline-block; }
.dl-more-btn {
  font: inherit; font-size: 11px; line-height: 1; cursor: pointer;
  padding: 4px 6px; margin-left: -3px;
  color: var(--ink-soft); background: none;
  border: 1px solid var(--panel-border); border-radius: 6px;
}
.dl-more-btn:hover { color: var(--ink); border-color: var(--accent); }
.dl-more-menu {
  position: absolute; z-index: 40; top: calc(100% + 4px); left: 0; min-width: 128px;
  display: flex; flex-direction: column; gap: 2px; padding: 5px;
  background: var(--panel); border: 1px solid var(--panel-border);
  border-radius: 9px; box-shadow: 0 6px 20px rgba(0,0,0,.18);
}
/* menu items are .dl-link pills stacked vertically — the ID-qualified variant
   outranks `#identify-links .dl-link`'s margin, which would otherwise win */
.dl-more-menu .dl-more-item,
#identify-links .dl-more-menu .dl-more-item { display: block; margin: 0; white-space: nowrap; text-align: center; }
#store-pref {
  display: flex; align-items: center; gap: 7px;
  margin-top: 7px; font-size: 11.5px; color: var(--ink-soft);
}
#store-select {
  font: inherit; font-size: 11.5px; color: var(--ink);
  padding: 3px 6px; border: 1px solid var(--panel-border);
  border-radius: 6px; background: var(--panel); cursor: pointer;
}

#identify-card {
  position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px;
  background: var(--panel); border: 1px solid var(--panel-border);
  border-left: 4px solid var(--accent);
  border-radius: 12px; padding: 10px 16px;
  transition: opacity .25s; /* fm-open fades it — see the fm-open block */
  backdrop-filter: blur(4px);
  text-align: left; min-width: 240px;
  box-shadow: 0 4px 18px rgba(0,0,0,.12);
}
#identify-img {
  flex: none; width: 62px; height: 62px; object-fit: contain;
  background: #fff; border: 1px solid var(--panel-border); border-radius: 8px;
}
.identify-body { min-width: 0; }
/* the card's ◀ name ▶ cycles: part style, shelf lip, drawer body (Standard / Gridfinity) */
#identify-style, #identify-lip, #identify-variant {
  display: flex; align-items: center; gap: 8px; margin-top: 7px;
  font-size: 12.5px; font-weight: 700;
}
#identify-style button, #identify-lip button, #identify-variant button {
  font: inherit; font-size: 11px; line-height: 1;
  width: 24px; height: 24px; border-radius: 50%;
  border: 1px solid var(--panel-border); background: #fff; color: var(--accent);
  cursor: pointer;
}
#identify-style button:hover, #identify-lip button:hover, #identify-variant button:hover { border-color: var(--accent); }
#style-name, #lip-name, #variant-name { min-width: 84px; text-align: center; }
#identify-name { font-weight: 700; font-size: 14px; }
#identify-qty { font-size: 12px; color: var(--ink-soft); margin: 2px 0 6px; }
/* 2-zone parts (EdgeLabel): Body + Grip color chips under the qty line */
#identify-zones { display: flex; gap: 6px; margin: 0 0 6px; }
.zone-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-size: 11.5px; font-weight: 700;
  border: 1px solid var(--panel-border); border-radius: 999px;
  padding: 3px 10px 3px 4px; background: #fff; cursor: pointer;
  /* a <button> does not inherit color - without this the dark stage drew black text on its navy chip */
  color: var(--ink);
}
.zone-chip i { width: 18px; height: 18px; border-radius: 50%; border: 1px solid rgba(0,0,0,.15); }
.zone-chip:hover { border-color: var(--accent); }
/* the zone the picker is currently editing — without it you can't tell which
   swatch your next pick lands on */
.zone-chip.on { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(255,138,64,.28); }
#identify-links .dl-link { margin: 0 6px 0 0; padding: 3px 12px; font-size: 12px; }
/* the label editor (label plan step 2) - keyed on the editor being OPEN (body.label-edit-open), not on viewport width:
   the planner's dock is a ~420-640 px pane that reads as desktop, and the card grows into a tall sheet there too */
body.label-edit-open #identify-card { max-height: 74%; overflow-y: auto; align-items: flex-start; }
#identify-label-edit { margin: 6px 0 4px; font-size: 12.5px; }
#identify-label-edit .le-row { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
#identify-label-edit .le-row > span:first-child { font-weight: 700; min-width: 40px; }
#label-edit-text {
  flex: 1; min-width: 180px; font: inherit; font-size: 13px; padding: 5px 8px;
  border: 1px solid var(--panel-border); border-radius: 7px; background: #fff; color: var(--ink);
}
#label-edit-text:focus { outline: none; border-color: var(--accent); }
/* shows the words the way the label prints them (ALL CAPS unless the style turns it off) without destroying their case */
#label-edit-text.caps { text-transform: uppercase; }
#label-edit-badge {
  width: 30px; height: 30px; flex: none; font: inherit; font-size: 13px; font-weight: 700; line-height: 1; padding: 4px;
  border: 1px solid var(--panel-border); border-radius: 7px; background: #fff; color: var(--ink); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; overflow: hidden;
}
#label-edit-badge svg { width: 18px; height: 18px; fill: currentColor; }
#label-edit-badge.predicted { border-style: dashed; color: var(--ink-soft); }   /* Auto: the generator's prediction */
#label-edit-badge.set { border-color: var(--accent); color: var(--accent); }     /* a manual icon or letter */
#label-edit-badge:disabled { opacity: .45; cursor: default; }
#label-edit-badge-state { color: var(--ink-soft); font-size: 12px; }
#label-edit-picker { margin-top: 8px; }
.le-pick-row { display: flex; gap: 6px; align-items: center; margin-bottom: 8px; }
.le-pick-row button, #label-edit-undo {
  font: inherit; font-size: 11.5px; font-weight: 700; padding: 5px 10px; cursor: pointer;
  border: 1px solid var(--panel-border); border-radius: 7px; background: #fff; color: var(--ink);
}
.le-pick-row button:hover, #label-edit-undo:hover { border-color: var(--accent); color: var(--accent); }
#label-pick-char { width: 56px; font: inherit; font-size: 13px; padding: 5px 7px; border: 1px solid var(--panel-border); border-radius: 7px; background: #fff; color: var(--ink); }
/* the icon groups (the generator's icon catalog): collapsible, in a box that scrolls */
#label-pick-search { display: block; width: 100%; box-sizing: border-box; margin-bottom: 6px; font: inherit; font-size: 13px; padding: 5px 8px; border: 1px solid var(--panel-border); border-radius: 7px; background: #fff; color: var(--ink); }
#label-pick-icons { max-height: 260px; overflow-y: auto; }
.le-group + .le-group { border-top: 1px solid var(--panel-border); }
.le-ghead { display: flex; align-items: center; gap: 6px; width: 100%; padding: 6px 2px; border: none; background: none; color: var(--ink); font: inherit; font-size: 12px; font-weight: 700; cursor: pointer; text-align: left; }
.le-ghead:hover { color: var(--accent); }
.le-caret { display: inline-block; width: 10px; color: var(--ink-soft); transition: transform .12s; }
.le-group.open .le-caret { transform: rotate(90deg); }
.le-gcount { margin-left: auto; font-size: 11px; color: var(--ink-soft); }
.le-cells { display: none; grid-template-columns: repeat(5, 36px); gap: 6px; padding-bottom: 8px; }
.le-group.open .le-cells { display: grid; }
.le-empty { font-size: 12px; color: var(--ink-soft); padding: 6px 2px; }
.le-caption { min-height: 1.4em; font-size: 12px; color: var(--ink-soft); padding: 4px 2px 0; line-height: 1.4; }
.le-upnote { font-size: 12px; color: var(--ink-soft); padding: 0 2px 8px; line-height: 1.4; }
.le-pick-row button:disabled { opacity: .45; cursor: default; }
.le-iname { display: none; }
/* A touch screen has no hover: there every icon shows its name under it, so the name is read BEFORE the tap that chooses it
   (ChatGPT's second review via Joey). Ids outrank the phone sizes further down. */
@media (hover: none), (any-pointer: coarse) {
  #label-pick-icons .le-cells { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #label-pick-icons .le-icon { width: auto; height: auto; flex-direction: column; gap: 3px; padding: 7px 3px 6px; }
  #label-pick-icons .le-icon svg { width: 24px; height: 24px; flex: none; }
  #label-pick-icons .le-iname { display: block; font-size: 10.5px; line-height: 1.2; text-align: center; color: var(--ink-soft); }
  /* the group headers are tap targets too: 44 px tall (they measured 29 px on a phone, readiness review 2026-10-10) */
  #label-pick-icons .le-ghead { min-height: 44px; }
}
/* an uploaded label icon: drawn as a mask over the current colour, never as markup */
.svg-mask { display: block; width: 18px; height: 18px; background: currentColor; -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; }
.le-icon {
  width: 36px; height: 36px; padding: 6px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--panel-border); border-radius: 7px; background: #fff; color: var(--ink);
}
.le-icon svg { width: 100%; height: 100%; fill: currentColor; }
.le-icon:hover { border-color: var(--accent); color: var(--accent); }
.le-icon.on { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(255,138,64,.28); color: var(--accent); }
.le-fit { margin-top: 6px; font-size: 12px; font-weight: 700; color: var(--bad, #d23a2e); }
.le-status-row { min-height: 0; }
#label-edit-status { font-size: 12px; color: var(--ink-soft); }
#label-edit-note { margin-top: 6px; font-size: 11px; color: var(--ink-soft); }
#label-edit-part { margin-top: 6px; font-size: 11px; color: var(--ink-soft); }
#identify-label-go {
  display: block; margin-top: 8px; font: inherit; font-size: 11.5px; font-weight: 700; text-align: left;
  color: var(--accent); background: none; cursor: pointer;
  border: 1px solid var(--panel-border); border-radius: 999px; padding: 4px 12px;
}
#identify-label-go:hover { border-color: var(--accent); background: rgba(255,138,64,.08); }
/* the Labels block in Build options: number rows with the generator's own min/max/step */
.opt-labels-head { margin-top: 10px; }
.opt-num-wrap { display: inline-flex; align-items: center; gap: 5px; }
.opt-num-wrap input {
  width: 64px; font: inherit; font-size: 12px; padding: 4px 6px; text-align: right;
  border: 1px solid var(--panel-border); border-radius: 7px; background: #fff; color: var(--ink);
}
.opt-num-wrap input:focus { outline: none; border-color: var(--accent); }
.opt-unit { font-size: 11px; color: var(--ink-soft); }
.opt-note.opt-note-warn { color: var(--bad, #d23a2e); }
#identify-remove {
  margin-top: 8px; font: inherit; font-size: 11.5px; font-weight: 700;
  color: var(--bad, #d23a2e); background: none; cursor: pointer;
  border: 1px solid var(--panel-border); border-radius: 999px; padding: 4px 12px;
}
#identify-remove:hover { border-color: var(--bad, #d23a2e); background: #fff2f0; }
/* faceplate isolation → drawer hand-off ("Open the drawer"), the explicit way
   out of an open drawer ("Close drawer"), and the label-generator handoff
   ("Design your labels") — accent pills in the card */
#identify-open-drawer, #identify-close-drawer, #identify-label-gen {
  display: inline-block; text-decoration: none;
  margin-top: 8px; font: inherit; font-size: 11.5px; font-weight: 700;
  color: var(--accent); background: none; cursor: pointer;
  border: 1px solid var(--panel-border); border-radius: 999px; padding: 4px 12px;
}
#identify-open-drawer:hover, #identify-close-drawer:hover, #identify-label-gen:hover { border-color: var(--accent); background: #fff6ee; }

#color-toggle {
  position: absolute; top: 120px; right: 12px;
  font: inherit; font-size: 12.5px; font-weight: 700;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--panel-border); border-right: 3px solid #2f9be0;
  border-radius: 999px; padding: 7px 14px;
  backdrop-filter: blur(4px); cursor: pointer;
  box-shadow: 0 2px 10px rgba(0,0,0,.08);
}
#color-toggle:hover { border-color: #2f9be0; }

/* 📏 measure tool — pill stacks under the parts/colors pills; the label is a
   floating readout tracking the measurement line's midpoint (mm + ΔXYZ) */
#measure-toggle {
  position: absolute; top: 164px; right: 12px;
  font: inherit; font-size: 12.5px; font-weight: 700;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--panel-border); border-right: 3px solid var(--accent);
  border-radius: 999px; padding: 7px 14px;
  backdrop-filter: blur(4px); cursor: pointer;
  box-shadow: 0 2px 10px rgba(0,0,0,.08);
}
#measure-toggle:hover { border-color: var(--accent); }
#measure-toggle.on { background: var(--accent); border-color: var(--accent); color: #fff; }
#measure-label {
  position: absolute; transform: translate(-50%, -135%);
  background: var(--panel); border: 1px solid var(--accent);
  border-radius: 8px; padding: 5px 10px;
  font-size: 13px; font-weight: 800; text-align: center; line-height: 1.25;
  pointer-events: none; white-space: nowrap;
  box-shadow: 0 3px 12px rgba(0,0,0,.14);
}
#measure-label small { display: block; font-size: 10.5px; font-weight: 600; color: var(--ink-soft); }

/* overall W/H/L dimension callouts on the final assembled step */
.dim-label {
  position: absolute; transform: translate(-50%, -50%);
  background: var(--panel); border: 1px solid var(--panel-border);
  border-radius: 7px; padding: 3px 8px;
  font-size: 12px; text-align: center; line-height: 1.2;
  pointer-events: none; white-space: nowrap;
  box-shadow: 0 2px 8px rgba(0,0,0,.10);
}
.dim-label b { font-weight: 800; color: var(--accent); margin-right: 2px; }
.dim-label small { display: block; font-size: 9.5px; font-weight: 600; color: var(--ink-soft); }

/* ?debug=1 part readout in the identify card (manifest pos + bbox mm) */
#identify-debug {
  font-family: ui-monospace, Consolas, monospace; font-size: 10.5px;
  color: var(--ink-soft); margin-top: 3px;
}

.identify-name-row { display: flex; align-items: center; gap: 7px; }
#identify-swatch {
  flex: none; width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid #fff; outline: 1px solid var(--panel-border);
  cursor: pointer; padding: 0;
}
#identify-swatch:hover { outline-color: var(--accent); }
#identify-swatch.locked { cursor: default; }
#identify-swatch.locked:hover { outline-color: var(--panel-border); }

#tap-hint {
  position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
  max-width: min(560px, 88%);
  display: flex; align-items: center; gap: 10px;
  background: var(--panel); border: 1px solid var(--panel-border);
  border-bottom: 3px solid var(--accent);
  border-radius: 999px; padding: 9px 10px 9px 18px;
  font-size: 13px; font-weight: 600; color: var(--ink);
  box-shadow: 0 6px 24px rgba(0,0,0,.16); backdrop-filter: blur(4px);
  pointer-events: auto; z-index: 20;
}
#tap-hint-x {
  font: inherit; font-size: 16px; line-height: 1; flex: none;
  width: 24px; height: 24px; border-radius: 50%;
  border: 1px solid var(--panel-border); background: none; color: var(--ink-soft);
  cursor: pointer;
}
#tap-hint-x:hover { color: var(--ink); border-color: var(--ink-soft); }

#filament-menu {
  position: absolute; bottom: 108px; left: 50%; transform: translateX(-50%);
  width: 300px;
  background: var(--panel); border: 1px solid var(--panel-border);
  border-radius: 12px; padding: 12px 14px;
  backdrop-filter: blur(6px);
  box-shadow: 0 6px 24px rgba(0,0,0,.16);
}
/* ---- fm-open: the stage clears while a colour is being judged ----
   Picking filament means you've temporarily stepped OUT of the instructions
   (Joey 2026-08-07), so everything except the model and the swatches yields.
   Class-only mechanism — body.fm-open is set/cleared in openFilamentMenu /
   closeFilamentMenu — so every panel returns in exactly its prior state. */
/* the step note hides on EVERY layout (mobile's sliver-of-model problem and
   the desktop's "not following along anyway" are the same reasoning) */
body.fm-open #note-panel { display: none; }
@media (min-width: 561px) {
  /* the menu used to sit dead-center OVER the model it exists to recolor —
     dock it right, where the parts panel (now hidden) kept space clear */
  body.fm-open #filament-menu { left: auto; right: 16px; transform: none; }
  body.fm-open #checklist-panel, body.fm-open #checklist-tab { display: none; }
  /* the identify card FADES instead of hiding: its zone chips (Body/Grip
     retargeting) must stay reachable mid-pick — hover/focus restores it */
  body.fm-open #identify-card { opacity: .25; }
  body.fm-open #identify-card:hover, body.fm-open #identify-card:focus-within { opacity: 1; }
}

/* the ✕ sits on the title row so it costs no vertical space; `position:
   relative` here is what anchors it (the menu itself is the positioned
   ancestor for the bottom-sheet layout, so don't anchor to that) */
.fm-head { font-weight: 800; font-size: 13px; margin-bottom: 7px; position: relative; padding-right: 26px; }
.fm-head span { font-weight: 600; color: var(--ink-soft); font-size: 11.5px; }
#fm-close {
  position: absolute; top: -3px; right: -4px;
  width: 26px; height: 26px; padding: 0; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  font: inherit; font-size: 19px; font-weight: 700;
  color: var(--ink-soft); background: none; border: 0; border-radius: 7px;
  cursor: pointer;
}
#fm-close:hover { color: var(--ink); background: rgba(0,0,0,.06); }
#fm-search {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 11.5px;
  border: 1px solid var(--panel-border); border-radius: 7px;
  padding: 5px 9px; margin-bottom: 8px; background: none; color: var(--ink);
}
#fm-search:focus { outline: none; border-color: var(--accent); }
#fm-brands { max-height: 264px; overflow-y: auto; overscroll-behavior: contain; }
.fm-brand + .fm-brand { margin-top: 4px; }
/* "In this build" — same visual weight as a brand head, but a plain label:
   the section is always open (a handful of swatches, nothing to fold) */
.fm-inbuild-head { font-size: 11.5px; font-weight: 800; color: var(--ink); margin: 2px 0 5px; }
.fm-brand-head {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  font: inherit; font-size: 11.5px; font-weight: 800; color: var(--ink);
  background: none; border: none; padding: 5px 2px; cursor: pointer; text-align: left;
}
.fm-brand-head i { font-style: normal; font-weight: 600; color: var(--ink-soft); font-size: 10.5px; }
.fm-brand-head:hover, .fm-brand-head:hover i { color: var(--accent); }
.fm-chev { color: var(--ink-soft); font-size: 10px; }
.fm-none { font-size: 11.5px; color: var(--ink-soft); padding: 8px 2px; }
.fm-swatches { display: grid; grid-template-columns: repeat(8, 1fr); gap: 7px; padding: 3px 2px 7px; }
.fm-swatches button {
  width: 26px; height: 26px; border-radius: 50%;
  border: 2px solid #fff; outline: 1px solid var(--panel-border);
  cursor: pointer; padding: 0;
}
.fm-swatches button:hover { outline: 2px solid var(--accent); }
.fm-swatches button.active { outline: 2.5px solid var(--accent); }
.fm-swatches button.pick { position: relative; }
.fm-swatches button.pick::after {
  content: "★"; position: absolute; top: -7px; right: -5px;
  font-size: 10px; color: var(--accent);
  text-shadow: 0 0 2px #fff;
}
.fm-note {
  margin-top: 9px; font-size: 10.5px; line-height: 1.4;
  color: var(--ink-soft);
}
/* the identify card's one commission line, right under its paid link(s)
   (2026-09-18 - it replaced a four-line paragraph; main.js cardDisclosure) */
.link-note {
  margin-top: 5px; font-size: 10.5px; line-height: 1.35;
  color: var(--ink-soft);
}
/* the Polymaker first-purchase deal — user benefit, so it reads a step above
   the fine print (same slot, accent ink, slightly larger) */
.fm-deal {
  margin-top: 10px; font-size: 11.5px; line-height: 1.4;
  color: var(--accent); font-weight: 600;
}
.fm-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 11px; font-size: 12px;
}
#fm-buy { color: var(--accent); font-weight: 700; text-decoration: none; }
#fm-buy:hover { text-decoration: underline; }
#fm-reset {
  font: inherit; font-size: 11px; font-weight: 600;
  border: 1px solid var(--panel-border); background: none; color: var(--ink-soft);
  border-radius: 999px; padding: 3px 10px; cursor: pointer;
}
#fm-reset:hover { color: var(--ink); border-color: var(--ink-soft); }

#outro-overlay {
  position: absolute; inset: 0;
  pointer-events: none;
}
.outro-card {
  position: absolute; left: 6%; top: 50%;
  transform: translateY(-50%);
  width: min(340px, 44vw);
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  background: rgba(255,255,255,0.82); border: 1px solid var(--panel-border);
  border-left: 4px solid var(--accent);
  border-radius: 16px; padding: 20px 24px;
  backdrop-filter: blur(9px);
  box-shadow: 0 8px 30px rgba(0,0,0,.14);
  pointer-events: auto;
}
.outro-head { display: flex; align-items: center; gap: 12px; } /* logo beside the title, not stacked */
#outro-logo { height: 40px; width: auto; flex: none; }
.outro-title { font-size: 21px; font-weight: 800; line-height: 1.1; }
.outro-sub { font-size: 13px; color: var(--ink-soft); line-height: 1.45; margin-bottom: 4px; }
.outro-btn {
  display: block; width: 100%; text-align: center; box-sizing: border-box;
  font-size: 14px; font-weight: 700; text-decoration: none;
  padding: 11px 16px; border-radius: 10px;
  border: 1px solid var(--panel-border); color: var(--ink); background: #fff;
}
.outro-btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.outro-btn:hover { filter: brightness(1.04); }
.outro-links { display: flex; gap: 16px; margin-top: 6px; font-size: 12.5px; font-weight: 700; }
.outro-links a { color: var(--ink-soft); text-decoration: none; }
.outro-links a:hover { color: var(--accent); }

/* Cover backdrop: a soft spotlight + warm brand glow + edge vignette that
   composites over the 3D for a "premium box front", then fades to the normal
   flat bg when leaving page 0 (goTo toggles .show; the canvas bg shows through
   the mostly-transparent center, so the build never looks tinted). */
#cover-bg {
  position: absolute; inset: 0; pointer-events: none; z-index: 1;
  opacity: 0; transition: opacity .7s ease;
  background:
    radial-gradient(115% 80% at 40% 40%, rgba(255,255,255,.55), rgba(255,255,255,0) 46%),
    radial-gradient(120% 100% at 50% 120%, rgba(255,138,64,.12), rgba(255,138,64,0) 55%),
    radial-gradient(145% 125% at 50% 48%, rgba(24,28,38,0) 52%, rgba(24,28,38,.20) 100%);
}
#cover-bg.show { opacity: 1; }

#cover-overlay {
  position: absolute; inset: 0;
  pointer-events: none; z-index: 2;
}
/* diagonal corner ribbon (top-left): a thick two-line box seal — big collection
   number over "COLLECTION". The band's CENTER sits on the corner diagonal
   (centerX = centerY: left = c − width/2, top = c − height/2 with c≈75) so both
   ends run off the top + left screen edges (overflow:hidden clips them there)
   instead of one end floating mid-canvas. */
#cover-ribbon { position: absolute; top: 0; left: 0; width: 208px; height: 208px; overflow: hidden; }
.cr-band {
  position: absolute; top: 45px; left: -55px; width: 260px;
  padding: 9px 0; transform: rotate(-45deg);
  display: flex; flex-direction: column; align-items: center; line-height: 1;
  background: linear-gradient(180deg, #ffa15c, var(--accent)); color: #fff;
  box-shadow: 0 5px 14px rgba(0,0,0,.24);
}
.cr-band b { font-size: 27px; font-weight: 800; text-shadow: 0 1px 2px rgba(0,0,0,.3); }
.cr-band span { margin-top: 3px; font-size: 11px; font-weight: 800; letter-spacing: .22em; text-transform: uppercase; opacity: .95; }
.cover-right {
  position: absolute; right: 7%; top: 50%;
  transform: translateY(-54%);
  width: min(360px, 38vw);
  display: flex; flex-direction: column; align-items: flex-start;
  pointer-events: auto;
  isolation: isolate;
}
/* soft light halo behind the whole overlay so the title + button stay legible
   over any build color (dark cases, red drawers, etc.) */
.cover-right::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -11% -14% -11% -22%;
  background: radial-gradient(ellipse at 55% 50%,
    rgba(244,246,248,0.94) 0%, rgba(244,246,248,0.80) 44%, rgba(244,246,248,0) 76%);
  filter: blur(8px);
}
#cover-logo { width: 100%; height: auto; }
/* dark-mode cover (Joey 2026-08-08): NO halo - the MODULITH wordmark carries its own charcoal and orange blocks, and the
   white lockup text carries the contrast */
body.stage-dark .cover-right::before { display: none; }
body.stage-dark .cover-dynamic { text-shadow: none; }
body.stage-dark .cover-manual { color: #f2f4ff; text-shadow: none; }
/* one-line lockup: italic blue "3D" + black all-caps "BUILD STUDIO" */
.cover-lede {
  margin-top: 22px; padding-top: 18px; position: relative;
  display: flex; flex-direction: row; align-items: baseline;
  gap: 10px; flex-wrap: wrap;
}
.cover-lede::before { /* thin accent rule tying the lockup together */
  content: ''; position: absolute; top: 0; left: 2px; width: 46px; height: 3px;
  border-radius: 3px; background: var(--accent);
}
.cover-dynamic {
  font-size: clamp(23px, 2.9vw, 34px); font-weight: 800; font-style: italic; line-height: 1.05;
  letter-spacing: .02em; text-transform: uppercase; color: #2f9be0;
  text-shadow: 0 1px 10px rgba(244,246,248,.95);
}
.cover-manual {
  font-size: clamp(23px, 2.9vw, 34px); font-weight: 800;
  letter-spacing: .02em; text-transform: uppercase; color: #33363c; line-height: 1.05;
  text-shadow: 0 1px 12px rgba(244,246,248,.95);
}
#btn-start {
  margin-top: 26px;
  display: inline-flex; align-items: center; gap: 9px;
  font: inherit; font-size: 17px; font-weight: 700;
  padding: 13px 30px; border-radius: 12px;
  border: none; background: var(--accent); color: #fff;
  cursor: pointer;
  box-shadow: 0 8px 22px rgba(255,138,64,0.42), 0 2px 8px rgba(0,0,0,0.16);
}
#btn-start i { font-style: normal; transition: transform .2s ease; }
#btn-start:hover { filter: brightness(1.05); }
#btn-start:hover i { transform: translateX(4px); }
#btn-start:active { transform: translateY(1px); }
/* quiet secondary action under the CTA — for people here to customize, not
   build. A translucent pill instead of bare text: the model sometimes sits
   right behind it, and gray-on-gray was unreadable at some camera angles. */
#btn-skip-end {
  margin-top: 12px; padding: 6px 14px;
  font: inherit; font-size: 13px; font-weight: 700;
  border: none; cursor: pointer; color: #3f434a;
  background: rgba(244,246,248,0.78);
  border-radius: 999px;
  box-shadow: 0 1px 6px rgba(0,0,0,0.10);
}
#btn-skip-end:hover { color: var(--accent); background: rgba(244,246,248,0.94); }
/* official kits only: the planner on-ramp — same quiet-pill family as the skip
   link, accent-tinted so "make it yours" reads as the next adventure, not chrome */
#btn-customize {
  margin-top: 8px; padding: 6px 14px;
  font: inherit; font-size: 13px; font-weight: 700;
  border: none; cursor: pointer; color: var(--accent);
  background: rgba(255,244,235,0.86);
  border-radius: 999px;
  box-shadow: 0 1px 6px rgba(0,0,0,0.10);
}
#btn-customize:hover { background: rgba(255,238,224,0.97); }
/* the pinned-link pill: same family, deliberately QUIETER than Customize —
   sharing is a secondary action, and it must not compete with the on-ramp.
   Sized to hold "✓ Link copied" and, when the clipboard is unavailable, the
   full URL as selectable text rather than a silent failure. */
#btn-copylink {
  margin-top: 6px; padding: 5px 13px;
  font: inherit; font-size: 12px; font-weight: 700;
  border: none; cursor: pointer; color: #4a4d56;
  background: rgba(255,255,255,0.78);
  border-radius: 999px;
  box-shadow: 0 1px 5px rgba(0,0,0,0.08);
  max-width: 100%; overflow-wrap: anywhere;
}
#btn-copylink:hover { background: rgba(255,255,255,0.95); color: var(--accent); }
body.stage-dark #btn-copylink { background: rgba(16,18,42,0.80); color: var(--ink-soft); }
body.stage-dark #btn-copylink:hover { background: rgba(16,18,42,0.95); color: var(--accent); }
/* manual-copy field: shown only when the clipboard API is unavailable
   (insecure context), focused and pre-selected so Ctrl/Cmd-C just works */
.copy-fallback {
  display: block; margin-top: 6px; width: 100%; max-width: 320px;
  font: inherit; font-size: 12px; padding: 5px 10px;
  border: 1px solid rgba(0,0,0,0.18); border-radius: 8px;
  background: #fff; color: #23252b;
}
.copy-fallback.hidden { display: none; }
body.stage-dark .copy-fallback { background: rgba(16,18,42,0.92); color: var(--ink); border-color: rgba(255,255,255,0.22); }
/* embed cover: the skip link's job is done better by the preview landing —
   swap it for the way back (same quiet-pill look) */
#cover-preview {
  display: none;
  margin-top: 12px; padding: 6px 14px;
  font: inherit; font-size: 13px; font-weight: 700;
  border: none; cursor: pointer; color: #3f434a;
  background: rgba(244,246,248,0.78);
  border-radius: 999px;
  box-shadow: 0 1px 6px rgba(0,0,0,0.10);
}
#cover-preview:hover { color: var(--accent); background: rgba(244,246,248,0.94); }
body.embed #btn-skip-end { display: none; }
body.embed #cover-preview { display: inline-block; }

/* LEGO-box stat badges (bottom-left): big "ONLY N PARTS" block + drawers /
   steps / real W×H×L chips — all engine-computed (renderCoverBadges) */
#cover-badges {
  position: absolute; left: 18px; bottom: 20px;
  display: flex; align-items: flex-end; gap: 9px; flex-wrap: wrap;
}
.cv-hero {
  display: flex; flex-direction: column; align-items: center;
  background: linear-gradient(160deg, #ffa15c, var(--accent));
  color: #fff; border-radius: 13px; padding: 9px 17px 8px;
  transform: rotate(-3deg);
  box-shadow: 0 6px 18px rgba(255,138,64,.45);
  animation: cvPop .5s cubic-bezier(.34,1.56,.64,1) both; /* playful entrance */
}
.cv-hero b { font-size: 32px; font-weight: 800; line-height: 1; }
.cv-hero > span:last-child { font-size: 10.5px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; }
.cv-chip {
  display: flex; flex-direction: column; align-items: center;
  background: var(--panel); border: 1px solid var(--panel-border);
  border-radius: 10px; padding: 7px 12px 6px;
  box-shadow: 0 2px 10px rgba(0,0,0,.08);
}
.cv-chip b { font-size: 15px; font-weight: 800; line-height: 1.15; color: var(--ink); }
.cv-chip span { font-size: 9px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-soft); }
@keyframes cvPop { from { transform: rotate(-3deg) scale(0); } to { transform: rotate(-3deg) scale(1); } }

#loading-overlay {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  background: var(--bg);
}
#loading-text { font-size: 13px; color: var(--ink-soft); }
.spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--panel-border); border-top-color: var(--accent);
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Embed mode (?embed=1 — docked inside the planner's split view) ----
   Slimmer chrome: the planner supplies the title + BOM exports, so the top
   bar and export buttons go; the "preview" landing additionally hides the
   step chrome and floats a Begin pill + a one-time orbit hint. All of it is
   class-driven (body.embed / body.embed-preview / body.embed-hint-on) so
   re-renders and regenerates can't undo it. */
body.embed #topbar { display: none; }
body.embed #checklist-actions { display: none; }   /* Copy/CSV live in the planner's BOM */
body.embed #store-pref { display: none; }          /* the docked planner owns the store preference */
/* the dock is narrower than a desktop but wider than the 560px mobile break:
   cap the note clear of the top-right pills, and give LONG notes the mobile
   treatment — capped height, text scrolls inside (Joey's ask) */
body.embed #note-panel { max-width: min(420px, calc(100% - 170px)); max-height: 34vh; }
body.embed #note-panel .note-body { overflow-y: auto; max-height: calc(34vh - 20px); pointer-events: auto; }
/* one sheet at a time (mobile's rule, panel-open set by setChecklist): an
   OPEN parts panel owns the pane — the note returns when it closes (✕, or
   tapping a part folds the panel) */
body.embed.panel-open #note-panel { display: none; }
/* ...and the identify card too (review D1, 2026-10-03): opened OVER an open label card, the panel's left column - the Labels
   rows and their snap-back note - sat under the card. Tapping a part already folds the panel (setSelected); this is the other
   order. The selection stays, so the card comes back when the panel closes (updatePointerLine drops the line meanwhile). */
body.embed.panel-open #identify-card { display: none; }
/* embed-only: the way back to the preview landing. Needs the double-id
   specificity — a bare #btn-preview{display:none} LOSES to the
   `#ctl-tools button{display:flex}` base rule, which shipped the Preview
   tool to the standalone viewer and wrapped the mobile controls bar
   (Joey's phone repro, 2026-07-19). */
#controls #btn-preview { display: none; }
body.embed #controls #btn-preview { display: flex; } /* flex (not inline-flex) — keeps the tool group's column icon/caption layout */
body.embed-preview #controls { display: none; }
body.embed-preview #note-panel { display: none; }
#embed-begin { display: none; }
body.embed-preview #embed-begin {
  display: inline-flex; align-items: center; gap: 8px;
  position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%);
  z-index: 30;
  font: inherit; font-weight: 700; font-size: 14px;
  padding: 11px 20px; border-radius: 8px; /* the planner's button shape (Joey) */
  border: 1px solid var(--accent); background: var(--accent); color: #fff;
  cursor: pointer; box-shadow: 0 6px 20px rgba(0,0,0,.22);
}
body.embed-preview #embed-begin:hover { filter: brightness(1.07); }
/* the Begin pill owns bottom-center on the preview — lift the identify card
   clear of it (Joey: tapping a part buried the card's style arrows under the
   pill). Desktop widths only: the ≤560 bottom-sheet card layers ABOVE the
   pill already (z 32 vs 30). */
@media (min-width: 561px) {
  body.embed-preview #identify-card { bottom: 72px; }
}
/* In-progress tabletop preview (2026-08-23): the layout is valid but a run
   is still being built up. One non-modal status pill, bottom-centre, and NO
   instruction chrome - there is nothing to step through yet. Orange heading,
   a progress glyph, role=status: guidance, never an alert. */
#incomplete-status {
  position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%);
  z-index: 30; max-width: min(560px, calc(100% - 32px));
  background: var(--panel); border: 1px solid var(--accent); border-radius: 10px;
  padding: 10px 16px; text-align: center; box-shadow: 0 6px 20px rgba(0,0,0,.22);
  pointer-events: none;
}
#incomplete-status.hidden { display: none; }
#incomplete-status b { display: block; color: var(--accent); font-size: 14px; }
#incomplete-status b::before { content: "\25D4  "; }
#incomplete-status span { display: block; font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
body.incomplete #controls, body.incomplete #note-panel, body.incomplete #embed-begin,
body.incomplete #embed-hint, body.incomplete #step-counter { display: none !important; }
@media (min-width: 561px) { body.incomplete #identify-card { bottom: 88px; } }
#embed-hint { display: none; }
body.embed-preview.embed-hint-on #embed-hint {
  display: block;
  position: absolute; left: 50%; bottom: 64px; transform: translateX(-50%);
  z-index: 29; pointer-events: none;
  font-size: 12px; color: var(--ink-soft);
  background: rgba(255,255,255,.92); border: 1px solid var(--panel-border);
  border-radius: 999px; padding: 6px 14px;
  box-shadow: 0 4px 14px rgba(0,0,0,.12);
}

/* ---- the shared paid-link line (2026-09-18) ----
   ONE line at the bottom of the stage while a paid link is on screen (main.js
   updatePaidNote): Amazon's required sentence, verbatim, plus Polymaker's when
   one of its links shows and nothing else names it. It is the "clearly and prominently on your Site"
   half of the disclosure, so it is never a click away; the links carry the
   "near the link" half themselves. pointer-events none, so it never blocks a
   tap; whatever is anchored to the stage's bottom edge makes room for its
   measured height (--paid-note-h, set by updatePaidNote). */
#paid-note {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 36;
  padding: 4px 14px 5px; text-align: center;
  font-size: 10.5px; line-height: 1.35; color: var(--ink-soft);
  background: var(--panel); border-top: 1px solid var(--panel-border);
  backdrop-filter: blur(4px);
  pointer-events: none;
}
@media (min-width: 561px) {
  body.paid-note-on #identify-card,
  body.paid-note-on #embed-begin,
  body.paid-note-on #incomplete-status { bottom: calc(16px + var(--paid-note-h, 24px)); }
  body.paid-note-on #tap-hint { bottom: calc(20px + var(--paid-note-h, 24px)); }
  body.paid-note-on.embed-preview #identify-card { bottom: calc(72px + var(--paid-note-h, 24px)); }
  /* the one-time orbit hint lasts until the first tap ON THE MODEL (or 9 s),
     and the Parts pill is not the model - its buy chips can bring the line up
     while the hint is still showing, and the lifted Begin pill would cover it */
  body.paid-note-on.embed-preview.embed-hint-on #embed-hint { bottom: calc(64px + var(--paid-note-h, 24px)); }
  body.paid-note-on.incomplete #identify-card { bottom: calc(88px + var(--paid-note-h, 24px)); }
}
/* phones: the card, parts list and filament picker are bottom sheets - the
   line sits in the open sheet's own bottom padding instead of lifting it */
@media (max-width: 560px) {
  body.paid-note-on #identify-card,
  body.paid-note-on #checklist-panel,
  body.paid-note-on #filament-menu { padding-bottom: calc(16px + var(--paid-note-h, 40px)); }
}

/* Live-sync blocked veil: the planner reported an un-instruction-able layout.
   Sits over the whole stage (scene stays mounted, dimmed behind) and eats
   pointer events so nothing is interactable until a legal layout arrives. */
#blocked-overlay {
  position: absolute; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(24, 25, 28, 0.55);
  backdrop-filter: blur(2px);
}
#blocked-overlay.hidden { display: none; }
.blocked-card {
  max-width: 420px; margin: 16px;
  background: #fff; border-radius: 14px;
  padding: 22px 26px;
  box-shadow: 0 12px 40px rgba(0,0,0,.35);
  text-align: center;
}
.blocked-icon { font-size: 30px; line-height: 1; }
.blocked-card h2 { margin: 10px 0 8px; font-size: 17px; color: var(--ink); }
#blocked-reason { margin: 0 0 10px; font-size: 13.5px; line-height: 1.5; color: var(--ink); }
.blocked-hint { margin: 0; font-size: 12px; line-height: 1.5; color: var(--ink-soft); }
/* the planner refused this window's last change (main.js noteRelayRejected): non-modal, top of the stage, above the veil */
#relay-rejected {
  position: absolute; left: 50%; top: 12px; transform: translateX(-50%); z-index: 61;
  width: max-content; max-width: min(520px, calc(100% - 32px)); box-sizing: border-box;
  background: var(--panel); color: var(--ink); border: 1px solid var(--bad, #d23a2e); border-radius: 10px;
  padding: 10px 14px; box-shadow: 0 6px 20px rgba(0,0,0,.22); font-size: 13px; line-height: 1.45;
}
#relay-rejected.hidden { display: none; }
#relay-rejected b { display: block; color: var(--bad, #d23a2e); font-size: 14px; }
#relay-rejected span { display: block; }
#relay-rejected-words { margin-top: 4px; font-weight: 700; user-select: text; overflow-wrap: anywhere; }
#relay-rejected .rr-actions { display: flex; gap: 8px; margin-top: 8px; }
#relay-rejected button {
  font: inherit; font-size: 12.5px; font-weight: 700; padding: 6px 12px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--panel-border); background: var(--panel); color: var(--ink);
}
#relay-rejected-load { border-color: var(--accent) !important; color: var(--accent) !important; }
#relay-rejected button.hidden { display: none; }

#controls {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 14px;
  background: #fff; border-top: 1px solid var(--panel-border);
}
#controls button {
  /* radius 8 + weight 700 = the planner's button vocabulary (2026-07-19,
     Joey: the two tools should read as one app; same accent + font already) */
  font: inherit; font-weight: 700; font-size: 14px;
  padding: 10px 18px; border-radius: 8px;
  border: 1px solid var(--panel-border); background: #fff; color: var(--ink);
  cursor: pointer;
}
#controls button:active { transform: translateY(1px); }
#btn-next { background: var(--accent); border-color: var(--accent); color: #fff; }
/* the three tool buttons sit together as one group: icon + tiny caption */
#ctl-tools { display: flex; gap: 6px; }
#ctl-tools button {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 6px 12px 5px; min-width: 64px;
}
#ctl-tools button i { font-style: normal; font-size: 15px; line-height: 1.1; }
#ctl-tools button span { font-size: 9.5px; font-weight: 700; line-height: 1; color: var(--ink-soft); }
#btn-slow.on { border-color: var(--accent); color: var(--accent); background: #fff6f0; box-shadow: inset 0 0 0 1px var(--accent); }
#btn-slow.on span { color: var(--accent); }
#btn-cam { border-color: var(--accent); } /* appears only while the user has camera control */
#btn-cam span { color: var(--accent); }
#controls button:disabled { opacity: .35; cursor: default; }

#step-dots { display: flex; gap: 5px; flex-wrap: wrap; justify-content: center; align-items: center; }
#step-dots .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--panel-border); cursor: pointer;
}
#step-dots .dot.on { background: var(--accent); }
/* the finished-build marker: the final assembly step's dot wears a check so
   customizers can jump straight to the completed model from the timeline */
#step-dots .dot.finish {
  width: 15px; height: 15px;
  display: flex; align-items: center; justify-content: center;
}
/* unreached: darker than the plain gray dots so the white check still reads */
#step-dots .dot.finish:not(.on) { background: #b9bec7; }
#step-dots .dot.finish::after {
  content: '\2713';
  font-size: 9.5px; font-weight: 800; line-height: 1; color: #fff;
}

.hidden { display: none !important; }

@media (max-width: 560px) {
  /* Mobile layout: the desktop floating panels dock to the bottom as full-width
     "sheets" (one at a time, layered by z-index), the step note stays pinned at
     the top, and the Parts / colors controls become bottom-corner pills — so
     nothing overlaps on a narrow screen. The parts list defaults to minimized on
     mobile (see main.js isMobile()); tap "Parts · N" to slide it up. */
  /* long step notes (wall bench text) used to eat half the phone screen and
     sit over the action — cap the panel and scroll the text inside instead;
     main.js also pans the camera down by the note's real height (view inset) */
  #note-panel { max-width: none; left: 8px; right: 8px; top: 8px; padding: 9px 12px; max-height: 34vh; }
  #note-panel .note-body { overflow-y: auto; max-height: calc(34vh - 20px); pointer-events: auto; }
  #step-title { font-size: 14.5px; }
  #step-note { font-size: 12.5px; }

  /* Parts tab + colors toggle: bottom-corner pills, clear of the note and each other */
  #checklist-tab { top: auto; bottom: 10px; right: 10px; font-size: 13px; padding: 9px 16px; }
  #color-toggle  { top: auto; bottom: 10px; left: 10px; right: auto; font-size: 12px; padding: 9px 13px; }
  #measure-toggle { top: auto; bottom: 58px; right: 10px; font-size: 12px; padding: 9px 13px; } /* stacks above the Parts pill */

  /* Parts list: full-width bottom sheet */
  #checklist-panel {
    top: auto; left: 0; right: 0; bottom: 0; width: auto; max-width: none;
    max-height: 74%; overflow-y: auto;
    border: 1px solid var(--panel-border); border-top: 4px solid var(--accent);
    border-radius: 16px 16px 0 0; padding: 12px 14px 16px;
    z-index: 30; box-shadow: 0 -6px 24px rgba(0,0,0,.18);
  }
  .checklist-head { font-size: 14px; }
  #checklist-close { font-size: 22px; padding: 0 6px; }

  /* Identify card: full-width bottom sheet (mutually exclusive with the parts list) */
  #identify-card {
    left: 0; right: 0; bottom: 0; transform: none; width: auto; max-width: none; min-width: 0;
    border-left: none; border-top: 4px solid var(--accent); border-radius: 16px 16px 0 0;
    padding: 12px 16px 16px;
    z-index: 32; box-shadow: 0 -6px 24px rgba(0,0,0,.18);
  }
  #identify-style button, #identify-lip button, #identify-variant button { width: 30px; height: 30px; }
  /* the label editor on a phone: 16 px fields (iOS zooms the page on focus below that - the generator's own rule), 44 px
     touch targets on the badge button and the icon grid; the card is already a sheet, and body.label-edit-open caps it */
  #label-edit-text, #label-pick-char, .opt-num-wrap input { font-size: 16px; }
  #label-edit-badge { width: 44px; height: 44px; }
  #label-edit-badge svg { width: 24px; height: 24px; }
  .le-cells { grid-template-columns: repeat(5, 44px); }
  #label-pick-search { font-size: 16px; }
  /* the open label editor is the one sheet on a phone (review D4): the step note and the card met, and with the icon picker
     open none of the model - the label being changed - was left on screen. The note returns when the editor closes, like
     body.fm-open's rule. */
  body.label-edit-open #note-panel { display: none; }
  .le-icon { width: 44px; height: 44px; }
  .le-pick-row button { padding: 10px 12px; }

  /* Filament picker: bottom sheet, sits above the identify card */
  #filament-menu {
    bottom: 0; left: 0; right: 0; transform: none; width: auto; max-width: none;
    border-radius: 16px 16px 0 0; padding: 12px 14px 16px;
    z-index: 34; box-shadow: 0 -6px 24px rgba(0,0,0,.18);
  }
  /* fm-open note-hide lives in the UNSCOPED rule beside the base menu styles
     (one source for every layout); updateViewInset recenters the model in the
     freed band here because display:none zeroes the note's rect */
  .fm-swatches button { width: 30px; height: 30px; }
  /* bottom sheet: the ✕ is the primary dismiss, so give it a real touch target */
  #fm-close { width: 34px; height: 34px; font-size: 23px; top: -6px; right: -6px; }
  .fm-head { padding-right: 34px; }
  #fm-brands { max-height: 42vh; } /* bottom-sheet: keep the list scrollable, footer visible */

  /* the "tap any part" hint rides above the bottom pills, not over them */
  #tap-hint { bottom: 64px; max-width: 92%; font-size: 12.5px; }

  /* Outro: compact promo card at the top — more translucent so the celebration
     scene shows through, and short enough to leave most of the build visible */
  .outro-card {
    left: 8px; right: 8px; top: 10px; bottom: auto; transform: none;
    width: auto; max-width: none; max-height: calc(100% - 20px); overflow-y: auto;
    padding: 13px 16px; gap: 7px;
    background: rgba(255,255,255,0.72); backdrop-filter: blur(11px);
  }
  #outro-logo { height: 32px; }
  .outro-title { font-size: 18px; }
  .outro-sub { font-size: 12px; line-height: 1.38; margin-bottom: 2px; }
  .outro-btn { padding: 9px 14px; font-size: 13.5px; }
  .outro-links { margin-top: 3px; font-size: 12px; }

  /* Cover: don't crush the brand text into a thin column */
  .cover-right { width: min(340px, 84vw); }
  #cover-ribbon { width: 168px; height: 168px; }
  .cr-band { top: 36px; left: -57px; width: 236px; padding: 7px 0; } /* center on corner diagonal (c≈61) → ends run off both edges */
  .cr-band b { font-size: 23px; }
  .cr-band span { font-size: 10px; letter-spacing: .2em; }
  #cover-badges { gap: 7px; bottom: 14px; left: 12px; }
  .cv-hero { padding: 8px 13px 7px; }
  .cv-hero b { font-size: 24px; }
  .cv-chip { padding: 6px 9px 5px; }
  .cv-chip b { font-size: 13px; }

  /* Back | 4 tools | Next must fit ONE row on a 360px phone with Resume cam
     visible (≈330px of buttons) — hence the tight paddings + gaps here */
  #controls { padding: 10px 10px calc(10px + env(safe-area-inset-bottom)); flex-wrap: wrap; gap: 5px; row-gap: 8px; }
  #controls button { padding: 11px 8px; }
  #ctl-tools { gap: 3px; }
  #ctl-tools button { padding: 5px 5px 4px; min-width: 0; }
  /* the embed adds a FIFTH tool (Preview) — slim Back/Next, the tools and
     the gaps so Back + 5 tools + Next hold ONE row even at the 380px dock
     floor (measured: the six-button row ran 389px at the old paddings) */
  body.embed #controls { gap: 8px 4px; }
  body.embed #ctl-tools { gap: 4px; }
  body.embed #controls button { padding: 8px 6px; font-size: 13px; }
  body.embed #ctl-tools button { padding: 4px 4px 3px; }
  body.embed #ctl-tools button span { font-size: 8px; }
  #ctl-tools button span { font-size: 8.5px; }
  /* the step dots get their own full-width row ABOVE the buttons — squeezed
     between Back and the tool group they used to wrap into a tall vertical
     column the moment Resume cam appeared (4 tools + 15 dots never fit 360px) */
  #step-dots { order: -1; flex-basis: 100%; }
}

/* ---- dark-glass chrome while the retrowave stage is up (Phase 3B) ----------
   Scoped to body.stage-dark so the LIGHT stage keeps today's white panels
   untouched. The token override re-skins every var()-consuming surface (note
   panel, checklist, identify card, filament menu, dim labels); the rules
   below catch the hardcoded-white surfaces. White-on-accent text stays white
   everywhere, and #identify-img stays a LIGHT well on purpose - the part
   renders are transparent PNGs and a black case dissolves on dark. */
body.stage-dark {
  --ink: #e9ebfa;
  --ink-soft: #a2a8cf;
  --panel: rgba(18, 20, 46, 0.9);
  --panel-border: #31356b;
  --bg: #0d0e21;
}
body.stage-dark #topbar,
body.stage-dark #btn-theme,
body.stage-dark #btn-quality,
body.stage-dark #btn-feedback,
body.stage-dark .opt-seg button,
body.stage-dark #identify-style button,
body.stage-dark #identify-lip button,
body.stage-dark #identify-variant button,
body.stage-dark #label-edit-text,
body.stage-dark #label-edit-badge,
body.stage-dark #label-pick-char,
body.stage-dark #label-pick-search,
body.stage-dark .le-pick-row button,
body.stage-dark #label-edit-undo,
body.stage-dark .le-icon,
body.stage-dark .opt-num-wrap input,
body.stage-dark .zone-chip,
body.stage-dark #identify-label-gen,
body.stage-dark .outro-btn,
body.stage-dark .blocked-card,
body.stage-dark #controls,
body.stage-dark #controls button { background: #141634; }
body.stage-dark .opt-seg button { color: var(--ink-soft); }
body.stage-dark .opt-seg button.on { background: var(--accent); color: #fff; }
body.stage-dark #identify-img { background: #e8eaf0; }
body.stage-dark #identify-remove:hover { background: rgba(229, 83, 75, 0.16); }
body.stage-dark #identify-open-drawer:hover,
body.stage-dark #identify-close-drawer:hover,
body.stage-dark #identify-label-gen:hover { background: rgba(255, 138, 64, 0.14); }
body.stage-dark #btn-slow.on { background: rgba(255, 138, 64, 0.14); }

/* ---- dark-mode focal control + breathing room (refinement pass 2026-08-08) --
   Measured first, then tuned: dark-mode text already cleared WCAG AAA
   (7.6-15.3:1), so this pass is NOT a contrast rescue - it is focus. The
   stage's grid ran edge-to-edge at one brightness and competed with the
   build, so a vignette pulls the eye back to the model, the parts list gets
   room to breathe, and the note panel reads as an overlay instead of a slab.
   Light mode is deliberately untouched. */
#stage-vignette { display: none; }
body.stage-dark #stage-vignette {
  display: block;
  position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: radial-gradient(115% 92% at 50% 47%,
    rgba(5, 6, 18, 0) 40%, rgba(5, 6, 18, 0.42) 76%, rgba(5, 6, 18, 0.8) 100%);
}
/* the panels are overlays on a lit stage, not opaque cards */
body.stage-dark { --panel: rgba(16, 18, 42, 0.85); }
/* let the parts list breathe: taller rows, dividers that separate without drawing */
body.stage-dark .checklist-row { padding: 6px 0; border-top-color: rgba(49, 53, 107, 0.5); }

/* the celebration card: the outro fades the room to night in BOTH modes, so
   a white slab always read as the odd one out there — on dark it becomes the
   same dark glass as the rest of the chrome, with the accent spine kept */
body.stage-dark .outro-card {
  background: rgba(16, 18, 42, 0.86);
  box-shadow: 0 8px 34px rgba(0, 0, 0, 0.5);
}
body.stage-dark .outro-links a:hover { color: var(--accent); }

/* ---- ?part=&mode=preview — the MODULITH product-page embed (2026-08-19) ----
   A transparent one-part iframe: the DOCUMENT background goes transparent (JS
   sets it inline; scene.background is nulled), the site's media panel shows
   through, and every piece of instruction chrome is off. The only DOM this
   mode owns is the loading spinner and the reset pill. */
/* NB #measure-label deliberately NOT in this hide list (2026-08-20): part
   mode has its own measure pill, and the label is the readout. Its .hidden
   class still governs it outside an active measurement. */
body.part-preview #topbar, body.part-preview #controls, body.part-preview #note-panel,
body.part-preview #checklist-tab, body.part-preview #checklist-panel, body.part-preview #color-toggle,
body.part-preview #measure-toggle, body.part-preview #identify-card,
body.part-preview #filament-menu, body.part-preview #cover-overlay, body.part-preview #outro-overlay,
body.part-preview #cover-bg, body.part-preview #tap-hint, body.part-preview #stage-vignette,
body.part-preview #embed-hint, body.part-preview #embed-begin { display: none !important; }
/* the part-mode measure label can carry the Case dovetail hint - let it wrap */
body.part-preview #measure-label { white-space: normal; max-width: min(300px, 76vw); text-align: center; }
body.part-preview #loading-overlay { background: transparent; }
#part-reset {
  /* TOP corners, both pills: the embedding site overlays its own Image|3D|Plate
     toggle on the iframe's bottom edge, and a 300px media stage has no room
     for both (caught on the live page - the pills collided) */
  position: absolute; right: 10px; top: 10px; z-index: 3;
  padding: 6px 12px; border: 1px solid var(--panel-border); border-radius: 999px;
  background: var(--panel); color: var(--ink-soft); font-size: 12px; font-weight: 700;
  cursor: pointer;
}
#part-reset:hover { color: var(--ink); border-color: var(--accent); }
#part-top {
  position: absolute; left: 10px; top: 10px; z-index: 3;
  padding: 6px 12px; border: 1px solid var(--panel-border); border-radius: 999px;
  background: var(--panel); color: var(--ink-soft); font-size: 12px; font-weight: 700;
  cursor: pointer;
}
#part-top:hover { color: var(--ink); border-color: var(--accent); }
#part-measure {
  position: absolute; left: 10px; top: 10px; z-index: 3;
  padding: 6px 12px; border: 1px solid var(--panel-border); border-radius: 999px;
  background: var(--panel); color: var(--ink-soft); font-size: 12px; font-weight: 700;
  cursor: pointer;
}
#part-measure:hover { color: var(--ink); border-color: var(--accent); }
#part-measure.on { color: #fff; background: var(--accent); border-color: var(--accent); }
/* plate boots show Top view in the left corner - measure stacks under it */
body.part-plate #part-measure { top: 46px; }
/* doesn't-fit banner: a full-width strip along the top edge, so it reads at
   every stage width (a centered pill collided with the corner pills in the
   site's 300px media column). The corner pills drop below it while it's up. */
#plate-overhang {
  position: absolute; left: 0; right: 0; top: 0; z-index: 2;
  padding: 8px 12px; text-align: center;
  background: rgba(197, 58, 69, 0.94); color: #fff;
  font-size: 12px; font-weight: 700; line-height: 1.2;
  pointer-events: none;
}
body.plate-overhang-on #part-top { top: 42px; }
body.plate-overhang-on #part-reset { top: 42px; }
body.plate-overhang-on.part-plate #part-measure { top: 78px; }
/* the site's narrowest media column is 300px - keep the strip to one line
   there so the dropped pills never collide with a wrapped second line */
@media (max-width: 360px) { #plate-overhang { font-size: 11px; } }

/* The quality pill in the DOCKED viewer (Joey 2026-09-18): #topbar is hidden there, so main.js moves the pill onto the stage.
   It sits top-right above the Parts pill (top 76) and wears the Parts pill's own shape. ⚠ After the dark-stage block on
   purpose - same specificity, so the later rule wins - and it overrides the 560px hide: the dock is narrow by design. */
body.embed #btn-quality {
  display: block; position: absolute; top: 32px; right: 12px; z-index: 5; margin: 0; min-width: 0;
  font-size: 12.5px; padding: 7px 14px;
  background: var(--panel); color: var(--accent);
  border: 1px solid var(--panel-border); border-right: 3px solid var(--accent);
  backdrop-filter: blur(4px); box-shadow: 0 2px 10px rgba(0,0,0,.08);
}
body.embed #btn-quality::before { content: 'Quality: '; color: var(--ink-soft); font-weight: 600; }
body.embed #btn-quality[data-q="balanced"] { color: var(--ink); }
body.embed #btn-quality:hover { border-color: var(--accent); }
body.embed.fm-open #btn-quality { display: none; }   /* the filament menu docks right, over this corner */
