:root {
  /* Construct brand palette — monochrome charcoal (matches apps.construct-ent.com). */
  --bg: #161616;
  --panel: #1d1d1d;
  --panel-2: #232323;
  --border: #2b2b2b;
  --text: #f7f7f7;
  --muted: #a4a4a4;
  /* "Accent" is a light-grey emphasis fill; every accent fill in this sheet
     pairs with white text, so mid-grey keeps them readable. Primary CTAs go
     white instead — see the .primary rules. */
  --accent: #555555;
  --accent-hover: #666666;
  /* Kept as the one functional colour: the 3D fixture-selection highlight. */
  --selected: #ffb84a;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  font-size: 13px;
  background: var(--bg);
  color: var(--text);
  overflow: hidden;
}

#app {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;
  background: #0d0d0d;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.title {
  font-weight: 600;
  font-size: 14px;
}

.actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.btn {
  display: inline-block;
  padding: 6px 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 0;
  cursor: pointer;
  font-size: 13px;
  font-family: inherit;
}
.btn:hover:not(:disabled) {
  background: var(--accent);
  border-color: var(--accent);
}
.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

#status {
  color: var(--muted);
  font-size: 12px;
  margin-left: 8px;
}

#gdtfshare-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 4px;
  padding: 4px 10px;
  border-radius: 0;
  font-size: 11px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--muted);
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
#gdtfshare-status:hover { color: var(--text); }
#gdtfshare-status::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #666;
}
#gdtfshare-status[data-state="loggedout"]::before { background: #666; }
#gdtfshare-status[data-state="loggedin"]::before  { background: #4ade80; }
#gdtfshare-status[data-state="loggedin"]          { color: var(--text); }
#gdtfshare-status[data-state="error"]::before     { background: #f87171; }
/* The explicit display above out-specifies the UA [hidden] rule, so hiding the
   pill (GDTF Share unreachable) needs this. */
#gdtfshare-status[hidden] { display: none; }

/* Modal */
.modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
}
.modal.hidden { display: none; }
.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0.6);
}
.modal-content {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 16px 18px;
  width: 360px;
  max-width: 90vw;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.modal-title {
  margin: 0 0 12px 0;
  font-size: 14px;
  font-weight: 600;
}
.modal-body { font-size: 12px; }
.modal-body .form-row {
  margin-bottom: 10px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.modal-body label { color: var(--muted); font-size: 11px; }
.modal-body input[type="email"],
.modal-body input[type="password"],
.modal-body input[type="text"] {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 8px;
  border-radius: 0;
  font-family: inherit;
  font-size: 12px;
}
.modal-body input:focus { outline: none; border-color: var(--accent); }
.modal-body .checkbox-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 12px;
}
.modal-body .checkbox-row label { color: var(--text); }
.modal-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 8px;
}
.modal-actions button {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 14px;
  border-radius: 0;
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
}
.modal-actions button.primary {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
}
.modal-actions button:hover:not(:disabled) { filter: brightness(1.15); }
.modal-actions button:disabled { opacity: 0.5; cursor: wait; }
.modal-error {
  background: rgba(248, 113, 113, 0.15);
  border: 1px solid rgba(248, 113, 113, 0.5);
  color: #fca5a5;
  padding: 6px 8px;
  border-radius: 0;
  font-size: 11px;
  margin-bottom: 10px;
}
.modal-info {
  font-size: 11px;
  color: var(--muted);
  margin-bottom: 10px;
}

main {
  display: flex;
  flex: 1;
  min-height: 0;
  position: relative;
}

:root {
  /* Driven by the JS drag handle + localStorage. Clamped to the same range
     the resize handle enforces (240px..720px). */
  --sidebar-width: 320px;
}
#sidebar {
  width: var(--sidebar-width);
  background: var(--panel);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  flex-shrink: 0;
}
/* No width transition while the user is actively dragging — instant feedback. */
#sidebar:not(.dragging) { transition: width 0.18s ease; }
#sidebar.collapsed {
  width: 0;
  border-right-width: 0;
}
#sidebar-toggle {
  position: absolute;
  z-index: 10;
  left: var(--sidebar-width);
  top: 50%;
  transform: translate(-50%, -50%);
  width: 18px;
  height: 36px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: none;
  border-radius: 0;
  color: var(--muted);
  cursor: pointer;
  font-size: 12px;
  padding: 0;
  font-family: inherit;
}
#sidebar:not(.dragging) ~ #sidebar-toggle { transition: left 0.18s ease; }
#sidebar-toggle:hover { color: var(--text); background: var(--panel-2); }
body.sidebar-collapsed #sidebar { width: 0; border-right-width: 0; }
body.sidebar-collapsed #sidebar-toggle { left: 0; }
body.sidebar-collapsed #sidebar-resize { display: none; }

