:root {
  /* The standard tab frame's viewer column, as a share of the workspace
     width (demo/modules/workspace-tabs/frame.js). The viewer is a check while
     editing forms — Full Screen gives the true view — so it is narrow; 20–25%
     is a one-line change here. */
  --viewer-share: 33%;
  /* The chrome (header and tab bar) sits on white; the workspace, and so the
     active tab that opens onto it, is the page grey. */
  --chrome-bg: #ffffff;
  --workspace-bg: #f3f5f8;
  --tab-rule: #c7d4ee;
  --tab-edge: #d7dfec;
  --tab-muted-bg: #e9eef6;
  --tab-muted-text: #5a6883;
  color-scheme: light;
  font-family: "Segoe UI Variable", "Segoe UI", Inter, Roboto, Arial, sans-serif;
  background: var(--workspace-bg);
  color: #172033;
  --btn-primary-bg: #334155;
  --btn-primary-border: #475569;
  --btn-primary-hover: #3f5167;
  --btn-primary-active: #2b3849;
  --btn-secondary-bg: #eef1f5;
  --btn-secondary-border: #cbd5e1;
  --btn-secondary-text: #334155;
  --btn-secondary-hover: #e5eaf1;
  --btn-load-bg: #e5ebfa;
  --btn-load-border: #bfcbeb;
  --btn-load-text: #1e3a8a;
  --btn-load-hover: #dae4fb;
  --btn-save-bg: #e7f3ec;
  --btn-save-border: #b7d7c3;
  --btn-save-text: #166534;
  --btn-save-hover: #dceddf;
  --btn-danger-bg: #fdebec;
  --btn-danger-border: #efc6cb;
  --btn-danger-text: #991b1b;
  --btn-danger-hover: #f9dde0;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  height: 100vh;
  max-height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: var(--workspace-bg);
}

/* The header (2026-09-25): ONE row — the name, its (i) and the build, then
   the status taking the row's spare width, then diagnostics and sign-in. TJ
   found the old two-line header with its subtitle "kinda big and empty"; the
   subtitle and the overview help became the About tab. */
.topbar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 24px;
  background: var(--chrome-bg);
  min-width: 0;
}

.title-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 1 auto;
  min-width: 0;
}

.title-row h1 {
  margin: 0;
  font-size: 1.2rem;
  letter-spacing: 0;
  font-weight: 700;
  white-space: nowrap;
}

/* The build: the first thing to give way on a narrow window. */
.app-version {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #5a6883;
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.app-title-icon {
  display: block;
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
}

/* What Studio last did (scene-authoring/status-line.js): the header's spare
   width, ONE line of ONE fixed height — a long message ends in an ellipsis and
   the tooltip holds all of it — so nothing on the page ever moves for it. It
   was a 28 px line of its own under the tab bar (C12) and, before that, the
   stats bar. */
.topbar-status {
  flex: 1 1 0;
  min-width: 0;
  box-sizing: border-box;
  height: 28px;
  margin: 0;
  padding: 0 10px;
  line-height: 26px;
  border: 1px solid #e3e8f1;
  border-radius: 7px;
  background: #f7f9fc;
  font-size: 0.8rem;
  color: #405273;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar-actions,
.row.actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.topbar-actions {
  align-items: center;
  justify-content: flex-end;
  flex: 0 0 auto;
  flex-wrap: nowrap;
}

.header-admin-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  border: 1px solid #d8deea;
  border-radius: 10px;
  background: #ffffff;
  padding: 3px 6px;
}

.header-admin-status {
  font-size: 0.78rem;
  color: #405273;
}

/* ── Sign-in only (2026-09-25; TJ: "Sign-in page; admins edit, operators
   look") ─────────────────────────────────────────────────────────────────
   html[data-studio-page] is studio-access/studio-gate.js's: "pending" until
   the first session read, then "sign-in" (the gate below the header, and
   nothing of the workspace — it has not booted), or "look" / "edit" /
   "expired" (the workspace). Before a mode is known the header shows only
   the logo, the name and the sign-in. */
html:not([data-studio-page="sign-in"]) #studio-gate {
  display: none;
}

html[data-studio-page="sign-in"] .workspace-tabs,
html[data-studio-page="sign-in"] #scene-workspace,
html[data-studio-page="sign-in"] #studio-about-button,
html[data-studio-page="sign-in"] #app-version,
html[data-studio-page="sign-in"] #status,
html[data-studio-page="sign-in"] #diagnostics-badge,
html[data-studio-page="pending"] .workspace-tabs,
html[data-studio-page="pending"] #scene-workspace,
html[data-studio-page="pending"] #studio-about-button,
html[data-studio-page="pending"] #app-version,
html[data-studio-page="pending"] #status,
html[data-studio-page="pending"] #diagnostics-badge {
  display: none;
}

/* With the status gone, the sign-in keeps the header's right-hand end. */
html[data-studio-page="sign-in"] .topbar-actions,
html[data-studio-page="pending"] .topbar-actions {
  margin-left: auto;
}

.studio-gate {
  flex: 1 1 auto;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 72px 16px 32px;
  overflow-y: auto;
  border-top: 1px solid var(--tab-rule);
}

.studio-gate-card {
  width: 100%;
  max-width: 520px;
  padding: 24px;
  border: 1px solid #d8deea;
  border-radius: 12px;
  background: #ffffff;
  box-shadow: 0 10px 28px rgba(23, 32, 51, 0.08);
}

.studio-gate-card h2 {
  margin: 0 0 10px;
  font-size: 1.15rem;
}

.studio-gate-intro {
  margin: 0 0 10px;
  font-size: 0.95rem;
  line-height: 1.5;
}

.studio-gate-note {
  margin: 0 0 18px;
  font-size: 0.85rem;
  line-height: 1.45;
  color: #405273;
}

.studio-gate-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.studio-gate-primary {
  padding: 8px 18px;
  font-size: 0.9rem;
}

.studio-gate-primary[hidden] {
  display: none;
}

.studio-gate-back {
  font-size: 0.85rem;
  color: #1e3a8a;
}

/* The header's fixed line for an operator (or a lost session): what this
   sign-in can do here. One line; the whole sentence is in its tooltip. */
.studio-mode-line {
  display: inline-block;
  max-width: 280px;
  padding: 3px 10px;
  border: 1px solid #c7d4ee;
  border-radius: 999px;
  background: #eef3fc;
  color: #1e3a8a;
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.studio-mode-line[data-state="expired"] {
  border-color: #f1d49a;
  background: #fff8e8;
  color: #8a5a00;
}

.studio-mode-line[hidden] {
  display: none;
}

.studio-mode-line-short {
  display: none;
}

@media (max-width: 1399px) {
  .studio-mode-line-long {
    display: none;
  }

  .studio-mode-line-short {
    display: inline;
  }
}

/* Studio is sign-in only, so its sign-in badge always carries an email; in
   this header it is kept short (the whole address is in its tooltip) so the
   one row keeps the status its room at 1024 — the header was measured with a
   signed-out "Public" badge until 2026-09-25. The name never gives way; the
   build does (.app-version, below). */
.topbar .cq-badge {
  max-width: 150px;
}

/* Below 1200 px the build gives way first, to an ellipsis, so the status
   keeps room beside a signed-in badge. */
@media (max-width: 1200px) {
  .app-version {
    max-width: 44px;
  }
}

.title-row h1,
.title-row .app-title-icon,
.title-row .info-icon {
  flex: 0 0 auto;
}

/* Every write below admin: greyed, never hidden, "Admins only" in its
   tooltip (studio-access/studio-mode.js applyStudioWriteGate). */
[data-studio-write]:disabled,
[data-studio-write][aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
}

button[data-studio-write]:disabled:hover {
  transform: none;
  box-shadow: none;
}

/* The tab bar (2026-09-25; TJ: the tabs "do not look like usual tabs i think
   there is a little line missing"). A baseline rule runs under the whole bar
   — drawn inside it (an inset shadow), so it survives the bar scrolling
   sideways on a phone — and every tab stands on it: inactive tabs muted, with
   top and side edges and the baseline across their foot; the active tab the
   colour of the workspace it opens onto, with no line under it, so tab and
   content read as one piece. About sits apart at the bar's far end. */
.workspace-tabs {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  padding: 2px 24px 0;
  background: var(--chrome-bg);
  box-shadow: inset 0 -1px 0 var(--tab-rule);
}

.workspace-tab {
  position: relative;
  border: 1px solid var(--tab-edge);
  border-bottom: 0;
  background: var(--tab-muted-bg);
  color: var(--tab-muted-text);
  border-radius: 8px 8px 0 0;
  padding: 7px 14px;
  font-size: 0.84rem;
  font-weight: 600;
  cursor: pointer;
  box-shadow: inset 0 -1px 0 var(--tab-rule);
}

.workspace-tab:hover {
  background: #f1f4f9;
  color: #2c3e5e;
  transform: none;
  box-shadow: inset 0 -1px 0 var(--tab-rule);
}

.workspace-tab.active,
.workspace-tab.active:hover {
  z-index: 1;
  background: var(--workspace-bg);
  color: #172033;
  font-weight: 700;
  border-color: var(--tab-rule);
  box-shadow: none;
}

.workspace-tab:focus-visible {
  outline: 2px solid #5b83d5;
  outline-offset: -3px;
}

.workspace-tab-about {
  margin-left: auto;
}

/* The standard tab frame (demo/modules/workspace-tabs/frame.js): on every tab
   that shows the one shared viewer, a narrow viewer column on the left
   (--viewer-share) — canvas on top, the viewer controls underneath — and the
   shown tab's documents on the right. body[data-workspace-view] names the tab;
   only that tab's documents panel is displayed. At 1200px and below the frame
   stacks (see the breakpoint below). */
.layout {
  display: grid;
  grid-template-columns: var(--viewer-share) minmax(0, 1fr);
  gap: 14px;
  padding: 12px 24px 16px;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

body:not([data-workspace-view="scene"]) #scene-documents,
body:not([data-workspace-view="simulation"]) #simulation-documents,
body:not([data-workspace-view="view"]) #view-documents,
body:not([data-workspace-view="stations"]) #stations-documents,
body:not([data-workspace-view="captions-sound"]) #captions-sound-documents,
body:not([data-workspace-view="catalog"]) #hosted-catalog-panel,
body:not([data-workspace-view="about"]) #about-documents {
  display: none;
}

/* About (2026-09-25): no viewer — its page takes the whole workspace. */
body[data-workspace-view="about"] .layout > .viewer-column {
  display: none;
}

#about-documents {
  grid-column: 1 / -1;
  min-height: 0;
  overflow-y: auto;
}

.about-body {
  max-width: 1280px;
  font-size: 0.86rem;
  line-height: 1.45;
  color: #25324a;
}

/* The workflow, the tiers and the links side by side where there is room. */
.about-columns {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) minmax(0, 0.8fr);
  gap: 8px 28px;
}

@media (max-width: 1100px) {
  .about-columns {
    grid-template-columns: minmax(0, 1fr);
  }
}

.about-body h3 {
  margin: 18px 0 6px;
  font-size: 0.95rem;
}

.about-body p {
  margin: 0 0 8px;
}

.about-intro {
  font-size: 0.92rem;
  max-width: 120ch;
}

.about-note {
  color: #53627e;
  font-size: 0.8rem;
}

.about-body table {
  width: 100%;
  border-collapse: collapse;
  margin: 4px 0 8px;
}

.about-body th,
.about-body td {
  text-align: left;
  vertical-align: top;
  padding: 5px 10px;
  border-bottom: 1px solid #e3e8f1;
}

.about-body thead th {
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #53627e;
  border-bottom-color: #c7d4ee;
}

.about-tabs tbody th {
  white-space: nowrap;
}

.about-body code {
  font-size: 0.8rem;
  color: #1e3a8a;
}

.about-tiers td[data-tier],
.about-tiers thead th:not(:first-child) {
  text-align: center;
}

.about-tiers td[data-tier] {
  width: 70px;
}

.about-steps {
  margin: 4px 0 8px;
  padding-left: 22px;
  max-width: 90ch;
}

