/* Group sidebar widths — collapsed (icon rail) and expanded (icons + labels).
   Shared by the panel itself and by the shift rules that keep the toolbar, the
   play/pause button and the splat slider clear of it, so they can't drift. */
/* The accent — the one colour a config may change (group `ui.accent`, page
   `look.accent`; applied by applyAccent in src/ui.js, which also picks black or
   white for `--accent-fg`, the text that sits ON it). */
:root {
  --accent: #00d2ff;
  --accent-hover: color-mix(in srgb, var(--accent) 78%, #fff);
  --accent-fg: #000;
}

:root {
  --sidebar-rail-w: 48px;
  --sidebar-w: 220px;
}

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: #111;
  font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  color: #eee;
  user-select: none;
  -webkit-user-select: none;
}

canvas#app {
  /* Pin to the viewport (not normal flow). iOS reports stale dimensions during
     an orientation flip, so PlayCanvas can briefly size the canvas to the old
     (portrait) height; keeping it `fixed` stops that over-tall canvas from
     making the document scrollable, which is what mis-positions the fixed
     overlay and makes its buttons untappable in landscape. */
  position: fixed;
  inset: 0;
  display: block;
  width: 100vw;
  height: 100vh;
  touch-action: none;
}

canvas.measure-cursor { cursor: crosshair; }

#overlay {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 10;
  transition: opacity 400ms ease-out;
}

#overlay.overlays-hidden {
  opacity: 0;
}

#overlay.overlays-hidden,
#overlay.overlays-hidden * {
  pointer-events: none !important;
}

#overlay button,
#overlay input,
#toolbar,
#readout,
#slider-container,
#nav-widget,
#orientation-gizmo,
#north-arrow,
#section-slider-container,
#animation-bar,
#measure-modal,
#settings-menu,
#sidebar-panel,
#sidebar-scrim {
  pointer-events: auto;
}

/* ---- Custom project overlay (`ui.overlay`) ------------------------------- */
/* Host for a config's own HTML chrome (see custom-overlay.js). Pinned to the
   viewport and pointer-transparent so it behaves identically whether it was
   injected INSIDE #overlay (the default, so it fades with the rest of the UI) or
   as a SIBLING of it (`fadeWithUI: false`, always on screen). Controls opt back
   into hit-testing the same way #overlay's own do; the project stylesheet can
   add `pointer-events: auto` to anything else it needs clickable. */
#custom-overlay {
  position: fixed;
  inset: 0;
  pointer-events: none;
}

#custom-overlay button,
#custom-overlay input,
#custom-overlay a { pointer-events: auto; }

/* Injected as a sibling of #overlay, so it needs #overlay's own z-index to clear
   the canvas. As a child it inherits that stacking context and must NOT set one,
   or it would layer over the toolbar. */
#custom-overlay.no-fade { z-index: 10; }

#toolbar {
  position: absolute;
  top: 12px;
  left: 12px;
  display: flex;
  gap: 6px;
  align-items: center;
  transition: left 220ms ease;
}

#toolbar button {
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid #444;
  color: #eee;
  padding: 6px 10px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  backdrop-filter: blur(4px);
}

#toolbar button:hover { background: rgba(0, 0, 0, 0.85); }
#toolbar button.active {
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent);
}

#toolbar svg { display: block; }

/* ---- Group sidebar ------------------------------------------------------- */
/* Picks between DISJOINT scenes (`splats[].group`) — the bottom slider stays
   the stepper WITHIN the selected group. Hidden entirely (`.hidden`) unless the
   config declares 2+ groups, so single-group projects are untouched.
   Collapsing WIDTH rather than sliding the panel away: the group icons stay on
   screen at all times and only their labels come and go, so the rail is always
   a one-click switch. Row 1 is the expand/collapse toggle itself. */

#sidebar-panel {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--sidebar-rail-w);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.65);
  border-right: 1px solid #444;
  backdrop-filter: blur(4px);
  transition: width 220ms ease;
}

#overlay.sidebar-open #sidebar-panel { width: var(--sidebar-w); }

/* One shared shape for the toggle, the group rows and the site links: a
   fixed-position icon (so nothing shifts horizontally as the rail widens) with
   the label to its right, revealed only when open. The `a.sidebar-row` arm is
   what lets `ui.sidebarLinks` render as anchors (real links — middle-click,
   copy-link, keyboard) while matching the buttons exactly. */
#sidebar-panel button,
#sidebar-panel a.sidebar-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  box-sizing: border-box;
  /* 14px + 20px icon + 14px = the 48px rail, so the icon is centered collapsed
     and holds that exact x once expanded. */
  padding: 12px 14px;
  background: transparent;
  border: none;
  border-radius: 0;
  color: #ddd;
  font-family: inherit;
  font-size: 13px;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
#sidebar-panel .sidebar-icon {
  flex: 0 0 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
#sidebar-panel .sidebar-icon svg { display: block; }
/* Labels are removed from flow while collapsed, not just clipped — otherwise
   they flash mid-transition as the rail widens past their first glyph. */
#sidebar-panel .sidebar-label { display: none; }
#overlay.sidebar-open #sidebar-panel .sidebar-label { display: inline; }

/* Double-id selectors below out-rank the `#sidebar-panel button` base above,
   which would otherwise win on specificity and flatten these states. */
#sidebar-panel #sidebar-toggle {
  color: #bbb;
  border-bottom: 1px solid #3a3a3a;
  font-weight: 600;
}
#sidebar-panel #sidebar-toggle:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }

