/* ════════════════════════════════════════════════════════════════════
   Topbar — v1 (DESIGN.md §8.11, monochrome) — 2026-05-29 redesign
   ────────────────────────────────────────────────────────────────────
   Two-section grid: left 1fr (brand + version + search, LEFT-aligned)
   | right auto (Bench dropdown + DB pill + icon buttons). Old
   Lab/Catalog/BOM nav + meta count/status removed. 48px tall, hairline
   bottom border. Background --surface-2 sits flush against the page.
   ════════════════════════════════════════════════════════════════════ */

#topbar.topbar-v1 {
  /* v2 (Mac menu bar): one flex row, left group hugs the wordmark, right group
     (status + search) hugs the corner. Was a 2-col grid — flex space-between
     reads more like the macOS bar and lets the search box sit flush right. */
  display: flex;
  /* Collapsible strip: the bar animates its height as --topbar-h drops to 0
     (topbar-collapse.js). overflow is left VISIBLE here so open menu dropdowns
     (bench-menu / scene-menu, positioned below the bar) are never clipped — the
     collapsed state re-adds overflow:hidden to clip content while it folds. */
  transition: height var(--dur-panel) var(--ease-out);
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 12px 0 14px;
  /* Liquid glass (DESIGN.md §6.4) — Canvas full-bleed behind, blur透出场景.
     Same tokens as the floating panels so the glass language is unified. */
  background: var(--float-bg);
  backdrop-filter: blur(var(--float-blur)) saturate(var(--float-sat));
  -webkit-backdrop-filter: blur(var(--float-blur)) saturate(var(--float-sat));
  border-bottom: 1px solid var(--line-1);
  box-shadow: var(--float-edge);
  z-index: 1400;   /* see base #topbar rule — raised so word-menu dropdowns clear dock + floating panels (DESIGN.md §8.4.A) */
  color: var(--ink-1);
  font-family: var(--font-ui);
  font-size: 13px;
}

.topbar-section {
  display: flex;
  align-items: center;
  min-width: 0;
}

/* Left group: wordmark sits a touch apart, then the menu bar runs tight. */
.topbar-section-left  { gap: 10px; }
.topbar-section-right { gap: 10px; justify-content: flex-end; }

/* ── Brand ─────────────────────────────────────────────────────────── */

.topbar-v1 .brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--ink-1);
  text-decoration: none;
  font-weight: 600;
  letter-spacing: -0.01em;
  font-size: 13px;
}

.topbar-v1 .brand-mark {
  width: 14px;
  height: 14px;
  border: 1.5px solid var(--ink-1);
  border-radius: 3px;
  position: relative;
}

.topbar-v1 .brand-mark::after {
  content: "";
  position: absolute;
  inset: 3px;
  background: var(--ink-1);
  border-radius: 1px;
}

/* v2.7.03: stacked two-line wordmark (smaller type). Tight leading so the two
   lines read as one compact lockup beside the mark; weight 600 + -0.01em per
   DESIGN.md §4.3/§4.4. */