.about-steps > li {
  margin-bottom: 4px;
}

.about-links {
  margin: 4px 0;
  padding-left: 18px;
}

/* Assets (Studio restructure C11): the same frame, with the tab's own preview
   (#catalog-preview-column, hosted-catalog/model-preview.js) where the shared
   viewer's column is on every other tab, and the catalogue as its documents. */
body:not([data-workspace-view="catalog"]) .catalog-preview-column {
  display: none;
}

body[data-workspace-view="catalog"] .layout > .viewer-column:not(.catalog-preview-column) {
  display: none;
}

/* Scene Graph documents: node tree + properties beside the Scene Graph card.
   Each sub-column scrolls on its own. */
.scene-documents {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-height: 0;
  min-width: 0;
}

/* View Editor documents (docs/VIEW_SETTINGS_MODEL.md §5 step 5): the View,
   Environment, Layers and Look cards in a 2x2 grid, each card scrolling on its
   own. */
.view-editor-column {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: auto repeat(2, minmax(0, 1fr));
  gap: 12px;
  min-height: 0;
  min-width: 0;
}

/* Open on a display: one bar across both card columns, above the 2x2 grid.
   The note keeps its row whether or not there is anything to report. */
.view-editor-launch {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.view-editor-launch > button {
  flex: 0 0 auto;
}

.view-editor-launch-note {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.3;
  /* Two lines reserved, so the cards below do not jump when the note
     changes between a one-line problem and the two-line list of keys. */
  min-height: 2.6em;
  display: flex;
  align-items: center;
  color: #5a7090;
  overflow-wrap: anywhere;
}

.view-editor-launch-note[data-state="blocked"] {
  color: var(--btn-danger-text);
}

.view-editor-launch-note[data-state="warn"] {
  color: #92400e;
}

.view-editor-column > .panel,
.tab-documents > .panel {
  min-height: 0;
  min-width: 0;
  overflow-y: auto;
}

.view-editor-column .row.actions,
.tab-documents .row.actions {
  gap: 6px;
}

.view-editor-column .row.actions button,
.view-editor-column .row.actions .sample-dropdown-wrap > button,
.tab-documents .row.actions button,
.tab-documents .row.actions .sample-dropdown-wrap > button {
  padding: 4px 8px;
  font-size: 0.78rem;
  line-height: 1.15;
}

/* The Simulation, Stations and Captions & Sound tabs (Studio restructure C6,
   C7, C9): each tab's cards fill its documents column and scroll on their own,
   headers staying put. Simulation: the scene-link strip over the one package
   card. Stations: the station list beside the Station card. Captions & Sound:
   the Captions and Sound cards side by side. */
.tab-documents {
  display: grid;
  gap: 12px;
  min-height: 0;
  min-width: 0;
}

/* Simulation (2026-09-25): two columns — the scene link over the package
   card, the live-simulation line over the Language view. */
.simulation-documents {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: auto minmax(0, 1fr);
}

.captions-sound-documents,
.stations-documents {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: minmax(0, 1fr);
}

/* Stations (C10): the preview strip across both columns, over the list and the
   Station card. */
.stations-documents {
  grid-template-rows: auto minmax(0, 1fr);
}

.stations-documents > .stations-preview {
  grid-column: 1 / -1;
}

.stations-preview-text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.8rem;
  line-height: 1.25;
  color: #405273;
  overflow: hidden;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.stations-preview[data-state="prompt"] .stations-preview-text {
  color: #92400e;
  font-weight: 600;
}

.stations-preview[data-state="error"] .stations-preview-text {
  color: #b42318;
}

/* A tab's strip: its tab-level line, ONE fixed height whatever it says and
   whether or not it has a button to offer, so the card below never moves
   (the View Editor's launch bar is the other). Registry keys are long: the
   chip takes two lines at most and the button truncates; both carry the whole
   text in their tooltip. */
.tab-strip {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  height: 44px;
  overflow: hidden;
}

.tab-strip > button {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 38%;
  padding: 4px 10px;
  font-size: 0.8rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tab-strip-label {
  flex: 0 0 auto;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #5b6b86;
}

.scene-link-chip {
  flex: 0 1 auto;
  min-width: 0;
  font-size: 0.78rem;
  line-height: 1.25;
  max-height: calc(2 * 1.25em + 6px);
  padding: 2px 10px;
  border-radius: 10px;
  border: 1px solid #dde3ec;
  background: #eef1f5;
  color: #405273;
  overflow: hidden;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.scene-link-chip[data-state="match"] {
  border-color: #b7e0c8;
  background: #ecf8f1;
  color: #0f5f3a;
}

.scene-link-chip[data-state="mismatch"] {
  border-color: #f3d19c;
  background: #fff7e8;
  color: #92400e;
}

/* What the live simulation on Fly runs: one line, two at most, the whole in
   its tooltip; "Live simulation: -" when it runs none or cannot be asked. */
.simulation-live-text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.8rem;
  line-height: 1.25;
  color: #405273;
  overflow: hidden;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.simulation-live-text[data-state="running"] {
  color: #0f5f3a;
}

/* The Language view: read-only facts, then the eight words, each a row of
   id · role · male · drive over its strip of on/off cells. Fixed rows: a
   built-in fallback draws the same eight, so nothing moves. */
.simulation-language-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.simulation-language-chip[data-source="built-in"] {
  border-color: #f3d19c;
  background: #fff7e8;
  color: #92400e;
}

.simulation-language-note {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.35;
  color: #53627e;
  min-height: 2.7em;
  overflow-wrap: anywhere;
}

.simulation-language-panel[data-source="built-in"] .simulation-language-note {
  color: #92400e;
}

.simulation-language-facts {
  display: grid;
  gap: 4px;
  margin: 0;
}

.simulation-language-facts > div {
  display: grid;
  grid-template-columns: 5.5em minmax(0, 1fr);
  gap: 8px;
  font-size: 0.8rem;
  line-height: 1.35;
}

.simulation-language-facts dt {
  font-weight: 600;
  color: #5b6b86;
}

.simulation-language-facts dd {
  margin: 0;
  color: #172033;
  overflow-wrap: anywhere;
}

.simulation-language-words {
  display: grid;
  gap: 6px;
}

.language-word {
  display: grid;
  gap: 3px;
}

.language-word-head {
  display: flex;
  gap: 8px;
  font-size: 0.76rem;
  line-height: 1.25;
  color: #53627e;
  white-space: nowrap;
  overflow: hidden;
}

.language-word-id {
  flex: 0 0 3.6em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 700;
  color: #172033;
}

.language-strip {
  display: grid;
  grid-template-columns: repeat(var(--language-cells, 40), minmax(0, 1fr));
  gap: 1px;
  height: 14px;
}

.language-cell {
  border-radius: 1px;
  background: #e6ebf3;
}

.language-cell[data-on="1"] {
  background: #2f4f7f;
}

/* The preamble (0–7) and sync gap (8–15) every word shares, set off faintly. */
.language-cell:nth-child(-n + 16) {
  box-shadow: inset 0 -2px 0 rgba(146, 64, 14, 0.25);
}

/* The Simulation Package card before a package is loaded (D18): the empty
   state in place of the form, which has nothing real to show. */
.doc-empty-state {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px 16px;
  border: 1px dashed #c7d4ee;
  border-radius: 10px;
  background: #f8faff;
  color: #405273;
  font-size: 0.85rem;
  line-height: 1.45;
}

.doc-empty-state[hidden] {
  display: none;
}

.doc-empty-state > strong {
  font-size: 0.95rem;
  color: #172033;
}

.simulation-package-panel.is-empty > .code-editor,
.simulation-package-panel.is-empty > .cfg-form-container {
  display: none;
}

/* Nothing to save or toggle until a package is loaded. */
.doc-head-actions button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Assets' documents: the catalogue fills its column; the table takes the
   height left over and scrolls on its own, its header row pinned. */
.hosted-catalog-panel {
  gap: 10px;
  min-width: 0;
  overflow-y: auto;
}

.hosted-catalog-panel > .panel-head,
.hosted-catalog-panel > .hint {
  margin-bottom: 0;
}

/* The frame's viewer column: the panel takes its natural height (canvas, then
   the controls under it) and the column scrolls if a short window cannot hold
   both — the canvas sizing rule keeps that rare. */
.viewer-column {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  min-width: 0;
  overflow-x: hidden;
  overflow-y: auto;
  padding-right: 2px;
}

.viewer-column > .viewer-panel,
.viewer-column > .model-preview-panel {
  flex: 0 0 auto;
}

/* The viewer controls (2026-09-25): ONE block, the same on every tab and in
   the Assets preview (workspace-tabs/frame.js VIEWER_TOOLS), stacked under the
   canvas in four rows — camera; Select · Move · Rotate and Animate; Viewport
   and View Frame; Near Clip and Details. Each row wraps in a narrow column
   instead of pushing its last control out of view, and every control is its
   own width; since every tab shows every control, the block is one height on
   every tab. In Full Screen the shared viewer's rows sit side by side in one
   floating bar as wide as what it holds (below); the Assets preview's stay
   under its canvas. */
.viewer-panel .viewer-control-row,
.model-preview-panel .viewer-control-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.viewer-panel:fullscreen .viewer-control-row {
  flex: 0 0 auto;
  flex-wrap: nowrap;
  width: auto;
}

/* Near Clip, the View Editor's (C12, D19; viewer/near-clip-control.js). */
.viewer-near-clip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  color: #3c567f;
  white-space: nowrap;
}

.viewer-near-clip input[type="range"] {
  width: 120px;
  padding: 0;
}

/* A fixed width, so a longer number never re-wraps the row. */
.viewer-near-clip-value {
  display: inline-block;
  width: 4ch;
  font-variant-numeric: tabular-nums;
  color: #53627e;
}

.viewer-panel:fullscreen .viewer-near-clip {
  font-size: 0.64rem;
}

.inspector-column {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  overflow-y: auto;
  padding-right: 2px;
}

.panel {
  border: 1px solid #d8deea;
  border-radius: 12px;
  padding: 14px;
  background: #ffffff;
  box-shadow: 0 2px 8px rgba(16, 24, 40, 0.05);
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.panel-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 6px;
  margin-bottom: 8px;
}

.panel.panel-dirty > .panel-head {
  background: #fffbeb;
  border-left: 3px solid #f59e0b;
  padding-left: 8px;
  margin-left: -8px;
  border-radius: 2px 0 0 2px;
}

/* The standard document header (Studio restructure C4,
   var/studio-restructure-plan.md §A.2), the same on every card:
     <Kind> (i)  Name  [key] [channel] [vN] [edited •]
     Load ▾  Save…  Apply  More ▾  [Form|JSON]
   The chips come from document identity (scene-authoring/document-header.js);
   the "edited •" chip replaces the old dot after the title. */
.panel-head.doc-head {
  flex-direction: column;
  align-items: stretch;
  flex-wrap: nowrap;
  gap: 6px;
}

/* The identity line: Kind, the name, then the chips. The name keeps at least
   ~12ch (ellipsis, full text in the tooltip); when the line is too narrow for
   the name and the chips, the chips wrap to a line of their own and truncate
   there first (Studio restructure C5 — the View card at 1440 showed "O…"). */
.doc-head-identity {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 8px;
  min-width: 0;
}

.doc-head-identity > .panel-title-group {
  flex: 0 0 auto;
  flex-wrap: nowrap;
}

.doc-head .doc-name {
  flex: 0 1 auto;
  margin: 0;
  min-width: min(12ch, 100%);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8rem;
}

.doc-identity {
  display: inline-flex;
  flex: 0 1 auto;
  max-width: 100%;
  flex-wrap: nowrap;
  gap: 4px;
  min-width: 0;
  overflow: hidden;
}

.doc-identity > .doc-chip {
  flex: 0 0 auto;
}

.doc-identity > .doc-chip-key {
  flex: 0 1 auto;
  min-width: 8ch;
}

.doc-chip {
  font-size: 0.72rem;
  line-height: 1.3;
  border: 1px solid #c7d4ee;
  border-radius: 999px;
  padding: 1px 7px;
  color: #3c567f;
  background: #eef3ff;
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.doc-chip-key {
  font-family: Consolas, "Courier New", monospace;
}

.doc-chip-channel,
.doc-chip-version {
  background: #ffffff;
}

.doc-chip-edited {
  border-color: #f59e0b;
  background: #fffbeb;
  color: #92400e;
  font-weight: 700;
}

/* The Scene Graph card's size, after its chips: "64 nodes · 9 controllers"
   (C12, D9: the stats bar folded into the card). */
.doc-counts {
  flex: 0 0 auto;
  font-size: 0.74rem;
  color: #53627e;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.row.actions.doc-head-actions {
  align-items: center;
  gap: 6px;
}

.doc-head-actions button,
.doc-head-actions .sample-dropdown-wrap > button,
.doc-head-actions .action-menu > summary {
  padding: 4px 8px;
  font-size: 0.78rem;
  line-height: 1.15;
}

/* The Form/JSON toggle is last in the row's order but sits at the header's
   top-right corner, beside the identity line, so it never wraps the actions
   onto a third line. Collapse, where a card still has it, ends the row. */
.panel-head.doc-head {
  position: relative;
  --doc-head-pad: 0px;
}

.doc-head:has(.doc-head-actions > .cfg-view-toggle) > .doc-head-identity {
  padding-right: 96px;
}

.doc-head-actions > .cfg-view-toggle {
  position: absolute;
  top: var(--doc-head-pad);
  right: var(--doc-head-pad);
}

/* On the View Editor (and every tab whose cards have their own space) each
   card scrolls on its own: its header stays put so Load / Save… / Apply are
   in reach at any scroll. */
.view-editor-column > .panel > .doc-head,
.tab-documents > .panel > .doc-head {
  --doc-head-pad: 14px;
  position: sticky;
  top: -14px;
  z-index: 5;
  margin: -14px -14px 8px;
  padding: 14px 14px 8px;
  background: #ffffff;
  border-radius: 12px 12px 0 0;
}

/* A card with a tab of its own scrolls as a whole under its sticky header, so
   its form takes the card's height instead of scrolling inside the shared
   360 px box — no scroll inside a scroll. */
.tab-documents > .panel > .cfg-form-container {
  max-height: none;
  overflow: visible;
  flex: 0 0 auto;
}

.view-editor-column > .panel.panel-dirty > .doc-head,
.tab-documents > .panel.panel-dirty > .doc-head {
  margin-left: -14px;
  padding-left: 11px;
  background: #fffbeb;
}

.panel-head-right {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.panel h2,
.panel h3 {
  margin: 0;
  font-size: 1.02rem;
  font-weight: 700;
}

.panel-title-group {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.panel-chip {
  font-size: 0.75rem;
  border: 1px solid #c7d4ee;
  border-radius: 999px;
  padding: 2px 9px;
  color: #3c567f;
  background: #eef3ff;
  white-space: nowrap;
  flex-shrink: 0;
}

/* Loaded config name label shown in the panel title row. */
.config-name-label {
  font-size: 0.74rem;
  font-style: italic;
  font-weight: 400;
  color: #3c567f;
  background: #eef3ff;
  border: 1px solid #c7d4ee;
  border-radius: 999px;
  padding: 1px 8px;
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Subtitle row below a panel-head showing the currently loaded file/config name. */
.panel-source-label {
  margin: -4px 0 6px;
  font-size: 0.78rem;
  color: #5a7090;
  font-style: italic;
}

.panel-source-label .config-name-label {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  color: #5a7090;
  font-size: 0.78rem;
  max-width: none;
}

/* Node tree: expand/collapse chevron + drag-reparent affordances. */
.tree-node-chevron {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  padding: 0;
  border: none;
  background: none;
  color: #5a7090;
  font-size: 0.7rem;
  line-height: 1;
  cursor: pointer;
}

.tree-node-chevron:hover {
  color: #1f3256;
}

.tree-node-chevron-spacer {
  visibility: hidden;
  cursor: default;
}

.tree-node.tree-drop-target,
.tree-add-root-bar.tree-drop-target {
  outline: 2px dashed #3b67c7;
  outline-offset: -2px;
  background: #e8f0fd;
}

.open-scene-card {
  max-width: 560px;
  width: min(560px, calc(100vw - 48px));
}

.open-scene-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.open-scene-section-title {
  margin: 6px 0 2px;
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #5a7090;
}

.open-scene-filter {
  width: 100%;
}

.open-scene-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 200px;
  overflow-y: auto;
}

.open-scene-catalog {
  max-height: 300px;
}

.open-scene-entry {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  text-align: left;
  background: #f7f9fd;
  /* Its own text colour: as a <button> it otherwise inherits the primary
     buttons' white text, invisible on this near-white row. */
  color: #1f3256;
  border: 1px solid #d8deea;
  border-radius: 8px;
  padding: 7px 10px;
  cursor: pointer;
}

.open-scene-entry:hover {
  background: #eef3ff;
  border-color: #c7d4ee;
}

.open-scene-entry.is-loading {
  opacity: 0.6;
  cursor: progress;
}

.open-scene-entry-key {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.82rem;
  overflow-wrap: anywhere;
}

.open-scene-entry-meta {
  font-size: 0.72rem;
  color: #5a7090;
  white-space: nowrap;
  flex-shrink: 0;
}

.open-scene-empty {
  margin: 2px 0;
  font-size: 0.8rem;
  color: #5a7090;
  font-style: italic;
}

.doc-mode-toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 4px 8px;
  border: 1px solid #c7d4ee;
  border-radius: 999px;
  background: #eef3ff;
}

.doc-mode-toggle label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.78rem;
  color: #3c567f;
  font-weight: 600;
}

.doc-mode-toggle input[type="radio"] {
  margin: 0;
}

.hint {
  margin: 0 0 8px;
  color: #61708b;
  font-size: 0.9rem;
}

.code-editor {
  width: 100%;
  flex: 1;
  background: #fbfcff;
  color: #152036;
  border: 1px solid #cfd7e6;
  border-radius: 8px;
  font: 12px/1.5 Consolas, "Courier New", monospace;
  outline: none;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: relative;
}

/* .code-editor uses display:flex, which overrides UA [hidden] display:none.
   Enforce hidden state explicitly so JSON/Form mode switches show only one. */
.code-editor[hidden],
.cfg-form-container[hidden] {
  display: none !important;
}

pre {
  width: 100%;
  background: #fbfcff;
  color: #152036;
  border: 1px solid #cfd7e6;
  border-radius: 8px;
  font: 12px/1.5 Consolas, "Courier New", monospace;
  outline: none;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 12px;
}

.code-editor:focus-within {
  border-color: #7a98cf;
  box-shadow: 0 0 0 3px rgba(87, 133, 255, 0.14);
}

.code-editor>.cm-editor {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  height: 100%;
}

.code-editor + .row.actions {
  margin-top: 8px;
}

.cm-editor .cm-scroller {
  font-family: Consolas, "Courier New", monospace;
  overflow: auto;
  height: 100%;
}

.cm-editor.cm-focused {
  outline: none !important;
}

.editor-panel {
  min-height: 0;
  flex: 0 0 auto;
}

.json-column {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  overflow-y: auto;
  padding-right: 2px;
}

.view-config-panel {
  background: #ffffff;
  padding: 12px;
  flex: 0 0 auto;
}

.view-config-panel .hint {
  margin-bottom: 8px;
  font-size: 0.82rem;
}

.view-config-editor {
  min-height: 220px;
  max-height: 300px;
  flex: 0 0 auto;
}

.config-editor {
  min-height: 180px;
  max-height: 260px;
  flex: 0 0 auto;
}

/* The Stations tab's list (Studio restructure C9): GET /api/stations in the
   View Gallery's groups, then, for admins only, "Unlisted and drafts",
   collapsed. The panel scrolls on its own and its bar (the note and Refresh)
   stays put. Every row is ONE fixed height whatever it holds (a still or its
   placeholder, a uses line or "-", the admin-only stale line or not), so the
   list never jumps as rows load. */
.station-list-bar {
  position: sticky;
  top: -14px;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 34px;
  margin: -14px -14px 10px;
  padding: 10px 14px 8px;
  background: #ffffff;
  border-bottom: 1px solid #edf0f6;
  border-radius: 12px 12px 0 0;
  flex: 0 0 auto;
}

.station-list-note {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.3;
  color: #5b6b86;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.station-list-note.is-outage {
  color: #92400e;
}

.station-list-bar > button {
  flex: 0 0 auto;
  padding: 4px 10px;
  font-size: 0.78rem;
}

/* The bar's second line: where a stills run is, "-" when idle. One line, one
   height, whatever it says (the full text is its tooltip). */
.station-list-bar {
  flex-wrap: wrap;
  row-gap: 4px;
}

/* The note shrinks (it clamps to two lines) so both buttons stay on line one. */
.station-list-bar > .station-list-note {
  flex-basis: 0;
}

.station-stills-status {
  flex: 1 0 100%;
  min-width: 0;
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.3;
  min-height: 1.3em;
  color: #5b6b86;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Station stills being retaken: a fixed box in the corner, on every tab, while
   a run is on (stations/station-stills-overlay.js). Over the workspace and its
   menus (200), under the dialogs (1000). The stage is ONE size whatever the
   station's aspect; the live frame is scaled down to fit it with a transform
   and keeps its full internal size — on screen, so it renders at full speed. */
.station-stills-overlay {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 900;
  width: 256px;
  box-sizing: border-box;
  padding: 8px;
  border-radius: 10px;
  background: #111827;
  color: #e5e7eb;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.35);
  font-size: 0.75rem;
}

.station-stills-overlay[hidden] {
  display: none;
}

.station-stills-overlay-text,
.station-stills-overlay-phase {
  margin: 0;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.station-stills-overlay-text {
  font-weight: 600;
}

.station-stills-overlay[data-state="paused"] .station-stills-overlay-text {
  color: #fbbf24;
}

.station-stills-overlay-phase {
  margin-bottom: 6px;
  color: #9ca3af;
}

.station-stills-stage {
  position: relative;
  width: 240px;
  height: 180px;
  overflow: hidden;
  border-radius: 6px;
  background: #000;
  pointer-events: none;
}

.station-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  flex: 0 0 auto;
}

.station-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.station-group-label {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #5b6b86;
}

.station-group-note {
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.35;
  color: #6b7a93;
}

details.station-group > summary.station-group-label {
  cursor: pointer;
}

.station-rows {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.station-rows-empty {
  margin: 0;
  padding: 6px 2px;
  font-size: 0.78rem;
  color: #5b6b86;
}

.station-row {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  column-gap: 10px;
  /* Name, uses, the admin-only stale line and the actions: room for all four. */
  height: 94px;
  box-sizing: border-box;
  padding: 7px;
  border: 1px solid #dde3ec;
  border-radius: 10px;
  background: #fbfcfe;
  flex: 0 0 auto;
}

.station-row:hover {
  background: #f3f6fb;
}

.station-row.is-selected {
  border-color: #8fb0ec;
  background: #eef4ff;
  box-shadow: inset 3px 0 0 #3b6fd6;
}

/* The still well: one shape for every row, portrait or landscape still. */
.station-still-box {
  width: 96px;
  height: 72px;
  border-radius: 6px;
  background: #1f2937;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.station-still {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.station-still-missing {
  padding: 4px 6px;
  font-size: 0.66rem;
  line-height: 1.25;
  text-align: center;
  color: #cbd5e1;
}

.station-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

/* The name, uses and stale lines are ONE button: selecting it loads the
   station into the Station form. */
.station-select,
.station-select:hover {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1px;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  transform: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.station-select:focus-visible {
  outline: 2px solid #3b6fd6;
  outline-offset: 2px;
  border-radius: 4px;
}

.station-name,
.station-uses,
.station-stale {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.station-name {
  font-size: 0.86rem;
  font-weight: 600;
  line-height: 1.3;
  color: #172033;
}

.station-uses {
  font-size: 0.75rem;
  line-height: 1.3;
  color: #405273;
}

.station-stale {
  font-size: 0.72rem;
  line-height: 1.3;
  color: #6b7a93;
}

.station-stale.is-stale {
  color: #92400e;
}

/* A retake was refused: the old still stays, and the line says why. */
.station-stale.is-refused {
  color: #b91c1c;
}

.station-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: auto;
  min-width: 0;
}

.station-actions button,
.station-actions .station-launch {
  font-size: 0.72rem;
  padding: 2px 8px;
  border: 1px solid var(--btn-secondary-border);
  border-radius: 6px;
  background: var(--btn-secondary-bg);
  color: var(--btn-secondary-text);
  text-decoration: none;
  line-height: 1.5;
  white-space: nowrap;
  cursor: pointer;
}

.station-actions button:hover,
.station-actions .station-launch:hover {
  background: var(--btn-secondary-hover);
}

/* Every config card in the scrolling .json-column sizes to its own content and
   never shrinks. Without this the flex default (0 1 auto) lets the column
   squeeze the card's border box while its fixed-min-height editor keeps its
   size, so the editor and action row render outside the card and cover the
   neighbours below. */
.lighting-config-panel,
.layers-config-panel,
.look-config-panel,
.commentary-config-panel,
.audio-config-panel,
.display-profile-config-panel,
.simulation-package-panel {
  flex: 0 0 auto;
}

.editor-panel .code-editor {
  flex: 0 0 auto;
  min-height: 220px;
  max-height: 420px;
}

.json-column .row.actions {
  gap: 6px;
}

.json-column .row.actions button,
.json-column .row.actions .sample-dropdown-wrap > button {
  padding: 4px 8px;
  font-size: 0.78rem;
  line-height: 1.15;
}

.cm-mesh-loaded {
  color: #0f5f3a;
  font-weight: 800;
}

.cm-mesh-missing {
  color: #8b1e2f;
  font-weight: 800;
}

.cm-mesh-indicator {
  margin-left: 8px;
  font-size: 0.68rem;
  vertical-align: baseline;
  border-radius: 999px;
  padding: 1px 7px;
  font-weight: 800;
  letter-spacing: 0.04em;
  border: 1px solid #d4dbea;
  font-family: "Segoe UI Variable", "Segoe UI", Inter, Roboto, Arial, sans-serif;
}

.cm-mesh-indicator.loaded {
  color: #0f5f3a;
  border-color: #a5dec3;
  background: #e9f8f0;
}

.cm-mesh-indicator.missing {
  color: #8b1e2f;
  border-color: #efc2c9;
  background: #fff3f5;
}

.cm-line.cm-mesh-line-loaded {
  background: linear-gradient(to right, rgba(16, 185, 129, 0.12), rgba(16, 185, 129, 0.04));
  border-left: 3px solid #34d399;
  padding-left: 6px;
}

.cm-line.cm-mesh-line-missing {
  background: linear-gradient(to right, rgba(239, 68, 68, 0.14), rgba(239, 68, 68, 0.05));
  border-left: 3px solid #f87171;
  padding-left: 6px;
}

.viewer-panel {
  min-height: 0;
  overflow: auto;
}

.viewer-panel:fullscreen {
  width: 100vw;
  height: 100vh;
  margin: 0;
  padding: 0;
  border-radius: 0;
  position: relative;
}

.viewer-panel:fullscreen .viewer-canvas {
  min-height: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  border: none;
  border-radius: 0;
}

.viewer-canvas {
  position: relative;
  flex: 0 0 auto;
  height: auto;
  min-height: 160px;
  /* Sized by ONE rule in JS (getViewerCanvasSizeLimits, viewer-layout-controls.js);
     the old 460x360 Scene Graph Editor cap is retired. */
  max-width: 100%;
  width: 100%;
  aspect-ratio: 1.6;
  margin: 0 auto;
  border: 1px solid #cfd7e6;
  border-radius: 8px;
  background: #f8faff;
  overflow: hidden;
  transition: border-color 150ms ease, background 150ms ease;
}

.viewer-panel:fullscreen .viewer-canvas {
  max-width: none;
  max-height: none;
  width: 100%;
  height: 100%;
}

.viewer-panel:fullscreen .panel-head,
.viewer-panel:fullscreen .viewer-status-block {
  display: none;
}

.viewer-overlay-toggle {
  display: none;
}

.viewer-panel:fullscreen .viewer-overlay-toggle {
  display: inline-flex;
  position: absolute;
  right: 14px;
  bottom: 92px;
  z-index: 24;
  font-size: 0.72rem;
  padding: 3px 7px;
  border: 1px solid rgba(203, 213, 225, 0.6);
  background: rgba(241, 245, 249, 0.82);
  backdrop-filter: blur(8px);
}

.viewer-panel:fullscreen.overlay-controls-hidden .viewer-overlay-toggle {
  bottom: 14px;
}

/* Qualified with .row.actions so it outranks the base .row.actions.viewer-actions
   grid below, which made every row as wide as the screen (C12). */
.viewer-panel:fullscreen .row.actions.viewer-actions {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  position: absolute;
  left: 50%;
  bottom: 14px;
  transform: translateX(-50%);
  z-index: 22;
  max-width: calc(100vw - 28px);
  width: max-content;
  min-width: 0;
  gap: 4px;
  padding: 6px 8px;
  border: 1px solid rgba(203, 213, 225, 0.6);
  border-radius: 12px;
  background: rgba(241, 245, 249, 0.82);
  backdrop-filter: blur(8px);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
  overflow-x: auto;
}

/* In the bar every control is small, so the whole block fits one row. */
.viewer-panel:fullscreen .viewer-actions button {
  font-size: 0.7rem;
  padding: 3px 6px;
}

.viewer-panel:fullscreen .viewer-radio-group {
  padding: 2px 6px;
}

.viewer-panel:fullscreen .viewer-radio-group legend {
  display: none;
}

.viewer-panel:fullscreen .viewer-radio-option,
.viewer-panel:fullscreen .viewer-tool-option {
  font-size: 0.66rem;
}

.viewer-panel:fullscreen .viewer-near-clip input[type="range"] {
  width: 72px;
}

.viewer-panel:fullscreen .viewer-actions .viewer-btn-system {
  border-color: #bfcbeb;
  background: #e5ebfa;
  color: #1e3a8a;
}

.viewer-panel:fullscreen .viewer-actions .viewer-btn-mode {
  border-color: #bfcbeb;
  background: #e5ebfa;
  color: #1e3a8a;
}

.viewer-panel:fullscreen .viewer-actions .viewer-btn-preview {
  border-color: #b7d7c3;
  background: #e7f3ec;
  color: #166534;
}

.viewer-panel:fullscreen .viewer-actions .viewer-btn-reset {
  border-color: #efc6cb;
  background: #fdebec;
  color: #991b1b;
}

.viewer-panel:fullscreen .viewer-actions .toggle-view {
  border-color: #bfcbeb;
  background: #e5ebfa;
  color: #1e3a8a;
}

.viewer-panel:fullscreen .viewer-actions .toggle-scene {
  border-color: #cbd5e1;
  background: #eef1f5;
  color: #334155;
}

.viewer-panel:fullscreen .viewer-actions .toggle-material {
  border-color: #b7d7c3;
  background: #e7f3ec;
  color: #166534;
}

.viewer-panel:fullscreen .viewer-actions .toggle-switch {
  font-size: 0.64rem;
  gap: 3px;
  padding: 2px 5px;
}

.viewer-panel:fullscreen .viewer-actions .toggle-switch input[type="checkbox"] {
  width: 11px;
  height: 11px;
}

.viewer-panel:fullscreen.overlay-controls-hidden .row.actions.viewer-actions {
  display: none;
}

.viewer-framing-guide {
  position: absolute;
  border: 2px dashed rgba(87, 133, 255, 0.75);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.85);
  pointer-events: none;
  z-index: 4;
  display: none;
}

.viewer-canvas.drop-active {
  border-color: #5785ff;
  border-width: 2px;
  background: #f2f6ff;
}

.viewer-canvas canvas {
  width: 100% !important;
  height: 100% !important;
  display: block;
}

.viewer-model-loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: rgba(7, 10, 18, 0.55);
  color: #f8fafc;
  z-index: 6;
  pointer-events: none;
}

.viewer-model-loading-overlay[hidden] {
  display: none !important;
}

.viewer-model-loading-spinner {
  width: 34px;
  height: 34px;
  border-radius: 999px;
  border: 3px solid rgba(255, 255, 255, 0.28);
  border-top-color: #e2e8f0;
  animation: viewerModelLoadingSpin 900ms linear infinite;
}

.viewer-model-loading-text {
  margin: 0;
  font-size: 0.88rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

@keyframes viewerModelLoadingSpin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.viewer-tooltip {
  position: absolute;
  z-index: 10;
  pointer-events: none;
  max-width: 260px;
  padding: 7px 9px;
  border: 1px solid #cad5ea;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.96);
  color: #1f2c46;
  box-shadow: 0 6px 16px rgba(15, 26, 47, 0.18);
  font: 12px/1.4 "Segoe UI", Arial, sans-serif;
  white-space: pre-line;
}

.viewer-tooltip[hidden] {
  display: none;
}

.row.actions.viewer-actions {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 6px;
  width: 100%;
}

.viewer-control-row {
  gap: 6px;
  width: 100%;
}

.viewer-control-row > button,
.viewer-control-row > .toggle-switch,
.viewer-control-row > .viewer-radio-group {
  width: auto;
}

/* Animate and Restart: one control, two parts. */
.viewer-tool-pair {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* A control that does not work on this tab: greyed, in its place, its tooltip
   saying where it works (viewer/viewer-tab-frame.js). Never hidden — so the
   block is the same on every tab. */
.viewer-actions [data-viewer-tool].is-disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.viewer-actions [data-viewer-tool].is-disabled *,
.viewer-actions button:disabled {
  cursor: not-allowed;
}

.viewer-actions button:disabled:hover,
.viewer-actions .is-disabled .toggle-switch:hover,
.viewer-actions .toggle-switch.is-disabled:hover {
  transform: none;
  box-shadow: none;
}

.viewer-actions button.secondary:disabled:hover {
  background: var(--btn-secondary-bg);
}

.viewer-actions button.viewer-btn-system:disabled:hover {
  background: var(--btn-primary-bg);
}

.viewer-radio-group {
  margin: 0;
  border: 1px solid #c7d4ee;
  background: #eef3ff;
  color: #3c567f;
  border-radius: 10px;
  padding: 4px 8px 6px;
  display: grid;
  /* One row of options however many there are (Gizmo has three). */
  grid-auto-flow: column;
  grid-auto-columns: max-content;
  gap: 4px 8px;
  min-width: 0;
  width: auto;
  justify-content: start;
}

.viewer-radio-group legend {
  padding: 0 4px;
  font-size: 0.72rem;
  font-weight: 700;
  color: #3c567f;
}

.viewer-radio-option {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: 5px;
  font-size: 0.76rem;
  line-height: 1.1;
  white-space: nowrap;
}

.viewer-radio-option input[type="radio"] {
  margin: 0;
}

.viewer-status-block {
  margin-top: 6px;
  padding: 0 2px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.viewer-status-line {
  margin: 0;
  font-size: 0.62rem;
  line-height: 1.35;
  color: #53627e;
}

/* The shared viewer's readouts: one row each, one line each — its value
   where the tab shows it, "<Name>: -" elsewhere (data-readout-state). */
.viewer-status-block [data-viewer-readout] {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.viewer-status-line[data-readout-state="empty"] > .readout-value,
.viewer-status-line:not([data-readout-state="empty"]) > .readout-empty {
  display: none;
}

.viewer-summary {
  margin: 0;
  flex: 1 1 100%;
  font-size: 0.82rem;
}

/* What a tab draws over the canvas shows only on that tab (the frame table's
   viewerOverlays). Controls and readouts are never hidden (above). */
.viewer-panel [data-viewer-overlay][hidden] {
  display: none !important;
}

/* Captions & Sound (Studio restructure C8): the display's caption rows over
   the viewer, styled by /shared/commentary-overlay.css. The stage is a
   virtual display the width of the viewer, scaled to fit
   (captions-sound/caption-preview.js computeCaptionStage sets the three
   --caption-stage-* properties); inside it the rows keep the display's own
   sizes, anchored to the stage instead of the window. */
.caption-preview {
  position: absolute;
  inset: 0;
  z-index: 5;
  overflow: hidden;
  pointer-events: none;
}

/* Full Screen with its controls showing: the sample lines end above the
   floating bar (its clearance is set on the panel by viewer-layout-controls.js
   updateFullscreenOverlayControlsState), so the bottom strip is never under
   it; Hide Controls gives the picture back (C12). */
.viewer-panel:fullscreen:not(.overlay-controls-hidden) .caption-preview {
  bottom: var(--viewer-bar-clearance, 0px);
}

.caption-preview-stage {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--caption-stage-width, 100%);
  height: var(--caption-stage-height, 100%);
  transform: scale(var(--caption-stage-scale, 1));
  transform-origin: 0 0;
  --commentary-overlay-position: absolute;
  --commentary-overlay-z-index: 1;
  /* Shares of the stage, as the display's are shares of its window (vw). */
  --commentary-overlay-bottom-max-width: min(680px, 60%);
  --commentary-overlay-right-max-width: min(340px, 30%);
}

/* Captions off: one plain line where the captions would be, so the preview
   says so instead of going blank. */
.caption-preview-off {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  margin: 0;
  padding: 7px 14px;
  border: 1px dashed rgba(151, 163, 184, 0.7);
  border-radius: 8px;
  background: rgba(16, 21, 29, 0.62);
  color: #cbd5e1;
  font: 15px/1.35 Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  white-space: nowrap;
}

.caption-preview-off.is-right {
  left: auto;
  right: 16px;
  top: 84px;
  bottom: auto;
  transform: none;
}

.caption-preview-off[hidden] {
  display: none;
}

/* "Sample lines": these are samples, not the live narration. */
.caption-preview-tag {
  position: absolute;
  top: 8px;
  left: 8px;
  padding: 2px 8px;
  border: 1px solid rgba(199, 212, 238, 0.9);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.9);
  color: #3c567f;
  font-size: 0.68rem;
  font-weight: 600;
  white-space: nowrap;
}

/* The Sound card's two play rows (2026-09-25): Play a signal in Spatial,
   Voiced lines (Play / Stop) in Narration, each with ONE fixed status block
   beside it — what is sounding, or why it is silent, "-" when idle. The block
   is always two lines tall and cut there, so the card never changes height;
   the tooltip has it all. It sits under its button, in the controls' column. */
.sound-play-btn {
  justify-self: start;
  padding: 3px 10px;
  font-size: 0.78rem;
  white-space: nowrap;
}

.sound-play-btn[aria-pressed="true"] {
  border-color: #2f6fd0;
  background: #e8f0fd;
  color: #1b4f9c;
}

.sound-play-status {
  grid-column: 2;
  min-width: 0;
  height: 2.7em;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
  font-size: 0.74rem;
  line-height: 1.35;
  color: #53627e;
}

.sound-play-status[data-state="playing"] {
  color: #0f5f3a;
}

.sound-play-status[data-state="silent"],
.sound-play-status[data-state="missing"],
.sound-play-status[data-state="error"],
.sound-play-status[data-state="unavailable"] {
  color: #92400e;
}

/* "Showing": what the viewer shows — the scene graph and the view, layers and
   look documents. One line; the tooltip names every key and channel. */
.viewer-panel > .panel-head,
.model-preview-panel > .panel-head {
  flex-wrap: nowrap;
  gap: 8px;
  min-width: 0;
}

.viewer-panel > .panel-head > .panel-title-group,
.model-preview-panel > .panel-head > .panel-title-group {
  flex: 0 0 auto;
}

.viewer-showing-chip {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: Consolas, "Courier New", monospace;
  font-size: 0.68rem;
}

/* Select · Move · Rotate: a small segmented tool group in the control block
   (it floated over the canvas's top-left until every tab showed the same
   controls; greyed there, it would have sat on the picture). */
.viewer-tool-group {
  display: inline-flex;
  gap: 2px;
  margin: 0;
  padding: 2px;
  min-width: 0;
  border: 1px solid #c7d4ee;
  border-radius: 8px;
  background: #ffffff;
}

.viewer-tool-option {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: 6px;
  font-size: 0.72rem;
  line-height: 1.3;
  color: #3c567f;
  cursor: pointer;
  white-space: nowrap;
}

.viewer-tool-option input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.viewer-tool-option:has(input:checked) {
  background: #1e3a8a;
  color: #ffffff;
}

.viewer-tool-option:has(input:focus-visible) {
  outline: 2px solid #5785ff;
  outline-offset: 1px;
}

/* Details fills the camera readout, which Full Screen does not show. */
.viewer-panel:fullscreen [data-viewer-tool="details"] {
  display: none;
}

/* A document's status line under its header (the Environment card's
   background readout). */
.doc-status-line {
  margin: 0 0 6px;
  font-size: 0.68rem;
  line-height: 1.35;
  color: #53627e;
}

.config-placeholder {
  margin: 0;
  min-height: 120px;
  max-height: 220px;
  overflow: auto;
  white-space: pre;
}

/* The Assets preview (Studio restructure C11): the viewer panel's shape —
   header, canvas, the controls under it, one-line readouts, then the selected
   entry's files — each part one fixed height, so selecting a row never
   resizes the column. */
.model-preview-panel:fullscreen {
  width: 100vw;
  height: 100vh;
  margin: 0;
  border-radius: 0;
  padding: 12px;
  display: flex;
  flex-direction: column;
}

.model-preview-panel:fullscreen .model-preview-canvas {
  flex: 1;
  min-height: 0;
  width: 100%;
  height: auto;
  max-width: none;
  max-height: none;
  aspect-ratio: auto;
}

.model-preview-panel:fullscreen > .panel-head,
.model-preview-panel:fullscreen .catalog-source-files {
  display: none;
}

/* Sized by the viewer canvas's rule in JS (getViewerCanvasSizeLimits,
   viewer-layout-controls.js); these are the fallbacks until it runs. */
.model-preview-canvas {
  position: relative;
  flex: 0 0 auto;
  width: 100%;
  max-width: 100%;
  min-height: 160px;
  aspect-ratio: 1.6;
  margin: 0 auto;
  border: 1px solid #cfd7e6;
  border-radius: 8px;
  background: #f8faff;
  overflow: hidden;
}

.model-preview-canvas canvas {
  width: 100% !important;
  height: 100% !important;
  display: block;
}

/* The preview's own settings, under its readouts. */
.model-preview-options {
  margin-top: 6px;
}

.model-preview-status,
.model-cache-readout {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.model-preview-panel:fullscreen .model-preview-status {
  white-space: normal;
}

.model-preview-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px;
  background: linear-gradient(180deg, rgba(244, 248, 255, 0.96), rgba(231, 239, 252, 0.96));
}

/* display:flex above overrides the UA stylesheet [hidden]=display:none, so enforce it explicitly */
.model-preview-overlay[hidden] {
  display: none;
}

.model-preview-overlay.transparent {
  background: transparent;
}

.model-preview-overlay-message {
  margin: 0;
  text-align: center;
  font-size: 0.74rem;
  line-height: 1.35;
  color: #2d446f;
}

.model-preview-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 6px;
  border: 1px solid #cfd7e6;
  background: #ffffff;
}

/* ── Catalog source files panel ─────────────────────────── */

.catalog-source-files {
  margin: 8px 0 0;
  border: 1px solid #d5deec;
  border-radius: 8px;
  background: #f7faff;
  padding: 6px 8px 5px;
}

.catalog-source-files-list {
  /* Four files' height whatever the entry holds; more scroll. */
  height: calc(4 * 1.6rem);
  overflow-y: auto;
}

.catalog-source-file-empty {
  padding: 3px 5px;
  font-size: 0.73rem;
  color: #6b7fa8;
}

.catalog-source-files-heading {
  font-size: 0.68rem;
  font-weight: 700;
  color: #3d5278;
  margin: 0 0 4px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.catalog-source-files-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.catalog-source-file-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 5px;
  border-radius: 5px;
  font-size: 0.73rem;
  font-family: "Segoe UI Variable", "Segoe UI", Inter, Roboto, Arial, sans-serif;
  color: #2a3d60;
  cursor: default;
}

.catalog-source-file-item.previewable {
  cursor: pointer;
}

.catalog-source-file-item.previewable:hover {
  background: #e4edfb;
}

.catalog-source-file-item.active {
  background: #d9e8fb;
  font-weight: 600;
}

.catalog-source-file-type {
  font-size: 0.63rem;
  font-weight: 700;
  padding: 1px 5px;
  border-radius: 4px;
  border: 1px solid #cdd7ee;
  background: #eef3ff;
  color: #4a65a0;
  flex-shrink: 0;
  font-family: "Segoe UI Variable", "Segoe UI", Inter, Roboto, Arial, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.catalog-source-file-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}

.catalog-source-file-status {
  flex-shrink: 0;
  font-size: 0.67rem;
}

.catalog-source-file-status.cached {
  color: #0f7a4c;
}

.catalog-source-file-status.not-cached {
  color: #9aabcc;
}

/* ── Models column upload panel (admin only) ────────────── */

.catalog-models-upload-panel {
  margin: 5px 0 0;
  border: 1px solid #d5deec;
  border-radius: 8px;
  background: #f7faff;
  padding: 6px 8px 8px;
}

.catalog-models-upload-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 12px 10px;
  border: 2px dashed #b8caef;
  border-radius: 6px;
  background: #f0f5ff;
  text-align: center;
  cursor: default;
  transition: border-color 0.15s, background 0.15s;
}

.catalog-models-upload-zone.drag-over {
  border-color: #3b67c7;
  background: #e8f0fd;
}

.catalog-models-upload-icon {
  font-size: 1.3rem;
  color: #7a96c4;
  line-height: 1;
}

.catalog-models-upload-label {
  margin: 0;
  font-size: 0.73rem;
  font-weight: 600;
  color: #1f3256;
}

.catalog-models-upload-browse-btn {
  display: inline-block;
  margin-top: 2px;
  padding: 4px 12px;
  font-size: 0.72rem;
  font-weight: 600;
  border: 1px solid #3b67c7;
  border-radius: 6px;
  background: #eef3ff;
  color: #1f3256;
  cursor: pointer;
}

.catalog-models-upload-browse-btn:hover {
  background: #dbe5f7;
}

.catalog-models-upload-progress {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.catalog-models-upload-status {
  margin: 4px 0 0;
  font-size: 0.68rem;
  color: #5a7099;
  min-height: 1em;
  word-break: break-word;
}

.catalog-models-upload-channel-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  font-size: 0.7rem;
  color: #5a7099;
}

.catalog-models-upload-channel-row select {
  font-size: 0.7rem;
  padding: 2px 4px;
}

/* Topbar diagnostics badge — replaces the always-visible Diagnostics panel.
   Click opens the diagnostics modal. */
.diagnostics-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #ffffff;
  border: 1px solid #d8deea;
  border-radius: 999px;
  padding: 4px 8px;
  cursor: pointer;
  color: inherit;
}

.diagnostics-badge:hover {
  background: #eef3ff;
}

.diagnostics-badge.is-clean .diag-badge.error,
.diagnostics-badge.is-clean .diag-badge.warn {
  color: #166534;
  border-color: #b7dfc6;
  background: #e8f7ee;
}

.diagnostics-badge.has-errors {
  border-color: #efc2c9;
  background: #fff3f5;
}

.diagnostics-badge.has-warnings {
  border-color: #f1d8b0;
  background: #fff8ee;
}

.diagnostics-card {
  max-width: 720px;
  width: min(720px, calc(100vw - 48px));
}

.diagnostics-card pre {
  margin: 0;
  max-height: 60vh;
  overflow: auto;
  white-space: pre-wrap;
  font-size: 0.8rem;
}

.diag-inline {
  display: flex;
  gap: 8px;
}

/* "More ▾" action menu — a native <details> holding a panel's secondary
   load/save actions so the primary row stays short. Button ids inside are
   unchanged; all existing wiring keeps working. */
.action-menu {
  position: relative;
  display: inline-block;
}

.action-menu > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--btn-secondary-border, #c4cede);
  background: var(--btn-secondary-bg, #f3f6fc);
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 0.85rem;
  user-select: none;
}

.action-menu > summary::-webkit-details-marker {
  display: none;
}

.action-menu[open] > summary {
  background: #e8f0fd;
}

.action-menu-items {
  position: absolute;
  z-index: 30;
  top: calc(100% + 4px);
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  min-width: 200px;
  padding: 8px;
  background: #ffffff;
  border: 1px solid #d8deea;
  border-radius: 10px;
  box-shadow: 0 8px 22px rgba(16, 24, 40, 0.14);
}

.action-menu-items > button,
.action-menu-items .sample-dropdown-wrap > button {
  width: 100%;
  text-align: left;
}

.diag-badge {
  font-size: 0.75rem;
  border-radius: 999px;
  padding: 3px 8px;
  border: 1px solid #d4dbea;
}

.diag-badge.error {
  color: #8b1e2f;
  border-color: #efc2c9;
  background: #fff3f5;
}

.diag-badge.warn {
  color: #7e4a00;
  border-color: #f1d8b0;
  background: #fff8ee;
}

button {
  border: 1px solid var(--btn-primary-border);
  background: var(--btn-primary-bg);
  color: #ffffff;
  border-radius: 7px;
  padding: 5px 9px;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0;
  cursor: pointer;
  transition: transform 120ms ease, background 120ms ease, box-shadow 120ms ease;
}

button.secondary {
  border-color: var(--btn-secondary-border);
  background: var(--btn-secondary-bg);
  color: var(--btn-secondary-text);
}

button.secondary:hover {
  background: var(--btn-secondary-hover);
}

button.load-action {
  border-color: var(--btn-load-border);
  background: var(--btn-load-bg);
  color: var(--btn-load-text);
}

button.load-action:hover {
  background: var(--btn-load-hover);
}

button.save-action {
  border-color: var(--btn-save-border);
  background: var(--btn-save-bg);
  color: var(--btn-save-text);
}

button.save-action:hover {
  background: var(--btn-save-hover);
}

button.danger-action {
  border-color: var(--btn-danger-border);
  background: var(--btn-danger-bg);
  color: var(--btn-danger-text);
}

button.danger-action:hover {
  background: var(--btn-danger-hover);
}

.info-icon {
  width: 22px;
  height: 22px;
  min-width: 22px;
  border-radius: 999px;
  border: 1px solid #c6d2e8;
  background: #f5f8ff;
  color: #35507f;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  padding: 0;
}

.info-icon:hover {
  background: #e9f0ff;
  box-shadow: none;
  transform: none;
}

.info-icon:active {
  transform: none;
}

.modal-shell {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal-shell.open {
  display: flex;
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 40, 0.42);
}

.modal-card {
  position: relative;
  width: min(680px, calc(100vw - 40px));
  max-height: calc(100vh - 60px);
  overflow: auto;
  border: 1px solid #d6deec;
  border-radius: 12px;
  background: #ffffff;
  box-shadow: 0 18px 50px rgba(17, 29, 53, 0.22);
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid #e2e8f4;
  padding: 14px 16px;
}

.modal-head h3 {
  margin: 0;
  font-size: 1.02rem;
}

.modal-close {
  min-width: 28px;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  border: 1px solid #d0d9ea;
  background: #f8faff;
  color: #3c4e6d;
  font-size: 16px;
  padding: 0;
}

.modal-close:hover {
  background: #eef3ff;
  transform: none;
  box-shadow: none;
}

.modal-body {
  padding: 14px 16px 16px;
  color: #2f3f5f;
  line-height: 1.6;
}

.modal-body p {
  margin: 0 0 10px;
}

.modal-body ul {
  margin: 0;
  padding-left: 20px;
}

.modal-select {
  width: 100%;
  border: 1px solid #c7d4ee;
  border-radius: 8px;
  padding: 8px 10px;
  background: #ffffff;
  color: #1e2f4d;
  font-size: 0.9rem;
}

/* Cloud save modal: prefix + editable file name inline row */
.cloud-save-form-label {
  display: block;
  font-size: 0.84rem;
  color: #33486b;
  margin-bottom: 4px;
}

.cloud-save-key-row {
  display: flex;
  align-items: stretch;
  border: 1px solid #c7d4ee;
  border-radius: 8px;
  background: #ffffff;
  overflow: hidden;
}

.cloud-save-prefix {
  padding: 8px 10px;
  background: #f0f4fb;
  color: #4a6080;
  font-size: 0.88rem;
  font-weight: 500;
  white-space: nowrap;
  border-right: 1px solid #c7d4ee;
  display: flex;
  align-items: center;
}

.cloud-save-sep {
  padding: 0 4px;
  color: #9baec8;
  font-size: 0.88rem;
  display: flex;
  align-items: center;
}

.cloud-save-key-row input {
  flex: 1;
  border: none;
  padding: 8px 10px;
  background: transparent;
  color: #1e2f4d;
  font-size: 0.9rem;
  min-width: 0;
}

.cloud-save-key-row input:focus {
  outline: none;
}

.cloud-save-key-preview {
  margin-top: 5px !important;
  color: #6b7d9c;
  font-size: 0.8rem;
}

/* Shown only while the channel is published: what the save replaces — and,
   on a line of its own, when the live simulation on Fly runs this package. */
.cloud-save-published-note {
  margin: 0;
  padding: 6px 10px;
  border: 1px solid #f59e0b;
  border-radius: 8px;
  background: #fffbeb;
  color: #92400e;
  font-size: 0.82rem;
  white-space: pre-line;
}

.cloud-save-published-note[hidden] {
  display: none;
}

button:hover {
  background: var(--btn-primary-hover);
  transform: translateY(-1px);
  box-shadow: 0 3px 8px rgba(45, 58, 73, 0.22);
}

button:active {
  transform: translateY(0);
}

.save-scene-btn,
.save-scene-btn.secondary {
  border-color: var(--btn-save-border);
  background: var(--btn-save-bg);
  color: var(--btn-save-text);
}

.save-scene-btn:hover,
.save-scene-btn.secondary:hover {
  background: var(--btn-save-hover);
}

.save-scene-btn:active,
.save-scene-btn.secondary:active {
  background: #d2e4d7;
}

.save-view-btn,
.save-view-btn.secondary {
  border-color: var(--btn-save-border);
  background: var(--btn-save-bg);
  color: var(--btn-save-text);
}

.save-view-btn:hover,
.save-view-btn.secondary:hover {
  background: var(--btn-save-hover);
}

.save-view-btn:active,
.save-view-btn.secondary:active {
  background: #d2e4d7;
}

.catalog-env-thumb {
  display: inline-block;
  width: 48px;
  height: 24px;
  margin-right: 6px;
  object-fit: cover;
  vertical-align: middle;
  border-radius: 3px;
  border: 1px solid #cdd7ee;
  background: #10131a;
}

.catalog-file-summary {
  display: inline-block;
  margin-left: 5px;
  font-size: 0.69rem;
  color: #5a6e99;
  background: #eef3ff;
  border: 1px solid #cdd7ee;
  border-radius: 4px;
  padding: 1px 5px;
  vertical-align: middle;
  font-family: "Segoe UI Variable", "Segoe UI", Inter, Roboto, Arial, sans-serif;
  white-space: nowrap;
}

.asset-registry-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.asset-admin-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border: 1px solid #d6deec;
  border-radius: 10px;
  padding: 10px;
  background: #f8fbff;
}

.asset-admin-status-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.asset-admin-status {
  margin: 0;
  font-size: 0.84rem;
  color: #223252;
}

.asset-admin-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px;
}

.asset-admin-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.84rem;
  color: #33486b;
}