/* ---- Sidebar logo -------------------------------------------------------- */
/* The toggle row carries THREE slots and shows two of them at a time.
   COLLAPSED it is the group's logo alone, centered in the rail — a mark is a
   better thing to hand a first-time visitor than a chevron, and the row is
   still the same button it always was. Hovering swaps that mark for
   `panel-left-open` IN PLACE: the label is `display: none` here, so whichever
   of the two icon slots is showing is the row's only child and lands at the
   same x. Nothing moves, so the swap reads as the mark turning into the
   control rather than as the row rearranging itself.
   OPEN, both show — the logo holds the icon column the page rows below line up
   on, and the chevron (now `panel-left-close`) stays out at the far right,
   where the collapse control has always lived.
   The hover swap is gated on `(hover: hover)`: a touch device can leave :hover
   latched after a tap, and there a steady logo is the honest state. The rail
   itself is the affordance on touch. */
#sidebar-panel #sidebar-toggle .sidebar-chevron { display: none; }

@media (hover: hover) {
  #overlay:not(.sidebar-open) #sidebar-panel #sidebar-toggle:hover .sidebar-logo { display: none; }
  #overlay:not(.sidebar-open) #sidebar-panel #sidebar-toggle:hover .sidebar-chevron { display: inline-flex; }
}
/* Keyboard parity — a tabbed-to toggle shows what a hovered one does, on every
   device, so the collapsed rail is never a button with no visible verb. */
#overlay:not(.sidebar-open) #sidebar-panel #sidebar-toggle:focus-visible .sidebar-logo { display: none; }
#overlay:not(.sidebar-open) #sidebar-panel #sidebar-toggle:focus-visible .sidebar-chevron { display: inline-flex; }

#overlay.sidebar-open #sidebar-panel #sidebar-toggle .sidebar-chevron { display: inline-flex; }

/* Open, the title takes the label column and pushes the chevron to the far
   edge. It needs no inset of its own: the logo is genuinely sitting in the icon
   column now, where the old `margin-left: 32px` (icon 20 + gap 12) was faking
   one so the project title would line up with the page labels below it. */
#overlay.sidebar-open #sidebar-panel #sidebar-toggle .sidebar-label {
  margin-right: auto;
}

/* A `logo` / `titleLogo` naming an SVG file renders as an <img> (see
   sidebar.js), sized to the slot it lands in and never tinted — a client's mark
   keeps its own colors. The BUNDLED arch1v3 default is inline <svg> in
   currentColor instead, so it picks up the toggle's hover/focus states like
   every other icon in the rail. */
#sidebar-panel .sidebar-logo img {
  display: block;
  width: 20px;
  height: 20px;
  object-fit: contain;
}
/* A wordmark in the heading slot: height-matched to the icon column, free
   width, and allowed to shrink rather than push the chevron off the panel. */
#overlay.sidebar-open #sidebar-panel #sidebar-title.has-logo {
  display: inline-flex;
  align-items: center;
  min-width: 0;
}
#sidebar-panel #sidebar-title img {
  display: block;
  height: 20px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

#sidebar-groups {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 6px 0;
}

#sidebar-groups .sidebar-row:hover:not(:disabled) { background: rgba(255, 255, 255, 0.1); color: #fff; }
#sidebar-groups .sidebar-row[aria-current="true"] { background: var(--accent); color: var(--accent-fg); font-weight: 600; }
#sidebar-groups .sidebar-row:disabled { cursor: default; }
#sidebar-groups .sidebar-row:disabled:not([aria-current="true"]) { opacity: 0.5; }

/* Site links (`ui.sidebarLinks`): the same row, one step quieter, under a rule
   that marks them as a different KIND of destination — the groups swap the scene
   in place, these leave the viewer. The rule is inset to the label column so it
   reads as a divider rather than a full-bleed border, and stays put as the rail
   widens (28px = the 14px row padding + the 20px icon − 6px). */
#sidebar-groups .sidebar-sep {
  height: 1px;
  margin: 6px 0 6px 28px;
  background: #3a3a3a;
}
#sidebar-groups a.sidebar-link { color: #aaa; text-decoration: none; }

/* Mobile-only dismiss layer behind the drawer (see the media query). */
#sidebar-scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  display: none;
}

/* The rail is always on screen, so the overlays in its column clear the RAIL
   width at rest and the full panel width when open. `has-sidebar` is set by
   sidebar.js only when it actually renders, leaving single-group configs at
   their original positions. Shifted via `left` and not `transform` — every child
   of #toolbar is in normal flow now, but a transformed ancestor would still make
   the toolbar the containing block for anything fixed dropped inside it later. */
#overlay.has-sidebar #toolbar { left: calc(12px + var(--sidebar-rail-w)); }
#overlay.has-sidebar #slider-container { left: calc(50% + var(--sidebar-rail-w) / 2); }

#overlay.has-sidebar.sidebar-open #toolbar { left: calc(12px + var(--sidebar-w)); }
#overlay.has-sidebar.sidebar-open #slider-container { left: calc(50% + var(--sidebar-w) / 2); }

/* Segmented control: a single bordered pill with an inline label and the
   level buttons sharing internal dividers, the active one filled. */
#detail-levels {
  display: inline-flex;
  align-items: stretch;
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid #444;
  border-radius: 4px;
  overflow: hidden;
  backdrop-filter: blur(4px);
}
#detail-levels .detail-label {
  display: inline-flex;
  align-items: center;
  padding: 0 9px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #ddd;
  background: rgba(255, 255, 255, 0.06);
  border-right: 1px solid #444;
  line-height: 16px;
}
#detail-buttons { display: inline-flex; }
#detail-levels button {
  background: transparent;
  border: none;
  border-radius: 0;
  color: #ddd;
  padding: 6px 11px;
  font-size: 12px;
  /* 16px line + 12px padding = 28px; with the pill's 2px border that's 30px,
     matching the 16px-icon toolbar buttons (16 + 12 + 2) to its left. */
  line-height: 16px;
  backdrop-filter: none;
}
#detail-levels button + button { border-left: 1px solid #3a3a3a; }
#detail-levels .detail-short { display: none; }
#detail-levels button:hover:not(:disabled) { background: rgba(255, 255, 255, 0.1); color: #fff; }
#detail-levels button.active { background: var(--accent); color: var(--accent-fg); }
#detail-levels button:disabled { cursor: default; }