.topbar-v1 .brand-name {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  line-height: 1.04;
}
.topbar-v1 .brand-line {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.topbar-v1 .brand-line-2 { color: var(--ink-2-v1); }   /* second line steps back a tone */

/* version moved off the wordmark into Setting ▸ footer (DESIGN.md §8.11). */

/* Compact persistence status replaces the duplicate topbar New Canvas action. */
.autosave-status-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  margin-right: 2px;
}
.autosave-status {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: 5px;
  width: 84px;
  min-width: 84px;
  height: 32px;
  padding: 0 7px;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: 4px;
  background: transparent;
  color: var(--ink-2-v1);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: color 120ms ease, background-color 120ms ease;
}
.autosave-status:hover,
.autosave-status[aria-expanded="true"] {
  background: var(--overlay-1);
  color: var(--ink-1);
}
.autosave-status:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--overlay-2);
}
.autosave-status-icon {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  transform-origin: center;
}
.autosave-status-icon [data-autosave-icon] { display: none; }
.autosave-status[data-state="saved"] [data-autosave-icon="saved"],
.autosave-status[data-state="backed-up"] [data-autosave-icon="backed-up"],
.autosave-status[data-state="pending"] [data-autosave-icon="pending"],
.autosave-status[data-state="saving"] [data-autosave-icon="saving"],
.autosave-status[data-state="failed"] [data-autosave-icon="failed"],
.autosave-status[data-state="unbound"] [data-autosave-icon="unbound"] {
  display: inline;
}
.autosave-status[data-state="saved"] .autosave-status-icon,
.autosave-status[data-state="backed-up"] .autosave-status-icon { color: var(--sig-ok); }
.autosave-status[data-state="pending"] .autosave-status-icon { color: var(--sig-warn); }
.autosave-status[data-state="failed"] .autosave-status-icon { color: var(--sig-error); }
.autosave-status[data-state="saving"] .autosave-status-icon {
  animation: autosave-status-spin 700ms linear infinite;
}
@keyframes autosave-status-spin { to { transform: rotate(360deg); } }
@media (max-width: 1120px) {
  .autosave-status {
    justify-content: center;
    width: 32px;
    min-width: 32px;
    padding: 0;
  }
  .autosave-status-text { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .autosave-status[data-state="saving"] .autosave-status-icon { animation: none; }
}
.autosave-status-live {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.autosave-status-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 1410;
  width: 240px;
  padding: 12px;
  border: 1px solid var(--line-1);
  border-radius: 6px;
  background: var(--surface-2);
  box-shadow: 0 8px 24px var(--overlay-2), var(--float-edge);
  color: var(--ink-1);
  animation: menu-pop var(--dur-enter) var(--ease-out);
}
.autosave-status-pop[hidden] { display: none; }
.autosave-status-pop-title {
  margin-bottom: 10px;
  font-size: 12px;
  font-weight: 600;
}
.autosave-status-details {
  display: grid;
  gap: 8px;
  margin: 0;
}
.autosave-status-summary {
  padding-bottom: 10px;
}
.autosave-status-details > div {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 8px;
  align-items: start;
}
.autosave-status-details dt,
.autosave-status-details dd {
  margin: 0;
  font-size: 11px;
  line-height: 1.35;
}
.autosave-status-details dt { color: var(--ink-3-v1); }
.autosave-status-details dd {
  color: var(--ink-1);
  overflow-wrap: anywhere;
}
.autosave-status-disclosure {
  display: flex;
  width: 100%;
  min-height: 28px;
  align-items: center;
  justify-content: space-between;
  padding: 6px 0;
  border: 0;
  border-top: 1px solid var(--line-1);
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
.autosave-status-disclosure:hover,
.autosave-status-disclosure:focus-visible {
  color: var(--ink-1);
}
.autosave-status-disclosure:focus-visible {
  outline: 1px solid var(--ink-1);
  outline-offset: 2px;
}
.autosave-status-disclosure svg {
  flex: 0 0 auto;
  transition: transform var(--dur-fast) var(--ease-out);
}
.autosave-status-disclosure[aria-expanded="true"] svg {
  transform: rotate(90deg);
}
.autosave-status-activity {
  padding: 4px 0 2px;
}
.autosave-status-activity[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .autosave-status-disclosure svg { transition: none; }
}

/* ── Search ────────────────────────────────────────────────────────── */

.topbar-search {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  /* v2: narrower + flush to the far-right corner (DESIGN.md §8.11). Was 360px
     center-left; the search is now a compact corner affordance (Spotlight-like). */
  width: 208px;
  max-width: 100%;
  height: 30px;
  padding: 0 10px;
  background: var(--surface-1);
  border: 1px solid var(--ctl-line);   /* v2 affordance：输入框静止可见边（U11 双线索）*/
  border-radius: 6px;
  cursor: text;
  transition:
    border-color 120ms ease,
    box-shadow 120ms ease;
}

.topbar-search:focus-within {
  border-color: var(--ink-1);
  box-shadow: 0 0 0 3px var(--overlay-2);
}

.topbar-search-icon {
  flex: 0 0 auto;
  color: var(--ink-3-v1);
}

.topbar-search-input {
  flex: 1 1 auto;
  appearance: none;
  background: transparent;
  border: none;
  outline: none;
  font: inherit;
  font-size: 13px;
  color: var(--ink-1);
  min-width: 0;
}

.topbar-search-input::placeholder {
  color: var(--ink-3-v1);
}

.topbar-search-hint {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-3-v1);
  background: var(--surface-2);
  border: 1px solid var(--line-1);
  border-radius: 3px;
  padding: 1px 5px;
  letter-spacing: 0;
}

/* ── Mac-style menu bar (DESIGN.md §8.11) ─────────────────────────────────
   Word-label triggers (Scene · Bench · File · View); each opens a dropdown
   that reuses the .bench-menu / .scene-menu skin below. The trigger shows
   ONLY a word — never the current value inline (that's the macOS menu-bar
   convention; the active item is checked inside the dropdown instead). */

.topbar-menubar {
  display: inline-flex;
  align-items: center;
  gap: 1px;            /* tight, like a real menu bar; padding gives the targets */
}

.topbar-menu {
  position: relative;
  display: inline-flex;
}

.topbar-menu-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  height: 32px;        /* ≥ 32 touch floor (DESIGN.md §8.1 / U1) */
  padding: 0 9px;
  /* user 2026-07-04：静止淡底座读作难看的「背景阴影」，撤回透明底 —— 顶栏保持干净
     Mac 菜单栏观感，hover/展开态仍有 fill 反馈（可辨性交给 hover）。 */
  background: transparent;
  border: 1px solid transparent;
  border-radius: 5px;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2-v1);
  cursor: pointer;
  white-space: nowrap;
  transition:
    background-color 80ms ease,
    color 80ms ease,
    border-color 80ms ease;
}
/* user 2026-07-04：Reset / Theme / Workbench 的 --ctl-line 描框也去掉（连座带边全撤）
   —— 顶栏统一为干净单词钮，可辨交给标签文字 + hover fill；不再靠边框区分直接动作。 */