.asset-admin-form input {
  width: 100%;
  border: 1px solid #c7d4ee;
  border-radius: 8px;
  padding: 8px 10px;
  background: #ffffff;
  color: #1e2f4d;
}

.password-input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
}

.password-input-wrapper input {
  padding-right: 36px;
}

.password-toggle {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  color: #5a6a8a;
  font-size: 0.95rem;
  padding: 0;
}

.password-toggle:hover {
  background: #eef2fb;
  color: #1e2f4d;
}

.password-toggle:focus-visible {
  outline: 2px solid #6584c1;
  outline-offset: 1px;
}

.password-toggle[aria-pressed="true"] .password-toggle-icon {
  opacity: 0.55;
}

.asset-admin-forgot-row {
  margin-top: 6px;
  display: flex;
  justify-content: flex-end;
}

.link-button {
  background: none;
  border: none;
  padding: 2px 4px;
  color: #3b5fa2;
  font-size: 0.83rem;
  cursor: pointer;
  text-decoration: underline;
}

.link-button:hover {
  color: #1e3a78;
}

.link-button:disabled {
  color: #8a99b6;
  cursor: not-allowed;
  text-decoration: none;
}

.asset-recover-status {
  margin-top: 8px;
  font-size: 0.84rem;
  color: #33486b;
  min-height: 1.2em;
}

