/* ============================================================
   Miami Noir — World Page v1 (mini-city pattern)
   Phase 1: scene + hotspots + drawer.

   Style note:
   - Full-bleed scene with CSS placeholder fallback (no video required).
   - Hotspots are absolutely positioned over the scene at % coords.
   - Drawer = bottom-sheet on mobile, right-sidebar on desktop.
   - Mood: wet asphalt + neon pools + grain + vignette.
   - Editorial typography. Mono only for telemetry/labels.

   Design tokens live in /css/style.css (--paper, --bg-deep, etc.)
   This stylesheet only adds world-page layout on top.
   ============================================================ */

/* Skip-link (a11y) */
.world-skiplink {
  position: absolute;
  left: -9999px;
  top: 1rem;
  z-index: 100;
  background: var(--paper);
  color: var(--bg-deep);
  padding: 0.5rem 0.85rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  border-radius: 2px;
  text-decoration: none;
}
.world-skiplink:focus {
  left: 1rem;
}

/* ============================================================
   BASE — body scoping for world pages
   ============================================================ */
.world-body {
  background: var(--bg-deep);
  color: var(--paper);
  font-family: var(--font);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Prevent body scroll on mobile when scene is full-bleed; drawer is the
     only thing that scrolls. Main page acts like an app shell. */
  overflow-x: hidden;
}

.world-body .mono {
  font-family: var(--font-mono);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* Triangle accent (OnSite signature) */
.world-body .tri {
  color: var(--onsite-red);
  font-style: normal;
  display: inline-block;
  margin-right: 0.45em;
  line-height: 1;
}

/* Lock body scroll while drawer is open */
.world-body.drawer-open {
  overflow: hidden;
}

/* ============================================================
   HEADER — slim sticky. Brand left, back-to-Atlas right.
   ============================================================ */
.world-header {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1.5rem;
  background: rgba(3, 3, 3, 0.72);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.world-header-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--paper);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  font-weight: 700;
  transition: opacity 0.2s;
}
.world-header-brand:hover { opacity: 0.85; }
.world-header-brand .tri { font-size: 1rem; }

.world-header-back {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  color: var(--paper-muted);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  font-weight: 600;
  padding: 0.45rem 0.85rem;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 2px;
  transition: color 0.22s, border-color 0.22s, background 0.22s;
}
.world-header-back:hover {
  color: var(--paper);
  border-color: rgba(255, 255, 255, 0.28);
  background: rgba(245, 240, 232, 0.04);
}
.world-header-back .back-arrow {
  color: var(--onsite-red);
  font-size: 0.85em;
  line-height: 1;
  transition: transform 0.22s;
}
.world-header-back:hover .back-arrow { transform: translateX(-3px); }

/* ============================================================
   SCENE — full-bleed cinematic street.
   Either a <video> background (when asset exists) or a layered
   CSS placeholder (default fallback). Hotspots overlay on top.
   ============================================================ */
.world-scene {
  position: relative;
  /* Fill viewport below the header. Header is ~58px; we don't measure
     it dynamically — close enough that the scene feels full-bleed and
     no hotspot falls below the fold on any reasonable viewport. */
  min-height: calc(100vh - 58px);
  /* Aspect-ratio cap so hotspot % positions stay readable on ultrawide
     screens. Above 16:9 we letterbox subtly via vignette. */
  overflow: hidden;
  isolation: isolate;
  background: #020608;
}

/* Background container — sits behind hotspots and chrome. */
.scene-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}

/* Optional <video> layer (Phase 1.6 hot-swap target). */
.scene-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;
}

/* CSS-only placeholder — wet asphalt + neon pools + grain. */
.scene-placeholder {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(180deg,
    #020608 0%,
    #061318 35%,
    #050a0e 65%,
    #030608 100%);
}

.scene-glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(60px);
  opacity: 0.85;
}
.scene-glow-cyan {
  top: -8%;
  left: -6%;
  width: 58%;
  height: 60%;
  background: radial-gradient(closest-side,
    rgba(0, 212, 255, 0.32) 0%,
    rgba(0, 130, 170, 0.16) 45%,
    transparent 75%);
}
.scene-glow-red {
  bottom: -10%;
  right: -8%;
  width: 55%;
  height: 55%;
  background: radial-gradient(closest-side,
    rgba(184, 8, 18, 0.28) 0%,
    rgba(140, 6, 14, 0.14) 50%,
    transparent 78%);
}
.scene-glow-pool {
  bottom: -20%;
  left: 25%;
  width: 60%;
  height: 45%;
  background: radial-gradient(closest-side,
    rgba(0, 90, 120, 0.32) 0%,
    rgba(0, 50, 70, 0.12) 55%,
    transparent 80%);
  filter: blur(80px);
}

/* Wet sheen — diagonal subtle highlight */
.scene-sheen {
  position: absolute;
  inset: 0;
  background: linear-gradient(108deg,
    transparent 28%,
    rgba(245, 240, 232, 0.025) 50%,
    transparent 72%);
  mix-blend-mode: screen;
}

/* Fine horizontal grain — like film scan lines but invisible-subtle */
.scene-grain {
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    0deg,
    transparent 0px,
    transparent 1px,
    rgba(255, 255, 255, 0.012) 1px,
    rgba(255, 255, 255, 0.012) 2px
  );
  mix-blend-mode: overlay;
  opacity: 0.6;
}

/* Vignette — cinematic frame */
.scene-vignette {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 80% 65% at 50% 45%, transparent 35%, rgba(0, 0, 0, 0.55) 100%),
    linear-gradient(180deg, transparent 60%, rgba(0, 0, 0, 0.45) 100%);
}

/* ============================================================
   v1.1 — Visual City Layer
   CSS-only Miami Noir street scene. Layered building silhouettes,
   road perspective, wet asphalt neon reflections. No external assets.
   All SVG paths are inline data URIs to keep zero network requests.
   ============================================================ */

.scene-skyline {
  position: absolute;
  left: 0;
  right: 0;
  pointer-events: none;
  background-position: bottom center;
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

/* Distant skyline — low-contrast, sits on the horizon line.
   12 buildings of varying heights, single dark fill. */
.scene-skyline-far {
  bottom: 30%;
  height: 16%;
  opacity: 0.7;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1280 200' preserveAspectRatio='none'><path d='M0 200L0 150L40 150L40 140L120 140L120 125L190 125L190 115L280 115L280 105L360 105L360 130L460 130L460 120L560 120L560 100L650 100L650 130L755 130L755 110L860 110L860 130L920 130L920 105L1010 105L1010 140L1140 140L1140 130L1280 130L1280 200Z' fill='%230a1418'/></svg>");
}

/* Mid skyline — closer, darker silhouettes with lit windows
   (amber = residential warm light, cyan = club / signage). */
.scene-skyline-mid {
  bottom: 24%;
  height: 24%;
  opacity: 0.96;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1280 280' preserveAspectRatio='none'><path d='M0 280L0 170L60 170L60 140L150 140L150 100L230 100L230 130L320 130L320 90L390 90L390 115L470 115L470 75L530 75L530 105L620 105L620 60L680 60L680 90L770 90L770 130L850 130L850 100L920 100L920 85L1000 85L1000 110L1080 110L1080 70L1150 70L1150 95L1230 95L1230 130L1280 130L1280 280Z' fill='%23030608'/><g fill='%23d4a04a' opacity='0.75'><rect x='75' y='160' width='3' height='3'/><rect x='90' y='155' width='3' height='3'/><rect x='168' y='115' width='3' height='3'/><rect x='192' y='118' width='3' height='3'/><rect x='340' y='100' width='3' height='3'/><rect x='500' y='85' width='3' height='3'/><rect x='720' y='105' width='3' height='3'/><rect x='885' y='115' width='3' height='3'/><rect x='960' y='95' width='3' height='3'/><rect x='1110' y='80' width='3' height='3'/></g><g fill='%2300c8e0' opacity='0.6'><rect x='108' y='150' width='3' height='3'/><rect x='400' y='130' width='3' height='3'/><rect x='648' y='75' width='3' height='3'/><rect x='872' y='108' width='3' height='3'/><rect x='1192' y='110' width='3' height='3'/></g></svg>");
}

/* Road — wet asphalt at ground level with one-point perspective.
   The radial darkens toward bottom; the ::before trapezoid suggests
   a street vanishing toward the horizon. */
.scene-road {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 32%;
  pointer-events: none;
  background:
    radial-gradient(ellipse 60% 80% at 50% 100%,
      rgba(0, 80, 110, 0.16) 0%,
      transparent 70%),
    linear-gradient(180deg,
      transparent 0%,
      rgba(6, 12, 18, 0.55) 100%);
}
.scene-road::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(14, 22, 30, 0.08) 0%,
    rgba(28, 42, 58, 0.42) 100%);
  clip-path: polygon(43% 0, 57% 0, 90% 100%, 10% 100%);
  opacity: 0.6;
}

/* Wet asphalt reflections — vertical neon light columns reflecting
   off the wet street. Slightly blurred for liquid feel.
   5 streaks in cyan / red / teal / amber / cyan, positioned across width. */
.scene-wet-streaks {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 28%;
  pointer-events: none;
  opacity: 0.55;
  background-image:
    linear-gradient(180deg, transparent 25%, rgba(0, 212, 255, 0.20) 100%),
    linear-gradient(180deg, transparent 35%, rgba(184, 8, 18, 0.14) 100%),
    linear-gradient(180deg, transparent 30%, rgba(0, 180, 200, 0.10) 100%),
    linear-gradient(180deg, transparent 40%, rgba(200, 140, 30, 0.10) 100%),
    linear-gradient(180deg, transparent 35%, rgba(0, 212, 255, 0.08) 100%);
  background-position: 22% 0, 76% 0, 48% 0, 62% 0, 34% 0;
  background-size: 3px 100%, 4px 100%, 2px 100%, 2px 100%, 2px 100%;
  background-repeat: no-repeat;
  filter: blur(1px);
}

/* Scene chrome — minimal world identity, top-left of scene.
   Sits above hotspots so it's always legible. */
.scene-chrome {
  position: absolute;
  top: 1.75rem;
  left: 1.75rem;
  z-index: 5;
  pointer-events: none;
  max-width: 480px;
}
.scene-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--paper-muted);
  margin: 0 0 0.65rem;
  display: inline-flex;
  align-items: center;
}
.scene-eyebrow .tri {
  color: var(--onsite-red);
  margin-right: 0.5em;
  font-size: 0.9rem;
}
.scene-byline {
  font-family: var(--font);
  font-size: clamp(0.92rem, 1.6vw, 1.1rem);
  font-weight: 400;
  font-style: italic;
  color: var(--paper);
  margin: 0;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6);
}
.scene-byline .by {
  color: var(--paper-muted);
  margin-right: 0.4em;
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 0.7em;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

/* Hint chip — bottom-center subtle prompt */
.scene-hint {
  position: absolute;
  bottom: 1.75rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--paper-muted);
  padding: 0.4rem 0.8rem;
  background: rgba(3, 3, 3, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 999px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0.85;
}
.scene-hint .hint-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--signal-cyan);
  box-shadow: 0 0 8px rgba(0, 212, 255, 0.7);
  animation: hint-pulse 2.4s ease-in-out infinite;
}
@keyframes hint-pulse {
  0%, 100% { opacity: 0.5; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.35); }
}