.topbar-menu-btn:hover {
  background: var(--hover-bg);
  color: var(--ink-1);
  border-color: var(--hover-border);
}
.topbar-menu-btn[aria-expanded="true"] {
  /* dropdown open → strongest state: solid ink edge + active bg */
  background: var(--active-bg);
  color: var(--ink-1);
  border-color: var(--active-border);
}
.topbar-menu-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--overlay-2);
}

/* Setting menu — version footer (always shown, bottom) + dev-only entries.
   The dev rows (Experiments / Database status + their divider) are hidden
   unless body.dev-mode (DESIGN.md §8.11 / §20.3). */
body:not(.dev-mode) .settings-dev-only { display: none; }

.settings-version {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 8px 4px;
  font-family: var(--font-mono);
  font-size: 11px;
}
.settings-version-num  { color: var(--ink-2-v1); font-weight: 500; }
.settings-version-date { color: var(--ink-4); font-size: 10px; }

.bench-menu,
.scene-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 220px;
  padding: 4px;
  /* SOLID surface — not transient glass. The dropdowns float at z:1400 over the
     busy Canvas/panels, so the old translucent glass let content bleed through
     and hurt readability (user 2026-06-15). --surface-2 = the floating-panel bg
     (§3.1): fully opaque + clearly elevated over the bg in both themes. No
     backdrop-filter (nothing to blur through a solid fill). */
  background: var(--surface-2);
  border: 1px solid var(--line-1);
  border-radius: 6px;
  box-shadow: 0 8px 24px var(--overlay-2), var(--float-edge);
  z-index: 40;
  /* UX-1: standard popover entrance (fade + 4px drop + 1% scale). */
  animation: menu-pop var(--dur-enter) var(--ease-out);
}
.bench-menu[hidden],
.scene-menu[hidden] { display: none; }
.bench-menu.is-leaving,
.scene-menu.is-leaving {
  animation: menu-pop-out var(--dur-exit) var(--ease-out) forwards;
  pointer-events: none;
}
@keyframes menu-pop {
  from { opacity: 0; transform: translateY(-4px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}
@keyframes menu-pop-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-4px) scale(0.99); }
}