/* FPS lives in the Detail tab's stats grid, as the `value` cell of its own row:
   a health dot plus the number. It was a bare status light in the toolbar with
   the number in a hover popup — which no touch device could ever reach, and
   which is exactly the number you want while choosing a detail level. */
#fps-display {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}
#fps-display::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #888;
}
#fps-display.fps-good::before { background: #4ade80; }
#fps-display.fps-warn::before { background: #facc15; }
#fps-display.fps-bad::before  { background: #f87171; }
#fps-readout { font-variant-numeric: tabular-nums; }

#nav-widget {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 110px;
  height: 110px;
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid #444;
  border-radius: 4px;
  backdrop-filter: blur(4px);
}

#orientation-gizmo {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

#north-arrow {
  position: absolute;
  inset: 0;
  cursor: pointer;
}
#north-arrow canvas { display: block; width: 100%; height: 100%; }

/* Fixed alignment reticle centered over the rotating compass — four corner
   brackets whose elbows point INWARD toward the center marking the current
   yaw/pitch reads against. The open center keeps the marking legible; a
   drop-shadow gives contrast on light backgrounds. Non-interactive so clicks
   fall through to the widget. The frame is a fixed-size box built from eight
   gradient segments (an L at each corner, elbow toward center), centered in the
   widget. */
#north-arrow .nav-reticle {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 28px;
  height: 28px;
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0.7;
  filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.9));
  background-repeat: no-repeat;
  background-image:
    linear-gradient(#fff, #fff), linear-gradient(#fff, #fff),  /* top-left    */
    linear-gradient(#fff, #fff), linear-gradient(#fff, #fff),  /* top-right   */
    linear-gradient(#fff, #fff), linear-gradient(#fff, #fff),  /* bottom-left */
    linear-gradient(#fff, #fff), linear-gradient(#fff, #fff);  /* bottom-right*/
  background-position:
    0 10px, 10px 0,
    16px 10px, 16px 0,
    0 16px, 10px 16px,
    16px 16px, 16px 16px;
  background-size:
    12px 2px, 2px 12px,
    12px 2px, 2px 12px,
    12px 2px, 2px 12px,
    12px 2px, 2px 12px;
}

/* Only one nav widget visible at a time — toggle keeps DOM dimensions intact
   so the north-arrow's canvas fit math stays correct after a window resize
   while it was the inactive view. */
.nav-hidden { visibility: hidden; pointer-events: none; }

#nav-toggle {
  position: absolute;
  top: 4px;
  right: 4px;
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid #444;
  color: #ccc;
  width: 20px;
  height: 20px;
  padding: 0;
  border-radius: 3px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0.75;
}
#nav-toggle:hover { opacity: 1; color: #fff; background: rgba(0, 0, 0, 0.85); }
#nav-toggle svg { display: block; }

#orientation-gizmo svg { display: block; }
#orientation-gizmo .axis-line { pointer-events: none; }
#orientation-gizmo .axis-end {
  cursor: pointer;
  transition: transform 120ms ease-out;
  transform-box: fill-box;
  transform-origin: center;
}
#orientation-gizmo .axis-end:hover { transform: scale(1.2); }
#orientation-gizmo .axis-label {
  pointer-events: none;
  font-size: 10px;
  font-weight: 700;
  font-family: system-ui, sans-serif;
}

#section-slider-container {
  position: absolute;
  top: 130px;
  right: 12px;
  bottom: 140px;
  width: 22px;
  display: flex;
  align-items: stretch;
  justify-content: center;
}

#section-slider {
  width: 18px;
  height: 100%;
  margin: 0;
  writing-mode: vertical-lr;
  accent-color: var(--accent);
  cursor: pointer;
}

#readout {
  position: absolute;
  bottom: 150px;
  right: 12px;
  background: rgba(0, 0, 0, 0.7);
  padding: 8px 12px;
  border-radius: 4px;
  font-variant-numeric: tabular-nums;
  font-size: 14px;
}

/* The bottom-center stack: the annotation bar sits above the splat stepper, and
   either can be absent. The container carries only the positioning (and the
   sidebar shift), so it is transparent and pointer-transparent — otherwise the
   empty column and the gap between the two pills would eat canvas drags. The
   overriding `pointer-events: none` has to come AFTER the shared `auto` block
   near the top of this file; the two pills opt back in. */
#slider-container {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  width: min(80vw, 600px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  transition: left 220ms ease;
  pointer-events: none;
}

#splat-stepper {
  align-self: stretch;
  box-sizing: border-box;
  background: rgba(0, 0, 0, 0.65);
  padding: 8px 14px 10px;
  border-radius: 8px;
  backdrop-filter: blur(4px);
  pointer-events: auto;
}

#animation-bar {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 6px;
  background: #000;
  box-sizing: border-box;
}

#anim-slider {
  display: block;
  width: 100%;
  height: 6px;
  margin: 0;
  padding: 0;
  appearance: none;
  -webkit-appearance: none;
  background: linear-gradient(to right, var(--accent) calc(var(--progress, 0) * 100%), #000 calc(var(--progress, 0) * 100%));
  border: none;
  outline: none;
  cursor: pointer;
}