/* Vertical drag handle pinned to the right edge of the sidebar. Sits flush
   with the border (4px wide hit target, invisible until hover). On drag,
   #sidebar gets a .dragging class which disables the width transition. */
#sidebar-resize {
  position: absolute;
  z-index: 11;
  left: calc(var(--sidebar-width) - 2px);
  top: 0;
  bottom: 0;
  width: 6px;
  cursor: ew-resize;
  background: transparent;
  user-select: none;
}
#sidebar-resize:hover,
#sidebar-resize.dragging {
  background: var(--accent);
  opacity: 0.55;
}
#sidebar:not(.dragging) ~ #sidebar-resize { transition: left 0.18s ease; }
/* While dragging anywhere on the page, force the resize cursor + suppress
   pointer events on the rest of the viewer so the canvas doesn't steal
   mouse moves. */
body.sidebar-dragging,
body.sidebar-dragging * { cursor: ew-resize !important; user-select: none; }
body.sidebar-dragging #viewer { pointer-events: none; }

.panel {
  border-bottom: 1px solid var(--border);
  padding: 12px;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.panel.grow {
  flex: 1;
  overflow: hidden;
}
.panel h2 {
  margin: 0 0 8px 0;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
}

.tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
  margin: -12px -12px 8px -12px;
  padding: 0 8px;
  flex-shrink: 0;
}
.tab {
  background: none;
  border: none;
  color: var(--muted);
  padding: 8px 12px;
  cursor: pointer;
  font-size: 12px;
  font-family: inherit;
  font-weight: 500;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tab:hover { color: var(--text); }
.tab.active {
  color: var(--text);
  border-bottom-color: var(--accent);
}

.tab-pane {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
.tab-pane.hidden { display: none; }

.list-header {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
  padding: 4px 8px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.list-toolbar {
  display: flex;
  gap: 4px;
  padding: 4px 0;
  flex-shrink: 0;
  flex-wrap: wrap;
}
.list-toolbar button {
  flex: 1;
  min-width: 48px;
  padding: 4px 6px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 0;
  font-size: 10px;
  font-family: inherit;
  cursor: pointer;
}
.list-toolbar button:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: white;
}

.slider-row {
  display: grid;
  grid-template-columns: 48px 1fr 40px;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
  font-size: 11px;
}
.slider-row label {
  color: var(--muted);
}
.slider-row input[type="range"] {
  width: 100%;
  accent-color: var(--accent);
}
.slider-row span {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  text-align: right;
}

.item-list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  flex: 1;
}
.item-list li {
  padding: 6px 8px;
  border-radius: 0;
  cursor: pointer;
  font-size: 12px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.item-list li:hover { background: var(--panel-2); }
.item-list li.selected {
  background: var(--accent);
  color: white;
}

.fixture-row {
  display: grid;
  grid-template-columns: 42px 1fr 70px 18px;
  gap: 8px;
  align-items: center;
}
.fixture-row .unit {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  text-align: right;
}
.fixture-row .name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fixture-row .addr {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  text-align: right;
  font-size: 11px;
}
.item-list li.selected .unit,
.item-list li.selected .addr { color: rgba(255,255,255,0.85); }

.object-row .type-badge {
  font-size: 10px;
  padding: 1px 5px;
  border-radius: 0;
  background: var(--panel-2);
  color: var(--muted);
  flex-shrink: 0;
}
.item-list li.selected .type-badge {
  background: rgba(255,255,255,0.2);
  color: white;
}
.object-row .obj-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.vis-toggle {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 12px;
  padding: 0;
  cursor: pointer;
  width: 18px;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  flex-shrink: 0;
}
.vis-toggle:hover { color: var(--text); }
.item-list li.hidden-object { opacity: 0.45; }
.item-list li.hidden-object .vis-toggle { color: var(--muted); }
.item-list li.selected .vis-toggle { color: white; }

.profile-list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  flex: 1;
}
.profile-list li {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.profile-name {
  font-size: 12px;
  font-weight: 500;
  color: var(--text);
}
.profile-spec {
  font-size: 10px;
  color: var(--muted);
  word-break: break-all;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.profile-meta {
  font-size: 11px;
  color: var(--muted);
}
.profile-actions {
  display: flex;
  gap: 6px;
  margin-top: 4px;
}
.profile-actions a, .profile-actions button {
  flex: 1;
  padding: 4px 8px;
  font-size: 11px;
  text-align: center;
  text-decoration: none;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 0;
  cursor: pointer;
  font-family: inherit;
}
.profile-actions a:hover, .profile-actions button:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: white;
}
.profile-row.replaced .profile-name::after {
  content: ' · replaced';
  color: var(--accent);
  font-weight: 500;
}
.profile-list li.drag-target {
  background: rgba(255, 255, 255, 0.08);
  outline: 1px dashed var(--accent);
  outline-offset: -2px;
}

.gdtf-share-results {
  margin-top: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 4px;
  max-height: 240px;
  overflow-y: auto;
}
.gdtf-share-result {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  border-radius: 0;
  font-size: 11px;
}
.gdtf-share-result:hover { background: var(--panel-2); }
.gdtf-share-result .gsr-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
}
.gdtf-share-result button {
  background: var(--accent);
  border: none;
  color: white;
  padding: 3px 8px;
  border-radius: 0;
  font-size: 10px;
  cursor: pointer;
  flex-shrink: 0;
}
.gdtf-share-result button:disabled {
  background: var(--panel-2);
  color: var(--muted);
  cursor: wait;
}

.profile-mode-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  font-size: 11px;
}
.profile-mode-row label {
  width: 36px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-size: 10px;
}
.profile-mode-row select {
  flex: 1;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 3px 6px;
  border-radius: 0;
  font-size: 11px;
  font-family: inherit;
  min-width: 0;
}
.profile-mode-row select:focus { outline: none; border-color: var(--accent); }
.profile-mode-row select option[disabled] { color: #f87171; }

.replace-mode-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  font-size: 11px;
  flex-wrap: wrap;
}
.replace-mode-toggle > label {
  width: 36px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-size: 10px;
}
.replace-mode-toggle .seg-group {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 0;
  overflow: hidden;
}
.replace-mode-toggle .seg-group button {
  background: var(--panel-2);
  border: none;
  color: var(--muted);
  padding: 3px 8px;
  font-size: 11px;
  font-family: inherit;
  cursor: pointer;
}
.replace-mode-toggle .seg-group button:not(:last-child) {
  border-right: 1px solid var(--border);
}
.replace-mode-toggle .seg-group button:hover { color: var(--text); }
.replace-mode-toggle .seg-group button.active {
  background: var(--accent);
  color: white;
}
.replace-mode-toggle .replace-src {
  font-size: 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#properties {
  font-size: 12px;
  max-height: 240px;
  overflow-y: auto;
}
/* Test-mode panel takes over the full sidebar (and grows tall). */
#properties:has(.test-mode-panel) {
  max-height: none;
  flex: 1;
  min-height: 0;
}

