/* 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. */
: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,
#share-modal,
#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: #00d2ff;
  color: #000;
  border-color: #00d2ff;
}

#toolbar svg { display: block; }

/* Play/pause is authored inside #toolbar (so the mobile flex `order` below can
   place it first), but on desktop it's lifted out to the bottom-left corner,
   just above the full-width scrub bar. `position: fixed` is viewport-relative,
   so its toolbar parent is irrelevant here; it still fades with #overlay. */
#anim-toggle {
  position: fixed;
  left: 12px;
  bottom: 14px;
  transition: left 220ms ease;
}

/* ---- 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 and the group rows: a fixed-position icon
   (so nothing shifts horizontally as the rail widens) with the label to its
   right, revealed only when open. */
#sidebar-panel button {
  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); }

/* Open, the collapse control belongs in the panel's top-RIGHT corner, out of
   the column the group icons hold — so the title takes the icon's old x and the
   icon is pushed to the far edge. The 32px is the icon (20px) plus the row gap
   (12px), i.e. exactly the group labels' inset, keeping the project title
   flush with the splat labels below it. Collapsed the row is untouched: the
   icon stays centered in the rail, since it is then the only thing there. */
#overlay.sidebar-open #sidebar-panel #sidebar-toggle .sidebar-label {
  order: -1;
  margin-left: 32px;
  margin-right: auto;
}

#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: #00d2ff; color: #000; font-weight: 600; }
#sidebar-groups .sidebar-row:disabled { cursor: default; }
#sidebar-groups .sidebar-row:disabled:not([aria-current="true"]) { opacity: 0.5; }

/* 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. Shifting via `left` and NOT `transform` is
   deliberate: #anim-toggle is `position: fixed` inside #toolbar, and a
   transformed parent would become its containing block and break the viewport
   pinning. */
#overlay.has-sidebar #toolbar,
#overlay.has-sidebar #anim-toggle { 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,
#overlay.has-sidebar.sidebar-open #anim-toggle { 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: #00d2ff; color: #000; }
#detail-levels button:disabled { cursor: default; }

#fps-display {
  position: relative;
  align-self: center;
  width: 12px;
  height: 12px;
  margin: 0 4px;
  border-radius: 50%;
  background: #888;
  border: 1px solid rgba(0, 0, 0, 0.5);
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
  cursor: default;
}
#fps-display.fps-good { background: #4ade80; }
#fps-display.fps-warn { background: #facc15; }
#fps-display.fps-bad  { background: #f87171; }

/* FPS number popup — hidden until the dot is hovered/focused. The toolbar sits
   at the top-left, so the popup drops below the dot rather than above it. */
#fps-readout {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.85);
  border: 1px solid #444;
  color: #ddd;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  backdrop-filter: blur(4px);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s ease;
}
#fps-display:hover #fps-readout,
#fps-display:focus #fps-readout { opacity: 1; }

#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: #00d2ff;
  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, #00d2ff 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: #00d2ff;
}

.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. */

#annotation-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  box-sizing: border-box;
  background: rgba(0, 0, 0, 0.65);
  padding: 5px 6px;
  border-radius: 999px;
  backdrop-filter: blur(4px);
  pointer-events: auto;
}

#annotation-nav .splat-arrow {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: transparent;
  border-color: transparent;
}
#annotation-nav .splat-arrow:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.12);
  border-color: transparent;
}

/* 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;
}

.annotation-hotspot {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.75);
  border: 2px solid rgba(255, 255, 255, 0.85);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  pointer-events: auto;
  backdrop-filter: blur(2px);
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}

.annotation-hotspot:hover { border-color: #00d2ff; color: #00d2ff; }
.annotation-hotspot.active {
  background: #00d2ff;
  border-color: #00d2ff;
  color: #000;
}

#annotation-popup {
  position: absolute;
  z-index: 30;
  box-sizing: border-box;
  max-width: min(280px, calc(100vw - 24px));
  background: rgba(20, 20, 20, 0.95);
  border: 1px solid #444;
  border-radius: 8px;
  padding: 11px 30px 12px 13px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  pointer-events: auto;
}

/* Arrow pointing back at the hotspot. `--arrow-top` is set by annotations.js so
   it tracks the pin as the card is clamped against a viewport edge. */
#annotation-popup::before {
  content: "";
  position: absolute;
  top: var(--arrow-top, 50%);
  transform: translateY(-50%);
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
}
#annotation-popup.arrow-right::before {
  left: -7px;
  border-right: 7px solid rgba(20, 20, 20, 0.95);
}
#annotation-popup.arrow-left::before {
  right: -7px;
  border-left: 7px solid rgba(20, 20, 20, 0.95);
}