/* Coord chip — preserved cultural telemetry */
.scene-coord {
  position: absolute;
  bottom: 1.5rem;
  right: 1.5rem;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 0.65em;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--paper-muted);
  padding: 0.38rem 0.65rem;
  background: rgba(3, 3, 3, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.scene-coord .coord-key { color: var(--signal-cyan); }
.scene-coord .coord-val { color: var(--paper); }

/* ============================================================
   HOTSPOTS — absolutely positioned <button> over scene
   Each hotspot has:
     - pulsing dot ring (the "signal")
     - label that appears on hover/focus
     - color variant (cyan = active, red = live-locked)
     - locked state (dimmer, no hover transform)
   ============================================================ */
.world-hotspots {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none; /* children re-enable */
}

.hotspot {
  position: absolute;
  /* x/y come from inline style:left/top set by world.js.
     Default (data-flip="right"): the DOT center sits exactly on x%,y%,
     and the label flows to the right. -9px matches half of the 18px dot. */
  transform: translate(-9px, -50%);
  pointer-events: auto;

  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  font-weight: 600;
  /* Tap target ≥44px enforced by .hotspot-dot ring outer size */
  -webkit-tap-highlight-color: transparent;
}

/* Smart-flip for hotspots in the right half of the scene:
   label flows LEFT of dot, dot still anchored on x%,y%.
   row-reverse keeps the dot visually on the right side of the button. */
.hotspot[data-flip="left"] {
  flex-direction: row-reverse;
  transform: translate(calc(-100% + 9px), -50%);
}

/* Pulsing signal dot */
.hotspot-dot {
  position: relative;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--signal-cyan);
  box-shadow:
    0 0 0 4px rgba(0, 212, 255, 0.18),
    0 0 18px rgba(0, 212, 255, 0.55);
  flex-shrink: 0;
  transition: transform 0.2s, box-shadow 0.2s;
}
.hotspot-dot::after {
  content: '';
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  border: 1px solid rgba(0, 212, 255, 0.4);
  animation: hotspot-pulse 2.4s ease-out infinite;
  pointer-events: none;
}
@keyframes hotspot-pulse {
  0%   { transform: scale(0.7); opacity: 0.8; }
  100% { transform: scale(2);   opacity: 0;   }
}

/* Red variant — for "live" / club hotspots */
.hotspot[data-color="red"] .hotspot-dot {
  background: var(--onsite-red);
  box-shadow:
    0 0 0 4px rgba(184, 8, 18, 0.18),
    0 0 18px rgba(184, 8, 18, 0.55);
}
.hotspot[data-color="red"] .hotspot-dot::after {
  border-color: rgba(184, 8, 18, 0.45);
}

/* Hotspot label — always visible but quieter, brightens on hover */
.hotspot-label {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.4rem 0.7rem;
  background: rgba(3, 3, 3, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 2px;
  white-space: nowrap;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transition: border-color 0.2s, background 0.2s, color 0.2s;
}
.hotspot-label .label-icon {
  color: var(--signal-cyan);
  font-size: 0.85em;
  line-height: 1;
}
.hotspot[data-color="red"] .hotspot-label .label-icon {
  color: var(--onsite-red);
}

/* Hover/focus: dot grows, label brightens */
.hotspot:hover .hotspot-dot,
.hotspot:focus-visible .hotspot-dot {
  transform: scale(1.18);
}
.hotspot:hover .hotspot-label,
.hotspot:focus-visible .hotspot-label {
  border-color: rgba(0, 212, 255, 0.45);
  background: rgba(3, 3, 3, 0.85);
  color: var(--paper);
}
.hotspot[data-color="red"]:hover .hotspot-label,
.hotspot[data-color="red"]:focus-visible .hotspot-label {
  border-color: rgba(184, 8, 18, 0.55);
}
.hotspot:focus-visible {
  outline: none;
}
.hotspot:focus-visible .hotspot-label {
  outline: 2px solid var(--paper);
  outline-offset: 3px;
}

/* Locked hotspots — dimmer, no pulse, lock icon in label */
.hotspot.is-locked .hotspot-dot {
  background: rgba(245, 240, 232, 0.35);
  box-shadow:
    0 0 0 4px rgba(245, 240, 232, 0.08),
    0 0 10px rgba(245, 240, 232, 0.15);
}
.hotspot.is-locked .hotspot-dot::after {
  animation-duration: 4.5s;
  border-color: rgba(245, 240, 232, 0.18);
}
.hotspot.is-locked .hotspot-label {
  color: var(--paper-muted);
}
/* v1.3.1 — OnSite Club variant: nightlife beacon (red, slower pulse, ⌂ glyph).
   Overrides .is-locked grey treatment because the Club is the brand's social
   anchor at the vanishing point. Drawer content stays "coming soon" until
   live programming is ready. Visually distinguished from The House (locked
   premium space) which keeps the default ▾ + grey treatment. */
.hotspot[data-variant="club"] .hotspot-dot {
  background: var(--onsite-red);
  box-shadow:
    0 0 0 5px rgba(184, 8, 18, 0.22),
    0 0 22px rgba(184, 8, 18, 0.65);
}
/* Locked + club: keep red identity, only slightly dimmed (NOT grey) */
.hotspot.is-locked[data-variant="club"] .hotspot-dot {
  background: var(--onsite-red);
  box-shadow:
    0 0 0 5px rgba(184, 8, 18, 0.18),
    0 0 18px rgba(184, 8, 18, 0.50);
  opacity: 0.92;
}
/* Beacon-quality pulse: 3.6s vs default 2.4s and locked 4.5s. Slower feels
   premium / nightlife / "this place breathes at its own pace." */
.hotspot[data-variant="club"] .hotspot-dot::after {
  border-color: rgba(184, 8, 18, 0.55);
  animation: club-beacon-pulse 3.6s ease-out infinite;
}
.hotspot.is-locked[data-variant="club"] .hotspot-dot::after {
  animation: club-beacon-pulse 3.6s ease-out infinite;
  border-color: rgba(184, 8, 18, 0.45);
}
@keyframes club-beacon-pulse {
  0%   { transform: scale(0.65); opacity: 0.9; }
  60%  { opacity: 0.4; }
  100% { transform: scale(2.4);  opacity: 0;   }
}
/* Label: red icon + subtle red border at rest, stronger red on hover */
.hotspot[data-variant="club"] .hotspot-label {
  border-color: rgba(184, 8, 18, 0.32);
}
.hotspot[data-variant="club"] .hotspot-label .label-icon {
  color: var(--onsite-red);
  font-size: 1em;
  line-height: 1;
}
.hotspot[data-variant="club"]:hover .hotspot-label,
.hotspot[data-variant="club"]:focus-visible .hotspot-label {
  border-color: rgba(184, 8, 18, 0.7);
  box-shadow: 0 0 14px rgba(184, 8, 18, 0.25);
}
/* Lock glyph stays on locked club — semantic still says "coming soon" */
.hotspot.is-locked[data-variant="club"] .hotspot-label {
  color: var(--paper);  /* override locked dim text — club label stays readable */
}
.hotspot.is-locked[data-variant="club"] .hotspot-label .label-lock {
  color: rgba(184, 8, 18, 0.7);  /* lock icon tinted red instead of grey */
}

.hotspot.is-locked .hotspot-label .label-lock {
  color: var(--paper-muted);
  margin-left: 0.4em;
  font-size: 0.9em;
}

/* ============================================================
   DRAWER — bottom-sheet on mobile, right-sidebar on desktop
   Hidden by default via [hidden]; open state toggled by JS.
   ============================================================ */
.world-drawer {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  pointer-events: none;
}
.world-drawer[hidden] {
  display: none;
}

.drawer-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(2, 4, 6, 0.62);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  pointer-events: auto;
  opacity: 0;
  transition: opacity 220ms ease-out;
}
.world-drawer.is-open .drawer-backdrop {
  opacity: 1;
}

.drawer-panel {
  position: absolute;
  background: #060a0d;
  color: var(--paper);
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.5);
  /* Default: mobile bottom-sheet */
  bottom: 0;
  left: 0;
  right: 0;
  max-height: 78vh;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  border-top-left-radius: 14px;
  border-top-right-radius: 14px;
  transform: translateY(100%);
  transition: transform 280ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.world-drawer.is-open .drawer-panel {
  transform: translateY(0);
}

/* Desktop (>880px): right-sidebar */
@media (min-width: 881px) {
  .drawer-panel {
    top: 0;
    bottom: 0;
    right: 0;
    left: auto;
    width: 440px;
    max-width: 92vw;
    max-height: 100vh;
    border-top: 0;
    border-left: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 0;
    transform: translateX(100%);
    box-shadow: -10px 0 40px rgba(0, 0, 0, 0.5);
  }
  .world-drawer.is-open .drawer-panel {
    transform: translateX(0);
  }
}

.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  flex-shrink: 0;
}
.drawer-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--paper-muted);
  margin: 0;
  display: inline-flex;
  align-items: center;
}
.drawer-eyebrow .tri {
  color: var(--onsite-red);
  margin-right: 0.4em;
}
.drawer-eyebrow .drawer-breadcrumb {
  color: var(--paper);
}

.drawer-close {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--paper);
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  border-radius: 2px;
  transition: background 0.2s, border-color 0.2s;
}
.drawer-close:hover {
  background: rgba(245, 240, 232, 0.08);
  border-color: rgba(255, 255, 255, 0.3);
}
.drawer-close:focus-visible {
  outline: 2px solid var(--signal-cyan);
  outline-offset: 2px;
}

.drawer-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 1.5rem 1.5rem 2rem;
  -webkit-overflow-scrolling: touch;
}

.drawer-title {
  font-family: var(--font);
  font-size: clamp(1.6rem, 4vw, 2.1rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--paper);
  margin: 0 0 0.5rem;
}

.drawer-tagline {
  font-family: var(--font);
  font-size: 1rem;
  font-style: italic;
  color: var(--paper-muted);
  margin: 0 0 1.5rem;
  line-height: 1.45;
}

.drawer-body-text {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--paper);
  margin: 0 0 1.5rem;
}

.drawer-embeds {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin: 0 0 1.5rem;
}
.drawer-embed {
  width: 100%;
}
.drawer-embed iframe {
  display: block;
  width: 100%;
  border: 0;
  border-radius: 8px;
}
.drawer-embed.embed-spotify iframe { height: 152px; }
.drawer-embed.embed-youtube iframe {
  aspect-ratio: 16 / 9;
  height: auto;
}

/* ============================================================
   ROOM-SCENE EMBED · cinematic room illusion inside drawer.
   Reusable pattern for Tony's Room, Rik's Room, Video Theater,
   Listening Room, The Road, Motel Light, OnSite Club.
   Pure CSS + HTMLMediaElement. Zero new dependencies. No 3D.
   ============================================================ */

.drawer-embed.embed-room-scene {
  padding: 0;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.06);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
}

.room-wall {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 11;
  overflow: hidden;
  isolation: isolate;
  /* Default room base — dark interior gradient */
  background:
    radial-gradient(ellipse at 30% 40%, rgba(20, 22, 28, 0.92) 0%, #07080b 70%),
    linear-gradient(180deg, #0a0c10 0%, #050608 100%);
}

/* Subtle floor seam — gives depth without paint stroke */
.room-wall::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 18%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.06) 35%,
    rgba(255, 255, 255, 0.06) 65%,
    transparent 100%);
  z-index: 1;
}

/* Ambient layer · suggestion of city light bleeding through a window */
.room-ambient {
  position: absolute;
  pointer-events: none;
  z-index: 1;
}

.room-ambient-window {
  /* Distant city glow on the left wall — cool cyan, soft */
  left: -6%;
  top: 14%;
  width: 28%;
  height: 56%;
  background: radial-gradient(ellipse at 35% 45%,
    rgba(0, 212, 255, 0.16) 0%,
    rgba(0, 212, 255, 0.06) 35%,
    transparent 70%);
  filter: blur(14px);
  opacity: 0.85;
}

.room-ambient-neon {
  /* Off-frame red neon spill — bottom-right · suggests street sign nearby */
  right: -8%;
  bottom: 6%;
  width: 36%;
  height: 38%;
  background: radial-gradient(ellipse at 60% 70%,
    rgba(184, 8, 18, 0.22) 0%,
    rgba(184, 8, 18, 0.08) 40%,
    transparent 75%);
  filter: blur(18px);
  opacity: 0.95;
}

/* TV / monitor frame · holds the screen media */
.room-tv {
  position: absolute;
  top: 22%;
  left: 50%;
  transform: translateX(-50%);
  width: 62%;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
}