/* When test mode is active, collapse the other sidebar panels (Scene,
   Fixtures/Profiles tab list, Lighting) so the test console gets the whole
   sidebar height — Presets stay sticky at the top, Channels scroll below.
   The user is focused on one fixture; the rest is noise until they exit. */
body.test-mode-active .panel:not(:has(#properties)) {
  display: none;
}
body.test-mode-active .panel:has(#properties) {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
/* Presets grid stays a fixed block; the Channels list takes the remaining
   vertical space inside the test-mode-panel and gets its own scrollbar so
   the user never sees the sidebar's outer scrollbar OR a clipped UI. */
body.test-mode-active .test-mode-panel {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* Beam + Room level sliders at the top of the test console. */
.test-mode-levels {
  padding: 6px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
body.test-mode-active .test-mode-channels {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  /* Reserve space for the scrollbar so text + value labels don't slide
     under it. `scrollbar-gutter` is the modern way (Chrome 94+, Safari
     14.1+, Firefox 97+) — falls back to the padding-right on older
     browsers. */
  scrollbar-gutter: stable;
  padding-right: 12px;
}
.test-mode-enter-btn {
  width: 100%;
  margin: 0 0 10px;
  background: var(--accent);
  color: white;
  border-color: var(--accent);
}
.test-mode-enter-btn:hover { filter: brightness(1.1); }

/* ─── Test mode panel ──────────────────────────────────────────────────── */
.test-mode-panel {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.test-mode-head {
  padding: 6px 8px;
  background: var(--panel-2);
  border: 1px solid var(--accent);
  border-radius: 0;
  margin-bottom: 4px;
}
.test-mode-head .prop-group-title {
  color: var(--accent);
  font-weight: 600;
  margin: 0 0 4px;
}
.test-mode-source { margin-top: 6px; }
.test-mode-source .seg-group {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 0;
  overflow: hidden;
  width: 100%;
}
.test-mode-source .seg-group button {
  flex: 1;
  background: var(--panel-2);
  border: none;
  color: var(--muted);
  padding: 4px 8px;
  font-size: 11px;
  font-family: inherit;
  cursor: pointer;
}
.test-mode-source .seg-group button:not(:last-child) {
  border-right: 1px solid var(--border);
}
.test-mode-source .seg-group button:hover { color: var(--text); }
.test-mode-source .seg-group button.active {
  background: var(--accent);
  color: white;
}

.test-mode-presets {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 4px;
}
.test-preset {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 4px 6px;
  font-size: 11px;
  font-family: inherit;
  border-radius: 0;
  cursor: pointer;
}
.test-preset:hover { background: var(--border); }

.test-mode-slider {
  display: grid;
  grid-template-columns: 30px 1fr 44px;
  align-items: center;
  gap: 6px;
  margin-bottom: 4px;
  font-size: 11px;
}
.test-slider-label {
  grid-column: 1 / 4;
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-top: 4px;
  margin-bottom: 1px;
}
.test-slider-label .ch-num {
  display: inline-block;
  min-width: 44px;
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  font-weight: 600;
  text-align: right;
  white-space: nowrap;
}
.test-slider-label .ch-attr { color: var(--text); }
.test-slider-label .ch-addr {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px;
  margin-left: auto;
}
.test-mode-slider input[type="range"] {
  grid-column: 2 / 3;
  width: 100%;
  accent-color: var(--accent);
}
.test-mode-slider input[type="range"]:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.test-mode-slider .test-slider-val {
  grid-column: 3 / 4;
  text-align: right;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--muted);
  font-size: 10px;
}
.prop-row {
  display: flex;
  align-items: center;
  margin-bottom: 4px;
  gap: 8px;
}
.prop-row label {
  width: 80px;
  color: var(--muted);
  font-size: 11px;
  flex-shrink: 0;
}
.prop-row input, .prop-row .prop-value {
  flex: 1;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 3px 6px;
  border-radius: 0;
  font-family: inherit;
  font-size: 12px;
  min-width: 0;
}
.prop-row input:focus {
  outline: none;
  border-color: var(--accent);
}
.prop-row .prop-value {
  background: transparent;
  border-color: transparent;
}
.prop-group {
  margin-bottom: 12px;
}
.prop-group-title {
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 6px;
}
.xyz-row {
  display: flex;
  gap: 4px;
}
.xyz-row input {
  flex: 1;
  width: 0;
}

#viewer {
  flex: 1;
  position: relative;
  background: #0f0f0f;
  min-width: 0;
}

#canvas {
  display: block;
  width: 100%;
  height: 100%;
}

#drop-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  text-align: center;
  pointer-events: none;
  transition: opacity 0.2s;
}
#drop-overlay.hidden {
  opacity: 0;
  pointer-events: none;
  display: none;
}
#drop-overlay.drag-active {
  background: rgba(255, 255, 255, 0.08);
  outline: 2px dashed var(--accent);
  outline-offset: -20px;
}
#drop-overlay p {
  margin: 4px 0;
  font-size: 14px;
}
#drop-overlay code {
  background: var(--panel-2);
  padding: 2px 6px;
  border-radius: 0;
}