.asset-recover-status.is-error {
  color: #b1203a;
}

.asset-recover-status.is-success {
  color: #1f6f3a;
}

.asset-registry-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
}

.toolbar-row-break {
  flex-basis: 100%;
  height: 0;
  margin: 0;
}

.asset-registry-toolbar-group {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
}

.asset-registry-toolbar-group[hidden] {
  display: none;
}

.mode-toggle-btn {
  border: none;
  border-radius: 0;
  background: #f3f7ff;
  color: #33486b;
  font-size: 0.84rem;
  font-weight: 600;
  padding: 6px 18px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
  flex: 0 0 auto;
}

.mode-toggle-btn:not(:last-child) {
  border-right: 1px solid #c7d4ee;
}

.mode-toggle-btn.active {
  background: #2563eb;
  color: #ffffff;
}

.mode-toggle-btn:not(.active):hover {
  background: #e5edff;
}

.asset-registry-toolbar label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.84rem;
  color: #33486b;
}

.asset-registry-toolbar input,
.asset-registry-toolbar select {
  width: 100%;
  border: 1px solid #c7d4ee;
  border-radius: 8px;
  padding: 8px 10px;
  background: #f8fbff;
  color: #1e2f4d;
}

.hosted-catalog-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.hosted-catalog-toolbar label {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

.hosted-catalog-toolbar select {
  width: auto;
  min-width: 170px;
}

.hosted-catalog-toolbar #hosted-catalog-refresh {
  margin-left: auto;
}

