/* Web AR Museum Guide — overlay UI.
   MindAR injects the camera feed as a <video> at z-index -2 inside <body>, so
   nothing here may paint an opaque layer over it. */

/* The names on the left are this file's own vocabulary, kept because a
   thousand lines below already speak it. What they point AT is the museum
   palette in css/theme.css - change a colour there, not here. */
:root {
  --bg: var(--c-bg);
  --panel: var(--c-glass);
  --panel-solid: var(--c-surface);
  --line: var(--c-hairline-soft);
  --text: var(--c-text);
  --muted: var(--c-text-2);
  /* Terracotta is the app's action colour; gold stays for hairlines and the
     scan instrumentation, which is what it does in the Kotlin app too. */
  --accent: var(--c-terracotta);
  --accent-ink: #2A1409;
  --ok: var(--c-jade-lt);
  --warn-c: var(--c-amber);
  --err: #ef5f5f;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  /* How far the action bar sits above the bottom edge, on top of the safe
     area. The last band of the screen belongs to the gesture bar and the
     browser's own chrome, and a button down there is awkward to reach. */
  --bar-lift: 38px;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
  touch-action: manipulation;
}

body { position: fixed; inset: 0; } /* stops iOS rubber-banding the AR view */

/* The <video> holding the file we map onto the painting is a texture source
   only — it must exist in the DOM but never be seen. */
#arVideo {
  position: absolute;
  width: 1px;
  height: 1px;
  top: -10px;
  left: -10px;
  opacity: 0;
  pointer-events: none;
}

a-scene, .a-canvas { width: 100% !important; height: 100% !important; }

/* WebXR's dom-overlay can only promote ONE element, so the whole UI lives in
   #overlay. It must not swallow taps meant for the AR canvas, so it is
   transparent to pointers and the interactive parts opt back in. */
#overlay {
  position: fixed;
  inset: 0;
  /* Above the browse shell (30) and the language screen (40), not below them.
     Everything in here except the debug button and the error banner is hidden
     while browsing, and those two are exactly the things that must stay
     reachable when the app is misbehaving - which is when someone is looking
     at the start screen wondering why. Safe only because this element is
     transparent to pointers and its children opt back in one by one; raising
     an opaque layer to 45 would swallow every tap in the shell. */
  z-index: 45;
  pointer-events: none;
}
#overlay > .screen,
#overlay > .status-chip,
#overlay > .action-bar,
#overlay > .error-banner,
#overlay > .log-toggle,
#overlay > .log-panel,
#overlay > .photo-sheet,
#overlay > .details-sheet,
#overlay > .adjust-toggle,
#overlay > .exit-ar,
#overlay > .adjust-panel { pointer-events: auto; }
.a-enter-vr, .a-enter-ar, .a-orientation-modal { display: none !important; }

.hidden { display: none !important; }

/* The way out of AR. Top-left and round, like the Kotlin scan screen's close
   button - and deliberately at the opposite corner from every action, because
   pressing it by accident means losing the artwork you had just found. */
.exit-ar {
  position: fixed;
  top: calc(10px + var(--safe-t));
  left: calc(12px + var(--safe-l));
  z-index: 24;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--c-hairline-soft);
  border-radius: 50%;
  background: var(--c-glass);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: var(--c-text);
  cursor: pointer;
  transition: transform var(--d-fast) var(--ease-press);
}
.exit-ar:active { transform: scale(0.92); }
.exit-ar svg { width: 19px; height: 19px; }

/* ---------------------------------------------------------------- buttons */
.btn {
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  padding: 10px 16px;
  border-radius: 999px;
  cursor: pointer;
  transition: transform 0.12s ease, background 0.15s ease, opacity 0.15s ease;
  user-select: none;
}
.btn:active { transform: scale(0.96); }
.btn:disabled { opacity: 0.45; pointer-events: none; }
.btn svg { flex: none; }