/* Cloud scenes now live INSIDE the File menu (DESIGN.md §8.11). The wrapper
   is layout-transparent so its divider + 3 items flow as direct File-menu
   rows; cloud-storage.js still hides the whole block (display:none) when not
   signed in. */
#cloud-select { display: contents; }

/* File / Setting dropdown rows carry descriptive labels → UI font reads better
   than the mono used for SKU/scene rows in Bench/Scene menus. */
.file-menu .bench-menu-item-main,
.setting-menu .bench-menu-item-main {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 500;
}

/* Library product right-click menu (UX-7) — same popover look, cursor-
   anchored (fixed; JS sets left/top, clamped to window). Above floating
   panels, below modals (DESIGN.md §8.4.A z-table: transient tier). */
.lib-ctx-menu {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1500;
}

.bench-menu-section,
.scene-menu-section {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.bench-menu-item,
.scene-menu-item {
  appearance: none;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: transparent;
  /* 1px transparent border at rest → hover swap = 0 layout shift
     (layout-shift-avoid; replaces the prior border:none). */
  border: 1px solid transparent;
  border-radius: 4px;
  font: inherit;
  color: var(--ink-2-v1);
  text-align: left;
  cursor: pointer;
  transition:
    background-color 80ms ease,
    color 80ms ease,
    border-color 80ms ease;
}
.bench-menu-item:hover:not(.is-disabled),
.scene-menu-item:hover:not(.is-disabled) {
  background: var(--hover-bg);
  color: var(--ink-1);
  border-color: var(--hover-border);
}
.bench-menu-item.is-active,
.scene-menu-item.is-active {
  background: var(--active-bg);
  color: var(--ink-1);
  border-color: var(--active-border);
}

.bench-menu-check,
.scene-menu-check {
  width: 12px;
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--ink-1);
  opacity: 0;
}
.bench-menu-item.is-active .bench-menu-check,
.scene-menu-item.is-active .scene-menu-check { opacity: 1; }

.bench-menu-item-main,
.scene-menu-item-main {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
}
.bench-menu-item-tag,
.scene-menu-item-tag {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-3-v1);
}

.bench-menu-divider,
.scene-menu-divider {
  height: 1px;
  margin: 4px 0;
  background: var(--line-1);
}

/* placeholder rows ("待更新" / "soon") — not selectable */
.bench-menu-item.is-disabled,
.scene-menu-item.is-disabled {
  cursor: default;
  color: var(--ink-4);
}
.bench-menu-item.is-disabled .bench-menu-item-main,
.bench-menu-item.is-disabled .bench-menu-item-tag,
.scene-menu-item.is-disabled .scene-menu-item-main,
.scene-menu-item.is-disabled .scene-menu-item-tag {
  color: var(--ink-4);
}

/* ── Icon button (Reset — the one icon kept in the v2 menu bar) ───────── */

.topbar-icon-btn {
  appearance: none;
  background: transparent;   /* user 2026-07-04：撤回静止淡底座（难看背景阴影），hover 再 fill */
  border: 1px solid transparent;
  border-radius: 6px;
  width: 34px;   /* ↑ from 28 — easier tap target (DESIGN.md §8.1) */
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-2-v1);
  cursor: pointer;
  transition:
    background-color 80ms ease,
    color 80ms ease,
    border-color 80ms ease;
}

.topbar-icon-btn:hover {
  background: var(--hover-bg);
  color: var(--ink-1);
  border-color: var(--hover-border);
}

.topbar-icon-btn:active {
  background: var(--active-bg);
  border-color: var(--active-border);
}