#anim-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 0;
  height: 0;
}

#anim-slider::-webkit-slider-runnable-track {
  height: 6px;
  background: transparent;
}

#anim-slider::-moz-range-thumb {
  appearance: none;
  width: 0;
  height: 0;
  border: none;
  background: transparent;
}

#anim-slider::-moz-range-track {
  height: 6px;
  background: transparent;
}

#splat-current {
  text-align: center;
  font-size: 13px;
  margin-bottom: 6px;
  font-variant-numeric: tabular-nums;
}

#splat-current-label { font-weight: 600; }
#splat-current-counter { opacity: 0.65; margin-left: 6px; }

#slider-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

#splat-slider {
  flex: 1;
  margin: 0;
  accent-color: var(--accent);
}

.splat-arrow {
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid #444;
  color: #eee;
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: 4px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.splat-arrow:hover:not(:disabled) { background: rgba(0, 0, 0, 0.9); border-color: #666; }
.splat-arrow:disabled { opacity: 0.35; cursor: default; }
.splat-arrow svg { display: block; }

/* ---- Annotations --------------------------------------------------------- */
/* World-anchored notes (config `annotations[]`, see src/annotations.js): the
   prev/next bar above the splat stepper, the numbered hotspots, and the popup
   card carrying the selected one's title + text. */

/* The prev/next pair wears the front door's chevron buttons (.fd-btn in
   html/arch1v3/frontdoor.css): no pill behind them, just two glass circles.
   The small dark arrows they replaced disappeared against a dim interior;
   a white ring on a blur, lifted by a shadow, holds up over any capture. The
   bar itself is transparent, so only the buttons take clicks. */
#annotation-nav {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 100%;
  box-sizing: border-box;
  pointer-events: none;
}

#annotation-nav .splat-arrow {
  /* Fixed, not shrinkable: the bar is a flex row inside a narrow column, and
     without this the circles squash into ovals. */
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 2px 20px rgba(0, 0, 0, 0.4);
  color: #fff;
  pointer-events: auto;
  transition: background 180ms ease, border-color 180ms ease, color 180ms ease, transform 180ms ease;
}
#annotation-nav .splat-arrow svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Hover only where hovering is real — a touch device latches :hover after a
   tap. Same guard the front door uses. */
@media (hover: hover) {
  #annotation-nav .splat-arrow:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.9);
    border-color: #fff;
    color: #111;
  }
}
#annotation-nav .splat-arrow:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}
#annotation-nav .splat-arrow:active:not(:disabled) { transform: scale(0.97); }

/* Placed each frame in CSS pixels by annotations.js; `left`/`top` are the pin's
   projected point, so the translate centers the dot on it. */
#annotation-hotspots {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* The button is a bare box around the marker; the DISC is what shows. `--size` is
   the disc's diameter (annotationStyle.size, set by annotations.js). Anchored on
   its centre by default; `.has-leader` stands it on a line and anchors the FOOT. */
.annotation-hotspot {
  --size: 26px;
  --fg: #fff;
  --bg: rgba(0, 0, 0, 0.75);
  --ring: rgba(255, 255, 255, 0.85);
  position: absolute;
  transform: translate(-50%, -50%);
  width: var(--size);
  height: var(--size);
  padding: 0;
  background: none;
  border: none;
  color: var(--fg);
  font-size: calc(var(--size) * 0.46);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  cursor: pointer;
  pointer-events: auto;
  transition: filter 450ms cubic-bezier(0.45, 0, 0.55, 1);
}
.annotation-hotspot.is-inverted {
  --fg: #000;
  --bg: rgba(255, 255, 255, 0.9);
  --ring: rgba(0, 0, 0, 0.85);
}
.annotation-disc {
  flex: 0 0 var(--size);
  width: var(--size);
  height: var(--size);
  box-sizing: border-box;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--ring);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  backdrop-filter: blur(2px);
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}

/* Behind a splat surface (annotations.js testOcclusion): dimmed, not hidden, and
   still clickable — SuperSplat's treatment. A FILTER rather than `opacity`, so it
   multiplies with the inline opacity a `near` visibility rule sets instead of
   fighting it. */
.annotation-hotspot.is-occluded { filter: opacity(0.4); }

.annotation-hotspot:hover .annotation-disc { border-color: var(--accent); color: var(--accent); }
.annotation-hotspot.active .annotation-disc {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
}
.annotation-hotspot svg { display: block; }

/* `marker: "image"` — the picture cropped to the disc, keeping its outline (white,
   black when inverted). The ring is thicker than a number's so it reads as a frame. */
.annotation-hotspot.marker-image .annotation-disc {
  border-width: 3px;
  background: rgba(0, 0, 0, 0.6);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
  backdrop-filter: none;
}
.annotation-hotspot.marker-image.is-inverted .annotation-disc { background: rgba(255, 255, 255, 0.6); }
.annotation-marker-img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  pointer-events: none;
}
.annotation-hotspot.marker-image.active .annotation-disc { background: rgba(0, 0, 0, 0.6); }

/* `leader: true` — any marker standing on a vertical line. The button's box is the
   whole assembly, anchored by its BOTTOM centre, so the foot of the line is the
   pinned point rather than the disc's middle. `--leader` is the line's length
   (`lineHeight`). */
.annotation-hotspot.has-leader {
  height: calc(var(--size) + var(--leader, 48px));
  transform: translate(-50%, calc(-100% + 3px));
}
.annotation-leader {
  flex: 1 1 auto;
  width: 2px;
  background: var(--ring);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
}
.annotation-foot {
  flex: 0 0 6px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ring);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
}
.annotation-hotspot.is-inverted .annotation-leader,
.annotation-hotspot.is-inverted .annotation-foot { box-shadow: 0 0 3px rgba(255, 255, 255, 0.6); }
.annotation-hotspot.active .annotation-leader,
.annotation-hotspot.active .annotation-foot { background: var(--accent); }