.room-tv-bezel {
  width: 100%;
  aspect-ratio: 1 / 1;
  background: #000;
  border: 6px solid #1a1c20;
  border-radius: 6px;
  box-shadow:
    /* Inset bezel highlight */
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    /* Soft glow from screen onto wall */
    0 0 36px rgba(0, 212, 255, 0.12),
    0 0 80px rgba(184, 8, 18, 0.10),
    /* Frame depth */
    0 6px 18px rgba(0, 0, 0, 0.6);
  overflow: hidden;
  position: relative;
}

.room-tv-screen {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
  background: #000;
}

/* Scanline overlay on the screen — vintage TV feel · keeps the video cinematic */
.room-tv-bezel::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    180deg,
    transparent 0,
    transparent 2px,
    rgba(255, 255, 255, 0.025) 2px,
    rgba(255, 255, 255, 0.025) 3px
  );
  mix-blend-mode: overlay;
  z-index: 3;
}

.room-tv-label {
  margin: 0;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.6875rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
  text-align: center;
}

/* ----------------------------------------------------------------
   ATMOSPHERE VARIANTS · same room geometry · different mood
   Each variant tunes the ambient layers and bezel glow per world.
   ---------------------------------------------------------------- */

/* Miami Noir night (Tony's Room default) — cyan window + red neon */
.atmosphere-miami-noir-night .room-ambient-window {
  background: radial-gradient(ellipse at 35% 45%,
    rgba(0, 212, 255, 0.18) 0%,
    rgba(0, 212, 255, 0.07) 35%,
    transparent 70%);
}
.atmosphere-miami-noir-night .room-ambient-neon {
  background: radial-gradient(ellipse at 60% 70%,
    rgba(184, 8, 18, 0.24) 0%,
    rgba(184, 8, 18, 0.09) 40%,
    transparent 75%);
}

/* Future variants — pre-wired for upcoming rooms (no current consumers) */
.atmosphere-desert-country-dusk .room-wall {
  background:
    radial-gradient(ellipse at 30% 40%, rgba(28, 22, 16, 0.92) 0%, #0a0805 70%),
    linear-gradient(180deg, #100c08 0%, #060403 100%);
}
.atmosphere-desert-country-dusk .room-ambient-window {
  background: radial-gradient(ellipse at 35% 45%,
    rgba(212, 160, 23, 0.20) 0%,
    rgba(212, 160, 23, 0.07) 35%,
    transparent 70%);
}
.atmosphere-desert-country-dusk .room-ambient-neon {
  background: radial-gradient(ellipse at 60% 70%,
    rgba(200, 60, 30, 0.18) 0%,
    rgba(200, 60, 30, 0.06) 40%,
    transparent 75%);
}

/* Reduced motion · disable the scanline overlay's potential reading shimmer */
@media (prefers-reduced-motion: reduce) {
  .room-tv-bezel::after { display: none; }
}

/* Mobile · room scales gracefully */
@media (max-width: 768px) {
  .room-wall { aspect-ratio: 4 / 3; }
  .room-tv { top: 18%; width: 72%; }
  .room-tv-bezel { border-width: 4px; }
  .room-tv-label { font-size: 0.625rem; }
}

.drawer-ctas {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  margin: 0 0 1.25rem;
}
.drawer-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5em;
  padding: 0.85rem 1rem;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--paper);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  font-weight: 600;
  border-radius: 2px;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.drawer-cta .cta-label {
  flex: 1 1 auto;
  text-align: left;
}
.drawer-cta:focus-visible {
  outline: 2px solid var(--signal-cyan);
  outline-offset: 2px;
}
.drawer-cta:hover {
  background: rgba(245, 240, 232, 0.05);
  border-color: var(--signal-cyan);
  color: var(--signal-cyan);
}
.drawer-cta.is-disabled,
.drawer-cta[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
.drawer-cta .arrow {
  color: var(--onsite-red);
  font-size: 0.95em;
  line-height: 1;
}

.drawer-footnote {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--paper-muted);
  margin: 1rem 0 0;
  opacity: 0.75;
}

/* Locked state styling (premium-locked, live-locked) */
.drawer-locked-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.32rem 0.6rem;
  background: rgba(184, 8, 18, 0.12);
  border: 1px solid rgba(184, 8, 18, 0.4);
  color: var(--onsite-red);
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  font-weight: 600;
  margin: 0 0 1rem;
  border-radius: 2px;
}

/* ============================================================
   FOOTER — minimal mono caps (hidden on mobile to keep scene clean)
   ============================================================ */
.world-footer {
  padding: 1.25rem 1.5rem;
  background: var(--bg-deep);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  text-align: center;
}
.footer-line {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--paper-muted);
  margin: 0;
  opacity: 0.7;
}
.footer-tri {
  color: var(--onsite-red);
  margin-right: 0.5em;
}

/* ============================================================
   RESPONSIVE — Mobile tightening
   ============================================================ */
@media (max-width: 768px) {
  .world-header {
    padding: 0.7rem 1rem;
  }
  .world-header-back {
    padding: 0.4rem 0.7rem;
    font-size: 0.6rem;
    letter-spacing: 0.18em;
  }
  .world-header-back .back-text {
    /* Keep text on mobile — it's short enough */
  }

  .world-scene {
    min-height: calc(100vh - 52px);
  }

  .scene-chrome {
    top: 1rem;
    left: 1rem;
    max-width: 70vw;
  }
  .scene-eyebrow {
    font-size: 0.6rem;
    letter-spacing: 0.24em;
  }
  .scene-byline {
    font-size: 0.92rem;
  }

  .scene-hint {
    bottom: 1rem;
    font-size: 0.55rem;
    letter-spacing: 0.22em;
    padding: 0.35rem 0.65rem;
  }

  .scene-coord {
    bottom: 0.9rem;
    right: 0.9rem;
    font-size: 0.52rem;
    letter-spacing: 0.18em;
    padding: 0.3rem 0.5rem;
  }
  /* On very small screens, hide the coord chip to keep the scene calm. */
  @media (max-width: 480px) {
    .scene-coord { display: none; }

    /* Bottom-row locked hotspots collide horizontally at narrow widths.
       Stack them vertically so labels never touch. !important overrides
       the inline style:top set by world.js (data-driven position). */
    .hotspot[data-place-id="the-house"]   { top: 78% !important; }
    .hotspot[data-place-id="onsite-club"] { top: 90% !important; }
  }

  .hotspot {
    font-size: 0.62rem;
    letter-spacing: 0.2em;
    gap: 0.5rem;
    /* Mobile dot is 16px; offset is half of that. */
    transform: translate(-8px, -50%);
  }
  .hotspot[data-flip="left"] {
    transform: translate(calc(-100% + 8px), -50%);
  }
  .hotspot-dot { width: 16px; height: 16px; }
  .hotspot-label {
    padding: 0.32rem 0.55rem;
    /* Cap label width on narrow screens so it never pushes the dot off-screen. */
    max-width: 42vw;
  }
  .hotspot-label .label-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .drawer-body {
    padding: 1.25rem 1.25rem 1.75rem;
  }

  .world-footer { padding: 1rem 1rem; }
  .footer-line { font-size: 0.55rem; letter-spacing: 0.2em; }
}

/* ============================================================
   Phase 2c.4 — Fade-in from Atlas portal.
   ============================================================ */
html.from-atlas {
  background: #030303;
}
html.from-atlas body {
  animation: onsite-fade-from-black 320ms ease-out;
}
@keyframes onsite-fade-from-black {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}

/* ============================================================
   REDUCED MOTION — disable animation cues
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .scene-hint .hint-dot { animation: none; }
  .hotspot-dot::after { animation: none; opacity: 0.3; }
  .hotspot:hover .hotspot-dot,
  .hotspot:focus-visible .hotspot-dot { transform: none; }
  .world-drawer .drawer-panel { transition: none; }
  .world-drawer .drawer-backdrop { transition: none; }
  .world-header-back:hover .back-arrow { transform: none; }
  html.from-atlas body { animation: none; }
  /* v1.2: kill parallax + fly-to motion too */
  .scene-placeholder { transform: none !important; }
  .world-scene.is-flying .world-hotspots,
  .world-scene.is-flying .scene-chrome,
  .world-scene.is-flying .scene-hint,
  .world-scene.is-flying .scene-coord { opacity: 1 !important; }
}

/* ============================================================
   v1.2 — Hero image + parallax + cinematic fly-to (Phase 1)
   Pure CSS + JS — zero new dependencies.
   ============================================================ */

/* Layer the hero image as background of .scene-placeholder.
   Children of placeholder (glows, sheen, grain, vignette) render ON TOP
   and tint the image. v1.1 procedural skylines/road kept in DOM as
   fallback (revealed only if image fails to load). */
/* v1.3 — dual-background place map:
   Desktop (landscape) uses miami-noir-street-hero.{webp,jpg} (from desktop v04 master)
   Mobile  (portrait)  uses miami-noir-street-hero-mobile.{webp,jpg} (from mobile v02 master)
   Asset swap via @media query below. */
.scene-placeholder {
  background-color: #020405;  /* solid fallback during image load */
  background-image: url('/img/worlds/miami-noir/miami-noir-street-hero.jpg');
  background-image: image-set(
    url('/img/worlds/miami-noir/miami-noir-street-hero.webp') type('image/webp'),
    url('/img/worlds/miami-noir/miami-noir-street-hero.jpg') type('image/jpeg')
  );
  background-size: cover;
  background-position: center 58%;  /* pull focus down to street/streetlight */
  background-repeat: no-repeat;
  /* Parallax + fly-to baseline: scale slightly so translate doesn't reveal edges */
  transform: scale(1.06);
  transform-origin: center center;
  will-change: transform;
  /* No CSS transition — JS rAF lerp owns the motion to avoid fighting */
}

/* Mobile portrait viewport: swap to the mobile master (1024x1536 portrait) and
   adjust focus point for vertical composition. The mobile master shows
   4 of 5 places (The House is not visible in portrait — see hide-on-mobile rule below). */
@media (max-width: 768px) {
  .scene-placeholder {
    background-image: url('/img/worlds/miami-noir/miami-noir-street-hero-mobile.jpg');
    background-image: image-set(
      url('/img/worlds/miami-noir/miami-noir-street-hero-mobile.webp') type('image/webp'),
      url('/img/worlds/miami-noir/miami-noir-street-hero-mobile.jpg') type('image/jpeg')
    );
    background-position: center center;  /* portrait composition centers naturally */
  }
}

/* v1.3 place map: hide The House hotspot on mobile viewports.
   Reason: mobile master (v02) does not contain a visible residential anchor
   for The House. JS also enforces this via the hide_on_mobile flag in the
   place-map JSON — this CSS rule is a redundant safety net. */
@media (max-width: 768px) {
  .world-hotspots .hotspot[data-place-id="the-house"] {
    display: none;
  }
}

/* Hide procedural layers replaced by the image. They remain in DOM so
   if the image fails (404, slow network, blocked), v1.1 still renders. */
.scene-skyline-far,
.scene-skyline-mid,
.scene-road,
.scene-wet-streaks {
  display: none;
}

/* Soften neon glow pools — image already has its own lighting */
.scene-glow-cyan { opacity: 0.30; }
.scene-glow-red  { opacity: 0.28; }
.scene-glow-pool { opacity: 0.22; }

/* Slightly stronger vignette to anchor focus on the central street */
.scene-vignette {
  background:
    radial-gradient(ellipse 80% 65% at 50% 50%, transparent 32%, rgba(0, 0, 0, 0.50) 100%),
    linear-gradient(180deg, transparent 55%, rgba(0, 0, 0, 0.55) 100%);
}

/* During hotspot fly-to: fade chrome + hotspots so user focuses on the zoom-in.
   The .is-flying class is toggled by world.js. */