.btn-primary {
  background: var(--accent);
  border-color: transparent;
  color: var(--accent-ink);
}
.btn-primary.placed { background: rgba(255, 255, 255, 0.14); color: var(--text); }
.btn-ghost { background: transparent; }
.btn-lg { font-size: 17px; padding: 14px 34px; }
.btn-wide { width: 100%; max-width: 420px; padding: 16px 22px; font-size: 17px; }
.btn-sm { font-size: 12.5px; padding: 6px 11px; border-radius: 8px; }
.btn-icon { margin-right: 8px; }

/* ---------------------------------------------------------------- screens */
.screen {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: calc(24px + var(--safe-t)) 20px calc(24px + var(--safe-b));
  /* Warm lamplight falling from above, not a cold blue screen wash. */
  background: radial-gradient(120% 80% at 50% 0%, #2A1B13 0%, var(--c-bg) 68%);
  text-align: center;
}

.intro-card { max-width: 420px; display: flex; flex-direction: column; align-items: center; gap: 14px; }
.eyebrow {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent);
}
.intro-card h1 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 32px;
  line-height: 1.15;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.intro-hint { margin: 0; color: var(--c-text-3); font-size: 12.5px; line-height: 1.5; }

/* loading */
.spinner {
  width: 38px;
  height: 38px;
  border: 3px solid rgba(255, 255, 255, 0.16);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
#loadingScreen p { margin: 0; color: var(--muted); font-size: 15px; }

/* ---------------------------------------------------------------- scanning */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  pointer-events: none;
}

.scan-frame {
  position: relative;
  width: min(62vw, 260px);
  aspect-ratio: 552 / 566;
  overflow: hidden;
}
.scan-frame .c {
  position: absolute;
  width: 26px;
  height: 26px;
  border: 2px solid var(--c-amber);
  box-shadow: 0 0 12px rgba(232, 163, 61, 0.35);
}
.scan-frame .tl { top: 0; left: 0; border-right: 0; border-bottom: 0; border-radius: 6px 0 0 0; }
.scan-frame .tr { top: 0; right: 0; border-left: 0; border-bottom: 0; border-radius: 0 6px 0 0; }
.scan-frame .bl { bottom: 0; left: 0; border-right: 0; border-top: 0; border-radius: 0 0 0 6px; }
.scan-frame .br { bottom: 0; right: 0; border-left: 0; border-top: 0; border-radius: 0 0 6px 0; }

.scan-line {
  position: absolute;
  left: 6%;
  right: 6%;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--c-amber), transparent);
  box-shadow: 0 0 18px 2px rgba(232, 163, 61, 0.45);
  animation: scan 2.4s ease-in-out infinite;
}
@keyframes scan { 0%, 100% { top: 6%; } 50% { top: 92%; } }

.scan-text {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  padding: 8px 16px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* ---------------------------------------------------------------- status chip */
.status-chip {
  position: fixed;
  top: calc(12px + var(--safe-t));
  /* Beside the close button, not on top of it - the same pairing as the
     Kotlin AR screen, where the X and the title pill share the top row.
     40px button + 12px gutter + 10px gap. */
  left: calc(62px + var(--safe-l));
  right: calc(12px + var(--safe-r));
  z-index: 22;
  width: fit-content;
  max-width: calc(100vw - 86px - var(--safe-l) - var(--safe-r));
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 13px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--line);
}
.status-chip .dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--muted); }
/* The chip carries the exhibit's name once one is being tracked, and a Sinhala
   or Tamil name is long. Let it clip rather than push itself off screen. */
#statusText { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.status-chip.ok .dot { background: var(--ok); box-shadow: 0 0 10px var(--ok); }
.status-chip.warn .dot { background: var(--warn-c); animation: pulse 1.3s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: 0.3; } }