.asset-registry-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  font-size: 0.84rem;
  color: #3f577e;
}

.asset-registry-status {
  margin: 0;
  border: 1px solid #d6deec;
  border-radius: 8px;
  padding: 8px 10px;
  background: #f8fbff;
  color: #223252;
  font-size: 0.84rem;
}

.asset-action-list {
  margin: 0;
  padding-left: 18px;
  color: #33486b;
  font-size: 0.84rem;
  line-height: 1.45;
}

.registry-row {
  align-items: flex-start;
}

.registry-row-text {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.registry-meta-line {
  font-size: 0.75rem;
  color: #445577;
  font-family: "Segoe UI Variable", "Segoe UI", Inter, Roboto, Arial, sans-serif;
}

.registry-badge {
  font-size: 0.72rem;
  border-radius: 999px;
  padding: 2px 8px;
  border: 1px solid #d4dbea;
  font-family: "Segoe UI Variable", "Segoe UI", Inter, Roboto, Arial, sans-serif;
  font-weight: 700;
  letter-spacing: 0.01em;
  flex: 0 0 auto;
}

.registry-badge.ok {
  color: #0f5f3a;
  border-color: #a5dec3;
  background: #e9f8f0;
}

.registry-badge.missing {
  color: #8b1e2f;
  border-color: #efc2c9;
  background: #fff3f5;
}

.registry-badge.config {
  color: #284d8f;
  border-color: #b8caef;
  background: #eef3ff;
}

.registry-badge.public {
  color: #6b4d11;
  border-color: #ead29a;
  background: #fff7dd;
}

.registry-badge.admin {
  color: #113d72;
  border-color: #a9c7f1;
  background: #eaf3ff;
}

.registry-badge.local,
.registry-badge.local-only {
  color: #3b5a2c;
  border-color: #9ecb85;
  background: #eef7e8;
}

.registry-badge.registry-local {
  color: #14532d;
  border-color: #86efac;
  background: #dcfce7;
}

.registry-badge.registry-only {
  color: #713f12;
  border-color: #fde68a;
  background: #fefce8;
}

/* ── Publish-scene form ────────────────────────────────── */
.publish-scene-details { margin-top: 8px; border: 1px solid #d6deec; border-radius: 8px; background: #f8fbff; }
.publish-scene-details summary { padding: 8px 12px; font-size: 0.84rem; font-weight: 600; color: #33486b; cursor: pointer; list-style: none; user-select: none; }
.publish-scene-details summary::before { content: "▸ "; color: #7a96c4; font-size: 0.7rem; }
.publish-scene-details[open] summary::before { content: "▾ "; }
.publish-scene-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; padding: 8px 12px 12px; }
.publish-scene-form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.82rem; color: #33486b; flex: 1 1 160px; }
.publish-scene-form input, .publish-scene-form select { border: 1px solid #c7d4ee; border-radius: 6px; padding: 6px 8px; font-size: 0.84rem; background: #ffffff; color: #1e2f4d; }
.upload-browse-btn { margin-top: 4px; display: inline-block; padding: 6px 16px; border: 1px solid #3b67c7; border-radius: 8px; background: #eef3ff; color: #1f3256; font-size: 0.84rem; font-weight: 600; cursor: pointer; }
.upload-browse-btn:hover { background: #dbe5f7; }
.upload-browse-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.upload-progress-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid #d6deec; }
.upload-progress-list:empty { display: none; }
.upload-progress-item { display: flex; align-items: center; gap: 8px; padding: 7px 14px; font-size: 0.82rem; border-bottom: 1px solid #edf2fb; }
.upload-progress-item:last-child { border-bottom: none; }
.upload-progress-item .up-name { flex: 1; color: #1f3256; font-family: monospace; font-size: 0.78rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.up-status.pending { color: #6b7fa8; } .up-status.uploading { color: #284d8f; } .up-status.ok { color: #0f5f3a; } .up-status.error { color: #8b1e2f; }

/* ── Filter tabs + browser toolbar ─────────────────────── */
.asset-browser-toolbar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; justify-content: space-between; }
.asset-filter-tabs { display: flex; flex-wrap: wrap; gap: 4px; }
.asset-filter-tab { padding: 5px 12px; border: 1px solid #c7d4ee; border-radius: 999px; background: #f0f4fc; color: #33486b; font-size: 0.78rem; font-weight: 500; cursor: pointer; }
.asset-filter-tab:hover { background: #dbe5f7; }
.asset-filter-tab.active, .asset-filter-tab[aria-selected="true"] { background: #1f3256; border-color: #1f3256; color: #ffffff; }
.asset-browser-actions { display: flex; align-items: flex-end; gap: 8px; }
.asset-browser-actions label { display: flex; flex-direction: column; gap: 3px; font-size: 0.78rem; color: #33486b; }
.asset-browser-actions select { border: 1px solid #c7d4ee; border-radius: 8px; padding: 6px 8px; font-size: 0.84rem; background: #f8fbff; color: #1e2f4d; }

/* ── Copy URL button ─────────────────────────────────────── */
.copy-url-btn { padding: 2px 8px; border: 1px solid #c7d4ee; border-radius: 6px; background: #f0f4fc; color: #33486b; font-size: 0.72rem; cursor: pointer; white-space: nowrap; }
.copy-url-btn:hover { background: #dbe5f7; }
.copy-url-btn.copied { background: #e9f8f0; color: #0f5f3a; border-color: #a5dec3; }
/* ── Sortable registry table ────────────────────────────── */

.asset-registry-table-wrap {
  overflow-x: auto;
  border: 1px solid #d6deec;
  border-radius: 10px;
  background: #ffffff;
}

/* Hosted catalog keeps table headers pinned while rows scroll; the table
   takes the catalogue panel's height left over. */
#hosted-catalog-panel .asset-registry-table-wrap {
  flex: 1 1 auto;
  min-height: 180px;
  overflow: auto;
}

/* Beside the preview the catalogue has about two thirds of the width: tighter
   cells, and the name — the one long value — wraps anywhere, so Download and
   Created stay on screen at 1440 and 1024 (tests/scene-studio-assets-browser). */
#hosted-catalog-table th,
#hosted-catalog-table td {
  padding: 6px 6px;
}

#hosted-catalog-table th {
  font-size: 0.68rem;
  letter-spacing: 0.01em;
}

#hosted-catalog-table .catalog-name-cell {
  min-width: 9em;
  overflow-wrap: anywhere;
}

/* "Config · scenegraph (legacy root)" and the like wrap at their spaces. */
#hosted-catalog-table .col-type {
  white-space: normal;
}

#hosted-catalog-table .col-version,
#hosted-catalog-table .col-channel,
#hosted-catalog-table .col-created {
  white-space: nowrap;
}

#hosted-catalog-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: #edf2fb;
}

.asset-registry-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
  color: #1f3256;
  table-layout: auto;
}

.asset-registry-table thead tr {
  background: #edf2fb;
  border-bottom: 1px solid #c7d4ee;
}

.asset-registry-table th {
  padding: 7px 10px;
  text-align: left;
  font-size: 0.73rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #4a6289;
  white-space: nowrap;
  user-select: none;
}

.asset-registry-table th.sortable {
  cursor: pointer;
}

.asset-registry-table th.sortable:hover {
  background: #dbe5f7;
  color: #1f3256;
}

.asset-registry-table th.active-sort {
  color: #1f3256;
  background: #dce6fa;
}

.sort-icon {
  display: inline-block;
  margin-left: 4px;
  opacity: 0.45;
  font-style: normal;
  font-size: 0.8em;
  vertical-align: middle;
}

.sort-icon.asc,
.sort-icon.desc {
  opacity: 1;
  color: #3b67c7;
}

.asset-registry-table tbody tr {
  border-bottom: 1px solid #edf2fb;
  transition: background 0.1s;
}

.asset-registry-table tbody tr:last-child {
  border-bottom: none;
}

.asset-registry-table tbody tr:hover {
  background: #f5f8ff;
}

.asset-registry-table tbody tr.catalog-row-selected {
  background: #e9f2ff;
  outline: 2px solid #4e7bd4;
  outline-offset: -2px;
}

.asset-registry-table td {
  padding: 7px 10px;
  vertical-align: top;
  line-height: 1.35;
}

.asset-registry-table .col-path {
  min-width: 220px;
  font-family: "Cascadia Code", "Consolas", monospace;
  font-size: 0.75rem;
  word-break: break-all;
}

.asset-registry-table .col-url {
  font-family: "Cascadia Code", "Consolas", monospace;
  font-size: 0.72rem;
  color: #33486b;
  word-break: break-all;
  max-width: 300px;
}

.asset-registry-table .col-version,
.asset-registry-table .col-channel,
.asset-registry-table .col-status,
.asset-registry-table .col-type {
  white-space: nowrap;
}

.hosted-cache-action-col {
  white-space: nowrap;
}

.hosted-cache-btn {
  padding: 3px 8px;
  font-size: 0.74rem;
}

.hosted-download-action-col {
  white-space: nowrap;
}

.hosted-download-btn {
  padding: 3px 8px;
  font-size: 0.74rem;
}

.registry-table-empty td {
  text-align: center;
  color: #6b7fa8;
  padding: 18px;
}

/* ── Sample dropdown ───────────────────────────────────── */
.sample-dropdown-wrap {
  position: relative;
  display: inline-flex;
}

.sample-dropdown-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 200;
  min-width: 200px;
  margin: 0;
  padding: 4px 0;
  list-style: none;
  background: #ffffff;
  border: 1px solid #c7d4ee;
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(17, 29, 53, 0.15);
}

.sample-dropdown-menu li {
  padding: 0;
  border: none;
}

.sample-dropdown-menu [role="menuitem"] {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-radius: 0;
  padding: 8px 14px;
  font-size: 0.88rem;
  font-weight: 500;
  color: #1f3256;
  box-shadow: none;
  transform: none;
}

.sample-dropdown-menu [role="menuitem"]:hover {
  background: #eef3ff;
  color: #2f4f89;
  transform: none;
  box-shadow: none;
}

/* ── Breakpoint: 1200px (existing) ─────────────────────── */
@media (max-width: 1200px) {
  .layout {
    grid-template-columns: 1fr;
  }

  /* The stacked frame, on every tab that shows the viewer: the viewer full
     width on top (its canvas capped at ~45% of the window height by the JS
     sizing rule), the tab's documents below it, each at its own height — the
     workspace scrolls instead of squeezing them. */
  .layout {
    grid-auto-rows: max-content;
    overflow-y: auto;
  }

  /* Stacked, the catalogue takes its content height, and the table keeps its
     own scroll so the page does not run to hundreds of rows. */
  #hosted-catalog-panel .asset-registry-table-wrap {
    flex: none;
    max-height: 70vh;
  }

  .viewer-column {
    overflow: visible;
  }

  .view-editor-column,
  .tab-documents {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    grid-auto-rows: max-content;
  }

  /* Stacked, the station list keeps its own scroll, so the Station card below
     it stays one short scroll away however many stations there are. */
  .station-list-panel {
    max-height: 480px;
  }

  .editor-panel textarea {
    min-height: 240px;
  }

  .view-config-editor {
    min-height: 180px;
    max-height: 220px;
  }
}

/* Scene Graph Editor, 769–1200px: the viewer stacks above the documents, and
   the node tree + properties sit beside the Scene Graph card below it. The
   base .layout is flex:1 inside a 100vh body with overflow:hidden, and each
   column has min-height:0, so without a real height the rows would share the
   workspace's ~445px at 768px tall (the node tree once got 40px) and nothing
   would scroll. Give the documents a real height; the workspace scrolls to
   them (the stacked frame above). ≤768px the page itself scrolls and the
   columns take their content height. */
@media (min-width: 769px) and (max-width: 1200px) {
  body[data-workspace-view="scene"] .scene-documents {
    height: max(420px, 72vh);
  }

  /* The tree shares its column with Node Properties; keep enough of it to
     read (the column scrolls to the properties below). Qualified so it
     outranks the base .node-tree-container rule, which comes later. */
  .inspector-column .node-tree-container {
    min-height: 240px;
  }
}

/* The header on a narrow window (2026-09-25): the status would be squeezed
   between the name and the sign-in, so it takes a line of its own, the
   header's whole width, under them — still one line of one height. */
@media (max-width: 960px) {
  .topbar {
    flex-wrap: wrap;
    row-gap: 6px;
  }

  .topbar-status {
    order: 3;
    flex: 1 1 100%;
  }

  /* The badges wrap within their own end of the row rather than widen the
     page: a signed-in badge, diagnostics and the mode line do not fit one
     phone-width line. */
  .topbar-actions {
    margin-left: auto;
    flex: 1 1 auto;
    min-width: 0;
    flex-wrap: wrap;
    row-gap: 6px;
  }
}

/* ── Mobile breakpoint: 768px ──────────────────────────── */
@media (max-width: 768px) {
  body {
    overflow: auto;
    max-height: none;
    height: auto;
  }

  .topbar {
    padding: 8px 16px;
  }

  .topbar-actions {
    flex-wrap: wrap;
  }

  .layout {
    padding: 12px 16px 16px;
    grid-template-columns: 1fr;
    overflow: visible;
    flex: none;
  }

  /* Seven tabs do not fit a phone: the tab bar scrolls sideways within
     itself, one row high, instead of widening the whole page. Its baseline is
     drawn inside it, so the scroll does not clip it. */
  .workspace-tabs {
    padding: 2px 16px 0;
    overflow-x: auto;
    overflow-y: hidden;
  }

  .workspace-tab {
    flex: 0 0 auto;
    white-space: nowrap;
  }

  .hosted-catalog-toolbar #hosted-catalog-refresh {
    margin-left: 0;
  }

  /* Assets on a phone: the preview stacks above the catalogue (the stacked
     frame), and each catalogue row becomes a card — its name first, on a
     line of its own, then its type, version and channel, then what is in
     this browser, then the two buttons and the date — so nothing
     scrolls sideways. The sort headers go; the order stays what it was. */
  #hosted-catalog-table,
  #hosted-catalog-table tbody {
    display: block;
  }

  #hosted-catalog-table thead {
    display: none;
  }

  #hosted-catalog-table tbody tr:not(.registry-table-empty) {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    padding: 8px 10px;
  }

  #hosted-catalog-table tbody tr:not(.registry-table-empty) > td {
    display: block;
    padding: 0;
    min-width: 0;
    font-size: 0.74rem;
    color: #53627e;
  }

  #hosted-catalog-table .catalog-name-cell {
    order: -1;
    flex: 1 1 100%;
    font-size: 0.82rem;
    font-weight: 600;
    color: #1f3256;
  }

  #hosted-catalog-table .col-type {
    font-weight: 600;
    color: #4a6289;
  }

  #hosted-catalog-table .col-cache {
    flex: 1 1 100%;
  }

  #hosted-catalog-table .col-cache::before {
    content: attr(data-label) ": ";
  }

  #hosted-catalog-table .col-created {
    margin-left: auto;
  }

  .viewer-canvas {
    width: 100%;
  }

  /* On a phone the Scene Graph Editor's documents stack too: the node tree
     and properties above the Scene Graph card. */
  .scene-documents {
    grid-template-columns: minmax(0, 1fr);
  }


  .sample-dropdown-menu {
    left: 0;
    right: auto;
    min-width: 180px;
  }
}