.topbar-icon-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--overlay-2);
}

/* ── Assemble-mounts FAB (bottom-right) ────────────────────────────────
   Single icon trigger + upward menu. The menu preserves the mainline Reasons
   action while keeping the bottom-right chrome compact. */
#fab-assemble-all {
  position: fixed;
  right: 16px;
  bottom: 24px;
  z-index: 200;            /* = .action-dock z-index */
}
#fab-assemble-all[hidden] { display: none; }

.fab-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  background: var(--float-bg);
  border: 1px solid var(--line-1);
  border-radius: 50%;
  backdrop-filter: blur(var(--float-blur)) saturate(var(--float-sat));
  -webkit-backdrop-filter: blur(var(--float-blur)) saturate(var(--float-sat));
  box-shadow: var(--float-shadow), var(--float-edge);
  color: var(--ink-1);
  cursor: pointer;
  transition:
    background-color 120ms ease,
    border-color 120ms ease,
    color 120ms ease,
    transform 120ms ease;
}
.fab-icon-btn:hover  { background: var(--hover-bg); border-color: var(--hover-border, var(--line-2)); }
.fab-icon-btn:active { transform: scale(0.96); }
.fab-icon-btn[aria-expanded="true"] { background: var(--active-bg); border-color: var(--active-border); }
.fab-icon-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--overlay-2), var(--float-shadow); }
.fab-icon-btn svg { display: block; }
#fab-assemble-all[data-mode="remove"] .fab-icon-btn:hover {
  color: var(--bad, var(--sig-error));
  border-color: var(--bad, var(--sig-error));
}
/* blocked = 台上有件但一件都装不上（user 2026-07-22：按钮不藏，点了用底部浮窗报错位）。
   与旧 reasons 态同一警示色，区别只在语义。 */