/* The infographic card. DOCKED, not anchored to its pin: right-hand side, under
   the 110px nav widget, scrolling within the space above the bottom stack. Being
   docked means it never covers the thing it describes and never has to chase the
   pin as the camera flies. Every part inside is optional per annotation. */
#annotation-popup {
  position: absolute;
  z-index: 30;
  top: 134px;
  right: 12px;
  box-sizing: border-box;
  width: min(320px, calc(100vw - 24px));
  max-height: calc(100vh - 134px - 150px);
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: rgba(20, 20, 20, 0.95);
  border: 1px solid #444;
  border-radius: 10px;
  padding: 14px 16px 16px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  pointer-events: auto;
}
/* No nav widget on this page — the card can start at the top. */
#overlay:has(#nav-widget.ui-off) #annotation-popup { top: 12px; max-height: calc(100vh - 12px - 150px); }

#annotation-popup-image {
  display: block;
  width: calc(100% + 32px);
  margin: -14px -16px 2px;
  max-height: 220px;
  object-fit: cover;
  border-radius: 10px 10px 0 0;
  background: #111;
}

#annotation-popup-title {
  font-size: 15px;
  font-weight: 700;
  color: #fff;
  padding-right: 22px; /* clear of the close button */
}

#annotation-popup-text {
  font-size: 13px;
  line-height: 1.5;
  color: #cfcfcf;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* The card's footer: prev / link / next, centred under the text. Either arrow
   pair or the link may be absent (one annotation; no link) — whatever is left
   stays centred. While the card shows, this replaces the #annotation-nav bar. */
#annotation-popup-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 6px;
}

/* The bar's glass circles, at card scale. */
.annotation-popup-arrow {
  flex: 0 0 32px;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 180ms ease, border-color 180ms ease, color 180ms ease, transform 180ms ease;
}
.annotation-popup-arrow svg {
  display: block;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
@media (hover: hover) {
  .annotation-popup-arrow:hover {
    background: rgba(255, 255, 255, 0.9);
    border-color: #fff;
    color: #111;
  }
}
.annotation-popup-arrow:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.annotation-popup-arrow:active { transform: scale(0.97); }

#annotation-popup-link {
  /* Shrinks and ellipsises before it can push the arrows out of the card. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-fg);
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
}
#annotation-popup-link:hover { background: var(--accent-hover); }
#annotation-popup-link:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

#annotation-popup-close {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 1;
  width: 24px;
  height: 24px;
  padding: 0;
  background: rgba(0, 0, 0, 0.55);
  border: none;
  border-radius: 50%;
  color: #cfcfcf;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
#annotation-popup-close:hover { color: #fff; background: rgba(0, 0, 0, 0.85); }
#annotation-popup-close svg { display: block; }

#loading {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 12px 18px;
  background: rgba(0, 0, 0, 0.8);
  border-radius: 6px;
  font-size: 14px;
  min-width: 220px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
#loading.hidden { display: none; }
/* A streamed splat's settle gate (splat-loader.js): the box becomes a full-screen black
   backdrop while the splat's chunks land, so nobody watches the scene assemble tile by
   tile. Still a sibling BEFORE #overlay (which carries z-index 10), so the toolbar and
   sidebar stay on top of the black — and it takes pointer events, so a drag can't move
   the camera and trigger more streaming mid-settle. */
#loading.streaming {
  inset: 0;
  top: 0;
  left: 0;
  transform: none;
  border-radius: 0;
  background: #000;
  justify-content: center;
  align-items: center;
  pointer-events: auto;
}
#loading.streaming > * { width: 260px; max-width: calc(100vw - 32px); }
#loading-label { text-align: center; }
#loading-bar-track {
  height: 6px;
  background: rgba(255, 255, 255, 0.15);
  border-radius: 3px;
  overflow: hidden;
}
#loading-bar-fill {
  height: 100%;
  width: 0%;
  background: var(--accent);
  border-radius: 3px;
  transition: width 0.1s linear;
}
#loading.indeterminate #loading-bar-fill {
  width: 35%;
  animation: loading-indeterminate 1.1s ease-in-out infinite;
}
@keyframes loading-indeterminate {
  from { transform: translateX(-110%); }
  to   { transform: translateX(305%); }
}
#loading-bytes {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.6);
  text-align: center;
  min-height: 1em;
}

/* ---- Controls card (`src/controls-help.js`) --------------------------------
   A reference card for driving the scene, after superspl.at's gallery viewer: a
   header naming the mode, then action / key-chip rows. Lower-right corner, the
   button at the bottom and the card right above it. controls-help.js lifts both
   (inline `bottom`) above the bottom-centre stack only where they would overlap
   it — a phone, a narrow window. Inside #overlay, so both fade with the chrome. */
#controls-toggle {
  position: absolute;
  right: 12px;
  bottom: max(18px, env(safe-area-inset-bottom));
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid #444;
  color: #eee;
  padding: 6px 10px;
  border-radius: 4px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  backdrop-filter: blur(4px);
}
#controls-toggle:hover { background: rgba(0, 0, 0, 0.85); }
/* While the card is open it takes the button's slot; its × closes it. */
#controls-toggle.card-open { display: none; }
#controls-toggle svg { display: block; }