/* Empty-state welcome (first run) — the overlay is pointer-events:none so drops
   pass through; the card re-enables pointers for its buttons. */
.welcome {
  pointer-events: auto;
  max-width: 480px;
  padding: 0 24px;
}
.welcome-title {
  font-family: 'Squada One', 'Oswald', 'Arial Narrow', sans-serif;
  font-size: 42px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
  margin-bottom: 16px;
}
.welcome-lead {
  color: var(--muted);
  font-size: 14px;
  line-height: 1.6;
  margin: 0 0 22px;
}
.welcome-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}
.welcome-actions .btn { padding: 10px 18px; font-size: 13px; }
.welcome-actions .btn.primary {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
}
.welcome-actions .btn.primary:hover {
  background: #ffffff;
  border-color: #ffffff;
}
.welcome-hint { margin-top: 18px; font-size: 12px; }

#hud {
  position: absolute;
  bottom: 8px;
  left: 8px;
  font-size: 11px;
  color: var(--muted);
  background: rgba(0,0,0,0.4);
  padding: 4px 8px;
  border-radius: 0;
  pointer-events: none;
}

#gizmo-mode,
#view-buttons {
  position: absolute;
  top: 8px;
  display: flex;
  gap: 2px;
  background: rgba(0,0,0,0.5);
  border-radius: 0;
  padding: 2px;
  z-index: 5;
}
#gizmo-mode  { left: 8px; }
#view-buttons { right: 8px; }
#gizmo-mode button,
#view-buttons button {
  background: transparent;
  border: none;
  color: var(--muted);
  padding: 4px 10px;
  border-radius: 0;
  cursor: pointer;
  font-size: 11px;
  font-family: inherit;
}
#gizmo-mode button:hover,
#view-buttons button:hover { color: var(--text); }
#gizmo-mode button.active,
#view-buttons button.active {
  background: var(--accent);
  color: white;
}