.toggle-switch {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  color: #405273;
  cursor: pointer;
  user-select: none;
  background: rgba(255, 255, 255, 0.4);
  padding: 4px 8px;
  border-radius: 6px;
  border: 1px solid rgba(203, 213, 225, 0.5);
  transition: all 0.2s;
}

.viewer-actions .toggle-switch {
  border: 1px solid #c7d4ee;
  background: #eef3ff;
  color: #3c567f;
  font-size: 10px;
  gap: 5px;
  padding: 2px 6px;
  border-radius: 999px;
  line-height: 1.1;
}

.viewer-actions .toggle-switch:hover {
  background: #e1e9fc;
  border-color: #a3badf;
}

.viewer-actions>button {
  padding: 4px 8px;
}

.toggle-switch:hover {
  background: #ffffff;
  border-color: #cbd5e1;
}

.toggle-switch input[type="checkbox"] {
  width: 11px;
  height: 11px;
  accent-color: #3b82f6;
  cursor: pointer;
}

/* ------------------------------------------------------------------ */
/* R-UI-2 / R-UI-4 / R-UI-6: Node Tree Inspector & Properties Panels  */
/* ------------------------------------------------------------------ */

.node-tree-panel,
.node-properties-panel {
  flex: 1;
  min-height: 0;
}