#fab-assemble-all[data-mode="reasons"] .fab-icon-btn:hover,
#fab-assemble-all[data-mode="blocked"] .fab-icon-btn:hover {
  color: var(--fault-warn, var(--sig-warn, #ef8a2b));
  border-color: var(--fault-warn, var(--sig-warn, #ef8a2b));
}

.fab-menu {
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  min-width: 196px;
  padding: 4px;
  background: var(--surface-2);
  border: 1px solid var(--line-1);
  border-radius: 8px;
  box-shadow: 0 8px 24px var(--overlay-2), var(--float-edge);
  display: flex;
  flex-direction: column;
  gap: 1px;
  animation: menu-pop var(--dur-enter) var(--ease-out);
}
.fab-menu[hidden] { display: none; }
.fab-menu-item {
  appearance: none;
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 7px 9px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 5px;
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-1);
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 80ms ease, border-color 80ms ease, color 80ms ease;
}
.fab-menu-item[hidden] { display: none; }
.fab-menu-item:hover { background: var(--hover-bg); border-color: var(--hover-border); }
.fab-menu-item:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--overlay-2); }
.fab-item-glyph { flex: 0 0 auto; width: 16px; text-align: center; color: var(--ink-3); }
.fab-menu-item-remove:hover {
  background: var(--bad-bg, var(--sig-error-bg));
  border-color: transparent;
  color: var(--bad, var(--sig-error));
}
.fab-menu-item-remove:hover .fab-item-glyph { color: var(--bad, var(--sig-error)); }
.fab-menu-item-reasons:hover,
.fab-menu-item-reasons.is-on {
  color: var(--fault-warn, var(--sig-warn, #ef8a2b));
}
.fab-menu-item-reasons:hover .fab-item-glyph,
.fab-menu-item-reasons.is-on .fab-item-glyph {
  color: var(--fault-warn, var(--sig-warn, #ef8a2b));
}
.fab-menu-item-reasons.is-on { background: var(--active-bg, var(--overlay-2)); }
/* Theme moved into the View menu (DESIGN.md §8.11) — the sun/moon morph
   button is gone; appearance is now explicit Light / Dark radio rows. The
   day↔night sweep (.theme-anim window, ripple) still fires from theme.js. */

/* ── Day ↔ night theme transition (2026-06-03) ─────────────────────────
   Three coordinated layers, fired from #theme-toggle-btn (theme.js):
     1. `.theme-anim *` — UI chrome cross-fades its colours for ~0.5s. Gated
        by the class so the transitions stay inert except during the swap;
        `transform`/`opacity` are included so the sun/moon glyph morphs too.
     2. `.theme-ripple` — the incoming --bg washes out from the click point.
     3. The 3D scene (scene3d.background + floor) is tweened in JS (theme.js),
        so the lab itself slides from daylight to night in the same beat.
   Honour prefers-reduced-motion: instant, no motion. */
html.theme-anim * {
  transition-property: background-color, color, border-color, fill, stroke, box-shadow, opacity, transform;
  transition-duration: 0.5s;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

.theme-ripple {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 9000;          /* over the chrome, under nothing it needs to block */
  opacity: 0;
  will-change: width, height, opacity;
}
.theme-ripple.is-playing {
  animation: theme-ripple-expand 0.6s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes theme-ripple-expand {
  0%   { width: 0; height: 0; opacity: 0.5; }
  100% { width: 280vmax; height: 280vmax; opacity: 0; }
}

/* ── Whole-bar collapse (2026-07-06, user) ────────────────────────────────
   The entire system topbar folds into a thin strip. A centered pull-tab hangs
   from the bar's underside; clicking it flips body[data-topbar-collapsed].
   Collapsed → --topbar-h:0, so every fixed element anchored to --topbar-h
   (canvas tabs, library, res-l, dock-edge toggle, workbench panel) glides up
   and the canvas tabs butt against the window top. Only the tabs + this handle
   remain (user spec). */
#topbar-collapse-toggle {
  position: fixed;
  left: 50%;
  top: var(--topbar-h);                 /* hangs flush from the bar's bottom edge */
  transform: translateX(-50%);
  z-index: 1402;                        /* above topbar(1400) + canvas tabs(1390) */
  width: 42px;
  height: 15px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  /* At rest: near-invisible — just a faint chevron hint hugging the edge
     (user 2026-07-06: 平时高透明度). No fill / border / shadow. */
  background: transparent;
  border: 1px solid transparent;
  border-top: none;                     /* rounded bottom only = a tab tucked under the bar */
  border-radius: 0 0 9px 9px;
  color: var(--ink-3-v1);
  opacity: 0.4;
  cursor: pointer;
  transition:
    top var(--dur-panel) var(--ease-out),
    opacity 150ms ease,
    color 150ms ease,
    background-color 150ms ease,
    border-color 150ms ease,
    box-shadow 150ms ease;
}
/* On hover: solidify into a glass pull-tab (user: 鼠标放上去变实). */
#topbar-collapse-toggle:hover {
  opacity: 1;
  color: var(--ink-1);
  background: var(--float-bg);
  backdrop-filter: blur(var(--float-blur)) saturate(var(--float-sat));
  -webkit-backdrop-filter: blur(var(--float-blur)) saturate(var(--float-sat));
  border-color: var(--glass-border);
  box-shadow: var(--float-shadow), var(--float-edge);
}
#topbar-collapse-toggle:focus-visible {
  outline: none;
  opacity: 1;
  color: var(--ink-1);
  box-shadow: 0 0 0 2px var(--overlay-2);
}
#topbar-collapse-toggle svg { display: block; transition: transform var(--dur-panel) var(--ease-out); }

#topbar-collapse-cluster {
  position: fixed;
  left: 50%;
  top: var(--topbar-h);
  transform: translateX(-50%);
  z-index: 1402;
  display: inline-flex;
  align-items: flex-start;
  gap: 4px;
  transition: top var(--dur-panel) var(--ease-out);
}
#topbar-collapse-cluster .topbar-collapse-action {
  position: static;
  transform: none;
  width: 42px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: var(--ctl-rest);
  border: 1px solid var(--ctl-line);
  border-top: none;
  border-radius: 0 0 9px 9px;
  color: var(--ink-2-v1);
  opacity: 0.86;
  cursor: pointer;
  transition:
    opacity 150ms ease,
    color 150ms ease,
    background-color 150ms ease,
    border-color 150ms ease,
    box-shadow 150ms ease;
}
#topbar-collapse-cluster .topbar-collapse-action:hover {
  opacity: 1;
  color: var(--ink-1);
  background: var(--float-bg);
  border-color: var(--glass-border);
}
#topbar-collapse-cluster .topbar-collapse-action:focus-visible {
  opacity: 1;
}
/* Workbench 关闭钮：强化视觉——从原来的淡红描边挂片改为**实心红**（白 ×、满不透明、
   加宽 + 红色投影发光），让「退出工作台」在折叠条下一眼可见、不再是低调小挂片。 */