.muted { color: var(--muted); }

/* ────────────────────────────────────────────────────────────────────────
   The manual/bridge source toggle stays hidden: the Art-Net WebSocket
   bridge was removed with the editor-only split (live DMX lives in the
   native app), so "Live DMX" has nothing to connect to. Presets + channel
   sliders are visible again — they drive the test-mode simple visualizer.
   ──────────────────────────────────────────────────────────────────────── */
body.vis-disabled .test-mode-source {
  display: none !important;
}

/* ────────────────────────────────────────────────────────────────────────
   Right-click context menu on fixture/object list rows. Tiny floating
   block positioned at the cursor; one action ("Delete") for now.
   ──────────────────────────────────────────────────────────────────────── */
.ctx-menu {
  position: fixed;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 0;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
  padding: 4px 0;
  min-width: 120px;
  z-index: 1000;
}
.ctx-menu.hidden { display: none; }
.ctx-item {
  display: block;
  width: 100%;
  background: none;
  border: none;
  text-align: left;
  padding: 6px 14px;
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.ctx-item:hover { background: var(--panel-2); }

/* ────────────────────────────────────────────────────────────────────────
   Header status error variant + toast notifications (friendlier than the
   browser alert() they replace).
   ──────────────────────────────────────────────────────────────────────── */
#status.status-error { color: #ff6b6b; }

#toast-host {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  z-index: 2000;
  pointer-events: none;
  padding: 0 16px;
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 0;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 13px;
  line-height: 1.45;
  max-width: min(92vw, 460px);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
  animation: toast-in 0.18s ease-out;
}
.toast-error   { border-color: #a33; background: #2a1d1d; }
.toast-success { border-color: #3a7; background: #1d2a22; }
.toast-msg { flex: 1; }
.toast-close {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 0 2px;
  flex-shrink: 0;
}
.toast-close:hover { color: var(--text); }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* ────────────────────────────────────────────────────────────────────────
   Small-screen / touch gate. The viewer needs a keyboard + mouse (WASD fly,
   drag-look, gizmos), so on phones/small tablets we show a "desktop
   recommended" card rather than the cramped desktop layout. Dismissible.
   ──────────────────────────────────────────────────────────────────────── */
#mobile-gate { display: none; }
.mobile-gate-card {
  max-width: 340px;
  text-align: center;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 28px 24px;
}
.mobile-gate-title { font-size: 20px; font-weight: 700; margin-bottom: 14px; }
.mobile-gate-card p { margin: 0 0 12px; line-height: 1.5; font-size: 14px; }
.mobile-gate-card button {
  margin-top: 8px;
  padding: 10px 18px;
  font: inherit;
  cursor: pointer;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 0;
}
.mobile-gate-card button:hover { background: var(--accent-hover); }

@media (max-width: 760px), (pointer: coarse) and (max-width: 1024px) {
  #mobile-gate {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 3000;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: var(--bg);
  }
  html.mobile-gate-dismissed #mobile-gate { display: none; }

  /* If they continue anyway, keep the header from overflowing and drop the
     keyboard cheatsheet (useless without a keyboard). */
  header { flex-wrap: wrap; gap: 6px; padding: 8px 10px; }
  .actions { flex-wrap: wrap; gap: 6px; }
  #hud { display: none; }
}

/* ────────────────────────────────────────────────────────────────────────
   Construct brand — header wordmark + "More tools" family menu. Matches the
   apps.construct-ent.com storefront: Squada One display face, monochrome
   charcoal, the "-WorkZ" suffix stepped down in grey (.wz).
   ──────────────────────────────────────────────────────────────────────── */
@font-face {
  font-family: 'Squada One';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/squada-one.woff2') format('woff2');
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  text-decoration: none;
  color: var(--text);
}
.brand-logo { height: 30px; width: 30px; display: block; }
.wordmark {
  font-family: 'Squada One', 'Oswald', 'Arial Narrow', sans-serif;
  font-size: 22px;
  letter-spacing: 0.06em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
}
.wz { color: var(--muted); }
.brand:hover .wz { color: var(--text); }

/* Give the mobile gate title the same brand face. */
.mobile-gate-title {
  font-family: 'Squada One', 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* "More tools" dropdown */
.menu { position: relative; display: inline-block; }
.menu-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 250px;
  background: #0d0d0d;
  border: 1px solid var(--border);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.55);
  z-index: 1500;
  display: flex;
  flex-direction: column;
}
.menu-dropdown.hidden { display: none; }
.menu-dropdown a {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 14px;
  color: var(--muted);
  text-decoration: none;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border);
}
.menu-dropdown a:last-child { border-bottom: none; }
.menu-dropdown a:hover { background: #1d1d1d; color: var(--text); }
.menu-dropdown .wz { color: #6f7070; }
.menu-dropdown a:hover .wz { color: var(--muted); }
.menu-sub {
  font-size: 10px;
  letter-spacing: 0.02em;
  text-transform: none;
  color: #6f7070;
}
.menu-all { color: var(--text) !important; font-weight: 700; }

/* ────────────────────────────────────────────────────────────────────────
   First-run legal gate (click-through Terms / Privacy acceptance) and the
   in-app persistent legal links. The gate shows by default (fail-closed) and
   is hidden once the visitor has accepted the current Terms version — the
   inline scripts in index.html add html.legal-accepted. It sits above every
   other overlay, including the mobile gate (z-index 3000).
   ──────────────────────────────────────────────────────────────────────── */
#legal-gate {
  position: fixed;
  inset: 0;
  z-index: 4000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--bg);
  overflow-y: auto;
}
html.legal-accepted #legal-gate { display: none; }