.node-tree-search-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
}

#node-tree-search {
  flex: 1;
  padding: 4px 8px;
  border: 1px solid var(--btn-secondary-border, #cbd5e1);
  border-radius: 4px;
  background: #ffffff;
  color: #172033;
  font-size: 0.85rem;
}

#node-tree-search:focus {
  outline: 2px solid #3b82f6;
  outline-offset: 1px;
}

.node-tree-container {
  flex: 1;
  min-height: 40px;
  overflow-y: auto;
}

.tree-empty-hint {
  color: #64748b;
  font-size: 0.8rem;
  margin: 4px 0;
}

.tree-node {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 6px;
  border-radius: 4px;
  cursor: pointer;
  user-select: none;
}

.tree-node:hover {
  background: rgba(59, 130, 246, 0.06);
}

.tree-node.selected {
  background: rgba(59, 130, 246, 0.12);
  outline: 1px solid rgba(59, 130, 246, 0.3);
}

.tree-node:focus {
  outline: 2px solid #3b82f6;
  outline-offset: 1px;
}

.tree-node-indent {
  display: inline-block;
  flex-shrink: 0;
}

.tree-node-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  color: #64748b;
  width: 16px;
}

.tree-node-icon svg {
  display: block;
}

.tree-node-type {
  font-size: 0.7rem;
  padding: 1px 5px;
  border-radius: 3px;
  background: #e2e8f0;
  color: #475569;
  flex-shrink: 0;
}