#controls-popup {
  position: absolute;
  right: 12px;
  /* The button's inset + its height (16px icon + 12px padding + 2px border) + gap. */
  bottom: calc(max(18px, env(safe-area-inset-bottom)) + 38px);
  box-sizing: border-box;
  width: min(280px, calc(100vw - 24px));
  max-height: calc(100vh - 140px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: rgba(20, 20, 20, 0.88);
  border: 1px solid #444;
  border-radius: 8px;
  backdrop-filter: blur(6px);
  color: #eee;
  font-size: 13px;
  pointer-events: auto;
  z-index: 25;
}
/* No button on this page, or the card is open — the card takes its slot. */
#overlay:has(#controls-toggle.ui-off) #controls-popup,
#overlay:has(#controls-toggle.card-open) #controls-popup { bottom: max(18px, env(safe-area-inset-bottom)); }
/* An annotation card is the active content while it shows; this is reference
   material, and on a phone the two would stack in the same bottom sheet slot. */
#overlay:has(#annotation-popup:not(.hidden):not(.ui-off):not(.scene-hidden)) #controls-popup { display: none; }

#controls-popup-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 10px 8px 12px;
  border-bottom: 1px solid #333;
  font-weight: 600;
}
#controls-popup-icon { display: inline-flex; color: var(--accent); }
#controls-popup-title { flex: 1; }
#overlay #controls-popup-close {
  background: none;
  border: 0;
  color: #aaa;
  padding: 4px;
  cursor: pointer;
  display: inline-flex;
  border-radius: 4px;
}
#overlay #controls-popup-close:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }

.controls-rows {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 12px 10px;
}
.controls-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 26px;
}
.controls-action { color: #ccc; }
.controls-keys { display: inline-flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
.controls-keys kbd {
  font: 500 11px/1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: #eee;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid #555;
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: 3px 6px;
  white-space: nowrap;
}

.controls-or, .controls-note { color: #999; font-size: 11px; }
.controls-divider { border-top: 1px solid #333; margin: 6px 0 4px; }
/* Mouse glyph: an outline mouse with the button in use filled, after a move-arrows
   mark for a drag or an up/down mark for the wheel. */
.controls-mouse { display: inline-flex; align-items: center; gap: 3px; color: #ccc; }
.controls-mouse .cm-mouse { width: 12px; height: 18px; display: block; }
.controls-mouse .cm-mark { width: 11px; height: 11px; display: block; fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; }
.controls-mouse .cm-body { fill: none; stroke: currentColor; stroke-width: 1.4; }
.controls-mouse .cm-active { fill: #fff; stroke: none; }
.controls-mouse .cm-mark .cm-fill { fill: currentColor; stroke: none; }

/* The same content as a settings-sheet tab (`minimal`). */
#sm-panel-controls .controls-panel-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  margin-bottom: 6px;
}
#sm-panel-controls .controls-panel-title svg { color: var(--accent); }
#sm-panel-controls .controls-rows { padding: 0; }

.measure-label {
  position: absolute;
  background: var(--accent);
  color: var(--accent-fg);
  padding: 3px 8px;
  border-radius: 3px;
  font-size: 12px;
  font-weight: 600;
  pointer-events: none;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  z-index: 20;
}

#measure-modal,
#splat-warn-modal,
#settings-menu {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}

#measure-modal .modal-backdrop,
#splat-warn-modal .modal-backdrop,
#settings-menu .modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(2px);
}

#measure-modal .modal-card,
#splat-warn-modal .modal-card,
#settings-menu .modal-card {
  position: relative;
  background: #1a1a1a;
  border: 1px solid #444;
  border-radius: 8px;
  padding: 22px 26px 18px;
  max-width: 360px;
  text-align: center;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
}

#measure-modal p,
#splat-warn-modal p {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.4;
}

#measure-modal button,
#splat-warn-modal button {
  background: var(--accent);
  color: var(--accent-fg);
  border: none;
  padding: 8px 22px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
}

#measure-modal button:hover,
#splat-warn-modal button:hover { background: var(--accent-hover); }

/* The render stats, at the bottom of the Detail tab. Two columns so a label and
   its figure read as a row; `.section-top` rules off the per-splat figures from
   the fixed ones above them. */
#info-stats {
  display: grid;
  grid-template-columns: auto auto;
  column-gap: 18px;
  row-gap: 4px;
  margin: 0;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
#info-stats .label { color: #8a8a8a; text-align: left; }
#info-stats .value { color: #d6d6d6; text-align: right; }
#info-stats .note { grid-column: 1 / -1; color: #7a7a7a; font-style: italic; font-size: 10px; margin-top: 2px; }
#info-stats .section-top { border-top: 1px solid #3a3a3a; padding-top: 8px; margin-top: 4px; }

/* The active splat's `notes`, the whole of the Info tab. */
#info-notes {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  color: #ddd;
}

.hidden { display: none !important; }

/* Walk mode hides orbit-only overlays (auto-rotate, orientation widget, section,
   share) without disturbing their config-driven `.hidden` state — removing this
   class on exit restores whatever base visibility each element had. */
.walk-hidden { display: none !important; }

/* Config-authored `ui.show*: false` (see applyUiVisibility in ui.js). The third
   of three orthogonal hide classes — `.hidden` is runtime state, `.walk-hidden`
   is nav mode, `.ui-off` is the config — so none of them can clobber another and
   a config-hidden control stays hidden through every splat swap and mode switch. */
.ui-off { display: none !important; }

/* The annotation layer while a splat is collapsing out, loading or revealing in
   (annotations.js, on splat-loader.js's `splat:hiding` / `splat:revealed`). A
   fourth class for the same reason: the layer's own `.hidden` state survives it.
   A fade, not a cut: opacity eases while `visibility` flips at the far end of the
   fade-out (so a faded layer takes no clicks) and at the start of the fade-in.
   Written against the ids so the two transitions out-rank nothing else on them. */