.world-scene .world-hotspots,
.world-scene .scene-chrome,
.world-scene .scene-hint,
.world-scene .scene-coord {
  transition: opacity 350ms ease-out;
}
.world-scene.is-flying .world-hotspots,
.world-scene.is-flying .scene-chrome,
.world-scene.is-flying .scene-hint,
.world-scene.is-flying .scene-coord {
  opacity: 0.18;
  pointer-events: none;  /* prevent click-through during fly */
}

/* ================================================================
   v2.0 — INTERIOR SCENE ENGINE
   ----------------------------------------------------------------
   Full-viewport overlay for sub-world places (Tony's Room, future
   Video Theater, Listening Room, etc). Distinct from the side drawer:
   entering an interior means *leaving* the street, not peeking at
   metadata. Objects (wall, window, bed, crt-tv, door, lamp) are
   sculpted in CSS — no images, no SVG, no generated assets in MVP.
   ================================================================ */

.world-interior {
  position: fixed;
  inset: 0;
  z-index: 90; /* above drawer (drawer is z=80ish) */
  background: #050608;
  opacity: 0;
  pointer-events: none;
  transition: opacity 540ms ease-out;
}
.world-interior.is-open {
  opacity: 1;
  pointer-events: auto;
}
.world-interior[hidden] { display: none; }

/* When interior is active, lock the underlying street from scrolling
   and reduce its visual presence so the room dominates. */
body.interior-open {
  overflow: hidden;
}
body.interior-open #world-main > .world-scene {
  filter: brightness(0.35) blur(2px);
  transform: scale(1.04);
  transition: filter 540ms ease-out, transform 540ms ease-out;
}

/* ---------- v3 Phase 2: scroll container + sections ----------
   The overlay's main child is now a native vertical scroll container.
   Each <section.interior-section> stacks a full viewport tall.
   Each section contains a .interior-stage absolutely-positioned to fill it.
   No scroll-snap, no scroll-jacking — native scroll + IntersectionObserver
   for active-section tracking. */
.interior-scroll {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.08) transparent;
}
.interior-scroll::-webkit-scrollbar {
  width: 6px;
}
.interior-scroll::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.08);
  border-radius: 3px;
}
.interior-scroll::-webkit-scrollbar-track {
  background: transparent;
}
@media (prefers-reduced-motion: reduce) {
  .interior-scroll { scroll-behavior: auto; }
}

.interior-section {
  position: relative;
  min-height: 100vh;
  width: 100%;
  /* Modern browsers skip layout/paint for offscreen sections — saves FPS
     once Phase 3+ adds more sections. Safe to set now: there's only one. */
  content-visibility: auto;
  contain-intrinsic-size: 100vh;
}

/* Screen-reader-only utility (used by per-section <h2>s).
   Heading exists for SR users; visually hidden so it never reads as a webpage heading. */
.sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* ---------- Interior stage (the room) ----------
   Phase 2 note: the stage now lives INSIDE a section, not the overlay.
   position: absolute resolves to the parent .interior-section (relative). */
.interior-stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Base black so transitions don't flash */
  background: #050608;
}

/* ---------- Chrome (discrete header — NOT a panel) ---------- */
.interior-chrome {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.4rem 1.8rem;
  z-index: 50;
  pointer-events: none; /* let scene below be inspectable; children re-enable */
}
.interior-eyebrow {
  margin: 0;
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  pointer-events: auto;
}
.interior-eyebrow .tri { color: rgba(0, 212, 255, 0.8); }
.interior-sep { opacity: 0.4; }
.interior-place { color: rgba(255, 255, 255, 0.85); }

.interior-close {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.55rem 0.95rem;
  background: rgba(8, 10, 16, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: rgba(255, 255, 255, 0.85);
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background 200ms ease, border-color 200ms ease, color 200ms ease;
}
.interior-close:hover,
.interior-close:focus-visible {
  background: rgba(0, 212, 255, 0.1);
  border-color: rgba(0, 212, 255, 0.55);
  color: rgba(255, 255, 255, 1);
  outline: none;
}
.interior-close .tri-back {
  color: rgba(0, 212, 255, 0.8);
  font-size: 0.65rem;
}

/* ---------- Base object positioning by anchor ---------- */
.scene-object {
  position: absolute;
  pointer-events: none; /* objects are decorative unless explicitly clickable later */
}
.scene-object[data-anchor="back"]              { inset: 0; z-index: 1; }
.scene-object[data-anchor="back-left"]         { top: 16%;  left: 7%;   width: 22%; height: 38%; z-index: 2; }
.scene-object[data-anchor="back-right"]        { top: 16%;  right: 7%;  width: 22%; height: 38%; z-index: 2; }
.scene-object[data-anchor="left"]              { bottom: 5%; left: 3%;  width: 38%; height: 30%; z-index: 4; }
.scene-object[data-anchor="right"]             { top: 8%;   right: 5%;  width: 16%; height: 84%; z-index: 3; }
.scene-object[data-anchor="center"]            { top: 38%;  left: 50%;  width: 28%; height: 40%; z-index: 4;
                                                  transform: translateX(-50%); }
.scene-object[data-anchor="right-foreground"]  { bottom: 6%; right: 24%; width: 9%;  height: 32%; z-index: 5; }
.scene-object[data-anchor="left-foreground"]   { bottom: 6%; left: 24%;  width: 9%;  height: 32%; z-index: 5; }

/* ----------------------------------------------------------------
   OBJECT: wall
   The back of the room. Vertical gradient (ceiling → floor),
   subtle vignette, atmosphere-driven color temperature.
   ---------------------------------------------------------------- */
.scene-object--wall .object-wall-base {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 110%, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 55%),
    linear-gradient(180deg,
      #07090e 0%,
      #0d1018 38%,
      #14131c 70%,
      #0a0a12 100%
    );
}
.scene-object--wall::after {
  /* Floor line — a hairline horizontal accent ~70% down */
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 72%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(0, 212, 255, 0.08) 30%,
    rgba(0, 212, 255, 0.18) 50%,
    rgba(0, 212, 255, 0.08) 70%,
    transparent 100%
  );
  z-index: 2;
}

/* ----------------------------------------------------------------
   OBJECT: window
   A back-wall opening. Cyan neon leaks through. Rain streaks
   suggest weather + 80s Miami noir. Casts light onto the wall.
   ---------------------------------------------------------------- */
.scene-object--window {
  /* Cast light onto the wall around the window */
  box-shadow:
    0 0 90px 30px rgba(0, 212, 255, 0.12),
    0 0 180px 80px rgba(0, 212, 255, 0.05);
}
.scene-object--window .object-window-frame {
  position: absolute;
  inset: 0;
  border: 4px solid #1c1d24;
  border-radius: 2px;
  background:
    linear-gradient(180deg,
      rgba(0, 212, 255, 0.28) 0%,
      rgba(184, 8, 18, 0.16) 55%,
      rgba(8, 4, 14, 0.85) 100%
    );
  box-shadow:
    inset 0 0 60px rgba(0, 212, 255, 0.25),
    inset 0 0 12px rgba(0, 0, 0, 0.6);
  overflow: hidden;
}
.scene-object--window .object-window-pane {
  position: absolute;
  inset: 0;
  background:
    /* distant city lights */
    radial-gradient(circle at 20% 70%, rgba(255, 168, 70, 0.55) 0%, rgba(255, 168, 70, 0) 4%),
    radial-gradient(circle at 32% 76%, rgba(255, 220, 120, 0.45) 0%, rgba(255, 220, 120, 0) 3%),
    radial-gradient(circle at 60% 80%, rgba(0, 212, 255, 0.5) 0%, rgba(0, 212, 255, 0) 4%),
    radial-gradient(circle at 78% 72%, rgba(255, 70, 90, 0.4) 0%, rgba(255, 70, 90, 0) 3%),
    radial-gradient(circle at 45% 65%, rgba(255, 255, 255, 0.25) 0%, rgba(255, 255, 255, 0) 2%);
}
.scene-object--window .object-window-cross {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, transparent 49.6%, #15161e 49.6%, #15161e 50.4%, transparent 50.4%),
    linear-gradient(180deg, transparent 49.6%, #15161e 49.6%, #15161e 50.4%, transparent 50.4%);
}
.scene-object--window .object-window-leak {
  /* Neon spill onto wall — extends beyond frame */
  position: absolute;
  inset: -45% -55% -50% -55%;
  background:
    radial-gradient(ellipse at 50% 45%,
      rgba(0, 212, 255, 0.22) 0%,
      rgba(0, 212, 255, 0.08) 35%,
      rgba(0, 212, 255, 0) 65%
    );
  pointer-events: none;
  z-index: -1;
}
.scene-object--window .object-window-rain {
  /* Diagonal streaks suggesting rain on glass */
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    105deg,
    transparent 0,
    transparent 12px,
    rgba(255, 255, 255, 0.06) 12px,
    rgba(255, 255, 255, 0.06) 13px,
    transparent 13px,
    transparent 28px
  );
  mix-blend-mode: screen;
  opacity: 0.55;
}

/* ----------------------------------------------------------------
   OBJECT: bed
   Low silhouette in the left foreground. Frame, mattress, sheet,
   pillow — each a subtle gradient block. Reads as "made of shadow".
   ---------------------------------------------------------------- */