#topbar-collapse-cluster .topbar-collapse-action.is-danger {
  display: none;
  width: 46px;
  opacity: 1;
  color: #FFFFFF;
  background: #D92D20;
  border-color: #D92D20;
  box-shadow: 0 2px 9px -1px rgba(217, 45, 32, 0.55);
}
#topbar-collapse-cluster .topbar-collapse-action.is-danger svg {
  width: 13px; height: 13px;
}
#topbar-collapse-cluster .topbar-collapse-action.is-danger:hover {
  opacity: 1;
  color: #FFFFFF;
  background: #B42318;
  border-color: #B42318;
  box-shadow: 0 3px 12px -1px rgba(180, 35, 24, 0.7);
}
[data-theme="dark"] #topbar-collapse-cluster .topbar-collapse-action.is-danger {
  color: #FFFFFF;
  background: #E5484D;
  border-color: #E5484D;
  box-shadow: 0 2px 9px -1px rgba(229, 72, 77, 0.55);
}
[data-theme="dark"] #topbar-collapse-cluster .topbar-collapse-action.is-danger:hover {
  color: #FFFFFF;
  background: #F0666A;
  border-color: #F0666A;
  box-shadow: 0 3px 12px -1px rgba(240, 102, 106, 0.7);
}
body[data-workbench="true"][data-topbar-collapsed="true"] #topbar-workbench-close {
  display: inline-flex;
}

/* Collapsed state: fold the bar to nothing; drop the handle onto the tab strip
   and flip its chevron (▲ collapse → ▼ expand). */
body[data-topbar-collapsed="true"] { --topbar-h: 0px; }
body[data-topbar-collapsed="true"] #topbar {
  overflow: hidden;                     /* clip the bar's contents while it folds */
  pointer-events: none;                 /* the handle (a sibling) stays clickable */
  border-bottom-color: transparent;
}
/* Collapsed: bar is gone (--topbar-h:0), so the handle rises to hang from the
   window top edge alongside the canvas tabs (user 2026-07-06: 折叠后移到顶部). */
body[data-topbar-collapsed="true"] #topbar-collapse-toggle { top: 0; }
body[data-topbar-collapsed="true"] #topbar-collapse-cluster { top: 0; }
body[data-topbar-collapsed="true"] #topbar-collapse-toggle svg { transform: rotate(180deg); }

/* Shell chrome anchored to --topbar-h glides with the fold. */
#library, #res-l, .canvas-tabs { transition: top var(--dur-panel) var(--ease-out); }

@media (prefers-reduced-motion: reduce) {
  html.theme-anim * { transition: none !important; }
  .theme-ripple.is-playing { animation: none; }
  /* UX-1: motion-system entrances/exits collapse to instant cuts.
     (ui/motion.js also short-circuits leaveThenHide under this query.) */
  .modal-backdrop, .modal-sheet,
  .panel-floating, .lib-pane,
  .bench-menu, .scene-menu,
  .db-toast {
    animation: none !important;
    transition: none !important;
  }
}