#annotation-hotspots,
#annotation-nav,
#annotation-popup { transition: opacity 300ms ease, visibility 0s; }
#annotation-hotspots.scene-hidden,
#annotation-nav.scene-hidden,
#annotation-popup.scene-hidden {
  opacity: 0;
  visibility: hidden;
  transition: opacity 200ms ease, visibility 0s 200ms;
}
#annotation-hotspots.scene-hidden *,
#annotation-nav.scene-hidden *,
#annotation-popup.scene-hidden { pointer-events: none; }

/* Mobile: hide the orientation gizmo and the animation scrubber, and give the
   toolbar and the splat slider room to clear the notch / home indicator.
   The TOOLBAR itself needs nothing here any more — it is the same five controls
   on every screen size, and everything else lives behind the gear (see
   settings-menu.js). Triggers on narrow widths (phones in portrait) and short
   heights (phones in landscape). */
@media (max-width: 768px), (max-height: 500px) {
  #nav-widget,
  #section-slider-container,
  #animation-bar {
    display: none !important;
  }

  #toolbar {
    top: max(10px, env(safe-area-inset-top));
    left: max(10px, env(safe-area-inset-left));
    flex-wrap: wrap;
  }

  #toolbar button {
    padding: 8px 12px;
    font-size: 14px;
  }

  /* Measure's distance readout would land under the splat stepper on a short
     screen; lift it above the bottom stack. */
  #readout { bottom: 170px; font-size: 13px; }

  #slider-container {
    bottom: max(16px, env(safe-area-inset-bottom));
    width: calc(100vw - 24px);
    max-width: none;
  }

  #splat-stepper { padding: 10px 14px 12px; }

  /* The annotation arrows are already at the 44px touch floor — no bump here. */

  /* The docked card becomes a bottom sheet sitting just above the splat stepper
     (the nav widget it sat under is hidden here anyway, and the annotation bar
     is hidden for as long as a card shows). --popup-lift is the stepper's height
     on this breakpoint (22px padding + label row + 36px arrows) plus the stack's
     8px gap; with no stepper — a single-splat page — the card drops to where the
     stepper would have been. */
  #overlay { --popup-lift: 94px; }
  #overlay:has(#splat-stepper.hidden) { --popup-lift: 0px; }
  #annotation-popup,
  #overlay:has(#nav-widget.ui-off) #annotation-popup {
    top: auto;
    left: max(10px, env(safe-area-inset-left));
    right: max(10px, env(safe-area-inset-right));
    bottom: calc(max(16px, env(safe-area-inset-bottom)) + var(--popup-lift));
    width: auto;
    max-height: min(45vh, calc(100vh - 86px - var(--popup-lift)));
  }
  #annotation-popup-image { max-height: 160px; }

  /* Collapsed on a phone is the TOGGLE ALONE — a compact chip in the corner
     rather than a full-height rail eating a strip of a small screen. The group
     icons come back with the drawer. */
  #sidebar-panel {
    bottom: auto;
    border-bottom: 1px solid #444;
    border-bottom-right-radius: 8px;
    z-index: 2;
    padding-top: env(safe-area-inset-top);
  }
  #sidebar-groups { display: none; }

  /* Open is an overlay drawer over a dismiss scrim; expanding it must not push
     the toolbar any further than the collapsed chip already does. */
  #overlay.sidebar-open #sidebar-panel {
    bottom: 0;
    width: min(78vw, 260px);
    border-bottom-right-radius: 0;
  }
  #overlay.sidebar-open #sidebar-groups { display: block; }
  #overlay.sidebar-open #sidebar-scrim { display: block; z-index: 1; }

  /* Undo the desktop shifts at matching specificity — the plain #toolbar /
     #slider-container rules in this block would lose to them. The toolbar still
     clears the collapsed chip; the bottom slider and the static play button
     never meet it. */
  #overlay.has-sidebar #toolbar,
  #overlay.has-sidebar.sidebar-open #toolbar {
    left: calc(max(10px, env(safe-area-inset-left)) + var(--sidebar-rail-w));
  }
  #overlay.has-sidebar #slider-container,
  #overlay.has-sidebar.sidebar-open #slider-container { left: 50%; }

  #splat-current { font-size: 14px; margin-bottom: 8px; }

  /* Bigger touch targets on phones */
  .splat-arrow {
    width: 36px;
    height: 36px;
  }

  #splat-slider { height: 28px; }
}

/* ---- Share panels -------------------------------------------------------- */
/* The contents of the settings sheet's Link and Screenshot tabs (share.js). The
   frame around them belongs to the sheet, further down. */

.share-link-row { display: flex; flex-direction: column; gap: 5px; }
.share-link-pick {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  font-weight: 600;
  color: #ddd;
  cursor: pointer;
}
.share-link-pick input { accent-color: var(--accent); cursor: pointer; }
.share-link-field { display: flex; gap: 6px; }
.share-link-field input {
  flex: 1;
  min-width: 0;
  background: #0e0e0e;
  border: 1px solid #3a3a3a;
  border-radius: 4px;
  color: #cfcfcf;
  padding: 7px 9px;
  font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* action buttons (copy / save / share / close) — cyan pill like other modals */
.share-copy,
#share-native,
#share-save,
#share-copy-img,
#share-share-img,
#settings-menu-close {
  background: var(--accent);
  color: var(--accent-fg);
  border: none;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.share-copy:hover,
#share-native:hover,
#share-save:hover,
#share-copy-img:hover,
#share-share-img:hover,
#settings-menu-close:hover { background: var(--accent-hover); }
.share-flashed { background: #34c759 !important; color: #000 !important; }

#share-native { align-self: center; }
#settings-menu-close { align-self: center; }

#share-qr {
  display: flex;
  justify-content: center;
  padding: 6px 0;
}
#share-qr canvas { border-radius: 6px; }

/* ---- screenshot editor --- */
#share-canvas-wrap {
  display: flex;
  justify-content: center;
  background:
    repeating-conic-gradient(#2a2a2a 0% 25%, #222 0% 50%) 50% / 16px 16px;
  border: 1px solid #3a3a3a;
  border-radius: 6px;
  overflow: hidden;
}
#share-draw {
  display: block;
  max-width: 100%;
  max-height: 48vh;
  cursor: crosshair;
  touch-action: none;
}