.legal-gate-card {
  max-width: 480px;
  width: 100%;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  padding: 30px 30px 26px;
}
.legal-gate-title {
  font-family: 'Squada One', 'Oswald', 'Arial Narrow', sans-serif;
  font-size: 30px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
  margin-bottom: 4px;
}
.legal-gate-lead { color: var(--muted); margin: 0 0 16px; font-size: 13px; }
.legal-gate-card p { line-height: 1.55; font-size: 13.5px; }
.legal-gate-card strong { color: #fff; }
.legal-gate-links { margin: 14px 0 20px; }
.legal-gate-card a { color: var(--text); text-decoration: underline; }
.legal-gate-card a:hover { color: #fff; }
.legal-gate-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.legal-gate-actions .btn { padding: 10px 16px; }
.legal-gate-fine { color: var(--muted); font-size: 11px; margin: 16px 0 0; }

/* Persistent legal links: sidebar footer + welcome overlay line. */
#sidebar-legal {
  padding: 14px 2px 2px;
  color: var(--muted);
  font-size: 10.5px;
  line-height: 1.5;
}
#sidebar-legal a { color: var(--muted); text-decoration: none; }
#sidebar-legal a:hover { color: var(--text); text-decoration: underline; }

.welcome-legal { font-size: 11.5px; margin-top: 14px; }
.welcome-legal a { color: var(--muted); text-decoration: underline; }
.welcome-legal a:hover { color: var(--text); }