.tree-node-id {
  font-size: 0.85rem;
  font-family: monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Node Properties Panel */
.node-properties-container {
  padding: 4px 0;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.node-prop-empty {
  color: #64748b;
  font-size: 0.8rem;
  margin: 4px 0;
}

.node-prop-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
  font-size: 0.85rem;
  margin: 0;
}

.node-prop-label {
  color: #64748b;
  font-size: 0.8rem;
  white-space: nowrap;
}

.node-prop-value {
  font-family: monospace;
  word-break: break-all;
  margin: 0;
}

/* ------------------------------------------------------------------ */
/* Admin-mode node property form                                        */
/* ------------------------------------------------------------------ */
.node-prop-form {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.82rem;
}
.node-prop-form-section {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid #e2e8f0;
}
.node-prop-form-section-title {
  font-size: 0.7rem;
  font-weight: 700;
  color: #475569;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 4px;
}
.node-prop-field {
  display: grid;
  grid-template-columns: 100px 1fr;
  gap: 4px;
  align-items: center;
}
.node-prop-field label {
  color: #64748b;
  font-size: 0.78rem;
  white-space: nowrap;
}
.node-prop-field input,
.node-prop-field select {
  width: 100%;
  padding: 3px 6px;
  border: 1px solid #cbd5e1;
  border-radius: 4px;
  font-size: 0.82rem;
  background: #ffffff;
  color: #172033;
}
.node-prop-field input[readonly] {
  background: #f1f5f9;
  color: #64748b;
}
.node-prop-apply-btn {
  margin-top: 8px;
  padding: 5px 14px;
  background: #3b82f6;
  color: #ffffff;
  border: none;
  border-radius: 6px;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
}
.node-prop-apply-btn:hover {
  background: #2563eb;
}
.node-prop-apply-feedback {
  font-size: 0.78rem;
  color: #16a34a;
  margin-top: 4px;
}
/* Tree move buttons (admin mode) */
.tree-node-actions {
  margin-left: auto;
  display: flex;
  gap: 2px;
  flex-shrink: 0;
}
.tree-move-btn {
  background: none;
  border: 1px solid #cbd5e1;
  border-radius: 3px;
  padding: 1px 4px;
  font-size: 0.7rem;
  cursor: pointer;
  color: #64748b;
  line-height: 1;
}
.tree-move-btn:hover {
  background: #e2e8f0;
}
.tree-add-btn:hover {
  color: #16a34a;
  border-color: #16a34a;
}
.tree-del-btn:hover {
  color: #dc2626;
  border-color: #dc2626;
}
.tree-add-root-bar {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed #e2e8f0;
}
.tree-add-root-btn {
  display: flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: 1px dashed #cbd5e1;
  border-radius: 4px;
  padding: 3px 8px;
  font-size: 0.75rem;
  color: #64748b;
  cursor: pointer;
  width: 100%;
  justify-content: center;
}
.tree-add-root-btn:hover {
  border-color: #3b82f6;
  color: #3b82f6;
}

/* ------------------------------------------------------------------ */
/* Config Form View (replaces generic tree inspector)                   */
/* ------------------------------------------------------------------ */

/* Scrollable container shared by all config form panels. */
.cfg-form-container {
  overflow-y: auto;
  max-height: 360px;
  border: 1px solid #cfd7e6;
  border-radius: 6px;
  padding: 8px 10px;
  background: #f8faff;
  margin-bottom: 6px;
}

/* The form inside the container reuses node-prop-form styles.
   Override label column width to be a bit narrower in these compact panels. */
.cfg-form-container .node-prop-field {
  grid-template-columns: 120px 1fr;
}

/* The Station form's key fields (C10): the document dropdown, then a small
   Open button at the END of the row that opens that document in its card and
   tab. The button's column is always there, so every row is one line and the
   dropdowns line up whether or not a key is set. */
.cfg-doc-key {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 3.1rem;
  gap: 4px;
  align-items: center;
  min-width: 0;
}

.cfg-doc-link-slot {
  display: block;
  min-width: 0;
}

.cfg-doc-link,
.cfg-doc-link:hover {
  width: 100%;
  padding: 2px 0;
  border-radius: 4px;
  box-shadow: none;
  transform: none;
  font-size: 0.72rem;
  line-height: 1.3;
}

.cfg-doc-link[hidden] {
  display: none;
}

/* A dropdown that names a document (config-form.js documentSelect): never
   wider than its cell, whatever its longest "Name · key" option. A key that is
   not published is kept, and the select turns amber — the border and fill
   only, so the row keeps its height. */
.node-prop-field select[data-doc-kind] {
  min-width: 0;
  text-overflow: ellipsis;
}

.node-prop-field select[data-doc-state="missing"] {
  border-color: #f59e0b;
  background: #fffbeb;
  color: #92400e;
}

/* Field note — the coupling a label cannot carry (e.g. that ambientIntensity
   only applies when every light is disabled). Spans both grid columns. */
.cfg-field-hint {
  display: block;
  grid-column: 1 / -1;
  margin: -2px 0 4px;
  color: #64748b;
  font-size: 0.7rem;
  line-height: 1.35;
}

/* The Layers form's ONE flat table (VIEW_SETTINGS_MODEL.md §5 step 5): a row
   per publishable layer in registry order — label, show box, departure mark —
   and the node-override rows beneath, in the same shape. The label column
   takes the slack and wraps, so a long label never pushes the box out of a
   narrow card. */
.cfg-layers-table {
  width: 100%;
  border-collapse: collapse;
  table-layout: auto;
  font-size: 0.8rem;
}
.cfg-layers-table th {
  text-align: left;
  font-size: 0.68rem;
  font-weight: 600;
  color: #64748b;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 4px 4px;
  border-bottom: 1px solid #e2e8f0;
}
.cfg-layers-table td {
  padding: 2px 4px;
  border-bottom: 1px solid #eef2f7;
  vertical-align: middle;
}
.cfg-layers-table .cfg-layer-label {
  width: 100%;
  color: #334155;
  overflow-wrap: break-word;
}
.cfg-layers-table .cfg-layer-wide select {
  max-width: 100%;
  margin-left: 4px;
}
.cfg-layers-table .cfg-layer-label label {
  cursor: pointer;
}
.cfg-layers-table .cfg-layer-show,
.cfg-layers-table .cfg-layer-departs,
.cfg-layers-table .cfg-node-override-remove {
  white-space: nowrap;
  text-align: center;
}
.cfg-layers-table .cfg-layer-show {
  width: 1%;
}
.cfg-layers-table select {
  padding: 2px 4px;
  border: 1px solid #cbd5e1;
  border-radius: 4px;
  font-size: 0.78rem;
  background: #ffffff;
  color: #172033;
}
.cfg-layers-table tr[data-departs="true"] .cfg-layer-label {
  font-weight: 600;
  color: #172033;
}
.cfg-departure-mark {
  display: inline-block;
  padding: 0 6px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e;
  font-size: 0.66rem;
  font-weight: 600;
  line-height: 1.5;
}
.cfg-node-overrides-table {
  margin-bottom: 6px;
}
/* Add a node override: the id field takes the width, the button keeps its
   one line. */
.cfg-node-add-row {
  display: flex;
  gap: 6px;
  align-items: center;
}
.cfg-node-add-row input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 3px 6px;
  border: 1px solid #cbd5e1;
  border-radius: 4px;
  font-size: 0.8rem;
  background: #ffffff;
  color: #172033;
}
.cfg-node-add-row button {
  flex: 0 0 auto;
  white-space: nowrap;
}
.cfg-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* View toggle button in panel head */
.cfg-view-toggle {
  font-size: 0.72rem;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
  flex-shrink: 0;
}