/* ---------------------------------------------------------------- action bar */
.action-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px calc(18px + var(--safe-r)) calc(var(--bar-lift) + var(--safe-b)) calc(18px + var(--safe-l));
  background: linear-gradient(to top, rgba(6, 8, 12, 0.85), transparent);
  transform: translateY(130%);
  transition: transform 0.38s cubic-bezier(0.2, 0.9, 0.3, 1), opacity 0.25s ease;
}
.action-bar.up { transform: translateY(0); }
.action-bar.dim { opacity: 0.45; }

/* ---------------------------------------------------------------- brand strip */
/* Decoration over the camera feed. js/capture.js draws the same row into the
   photo itself, so this is only here to show where it will land. */
.brand-bar {
  position: fixed;
  z-index: 25;
  top: calc(10px + var(--safe-t));
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 6px 12px;
  pointer-events: none !important;   /* see .shutter-flash on why !important */
}
/* The strip owns the top of the screen while it is up, so the status chip and
   the debug button step down out from under it rather than sitting on a logo. */
.framing .status-chip,
.framing .log-toggle { top: calc(58px + var(--safe-t)); }
.framing .adjust-toggle { top: calc(110px + var(--safe-t)); }

.brand-bar img {
  height: 26px;
  width: auto;
  max-width: 28vw;
  object-fit: contain;
  filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.55));
}
/* A slot whose file is not there yet, matching what the photo draws. */
.brand-slot {
  height: 26px;
  min-width: 62px;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1.5px dashed rgba(255, 255, 255, 0.6);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.10);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.85);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

/* ---------------------------------------------------------------- shutter */
.shutter {
  appearance: none;
  -webkit-appearance: none;
  width: 66px;
  height: 66px;
  padding: 0;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.92);
  background: rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.12s ease;
}
.shutter:active { transform: scale(0.92); }
.action-bar.with-shutter .shutter { order: -1; }
.action-bar.with-shutter::after {
  content: '';
  order: -1;
  flex-basis: 100%;
  height: 0;
}
.shutter:disabled { opacity: 0.5; pointer-events: none; }
.shutter-ring {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: #fff;
  transition: transform 0.12s ease;
}
.shutter:active .shutter-ring { transform: scale(0.86); }
.shutter.busy .shutter-ring { background: var(--accent); }

/* A-Frame's dom-overlay injects
     .a-dom-overlay:not(.a-no-style) > * { pointer-events: auto }
   which outranks a plain class rule (0,3,0 beats 0,1,0). So every direct child
   of #overlay is clickable whatever this file says, and a full-bleed layer here
   swallows every tap on the page - which is exactly what this one did to
   "Start AR". Hence both belt and braces: kept out of the DOM's hit-testing
   entirely unless it is actually flashing, AND !important on top. */
.shutter-flash {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: #fff;
  opacity: 0;
  display: none;
  pointer-events: none !important;
}
.shutter-flash.fire { display: block; animation: flash 0.32s ease-out; }
@keyframes flash { 0% { opacity: 0.85; } 100% { opacity: 0; } }

/* ---------------------------------------------------------------- language */
.lang-card { gap: 18px; width: 100%; }
.lang-title { margin: 4px 0 0; font-size: 15px; color: var(--muted); }

.lang-list { display: flex; flex-direction: column; gap: 10px; width: 100%; }

/* Each language names itself in its own script, because someone who reads only
   Tamil cannot be expected to find themselves in a list written in English.
   The English name rides along underneath for staff and for the curious. */
.lang-option {
  appearance: none;
  -webkit-appearance: none;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px 18px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.05);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.12s ease;
}
.lang-option:active { transform: scale(0.985); }
.lang-option.on {
  border-color: var(--accent);
  background: rgba(224, 103, 58, 0.14);
}
.lang-option .native { font-size: 18px; font-weight: 600; line-height: 1.2; }
.lang-option .latin { font-size: 12.5px; color: var(--muted); }
.lang-option .tick { margin-left: auto; color: var(--accent); opacity: 0; font-size: 17px; }
.lang-option.on .tick { opacity: 1; }