#share-draw-tools,
#share-shot-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
#share-shot-actions { justify-content: center; }
.share-tool-group { display: inline-flex; gap: 4px; }

.share-swatch {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid #555;
  padding: 0;
  cursor: pointer;
}
.share-swatch.active { border-color: #fff; box-shadow: 0 0 0 2px var(--accent); }

.share-width {
  min-width: 26px;
  height: 26px;
  background: #2c2c2c;
  color: #ddd;
  border: 1px solid #3a3a3a;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}
.share-width.active { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }

#share-undo,
#share-clear {
  background: #2c2c2c;
  color: #ddd;
  border: 1px solid #3a3a3a;
  border-radius: 4px;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  margin-left: auto;
}
#share-clear { margin-left: 0; }
#share-undo:hover,
#share-clear:hover { background: #3a3a3a; }

/* ---- Settings sheet ------------------------------------------------------ */
/* The gear's tabbed overlay — the viewer's second control surface, identical on
   every screen size. Almost everything inside it is styled by the rules above
   (the share panels, the detail pill, the stats grid); what's here is the frame,
   the tab strip, and the one control the sheet introduces itself, the switch. */

#settings-menu .modal-card {
  box-sizing: border-box;
  width: calc(100vw - 20px);
  max-width: 460px;
  max-height: calc(100vh - 2 * max(16px, env(safe-area-inset-top)));
  overflow-y: auto;
  text-align: left;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

#settings-menu-tabs {
  display: flex;
  gap: 2px;
  background: #0e0e0e;
  border: 1px solid #3a3a3a;
  border-radius: 6px;
  padding: 2px;
}
/* Four tabs have to fit a 375px card, so they run tighter than a two-tab strip
   could afford. A strip with one surviving tab is a heading, not a choice. */
.sm-tab {
  flex: 1;
  background: transparent;
  color: #bbb;
  border: none;
  padding: 7px 2px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.sm-tab.active { background: #2c2c2c; color: #fff; }
#settings-menu-card.sm-single #settings-menu-tabs { background: transparent; border-color: transparent; padding: 0; }
#settings-menu-card.sm-single .sm-tab { background: transparent; color: #fff; font-size: 13px; }

.sm-panel { display: flex; flex-direction: column; gap: 12px; }

/* Rule between the two halves of the Detail tab: what you change above it, what
   tells you whether the change worked below it. */
.sm-rule {
  border: 0;
  border-top: 1px solid #3a3a3a;
  margin: 2px 0 0;
  width: 100%;
}

/* The level picker gets the full card width it never had in the toolbar, so the
   levels read as a row of labelled choices rather than initials. */
#sm-panel-detail #detail-levels { display: flex; }
#sm-panel-detail #detail-buttons { flex: 1; display: flex; }
#sm-panel-detail #detail-levels button { flex: 1; padding: 9px 8px; font-size: 13px; }

/* The streamed-splat counterpart of the level picker: one budget slider. */
#detail-budget { display: flex; flex-direction: column; gap: 6px; padding: 2px 2px 4px; }
#detail-budget.hidden { display: none; }
.detail-budget-head { display: flex; justify-content: space-between; color: #ddd; font-size: 14px; }
#detail-budget-value { color: var(--accent); font-variant-numeric: tabular-nums; }
#detail-budget-range {
  width: 100%;
  height: 6px;
  margin: 8px 0 2px;
  appearance: none;
  -webkit-appearance: none;
  border-radius: 3px;
  background: linear-gradient(to right, var(--accent) calc(var(--p, 0) * 100%), #3a3a3a calc(var(--p, 0) * 100%));
  outline: none;
  cursor: pointer;
}
#detail-budget-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px; height: 18px; border-radius: 50%;
  background: #fff; border: none; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
#detail-budget-range::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: #fff; border: none; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
#detail-budget-range:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--accent); outline-offset: 2px; }
.detail-budget-scale { display: flex; justify-content: space-between; color: #888; font-size: 11px; }
#detail-budget-note { color: #999; font-size: 12px; }
#detail-budget-note.hidden { display: none; }

/* Switch — a setting in a list, not an icon button. `.on` is the state class
   (main.js drives it for performance mode); note this is `#quality-toggle`,
   which is no longer inside #toolbar and so picks up none of its button rules. */
.sm-switch {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  box-sizing: border-box;
  padding: 8px 2px;
  background: none;
  border: none;
  color: #ddd;
  font-family: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.sm-switch-track {
  position: relative;
  flex: 0 0 auto;
  width: 42px;
  height: 24px;
  border-radius: 999px;
  background: #3a3a3a;
  transition: background 140ms ease;
}
.sm-switch-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #cfcfcf;
  transition: transform 140ms ease, background 140ms ease;
}
.sm-switch.on .sm-switch-track { background: var(--accent); }
.sm-switch.on .sm-switch-thumb { transform: translateX(18px); background: var(--accent-fg); }