.scene-object--bed .object-bed-frame {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 22%;
  background: linear-gradient(180deg, #0c0d14 0%, #06070b 100%);
  border-top: 1px solid rgba(255, 255, 255, 0.04);
}
.scene-object--bed .object-bed-mattress {
  position: absolute;
  bottom: 18%;
  left: 4%;
  right: 4%;
  height: 32%;
  background: linear-gradient(180deg, #1a1820 0%, #100f17 100%);
  border-radius: 4px 4px 0 0;
  box-shadow:
    inset 0 8px 18px rgba(0, 0, 0, 0.55),
    0 -2px 0 rgba(255, 255, 255, 0.025);
}
.scene-object--bed .object-bed-sheet {
  position: absolute;
  bottom: 28%;
  left: 8%;
  right: 18%;
  height: 30%;
  background:
    linear-gradient(160deg,
      rgba(255, 255, 255, 0.06) 0%,
      rgba(255, 255, 255, 0.02) 50%,
      rgba(0, 0, 0, 0.3) 100%
    ),
    #15151d;
  transform: skewX(-4deg);
  border-radius: 2px;
}
.scene-object--bed .object-bed-pillow {
  position: absolute;
  bottom: 44%;
  left: 6%;
  width: 24%;
  height: 14%;
  background:
    radial-gradient(ellipse at 50% 30%, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0) 70%),
    #1c1c26;
  border-radius: 50%;
  box-shadow: 0 -2px 4px rgba(255, 255, 255, 0.04);
}

/* ----------------------------------------------------------------
   OBJECT: crt-tv
   The room's focal element. A boxy 80s TV silhouette with a phosphor
   screen playing the visualizer. Re-uses v1 bezel/scanline language.
   ---------------------------------------------------------------- */
.scene-object--crt-tv {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
}
.scene-object--crt-tv .object-tv-stand {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 30%;
  height: 8%;
  background: linear-gradient(180deg, #1a1822 0%, #0a0910 100%);
  border-radius: 4px 4px 1px 1px;
  z-index: 1;
}
.scene-object--crt-tv .object-tv-body {
  position: relative;
  width: 100%;
  flex: 1 1 auto;
  margin-bottom: 8%;
  background:
    linear-gradient(180deg, #16151d 0%, #0c0b14 100%);
  border-radius: 18px 18px 14px 14px;
  border: 1px solid rgba(255, 255, 255, 0.05);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -2px 8px rgba(0, 0, 0, 0.6),
    0 18px 36px rgba(0, 0, 0, 0.5),
    0 0 90px 12px rgba(0, 212, 255, 0.08);
  padding: 9% 9% 14% 9%;
}
.scene-object--crt-tv .object-tv-bezel {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: #02050a;
  border-radius: 14px;
  border: 1px solid rgba(0, 0, 0, 0.7);
  box-shadow:
    inset 0 0 24px rgba(0, 0, 0, 0.9),
    inset 0 0 1px rgba(0, 212, 255, 0.4),
    0 0 28px rgba(0, 212, 255, 0.18);
  overflow: hidden;
}
.scene-object--crt-tv .object-tv-screen {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 12px;
  /* Subtle CRT softening */
  filter: contrast(1.05) saturate(1.1) brightness(0.95);
}
.scene-object--crt-tv .object-tv-bezel::after {
  /* CRT scanlines */
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    180deg,
    rgba(0, 0, 0, 0) 0,
    rgba(0, 0, 0, 0) 2px,
    rgba(0, 0, 0, 0.18) 2px,
    rgba(0, 0, 0, 0.18) 3px
  );
  mix-blend-mode: multiply;
  z-index: 3;
  border-radius: 12px;
}
.scene-object--crt-tv .object-tv-glow {
  /* Soft inner halo + slight curvature hint */
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center,
    rgba(0, 212, 255, 0.1) 0%,
    rgba(0, 212, 255, 0) 65%);
  pointer-events: none;
  z-index: 2;
}
.scene-object--crt-tv .object-tv-controls {
  position: absolute;
  bottom: 3%;
  right: 6%;
  display: flex;
  gap: 0.4rem;
}
.scene-object--crt-tv .object-tv-knob {
  display: block;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background:
    radial-gradient(circle at 35% 35%, rgba(255, 255, 255, 0.25), rgba(0, 0, 0, 0.4) 70%);
  border: 1px solid rgba(0, 0, 0, 0.6);
}
.scene-object--crt-tv .object-tv-label {
  position: absolute;
  bottom: -2.4rem;
  left: 0;
  right: 0;
  margin: 0;
  text-align: center;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.6875rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

/* ----------------------------------------------------------------
   OBJECT: door
   A closed door with a brass knob. Locked state shows a small label
   below it. Stays right-anchored as the boundary of the room.
   ---------------------------------------------------------------- */
.scene-object--door {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.scene-object--door .object-door-frame {
  position: relative;
  width: 100%;
  flex: 1 1 auto;
  background: linear-gradient(180deg, #0f0d16 0%, #06050a 100%);
  border-left: 2px solid rgba(255, 255, 255, 0.05);
  border-right: 2px solid rgba(255, 255, 255, 0.05);
  border-top: 2px solid rgba(255, 255, 255, 0.08);
  box-shadow:
    inset 6px 0 14px rgba(0, 0, 0, 0.6),
    inset -6px 0 14px rgba(0, 0, 0, 0.6),
    0 0 30px rgba(0, 0, 0, 0.6);
}
.scene-object--door .object-door-panel {
  position: absolute;
  inset: 8% 12% 8% 12%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 6%;
}
.scene-object--door .object-door-inset {
  flex: 1 1 0;
  background: linear-gradient(180deg, #08070d 0%, #0d0c14 100%);
  border: 1px solid rgba(255, 255, 255, 0.04);
  box-shadow:
    inset 0 2px 6px rgba(0, 0, 0, 0.6),
    inset 0 -1px 0 rgba(255, 255, 255, 0.03);
}
.scene-object--door .object-door-knob {
  position: absolute;
  top: 52%;
  left: 14%;
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 50%;
  background:
    radial-gradient(circle at 35% 35%, #d4a352 0%, #6b4a1a 60%, #2a1c08 100%);
  box-shadow: 0 0 4px rgba(212, 163, 82, 0.45);
}
.scene-object--door[data-state="locked"] .object-door-knob {
  /* dim knob when locked */
  filter: saturate(0.6) brightness(0.7);
}
.scene-object--door .object-door-label {
  position: absolute;
  bottom: -2.6rem;
  right: 0;
  margin: 0;
  padding: 0.35rem 0.7rem;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.55rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  text-align: center;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
  background: rgba(8, 10, 16, 0.65);
  border: 1px solid rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.scene-object--door .object-door-lock {
  display: inline-block;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: rgba(184, 8, 18, 0.85);
  box-shadow: 0 0 6px rgba(184, 8, 18, 0.6);
  margin-right: 0.45rem;
}

/* ----------------------------------------------------------------
   OBJECT: lamp
   Foreground amber light source. Pools warm light onto the wall.
   ---------------------------------------------------------------- */
.scene-object--lamp .object-lamp-glow {
  position: absolute;
  inset: -120% -200% -50% -200%;
  background: radial-gradient(ellipse at 50% 35%,
    rgba(255, 168, 70, 0.22) 0%,
    rgba(255, 168, 70, 0.08) 35%,
    rgba(255, 168, 70, 0) 65%);
  pointer-events: none;
  z-index: -1;
}
.scene-object--lamp .object-lamp-shade {
  position: absolute;
  top: 14%;
  left: 50%;
  transform: translateX(-50%);
  width: 70%;
  height: 36%;
  background:
    linear-gradient(180deg,
      rgba(255, 168, 70, 0.55) 0%,
      rgba(255, 168, 70, 0.25) 60%,
      rgba(40, 22, 8, 0.95) 100%
    );
  border-radius: 50% 50% 14% 14% / 60% 60% 14% 14%;
  box-shadow:
    inset 0 -4px 10px rgba(0, 0, 0, 0.5),
    0 0 22px rgba(255, 168, 70, 0.4);
}
.scene-object--lamp .object-lamp-stem {
  position: absolute;
  top: 48%;
  left: 50%;
  transform: translateX(-50%);
  width: 6%;
  height: 38%;
  background: linear-gradient(180deg, #2a1c0a 0%, #1c1208 100%);
  box-shadow: inset 1px 0 0 rgba(255, 168, 70, 0.18);
}
.scene-object--lamp .object-lamp-base {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 32%;
  height: 8%;
  background: linear-gradient(180deg, #2a1c0a 0%, #100804 100%);
  border-radius: 40% 40% 6% 6%;
  box-shadow: 0 -2px 6px rgba(255, 168, 70, 0.12);
}

/* ----------------------------------------------------------------
   ATMOSPHERE VARIANT: miami-noir-bedroom-1980s
   Tunes the room palette + adds a film grain + corner vignette.
   ---------------------------------------------------------------- */
.atmosphere-miami-noir-bedroom-1980s::before {
  /* Global vignette + corner shadows */
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 55%, transparent 35%, rgba(0, 0, 0, 0.55) 100%);
  pointer-events: none;
  z-index: 40;
}
.atmosphere-miami-noir-bedroom-1980s::after {
  /* Faint film grain */
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px);
  background-size: 3px 3px;
  pointer-events: none;
  z-index: 41;
  mix-blend-mode: screen;
}

/* ---------- Animations (respect reduced motion) ---------- */
@keyframes interior-neon-drift {
  0%, 100% { opacity: 0.78; transform: translateX(0); }
  50%      { opacity: 1;    transform: translateX(0.4%); }
}
@keyframes interior-lamp-flicker {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.94; }
}
@media (prefers-reduced-motion: no-preference) {
  .scene-object--window .object-window-leak {
    animation: interior-neon-drift 7.5s ease-in-out infinite;
  }
  .scene-object--lamp .object-lamp-glow {
    animation: interior-lamp-flicker 5s ease-in-out infinite;
  }
}

/* ---------- Mobile pass ---------- */
@media (max-width: 768px) {
  .interior-chrome {
    padding: 1rem 1.1rem;
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  .interior-close-label { display: none; }
  .interior-close { padding: 0.5rem 0.7rem; }

  /* Hide secondary objects on mobile so the focal three (window, CRT, door)
     read clearly without crowding. */
  .scene-object.is-mobile-hidden { display: none; }

  /* Re-anchor objects for the smaller canvas */
  .scene-object[data-anchor="back-left"]   { top: 14%; left: 6%;  width: 36%; height: 30%; }
  .scene-object[data-anchor="center"]      { top: 32%; left: 50%; width: 70%; height: 42%; }
  .scene-object[data-anchor="right"]       { top: 14%; right: 4%; width: 22%; height: 56%; }
  .scene-object[data-anchor="left"]        { bottom: 6%; left: 0; width: 60%; height: 22%; }
  .scene-object--crt-tv .object-tv-label {
    bottom: -1.8rem;
    font-size: 0.6rem;
  }
  .scene-object--door .object-door-label {
    font-size: 0.55rem;
  }
}

/* ================================================================
   v3 Phase 3 — MEMORY WALL
   ----------------------------------------------------------------
   Section 2 of Tony's Room. Dark archive wall with scattered
   polaroids. No grid, no gallery — evidence, not content.
   One polaroid is interactive (button) and triggers a torn-paper
   memory fragment that drops inside the section.
   ================================================================ */

/* Section-level height override (memory-wall is 120vh per JSON) */
.interior-section[data-section-id="memory-wall"] {
  min-height: 120vh;
  contain-intrinsic-size: 120vh;
}

/* Atmosphere variant: archive room. Cooler, more desaturated than the
   bedroom. Slight cyan top, deep black bottom. Faint film grain via the
   shared atmosphere pseudo-elements (defined for miami-noir-archive below). */
.atmosphere-miami-noir-archive {
  background:
    linear-gradient(180deg,
      #07080d 0%,
      #0a0c14 38%,
      #060710 100%
    );
}
.atmosphere-miami-noir-archive::before {
  /* Tight corner vignette */
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 50%, transparent 30%, rgba(0, 0, 0, 0.6) 100%);
  pointer-events: none;
  z-index: 40;
}
.atmosphere-miami-noir-archive::after {
  /* Paper grain */
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(rgba(255, 255, 255, 0.018) 1px, transparent 1px);
  background-size: 3px 3px;
  pointer-events: none;
  z-index: 41;
  mix-blend-mode: screen;
}

/* ----------------------------------------------------------------
   OBJECT: memory-wall
   The back wall behind the polaroids. Cooler indigo, faint vertical
   striations, a hairline floor line. Reads as a private room, not
   a museum.
   ---------------------------------------------------------------- */
.scene-object--memory-wall {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.scene-object--memory-wall .object-archive-wall {
  position: absolute;
  inset: 0;
  background:
    /* Faint vertical "wallpaper" striations */
    repeating-linear-gradient(90deg,
      transparent 0,
      transparent 60px,
      rgba(255, 255, 255, 0.012) 60px,
      rgba(255, 255, 255, 0.012) 61px
    ),
    radial-gradient(ellipse at 50% 30%, rgba(0, 212, 255, 0.05) 0%, rgba(0, 212, 255, 0) 50%),
    linear-gradient(180deg, #07080d 0%, #0d0e15 40%, #060710 100%);
}
.scene-object--memory-wall .object-archive-floor {
  position: absolute;
  left: 0; right: 0;
  top: 78%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.08) 30%,
    rgba(255, 255, 255, 0.14) 50%,
    rgba(255, 255, 255, 0.08) 70%,
    transparent 100%
  );
  z-index: 2;
}
.scene-object--memory-wall .object-archive-grain {
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(180deg,
      rgba(255, 255, 255, 0.014) 0,
      rgba(255, 255, 255, 0.014) 1px,
      transparent 1px,
      transparent 3px
    );
  opacity: 0.5;
  mix-blend-mode: screen;
  z-index: 3;
}

/* ----------------------------------------------------------------
   OBJECT: polaroid
   Scattered cards taped to the wall. Position + rotation come from
   inline style (left/top/--object-rotation), tint comes from
   data-tint (6 variants below). Caption uses the mono font.
   ---------------------------------------------------------------- */
.scene-object--polaroid {
  position: absolute;
  width: 16%;
  /* Sensible bounds per breakpoint — see mobile override below. */
  min-width: 140px;
  max-width: 200px;
  aspect-ratio: 4 / 5;
  z-index: 10;
  transform: rotate(var(--object-rotation, 0deg));
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.55));
  /* Reset button browser defaults for interactive polaroids */
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: default;
  pointer-events: none;
}
.scene-object--polaroid.is-interactive {
  pointer-events: auto;
  cursor: pointer;
  transition: transform 240ms ease, filter 240ms ease;
}
.scene-object--polaroid.is-interactive:hover,
.scene-object--polaroid.is-interactive:focus-visible {
  transform: rotate(var(--object-rotation, 0deg)) translateY(-4px) scale(1.04);
  filter:
    drop-shadow(0 14px 22px rgba(0, 0, 0, 0.7))
    drop-shadow(0 0 18px rgba(0, 212, 255, 0.35));
  outline: none;
}
.scene-object--polaroid.is-interactive::after {
  /* Subtle "click me" pulse on the interactive polaroid */
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 2px;
  border: 1px solid rgba(0, 212, 255, 0.18);
  pointer-events: none;
  opacity: 0;
  transition: opacity 240ms ease;
}
.scene-object--polaroid.is-interactive:hover::after,
.scene-object--polaroid.is-interactive:focus-visible::after {
  opacity: 1;
}

/* Tape strip at the top — rotates slightly off from the polaroid */
.scene-object--polaroid .object-polaroid-tape {
  position: absolute;
  top: -8px;
  left: 50%;
  transform: translateX(-50%) rotate(-3deg);
  width: 36%;
  height: 14px;
  background:
    linear-gradient(180deg,
      rgba(255, 240, 200, 0.35) 0%,
      rgba(255, 240, 200, 0.22) 100%
    );
  border: 1px solid rgba(255, 240, 200, 0.18);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  z-index: 3;
}

/* The white polaroid frame */
.scene-object--polaroid .object-polaroid-frame {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, #f0ece1 0%, #d8d3c4 100%);
  padding: 8% 8% 18% 8%;
  border-radius: 1px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    inset 0 -2px 0 rgba(0, 0, 0, 0.08);
}

/* The "photo" area — a tinted gradient placeholder, no real image */
.scene-object--polaroid .object-polaroid-photo {
  position: relative;
  width: 100%;
  height: 72%;
  background: #14141a;
  overflow: hidden;
  /* Each tint variant overrides this background — see below */
}
.scene-object--polaroid .object-polaroid-grain {
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(0deg,
      rgba(255, 255, 255, 0.04) 0,
      rgba(255, 255, 255, 0.04) 1px,
      transparent 1px,
      transparent 3px
    );
  mix-blend-mode: overlay;
  opacity: 0.7;
}
.scene-object--polaroid .object-polaroid-photo::after {
  /* Soft vignette inside the photo */
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 45%, transparent 40%, rgba(0, 0, 0, 0.55) 100%);
  pointer-events: none;
}

/* Caption underneath the photo */
.scene-object--polaroid .object-polaroid-caption {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 4%;
  margin: 0;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: lowercase;
  color: #2b2620;
  text-align: center;
}

/* ----------------------------------------------------------------
   POLAROID TINTS — each suggests a mood without being a literal photo
   ---------------------------------------------------------------- */
.scene-object--polaroid[data-tint="magenta-dusk"] .object-polaroid-photo {
  background:
    radial-gradient(circle at 30% 40%, rgba(255, 60, 140, 0.65), transparent 60%),
    radial-gradient(circle at 70% 60%, rgba(40, 0, 50, 0.9), transparent 70%),
    linear-gradient(160deg, #2a0820 0%, #0a020e 100%);
}
.scene-object--polaroid[data-tint="cyan-static"] .object-polaroid-photo {
  background:
    radial-gradient(circle at 50% 50%, rgba(0, 212, 255, 0.45), transparent 60%),
    repeating-linear-gradient(180deg,
      rgba(255, 255, 255, 0.06) 0,
      rgba(255, 255, 255, 0.06) 1px,
      transparent 1px,
      transparent 3px),
    linear-gradient(180deg, #051820 0%, #020a10 100%);
}
.scene-object--polaroid[data-tint="amber-fade"] .object-polaroid-photo {
  background:
    radial-gradient(ellipse at 40% 70%, rgba(255, 168, 70, 0.55), transparent 60%),
    radial-gradient(ellipse at 70% 40%, rgba(120, 60, 20, 0.6), transparent 65%),
    linear-gradient(180deg, #1a0e04 0%, #060302 100%);
}
.scene-object--polaroid[data-tint="red-leak"] .object-polaroid-photo {
  background:
    radial-gradient(circle at 60% 50%, rgba(255, 40, 60, 0.55), transparent 55%),
    radial-gradient(circle at 20% 70%, rgba(80, 0, 0, 0.9), transparent 65%),
    linear-gradient(160deg, #200408 0%, #08010a 100%);
}
.scene-object--polaroid[data-tint="gray-redacted"] .object-polaroid-photo {
  background: linear-gradient(180deg, #1a1a20 0%, #0a0a10 100%);
}
.scene-object--polaroid[data-tint="gray-redacted"] .object-polaroid-photo::before {
  /* Black redacted bar across the photo */
  content: "";
  position: absolute;
  left: 8%;
  right: 8%;
  top: 38%;
  height: 22%;
  background: #000;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  z-index: 2;
}
.scene-object--polaroid[data-tint="cream-warm"] .object-polaroid-photo {
  background:
    radial-gradient(ellipse at 50% 60%, rgba(255, 220, 160, 0.42), transparent 65%),
    linear-gradient(180deg, #1a1408 0%, #08060a 100%);
}

/* ----------------------------------------------------------------
   FRAGMENT-NOTE
   Torn-paper memory reveal triggered by the interactive polaroid.
   Lives inside the active section, not as a global modal. Cinematic,
   not a "popup".
   ---------------------------------------------------------------- */
.fragment-note {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(380px, 78%);
  padding: 1.6rem 1.4rem 1.3rem;
  background:
    linear-gradient(180deg, #f4ecd8 0%, #ddd2b4 100%);
  color: #1a1408;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.95rem;
  line-height: 1.5;
  letter-spacing: 0.01em;
  z-index: 60;
  opacity: 0;
  transform: translate(-50%, -50%) rotate(-2deg) scale(0.95);
  transition: opacity 320ms ease, transform 320ms ease;
  box-shadow:
    0 20px 40px rgba(0, 0, 0, 0.75),
    inset 0 0 30px rgba(120, 90, 40, 0.12);
  /* Torn-paper top + bottom edges via clip-path polygon */
  clip-path: polygon(
    0% 6%, 2% 2%, 5% 5%, 9% 1%, 14% 4%, 18% 1%, 23% 5%, 28% 2%,
    34% 5%, 40% 2%, 46% 5%, 52% 1%, 58% 4%, 64% 1%, 70% 5%, 76% 2%,
    82% 5%, 88% 1%, 94% 4%, 98% 2%, 100% 6%,
    100% 94%, 98% 98%, 94% 95%, 88% 99%, 82% 95%, 76% 98%, 70% 95%,
    64% 99%, 58% 95%, 52% 99%, 46% 95%, 40% 98%, 34% 95%, 28% 98%,
    23% 95%, 18% 99%, 14% 95%, 9% 98%, 5% 95%, 2% 98%, 0% 94%
  );
  /* Tape strip overlay via background-image (a faint horizontal mark) */
  background-image:
    radial-gradient(rgba(120, 90, 40, 0.06) 1px, transparent 1px),
    linear-gradient(180deg, #f4ecd8 0%, #ddd2b4 100%);
  background-size: 3px 3px, 100% 100%;
}
.fragment-note.is-open {
  opacity: 1;
  transform: translate(-50%, -50%) rotate(-2deg) scale(1);
}
.fragment-note-text {
  margin: 0 0 0.5rem 0;
  font-size: 1rem;
  font-weight: 500;
  color: #1a1408;
}
.fragment-note-footnote {
  margin: 0;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: rgba(26, 20, 8, 0.65);
  font-style: italic;
}
.fragment-note-close {
  position: absolute;
  top: 6px;
  right: 10px;
  width: 22px;
  height: 22px;
  background: transparent;
  border: 0;
  color: rgba(26, 20, 8, 0.5);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.fragment-note-close:hover,
.fragment-note-close:focus-visible {
  color: rgba(184, 8, 18, 0.9);
  outline: none;
}

@media (prefers-reduced-motion: reduce) {
  .fragment-note { transition: opacity 0ms; transform: translate(-50%, -50%) rotate(-2deg); }
  .fragment-note.is-open { transform: translate(-50%, -50%) rotate(-2deg); }
  .scene-object--polaroid.is-interactive { transition: none; }
}

/* ---------- Memory Wall mobile pass ---------- */
@media (max-width: 768px) {
  .scene-object--polaroid {
    width: 38%;
    min-width: 0;
    max-width: 180px;
  }
  /* Re-scatter polaroids vertically on mobile (override inline coords with safer ones).
     Each polaroid is positioned via its own data-object-id for surgical control. */
  .scene-object--polaroid[data-object-id="polaroid-oranjestad"]    { left: 6%  !important; top: 6%  !important; }
  .scene-object--polaroid[data-object-id="polaroid-test-pressing"] { left: 52% !important; top: 4%  !important; }
  .scene-object--polaroid[data-object-id="polaroid-coast"]         { left: 8%  !important; top: 30% !important; }
  .scene-object--polaroid[data-object-id="polaroid-signal"]        { left: 50% !important; top: 32% !important; }
  .scene-object--polaroid[data-object-id="polaroid-no-return"]     { left: 6%  !important; top: 58% !important; }
  .scene-object--polaroid[data-object-id="polaroid-room-1986"]     { left: 52% !important; top: 60% !important; }

  .fragment-note {
    width: 84%;
    padding: 1.2rem 1rem;
    font-size: 0.9rem;
  }
  .fragment-note-text { font-size: 0.95rem; }
}

/* ================================================================
   v3 Phase 4 — SOUND LAB
   ----------------------------------------------------------------
   Section 3 of Tony's Room. Analog music corner: cassette deck,
   speakers, three cassettes (clickable, open Spotify in new tab),
   pulsing signal LED. Tony's music as physical objects, not links.
   ================================================================ */

.interior-section[data-section-id="sound-lab"] {
  min-height: 120vh;
  contain-intrinsic-size: 120vh;
}

/* Atmosphere variant: tape room.
   Cooler base than the bedroom, warmer amber pop from the deck/LED. */
.atmosphere-miami-noir-tape {
  background:
    radial-gradient(ellipse at 50% 80%, rgba(184, 8, 18, 0.06) 0%, rgba(0, 0, 0, 0) 50%),
    radial-gradient(ellipse at 50% 20%, rgba(255, 168, 70, 0.07) 0%, rgba(0, 0, 0, 0) 55%),
    linear-gradient(180deg, #060810 0%, #0a0d16 38%, #050608 100%);
}
.atmosphere-miami-noir-tape::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 50%, transparent 30%, rgba(0, 0, 0, 0.65) 100%);
  pointer-events: none;
  z-index: 40;
}
.atmosphere-miami-noir-tape::after {
  /* faint paper/dust grain */
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(rgba(255, 255, 255, 0.022) 1px, transparent 1px);
  background-size: 3px 3px;
  pointer-events: none;
  z-index: 41;
  mix-blend-mode: screen;
}

/* ----------------------------------------------------------------
   OBJECT: sound-lab (back wall + paneling + floor)
   ---------------------------------------------------------------- */
.scene-object--sound-lab {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.scene-object--sound-lab .object-lab-wall {
  position: absolute;
  inset: 0;
  background:
    /* tall thin paneling stripes */
    repeating-linear-gradient(90deg,
      transparent 0,
      transparent 90px,
      rgba(255, 255, 255, 0.012) 90px,
      rgba(255, 255, 255, 0.012) 91px
    ),
    linear-gradient(180deg, #060810 0%, #0c0e18 40%, #06060c 100%);
}
.scene-object--sound-lab .object-lab-paneling {
  /* darker horizontal band suggesting a counter the gear sits on */
  position: absolute;
  left: 0; right: 0;
  top: 46%;
  height: 8%;
  background: linear-gradient(180deg, #04050a 0%, #0a0c14 100%);
  border-top: 1px solid rgba(255, 255, 255, 0.04);
  border-bottom: 1px solid rgba(0, 0, 0, 0.6);
}
.scene-object--sound-lab .object-lab-floor {
  /* hairline floor */
  position: absolute;
  left: 0; right: 0;
  top: 85%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(255, 168, 70, 0.06) 30%,
    rgba(255, 168, 70, 0.12) 50%,
    rgba(255, 168, 70, 0.06) 70%,
    transparent 100%);
}
.scene-object--sound-lab .object-lab-glow {
  /* localized amber pool centered behind the deck */
  position: absolute;
  inset: 10% 18% 35% 18%;
  background: radial-gradient(ellipse at 50% 40%,
    rgba(255, 168, 70, 0.08) 0%,
    rgba(255, 168, 70, 0.02) 50%,
    rgba(255, 168, 70, 0) 75%);
  pointer-events: none;
}

/* ----------------------------------------------------------------
   OBJECT: speaker
   Stereo pair flanking the deck. Black box silhouette + 2 cones +
   a hairline brand mark.
   ---------------------------------------------------------------- */
.scene-object--speaker {
  position: absolute;
  width: 16%;
  min-width: 130px;
  max-width: 180px;
  aspect-ratio: 5 / 7;
  z-index: 4;
  pointer-events: none;
  transform: rotate(var(--object-rotation, 0deg));
}
.scene-object--speaker .object-speaker-body {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, #14141a 0%, #08080c 100%);
  border: 1px solid rgba(255, 255, 255, 0.04);
  border-radius: 4px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 18px 36px rgba(0, 0, 0, 0.6);
}
.scene-object--speaker .object-speaker-cone {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  border-radius: 50%;
  background:
    radial-gradient(circle at 35% 35%,
      #1c1c24 0%,
      #0c0c12 40%,
      #04040a 100%);
  border: 1px solid rgba(0, 0, 0, 0.7);
  box-shadow:
    inset 0 2px 4px rgba(255, 255, 255, 0.05),
    inset 0 -2px 4px rgba(0, 0, 0, 0.6);
}
.scene-object--speaker .object-speaker-cone--lg {
  top: 12%;
  width: 72%;
  aspect-ratio: 1;
}
.scene-object--speaker .object-speaker-cone--sm {
  bottom: 8%;
  width: 32%;
  aspect-ratio: 1;
}
.scene-object--speaker .object-speaker-brand {
  position: absolute;
  bottom: 4%;
  left: 0; right: 0;
  text-align: center;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.5rem;
  letter-spacing: 0.32em;
  color: rgba(255, 255, 255, 0.18);
}

/* ----------------------------------------------------------------
   OBJECT: cassette-deck
   The focal piece of the Sound Lab. Brushed-metal body, twin tape
   bay with one tape in motion (left window), VU meter (right), knobs
   + power LED.
   ---------------------------------------------------------------- */
.scene-object--cassette-deck {
  position: absolute;
  width: 56%;
  min-width: 280px;
  max-width: 600px;
  aspect-ratio: 16 / 7;
  z-index: 5;
  pointer-events: none;
}
.scene-object--cassette-deck .object-deck-body {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      #1a1c22 0%,
      #0e0f14 50%,
      #08080c 100%);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 6px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -2px 0 rgba(0, 0, 0, 0.5),
    0 22px 44px rgba(0, 0, 0, 0.65);
  padding: 4% 4%;
  display: flex;
  flex-direction: column;
  gap: 4%;
}
.scene-object--cassette-deck .object-deck-brand {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.55rem;
  letter-spacing: 0.32em;
  color: rgba(255, 168, 70, 0.55);
  text-transform: uppercase;
}
.scene-object--cassette-deck .object-deck-tape-bay {
  flex: 1 1 auto;
  display: flex;
  gap: 4%;
  align-items: stretch;
}
.scene-object--cassette-deck .object-deck-window {
  position: relative;
  flex: 0 0 60%;
  background:
    linear-gradient(180deg, #04060a 0%, #0a0c12 100%);
  border: 1px solid rgba(0, 0, 0, 0.7);
  border-radius: 4px;
  box-shadow:
    inset 0 0 16px rgba(0, 0, 0, 0.85),
    inset 0 0 1px rgba(255, 168, 70, 0.18);
  overflow: hidden;
}
.scene-object--cassette-deck .object-deck-reel {
  position: absolute;
  top: 50%;
  width: 22%;
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at center,
      #14141a 0%,
      #14141a 38%,
      #1c1c26 42%,
      #14141a 100%);
  border: 1px solid rgba(255, 255, 255, 0.04);
  transform: translateY(-50%);
  box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.7);
}
.scene-object--cassette-deck .object-deck-reel::before {
  /* spool hub */
  content: "";
  position: absolute;
  inset: 28%;
  border-radius: 50%;
  background: radial-gradient(circle at center, #2a2a36 0%, #0c0c14 100%);
}
.scene-object--cassette-deck .object-deck-reel--a { left: 14%; }
.scene-object--cassette-deck .object-deck-reel--b { right: 14%; }
.scene-object--cassette-deck .object-deck-tape-strip {
  position: absolute;
  top: 50%;
  left: 26%;
  right: 26%;
  height: 8%;
  background: linear-gradient(180deg, #2a1c0a 0%, #100804 100%);
  transform: translateY(-50%);
  opacity: 0.85;
}
.scene-object--cassette-deck .object-deck-vu {
  position: relative;
  flex: 1 1 0;
  background:
    linear-gradient(180deg, #1a1612 0%, #100c08 100%);
  border: 1px solid rgba(0, 0, 0, 0.7);
  border-radius: 4px;
  overflow: hidden;
}
.scene-object--cassette-deck .object-deck-vu-scale {
  position: absolute;
  inset: 18% 8%;
  background:
    repeating-linear-gradient(90deg,
      transparent 0,
      transparent 6%,
      rgba(255, 168, 70, 0.32) 6%,
      rgba(255, 168, 70, 0.32) 6.4%
    );
  border-bottom: 1px solid rgba(255, 168, 70, 0.5);
}
.scene-object--cassette-deck .object-deck-vu-needle {
  position: absolute;
  bottom: 18%;
  left: 50%;
  transform-origin: bottom center;
  transform: translateX(-50%) rotate(-12deg);
  width: 2px;
  height: 60%;
  background: linear-gradient(180deg, rgba(255, 168, 70, 0.9) 0%, rgba(255, 168, 70, 0.2) 100%);
  box-shadow: 0 0 6px rgba(255, 168, 70, 0.5);
}
.scene-object--cassette-deck .object-deck-controls {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  height: 22%;
}
.scene-object--cassette-deck .object-deck-knob {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 35% 35%, #3a3a48 0%, #14141a 70%, #08080c 100%);
  border: 1px solid rgba(0, 0, 0, 0.7);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 1px 2px rgba(0, 0, 0, 0.5);
}
.scene-object--cassette-deck .object-deck-led {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: radial-gradient(circle at center, #ff5a3d 0%, #b80812 70%, #2a0408 100%);
  box-shadow: 0 0 8px rgba(255, 90, 60, 0.65);
}

/* Reel spin animation (only when motion is OK) */
@keyframes deck-reel-spin {
  to { transform: translateY(-50%) rotate(360deg); }
}
@media (prefers-reduced-motion: no-preference) {
  .scene-object--cassette-deck .object-deck-reel--a {
    animation: deck-reel-spin 2.6s linear infinite;
  }
  .scene-object--cassette-deck .object-deck-reel--b {
    animation: deck-reel-spin 3.2s linear infinite;
  }
}

/* ----------------------------------------------------------------
   OBJECT: signal-light
   Tiny pulsing red LED — analog "still running" cue.
   ---------------------------------------------------------------- */
.scene-object--signal-light {
  position: absolute;
  width: 14px;
  height: 14px;
  z-index: 6;
  pointer-events: none;
}
.scene-object--signal-light .object-signal-core {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 40% 40%,
    #ff7060 0%,
    #b80812 60%,
    #200408 100%);
  box-shadow: 0 0 6px rgba(184, 8, 18, 0.55);
}
.scene-object--signal-light .object-signal-pulse {
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  background: radial-gradient(circle at center,
    rgba(184, 8, 18, 0.45) 0%,
    rgba(184, 8, 18, 0) 70%);
  pointer-events: none;
}
@keyframes signal-pulse {
  0%, 100% { opacity: 0.4; transform: scale(0.95); }
  50%      { opacity: 1;   transform: scale(1.15); }
}
@media (prefers-reduced-motion: no-preference) {
  .scene-object--signal-light .object-signal-pulse {
    animation: signal-pulse 1.6s ease-in-out infinite;
  }
}

/* ----------------------------------------------------------------
   OBJECT: cassette
   Clickable music object. Real <a> element with href to Spotify.
   Black shell, twin spools visible through the window, side-A label
   with track name + metadata. Slight rotation per instance via
   --object-rotation. Tint variant colors the spine + label accent.
   ---------------------------------------------------------------- */
.scene-object--cassette {
  position: absolute;
  width: 22%;
  min-width: 180px;
  max-width: 280px;
  aspect-ratio: 5 / 3;
  z-index: 8;
  transform: rotate(var(--object-rotation, 0deg));
  filter: drop-shadow(0 10px 16px rgba(0, 0, 0, 0.6));
  /* Reset anchor browser defaults */
  text-decoration: none;
  color: inherit;
  display: block;
  cursor: pointer;
  transition: transform 240ms ease, filter 240ms ease;
}
.scene-object--cassette:hover,
.scene-object--cassette:focus-visible {
  transform: rotate(var(--object-rotation, 0deg)) translateY(-4px) scale(1.04);
  filter:
    drop-shadow(0 18px 22px rgba(0, 0, 0, 0.75))
    drop-shadow(0 0 18px rgba(0, 212, 255, 0.32));
  outline: none;
}
.scene-object--cassette::after {
  /* Subtle interactive ring */
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 6px;
  border: 1px solid rgba(0, 212, 255, 0.18);
  pointer-events: none;
  opacity: 0;
  transition: opacity 240ms ease;
}
.scene-object--cassette:hover::after,
.scene-object--cassette:focus-visible::after {
  opacity: 1;
}

.scene-object--cassette .object-cassette-shell {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, #14141a 0%, #08080c 100%);
  border: 1px solid rgba(255, 255, 255, 0.04);
  border-radius: 4px 4px 6px 6px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -2px 4px rgba(0, 0, 0, 0.5);
  padding: 6%;
  display: flex;
  flex-direction: column;
  gap: 6%;
}

.scene-object--cassette .object-cassette-window {
  position: relative;
  flex: 0 0 38%;
  background: linear-gradient(180deg, #04060a 0%, #0a0c12 100%);
  border: 1px solid rgba(0, 0, 0, 0.7);
  border-radius: 2px;
  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.9);
}
.scene-object--cassette .object-cassette-reel {
  position: absolute;
  top: 50%;
  width: 22%;
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at center,
      #1a1a22 0%,
      #1a1a22 32%,
      #2a2a36 36%,
      #1a1a22 100%);
  transform: translateY(-50%);
}
.scene-object--cassette .object-cassette-reel::before {
  content: "";
  position: absolute;
  inset: 32%;
  border-radius: 50%;
  background: radial-gradient(circle at center, #3a3a48 0%, #0c0c14 100%);
}
.scene-object--cassette .object-cassette-reel--a { left: 12%; }
.scene-object--cassette .object-cassette-reel--b { right: 12%; }
.scene-object--cassette .object-cassette-tape {
  position: absolute;
  top: 50%;
  left: 24%;
  right: 24%;
  height: 12%;
  transform: translateY(-50%);
  background: linear-gradient(180deg, #2a1c0a 0%, #100804 100%);
  opacity: 0.9;
}

.scene-object--cassette .object-cassette-label {
  position: relative;
  flex: 1 1 auto;
  background: linear-gradient(180deg, #f0ece1 0%, #d8d3c4 100%);
  border-radius: 2px;
  padding: 5% 7%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  color: #1a1408;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
}
.scene-object--cassette .object-cassette-side {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.45rem;
  letter-spacing: 0.34em;
  color: rgba(26, 20, 8, 0.5);
  text-transform: uppercase;
  margin-bottom: 0.15rem;
}
.scene-object--cassette .object-cassette-title {
  margin: 0;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: #1a1408;
  line-height: 1.1;
}
.scene-object--cassette .object-cassette-sub {
  margin: 0.15rem 0 0 0;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.5rem;
  letter-spacing: 0.06em;
  color: rgba(26, 20, 8, 0.55);
}

/* Tint variants color the label accent (left spine of the label) */
.scene-object--cassette[data-tint="magenta"] .object-cassette-label {
  border-left: 4px solid rgba(255, 60, 140, 0.7);
}
.scene-object--cassette[data-tint="amber"] .object-cassette-label {
  border-left: 4px solid rgba(255, 168, 70, 0.75);
}
.scene-object--cassette[data-tint="cyan"] .object-cassette-label {
  border-left: 4px solid rgba(0, 212, 255, 0.7);
}

/* Cassette spool animation — only on hover/focus, only with motion OK */
@keyframes cassette-reel-spin {
  to { transform: translateY(-50%) rotate(360deg); }
}
@media (prefers-reduced-motion: no-preference) {
  .scene-object--cassette:hover .object-cassette-reel--a,
  .scene-object--cassette:focus-visible .object-cassette-reel--a {
    animation: cassette-reel-spin 2.4s linear infinite;
  }
  .scene-object--cassette:hover .object-cassette-reel--b,
  .scene-object--cassette:focus-visible .object-cassette-reel--b {
    animation: cassette-reel-spin 2.9s linear infinite;
  }
}

/* ---------- Sound Lab mobile pass ---------- */
@media (max-width: 768px) {
  /* Hide stereo pair on mobile (deck + cassettes are the focal three) */
  .scene-object--speaker { display: none; }

  /* Cassette deck: wider, repositioned upward */
  .scene-object--cassette-deck {
    width: 92%;
    min-width: 0;
    left: 4% !important;
    top: 8% !important;
  }

  /* Signal light: nudged into the deck area */
  .scene-object--signal-light {
    left: 84% !important;
    top: 24% !important;
  }

  /* Cassettes stacked vertically, full-width-ish */
  .scene-object--cassette {
    width: 86%;
    min-width: 0;
    max-width: none;
    left: 7% !important;
    /* Per-cassette top overrides — vertical stack */
  }
  .scene-object--cassette[data-object-id="cassette-white-lines"]    { top: 38% !important; }
  .scene-object--cassette[data-object-id="cassette-overtown"]       { top: 58% !important; }
  .scene-object--cassette[data-object-id="cassette-the-last-night"] { top: 78% !important; }
}

/* ================================================================
   v3 Phase 5 — ARTIST DNA
   ----------------------------------------------------------------
   Section 4 of Tony's Room. Scattered evidence cards — classified
   dossier feel. Not a bio. Not a grid. Old paper, typewriter
   labels, redacted lines, rubber stamps.
   ================================================================ */

.interior-section[data-section-id="artist-dna"] {
  min-height: 120vh;
  contain-intrinsic-size: 120vh;
}

/* Atmosphere variant: dossier room.
   Slightly warmer than Memory Wall — manila/sepia underpinning,
   cooler vignette to keep it noir not sentimental. */
.atmosphere-miami-noir-dossier {
  background:
    radial-gradient(ellipse at 50% 30%, rgba(255, 168, 70, 0.04) 0%, rgba(0, 0, 0, 0) 55%),
    linear-gradient(180deg, #0a0a10 0%, #0e0d14 40%, #060508 100%);
}
.atmosphere-miami-noir-dossier::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 55%, transparent 30%, rgba(0, 0, 0, 0.7) 100%);
  pointer-events: none;
  z-index: 40;
}
.atmosphere-miami-noir-dossier::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px);
  background-size: 3px 3px;
  pointer-events: none;
  z-index: 41;
  mix-blend-mode: screen;
}

/* ----------------------------------------------------------------
   OBJECT: dossier-board
   ---------------------------------------------------------------- */
.scene-object--dossier-board {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.scene-object--dossier-board .object-dossier-wall {
  position: absolute;
  inset: 0;
  background:
    /* Faint horizontal "shelf" striations */
    repeating-linear-gradient(0deg,
      transparent 0,
      transparent 80px,
      rgba(255, 255, 255, 0.008) 80px,
      rgba(255, 255, 255, 0.008) 81px
    ),
    linear-gradient(180deg, #0c0c14 0%, #0a0a10 100%);
}
.scene-object--dossier-board .object-dossier-grain {
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(45deg,
      rgba(255, 255, 255, 0.012) 0,
      rgba(255, 255, 255, 0.012) 1px,
      transparent 1px,
      transparent 6px
    );
  opacity: 0.6;
  mix-blend-mode: screen;
}
.scene-object--dossier-board .object-dossier-tape-line {
  /* A single subtle horizontal line at mid-height — suggests a string
     of pinned evidence even without explicit threads. */
  position: absolute;
  top: 56%;
  left: 4%;
  right: 4%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(255, 168, 70, 0.06) 25%,
    rgba(255, 168, 70, 0.12) 50%,
    rgba(255, 168, 70, 0.06) 75%,
    transparent 100%
  );
}

/* ----------------------------------------------------------------
   OBJECT: file-card
   Scattered evidence cards. label + value + optional stamp/redacted.
   Each card is rotated via --object-rotation. Sized small to mid
   (~17% wide desktop, larger on mobile). Old paper texture +
   typewriter font + subtle shadow.
   ---------------------------------------------------------------- */
.scene-object--file-card {
  position: absolute;
  width: 22%;
  min-width: 200px;
  max-width: 300px;
  z-index: 6;
  transform: rotate(var(--object-rotation, 0deg));
  filter: drop-shadow(0 8px 14px rgba(0, 0, 0, 0.55));
  transition: transform 240ms ease, filter 240ms ease;
  pointer-events: auto;
}
.scene-object--file-card:hover,
.scene-object--file-card:focus-within {
  transform: rotate(var(--object-rotation, 0deg)) translateY(-3px) scale(1.03);
  filter: drop-shadow(0 14px 20px rgba(0, 0, 0, 0.7));
}

.scene-object--file-card .object-card-paper {
  position: relative;
  background:
    /* faint paper grain */
    radial-gradient(rgba(80, 60, 30, 0.04) 1px, transparent 1px),
    linear-gradient(170deg, #e8dfc8 0%, #d4c8a8 100%);
  background-size: 3px 3px, 100% 100%;
  padding: 0.9rem 1rem 1rem;
  border: 1px solid rgba(120, 100, 60, 0.18);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    inset 0 -1px 0 rgba(0, 0, 0, 0.06);
  color: #1a1408;
  /* Reset default <article> margins from the user agent */
  margin: 0;
}

.scene-object--file-card .object-card-tape {
  /* Tape strip at the top — looks pinned/taped to the dossier */
  position: absolute;
  top: -7px;
  left: 38%;
  width: 24%;
  height: 12px;
  background: linear-gradient(180deg,
    rgba(255, 240, 200, 0.4) 0%,
    rgba(255, 240, 200, 0.22) 100%);
  border: 1px solid rgba(255, 240, 200, 0.2);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  transform: rotate(-3deg);
  z-index: 3;
}

.scene-object--file-card .object-card-label {
  margin: 0 0 0.4rem 0;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.55rem;
  letter-spacing: 0.32em;
  font-weight: 500;
  color: rgba(26, 20, 8, 0.5);
  text-transform: uppercase;
}

.scene-object--file-card .object-card-value {
  margin: 0;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.25;
  color: #1a1408;
  position: relative;
}

/* Redacted variant: visual black bar + sr-only true value for SR users */
.scene-object--file-card[data-redacted="true"] .object-card-value {
  display: flex;
  align-items: center;
  min-height: 1.4em;
}
.scene-object--file-card .object-card-redact-bar {
  display: inline-block;
  width: 78%;
  height: 1.1em;
  background: #050608;
  border-top: 1px solid rgba(255, 255, 255, 0.04);
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
  box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.5);
}

/* Rubber stamp (right corner of the card) */
.scene-object--file-card .object-card-stamp {
  position: absolute;
  bottom: 0.45rem;
  right: 0.55rem;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 0.5rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(184, 8, 18, 0.55);
  border: 1.5px solid rgba(184, 8, 18, 0.55);
  padding: 0.18rem 0.4rem;
  transform: rotate(-8deg);
  /* Slight "rubber stamp" ink-spread look */
  text-shadow: 0 0 0.5px rgba(184, 8, 18, 0.5);
  opacity: 0.85;
}

/* ----------------------------------------------------------------
   OBJECT: stamp-mark
   Floating rubber-stamp text drawn over the dossier board.
   Decorative — aria-hidden in markup.
   ---------------------------------------------------------------- */
.scene-object--stamp-mark {
  position: absolute;
  z-index: 7;
  pointer-events: none;
  transform: rotate(var(--object-rotation, 0deg));
}
.scene-object--stamp-mark .object-stamp-text {
  display: inline-block;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: 0.28em;
  color: rgba(184, 8, 18, 0.5);
  border: 2.5px solid rgba(184, 8, 18, 0.5);
  padding: 0.35rem 0.85rem;
  text-shadow: 0 0 0.5px rgba(184, 8, 18, 0.4);
  opacity: 0.7;
  /* Slight imperfection — uneven pressure */
  filter: blur(0.2px);
}
.scene-object--stamp-mark[data-tint="red"] .object-stamp-text {
  color: rgba(184, 8, 18, 0.55);
  border-color: rgba(184, 8, 18, 0.55);
}

/* Reduced-motion: kill card hover lift transition */
@media (prefers-reduced-motion: reduce) {
  .scene-object--file-card { transition: none; }
}

/* ---------- Artist DNA mobile pass ---------- */
@media (max-width: 768px) {
  .scene-object--file-card {
    width: 88%;
    min-width: 0;
    max-width: none;
  }
  /* Re-scatter cards vertically on mobile — overrides JSON inline positions.
     First card starts at 9% to clear the fixed chrome at the top of the
     overlay. */
  .scene-object--file-card[data-object-id="dna-origin"]     { left: 4%  !important; top: 9%  !important; width: 90% !important; }
  .scene-object--file-card[data-object-id="dna-signal"]     { left: 4%  !important; top: 21% !important; width: 90% !important; }
  .scene-object--file-card[data-object-id="dna-obsession"]  { left: 4%  !important; top: 32% !important; width: 90% !important; }
  .scene-object--file-card[data-object-id="dna-status"]     { left: 4%  !important; top: 44% !important; width: 90% !important; }
  .scene-object--file-card[data-object-id="dna-last-seen"]  { left: 4%  !important; top: 56% !important; width: 90% !important; }
  .scene-object--file-card[data-object-id="dna-known-as"]   { left: 4%  !important; top: 67% !important; width: 90% !important; }
  .scene-object--file-card[data-object-id="dna-frequency"]  { left: 4%  !important; top: 78% !important; width: 90% !important; }
  .scene-object--file-card[data-object-id="dna-method"]     { left: 4%  !important; top: 89% !important; width: 90% !important; }

  .scene-object--stamp-mark {
    /* Push to the very bottom of the section on mobile so it doesn't
       collide with the fixed chrome breadcrumb at the top of the overlay. */
    right: 6% !important;
    top: auto !important;
    bottom: 2% !important;
    left: auto !important;
  }
  .scene-object--stamp-mark .object-stamp-text {
    font-size: 0.7rem;
    padding: 0.22rem 0.5rem;
  }
}