#annotation-popup-title {
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 5px;
  color: #fff;
}

#annotation-popup-text {
  font-size: 12px;
  line-height: 1.45;
  color: #cfcfcf;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

#annotation-popup-close {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 20px;
  height: 20px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 4px;
  color: #8a8a8a;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
#annotation-popup-close:hover { color: #fff; background: rgba(255, 255, 255, 0.1); }
#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; }
#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: #00d2ff;
  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;
}

.measure-label {
  position: absolute;
  background: #00d2ff;
  color: #000;
  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,
#info-modal,
#share-modal {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}

#measure-modal .modal-backdrop,
#splat-warn-modal .modal-backdrop,
#info-modal .modal-backdrop,
#share-modal .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,
#info-modal .modal-card,
#share-modal .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,
#info-modal p {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.4;
}

#measure-modal button,
#splat-warn-modal button,
#info-modal button {
  background: #00d2ff;
  color: #000;
  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,
#info-modal button:hover { background: #38dfff; }

#info-modal .modal-card {
  max-width: 440px;
  text-align: left;
  padding: 20px 24px 18px;
}
#info-modal p {
  margin: 0 0 16px;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  color: #ddd;
}
#info-stats {
  display: grid;
  grid-template-columns: auto auto;
  column-gap: 18px;
  row-gap: 4px;
  margin: 0 0 18px;
  font-size: 11px;
  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; }
#info-separator {
  border: 0;
  border-top: 1px solid #3a3a3a;
  margin: 0 0 14px;
}
#info-modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
}
#info-modal-nav {
  margin-right: auto;
  display: inline-flex;
  align-items: stretch;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid #444;
  border-radius: 4px;
  overflow: hidden;
}
#info-modal-nav .splat-arrow {
  background: transparent;
  border: none;
  border-radius: 0;
  color: #ddd;
  padding: 7px 14px;
  width: auto;
  height: auto;
  font-weight: normal;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
#info-modal-nav .splat-arrow:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.12);
  border-color: transparent;
}
#info-modal-counter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 600;
  color: #ddd;
  font-variant-numeric: tabular-nums;
  border-left: 1px solid #3a3a3a;
  border-right: 1px solid #3a3a3a;
}

.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; }

/* Mobile: hide measure tool, info readout, orientation gizmo, and animation
   scrubber. Reposition the toolbar and splat slider so they sit clear of the
   notch / home indicator on phones. Triggers on narrow widths (phones in
   portrait) and short heights (phones in landscape). */
@media (max-width: 768px), (max-height: 500px) {
  #fullscreen-toggle,
  #measure-toggle,
  #measure-clear,
  #nav-widget,
  #section-slider-container,
  #animation-bar,
  #readout,
  #measure-modal {
    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;
  }

  /* On mobile there's no bottom scrub bar, so play returns to the toolbar flow,
     ordered first (the fullscreen slot — fullscreen itself stays hidden here). */
  #anim-toggle {
    position: static;
    order: -1;
  }

  #detail-levels .detail-full { display: none; }
  #detail-levels .detail-short { display: inline; }
  #detail-levels button { padding: 6px 9px; }

  #slider-container {
    bottom: max(16px, env(safe-area-inset-bottom));
    width: calc(100vw - 24px);
    max-width: none;
  }

  #splat-stepper { padding: 10px 14px 12px; }

  /* Match the bigger touch targets the splat arrows get below. */
  #annotation-nav .splat-arrow { width: 34px; height: 34px; }

  /* 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 #anim-toggle,
  #overlay.has-sidebar.sidebar-open #anim-toggle { left: auto; }
  #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 modal --------------------------------------------------------- */

#share-modal .modal-card {
  max-width: 460px;
  width: calc(100vw - 32px);
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  text-align: left;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

#share-tabs {
  display: flex;
  gap: 2px;
  background: #0e0e0e;
  border: 1px solid #3a3a3a;
  border-radius: 6px;
  padding: 2px;
}
.share-tab {
  flex: 1;
  background: transparent;
  color: #bbb;
  border: none;
  padding: 7px 0;
  border-radius: 4px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.share-tab.active { background: #2c2c2c; color: #fff; }

.share-panel { display: flex; flex-direction: column; gap: 12px; }

.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: #00d2ff; 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,
#share-modal-close {
  background: #00d2ff;
  color: #000;
  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,
#share-modal-close:hover { background: #38dfff; }
.share-flashed { background: #34c759 !important; color: #000 !important; }

#share-native { align-self: center; }
#share-modal-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 #00d2ff; }

.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: #00d2ff; color: #000; border-color: #00d2ff; }

#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; }