/* ---------------------------------------------------------------- details sheet */
/* The label. A bottom sheet rather than a full screen: the artwork stays
   visible above it, which is the whole point of reading it here and not at
   home. */
.details-sheet {
  position: fixed;
  inset: 0;
  z-index: 85;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(6, 8, 12, 0.55);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: detailsFade 0.18s ease-out;
}
@keyframes detailsFade { from { opacity: 0; } to { opacity: 1; } }

.details-card {
  width: 100%;
  max-width: 560px;
  max-height: 82vh;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: 20px 20px 0 0;
  padding: 0 0 calc(10px + var(--safe-b));
  animation: detailsUp 0.24s cubic-bezier(0.2, 0.8, 0.25, 1);
}
@keyframes detailsUp { from { transform: translateY(14%); } to { transform: translateY(0); } }

.details-head {
  position: relative;
  flex: 0 0 auto;
  padding: 8px 52px 10px 20px;
}
.details-grab {
  width: 38px;
  height: 4px;
  margin: 0 auto 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.22);
}
.details-head h2 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 22px;
  line-height: 1.3;
  font-weight: 600;
}
.details-x { position: absolute; top: 14px; right: 14px; }

/* Language chips. Only the languages this exhibit is actually written in are
   offered, so a chip never leads to an empty sheet. */
.details-langs {
  flex: 0 0 auto;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 2px 20px 10px;
  scrollbar-width: none;
}
.details-langs::-webkit-scrollbar { display: none; }
.details-langs:empty { display: none; }
.details-lang {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 14px;
  cursor: pointer;
}
.details-lang.on { border-color: var(--accent); color: var(--c-terracotta-lt); background: rgba(224, 103, 58, 0.14); }

.details-fallback {
  flex: 0 0 auto;
  margin: 0 20px 8px;
  padding: 8px 12px;
  border-radius: 10px;
  background: rgba(224, 167, 43, 0.12);
  border: 1px solid rgba(224, 167, 43, 0.3);
  color: var(--warn-c);
  font-size: 12.5px;
  line-height: 1.45;
}

/* The museum's own words. Only the tags js/content.js allows can appear here,
   so every one of them is styled - there is no unknown-element case. */
.details-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 20px 4px;
  font-size: 15.5px;
  line-height: 1.62;
  color: rgba(238, 241, 246, 0.92);
  overscroll-behavior: contain;
}
.details-body > :first-child { margin-top: 0; }
.details-body > :last-child { margin-bottom: 0; }
.details-body h2 { font-size: 17.5px; line-height: 1.3; margin: 20px 0 8px; font-weight: 700; color: var(--text); }
.details-body h3 { font-size: 15.5px; line-height: 1.35; margin: 16px 0 6px; font-weight: 700; color: var(--text); }
.details-body p { margin: 0 0 12px; }
.details-body ul, .details-body ol { margin: 0 0 12px; padding-left: 22px; }
.details-body li { margin: 0 0 6px; }
.details-body li::marker { color: var(--accent); }
.details-body strong { font-weight: 700; color: var(--text); }
.details-body u { text-underline-offset: 3px; }
.details-body .empty-note { color: var(--muted); font-style: italic; }

.details-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 20px 4px;
  border-top: 1px solid var(--line);
}
.details-foot:not(.has-audio) { display: none; }
.details-play { flex: 0 0 auto; }
.details-progress {
  flex: 1 1 auto;
  height: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
  overflow: hidden;
}
#detailsProgressFill {
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--accent);
  transition: width 0.2s linear;
}
#detailsAudio { display: none; }

/* ---------------------------------------------------------------- photo sheet */
.photo-sheet {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(16px + var(--safe-t)) 16px calc(16px + var(--safe-b));
  background: rgba(6, 8, 12, 0.88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.photo-card {
  width: 100%;
  max-width: 420px;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.photo-card img {
  min-height: 0;
  max-width: 100%;
  flex: 1 1 auto;
  object-fit: contain;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: #000;
}
.photo-hint {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--muted);
  text-align: center;
}
.photo-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

/* ---------------------------------------------------------------- adjust */
/* Tuning the figure while standing in front of it. Kept apart from the log on
   purpose: the log is a wall of text and this needs the picture visible. */
.adjust-toggle {
  position: fixed;
  z-index: 70;
  top: calc(62px + var(--safe-t));
  right: calc(10px + var(--safe-r));
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
}
.adjust-toggle.on { background: var(--accent); color: var(--accent-ink); border-color: transparent; }

.adjust-panel {
  position: fixed;
  z-index: 82;
  left: 0;
  right: 0;
  bottom: 0;
  /* Under half the screen: the whole point is watching the figure change, so
     the body scrolls rather than the sheet growing. */
  max-height: min(50vh, 430px);
  display: flex;
  flex-direction: column;
  background: var(--panel);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-top: 1px solid var(--line);
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -18px 50px rgba(0, 0, 0, 0.5);
  padding-bottom: var(--safe-b);
}

.adjust-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px 8px;
}
.adjust-head strong { font-size: 15px; }
.adjust-head .spacer { flex: 1; }
.adjust-who {
  font-size: 12px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 45%;
}

.adjust-tabs {
  display: flex;
  gap: 6px;
  padding: 0 14px 10px;
  border-bottom: 1px solid var(--line);
}
.adjust-tab {
  appearance: none;
  -webkit-appearance: none;
  flex: 1;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 8px 6px;
  border-radius: 10px;
  cursor: pointer;
}
.adjust-tab.on { background: rgba(255, 255, 255, 0.12); color: var(--text); }

.adjust-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 10px 14px 4px;
}

.adj-row {
  display: grid;
  grid-template-columns: 74px 34px 1fr 34px 62px;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
}
.adj-row > label {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
}
.adj-row output {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--text);
}
.adj-step {
  appearance: none;
  -webkit-appearance: none;
  width: 34px;
  height: 30px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  border-radius: 8px;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}
.adj-step:active { background: rgba(255, 255, 255, 0.18); }

/* A slider you can actually hit with a thumb. */
.adj-row input[type="range"] {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  height: 30px;
  background: transparent;
  cursor: pointer;
}
.adj-row input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.18);
}
.adj-row input[type="range"]::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.18);
}
.adj-row input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  margin-top: -9px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid rgba(0, 0, 0, 0.35);
}
.adj-row input[type="range"]::-moz-range-thumb {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid rgba(0, 0, 0, 0.35);
}

/* Toggles and pickers reuse the row grid, spanning the slider columns. */
.adj-row.wide { grid-template-columns: 74px 1fr; }
.adj-row .adj-choice {
  display: flex;
  gap: 6px;
}
.adj-choice button {
  appearance: none;
  -webkit-appearance: none;
  flex: 1;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 7px 8px;
  border-radius: 8px;
  cursor: pointer;
}
.adj-choice button.on { background: var(--accent); color: var(--accent-ink); border-color: transparent; }

/* Shadow colours. Fixed swatches, not a colour input: see buildAdjustRow. */
.adj-row .adj-swatch {
  display: flex;
  gap: 6px;
}
.adj-swatch button {
  appearance: none;
  -webkit-appearance: none;
  flex: 1;
  height: 30px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
}
.adj-swatch button.on {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* The shadow list: a heading per ellipse, then its rows. */
.adj-group {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 10px 0 2px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.adj-drop {
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  padding: 4px 9px;
  border-radius: 7px;
  cursor: pointer;
}
.adj-drop:active { background: rgba(239, 95, 95, 0.22); color: var(--text); }
.adj-add { width: 100%; margin: 12px 0 4px; }

.adj-hint {
  margin: 2px 0 10px;
  font-size: 11.5px;
  line-height: 1.5;
  color: rgba(154, 164, 181, 0.8);
}

.adjust-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 14px 12px;
  border-top: 1px solid var(--line);
}
.adjust-note {
  flex: 1 0 100%;
  margin: 0;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--muted);
  min-height: 1em;
}
.adjust-note.ok { color: var(--ok); }
.adjust-note.bad { color: var(--err); }

/* ---------------------------------------------------------------- error */
.error-banner {
  position: fixed;
  z-index: 60;
  left: calc(12px + var(--safe-l));
  right: calc(12px + var(--safe-r));
  top: calc(12px + var(--safe-t));
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 15px;
  border-radius: 14px;
  background: rgba(60, 16, 16, 0.94);
  border: 1px solid rgba(239, 95, 95, 0.5);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
}
.error-banner p { margin: 0; flex: 1; font-size: 13.5px; line-height: 1.45; }

/* ---------------------------------------------------------------- log window */
.log-toggle {
  position: fixed;
  z-index: 70;
  top: calc(10px + var(--safe-t));
  right: calc(10px + var(--safe-r));
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
}
.log-toggle:active { transform: scale(0.94); }
/* While the browse shell is up, this would sit exactly on the language chip in
   its top bar - both are the top-right corner. It drops to the other end of
   the screen instead: still one tap away, over a part of the page that has
   nothing in it, and back where it belongs the moment the camera starts. */
.log-toggle.browsing {
  top: auto;
  bottom: calc(92px + var(--safe-b));
}
.log-toggle.has-error { border-color: var(--err); box-shadow: 0 0 0 3px rgba(239, 95, 95, 0.22); }

.log-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--err);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 19px;
}

.log-panel {
  position: fixed;
  z-index: 80;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 72vh;
  max-height: 72dvh;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-top: 1px solid var(--line);
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -18px 50px rgba(0, 0, 0, 0.6);
  padding-bottom: var(--safe-b);
}

.log-head {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 12px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.log-head strong { font-size: 14px; }
.log-head .spacer { flex: 1; }
.log-count {
  font-size: 11px;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.08);
  padding: 2px 7px;
  border-radius: 999px;
}

.log-tools {
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.tool-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tool-row label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.07em; }

.log-list {
  margin: 0;
  padding: 8px 10px calc(14px + var(--safe-b));
  list-style: none;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  flex: 1;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  font-size: 11.5px;
  line-height: 1.5;
}

.log-entry {
  display: flex;
  gap: 8px;
  padding: 2px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  word-break: break-word;
}
.log-t { color: #5d6675; white-space: pre; flex: none; }
.log-m { white-space: pre-wrap; flex: 1; }

.log-info  .log-m { color: #c8d0dd; }
.log-debug .log-m { color: #7d8797; }
.log-ok    .log-m { color: var(--ok); }
.log-event .log-m { color: #6fb3ff; }
.log-warn  .log-m { color: var(--warn-c); }
.log-error .log-m { color: var(--err); font-weight: 600; }

.copy-toast {
  position: absolute;
  left: 50%;
  bottom: calc(16px + var(--safe-b));
  transform: translateX(-50%);
  margin: 0;
  padding: 9px 16px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.88);
  border: 1px solid var(--line);
  font-size: 13px;
  white-space: nowrap;
}

/* Landscape phones: keep the chrome out of the way. */
@media (orientation: landscape) and (max-height: 500px) {
  .intro-card h1 { font-size: 24px; }
  .details-card { max-height: 88vh; }
  .details-head h2 { font-size: 18px; }
  .details-body { font-size: 15px; }
  .log-panel { max-height: 86vh; }
  .action-bar { padding-top: 8px; padding-bottom: calc(10px + var(--safe-b)); }
}

/* ---------------------------------------------------------------- floor scan */
/* Scene 2 draws its own reticle in 3D at the centre of the screen, so the
   prompt has to keep out of its way. */
.overlay-bottom {
  justify-content: flex-end;
  padding-bottom: calc(112px + var(--safe-b));
}
}
