/* ODE · Seoul Encore hanging words — ALIVE monograph tokens */

:root {
  color-scheme: light;
  --ink: #0f0d0b;
  --ink-soft: #2a241c;
  --ink-60: rgba(15, 13, 11, 0.62);
  --ink-40: rgba(15, 13, 11, 0.4);
  --ink-18: rgba(15, 13, 11, 0.18);
  --paper: #f5f0e4;
  --paper-warm: #ebe3d1;
  --paper-hi: #fbf7ee;
  --terracotta: #c4714a;
  --warm-amber: #e2a820;
  --sage: #7a9464;
  --signal: #d8291d;
  --ultramarine: #2a46c8;
  --font-display: "Newsreader", "Times New Roman", serif;
  --font-wordmark: "Archivo Black", "Inter", sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;
  --font-kr: "Noto Sans KR", "Apple SD Gothic Neo", sans-serif;
  --font-kid: "Rock Salt", "Segoe Print", "Comic Sans MS", cursive;
  --easing: cubic-bezier(0.2, 0.8, 0.2, 1);
  /*
   * Vertical composition reserves — the building box is centered in the band
   * left between the fixed header (top) and the fixed score + footer (bottom).
   * Tuned per breakpoint below. Keeping the building sized to this band (rather
   * than a fixed pixel lift) is what prevents top-clipping on short/landscape
   * screens and the dead void on tall/wide screens.
   */
  --top-reserve: 84px;
  --bottom-reserve: 196px;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  min-height: 100%;
  background: var(--paper);
  color: var(--ink);
  /* Belt-and-suspenders: never let decorative bleed create a wider layout
     viewport (which would push fixed chrome off-center on mobile). */
  overflow-x: clip;
}

body {
  min-height: 100svh;
  overflow: hidden;
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  background:
    radial-gradient(ellipse 55vw 50vh at 78% 42%, rgba(226, 168, 32, 0.09), transparent 55%),
    radial-gradient(ellipse 45vw 55vh at 12% 70%, rgba(196, 113, 74, 0.07), transparent 50%),
    linear-gradient(160deg, var(--paper-hi) 0%, var(--paper) 48%, var(--paper-warm) 100%);
}

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: 0;
  background: transparent;
}

.grain {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  opacity: 0.42;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='280' height='280'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.06  0 0 0 0 0.05  0 0 0 0 0.04  0 0 0 0.38 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

/* Floating butterflies — same paper-cut flock as ALIVE flower.html.
   Sit in the air above the building, under grain / chrome; never capture pointer. */
.butterfly-field {
  position: fixed;
  inset: 0;
  z-index: 7;
  pointer-events: none;
  overflow: hidden;
}
.bfly {
  position: absolute;
  top: 0;
  left: 0;
  will-change: transform;
}
.bfly svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  filter: drop-shadow(0 8px 10px rgba(176, 81, 63, 0.10));
}
.bfly .wing {
  transform-box: view-box;
  transform-origin: 50% 50%;
  animation: bfly-flap var(--flap, 0.9s) ease-in-out infinite alternate;
  animation-delay: var(--flap-delay, 0s);
}
@keyframes bfly-flap {
  from { transform: scaleX(1); }
  to   { transform: scaleX(0.24); }
}
@media (prefers-reduced-motion: reduce) {
  .bfly .wing { animation: none; }
}

/* —— top bar —— */
.top-bar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  padding: 18px clamp(16px, 3vw, 36px) 14px;
  pointer-events: none;
}

.meta-left,
.meta-right {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-60);
  white-space: nowrap;
}

.meta-left .kr,
.meta-right .kr {
  font-family: var(--font-kr);
  letter-spacing: 0.04em;
  text-transform: none;
}

.meta-right { text-align: right; }
.dot { opacity: 0.45; margin: 0 0.35em; }

.tagline {
  font-family: var(--font-kid);
  font-weight: 400;
  font-style: normal;
  /* Rock Salt runs ~45% wider than Indie Flower (~27em for this title), so it
     is sized down to hold on one line. */
  font-size: clamp(13px, 1.9vw, 23px);
  letter-spacing: 0;
  color: var(--ink-soft);
  text-align: center;
  white-space: nowrap;
}
.tagline .alive {
  /* ALIVE poster's dry-brush blue */
  color: #2f6ccb;
}

/* —— stage —— */
.stage {
  position: relative;
  width: 100%;
  height: 100dvh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Center the building in the band between header and the fixed score/footer */
  justify-content: center;
  gap: 0;
  /* Reserve header (top) + score/footer (bottom); building fits between */
  padding: var(--top-reserve) 0 var(--bottom-reserve);
  isolation: isolate;
  /*
   * .sky bleeds 25% past each side for a soft atmospheric edge. Clip that
   * horizontal bleed here so it can't expand the mobile LAYOUT viewport —
   * otherwise position: fixed chrome (header, score) centers against the wider
   * layout width while the in-flow building centers against the visual width,
   * and the two drift out of alignment. clip on X keeps Y overflow visible
   * (building shadow/glow still spill vertically).
   */
  overflow-x: clip;
}

.stage .installation {
  margin-top: 0;
  /* Allow the box to shrink to fit the band on short screens (no overlap) */
  flex-shrink: 1;
  min-height: 0;
  /* No fixed lift — centering + band sizing places it on every viewport */
  transform: none;
}

.stage .installation .building-wrap {
  /* Desktop: building sit 10px lower than prior -50px lift; curtain stays put */
  transform: translateY(-40px);
}

/* Full-stage atmosphere — diffuse sky + warm evening haze (no hard oval blobs) */
.sky {
  position: absolute;
  inset: -12% -25% 18% -25%;
  pointer-events: none;
  background:
    /* Cool daylight field — very wide, soft falloff */
    radial-gradient(ellipse 130% 100% at 50% -5%,
      rgba(198, 216, 234, 0.58) 0%,
      rgba(214, 226, 236, 0.32) 38%,
      rgba(232, 228, 218, 0.1) 62%,
      transparent 78%),
    /* Warm evening haze — broad horizontal veil, not a spotlight oval */
    radial-gradient(ellipse 160% 70% at 48% 12%,
      rgba(255, 244, 220, 0.34) 0%,
      rgba(255, 228, 180, 0.14) 28%,
      rgba(255, 214, 150, 0.05) 48%,
      transparent 68%),
    /* Gentle top wash (sunlight through paper) */
    linear-gradient(185deg,
      rgba(255, 250, 236, 0.28) 0%,
      rgba(255, 242, 210, 0.1) 14%,
      transparent 36%),
    /* Faint cool lift on the left so it doesn’t feel flat */
    radial-gradient(ellipse 70% 80% at 12% 30%,
      rgba(245, 250, 255, 0.18) 0%,
      transparent 55%);
  /* Soft vertical dissolve into the page — no circular mask */
  mask-image: linear-gradient(
    180deg,
    #000 0%,
    #000 42%,
    rgba(0, 0, 0, 0.55) 62%,
    transparent 88%
  );
  -webkit-mask-image: linear-gradient(
    180deg,
    #000 0%,
    #000 42%,
    rgba(0, 0, 0, 0.55) 62%,
    transparent 88%
  );
}

/* Foreground plaza — flat plane that dissolves into paper (no disc/oval) */
.ground {
  position: absolute;
  inset: 46% 0 -20% 0;
  /* Match building + flower floor nudge */
  transform: translateY(10px);
  pointer-events: none;
  background:
    /* Horizontal band of pavement tone */
    linear-gradient(180deg,
      transparent 0%,
      rgba(165, 160, 150, 0.07) 8%,
      rgba(155, 150, 140, 0.14) 22%,
      rgba(148, 144, 134, 0.18) 40%,
      rgba(160, 154, 142, 0.12) 58%,
      rgba(180, 172, 158, 0.05) 75%,
      transparent 92%),
    /* Barely-there center emphasis so it still feels grounded under the building */
    radial-gradient(ellipse 100% 55% at 50% 28%,
      rgba(170, 165, 155, 0.1) 0%,
      transparent 70%);
  /* Fade only top/bottom into paper — full width, no side “egg” */
  mask-image: linear-gradient(
    180deg,
    transparent 0%,
    #000 14%,
    #000 58%,
    transparent 100%
  );
  -webkit-mask-image: linear-gradient(
    180deg,
    transparent 0%,
    #000 14%,
    #000 58%,
    transparent 100%
  );
}

.installation {
  position: relative;
  z-index: 4;
  /*
   * Uniform 720/900 box (building proportions untouched — object-fit: contain).
   * Size is driven by the SHORTER of: the available vertical band (height 100%
   * of the stage content box), the width cap expressed as a height, and an
   * absolute cap. min() keeps the building whole on every viewport while the
   * aspect-ratio guarantees the scale stays uniform.
   */
  height: min(100%, calc(88vw * 900 / 720), 792px);
  width: auto;
  aspect-ratio: 720 / 900;
  max-width: 92vw;
  margin-inline: auto;
  flex-shrink: 1;
  min-height: 0;
  overflow: visible;
  touch-action: none;
  cursor: crosshair;
  user-select: none;
  -webkit-user-select: none;
}

.building-wrap {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  overflow: visible;
}

.building-svg,
.building {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  object-position: center center;
  /* Critical: default SVG overflow is hidden and hard-clips soft shadow */
  overflow: visible;
  pointer-events: none;
  user-select: none;
  display: block;
  margin: 0 auto;
}

/* Code-drawn facade — crown light pulse (evening ref) */
@media (prefers-reduced-motion: no-preference) {
  .building-svg .crown-core {
    animation: crown-breathe 4.5s ease-in-out infinite;
  }
}

/* Interactive room lights — panel by panel, gentle on / off */
.building-svg .panel-glow,
.building-svg .panel-led {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.75s cubic-bezier(0.22, 0.8, 0.25, 1);
}

.building-svg .room-panel.is-lit .panel-glow {
  opacity: 0.62;
}

.building-svg .room-panel.is-lit .panel-led {
  opacity: 0.95;
}

@media (prefers-reduced-motion: reduce) {
  .building-svg .panel-glow,
  .building-svg .panel-led {
    transition-duration: 0.12s;
  }
}

@keyframes crown-breathe {
  0%, 100% { opacity: 0.82; }
  50% { opacity: 1; }
}

#curtain {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 2;
  /* Canvas still has its own pixel bounds, but no CSS box paint */
  background: transparent;
  overflow: visible;
}

/* Full-stage bloom layer — can drift into sky / ground beyond the building card */
#fx {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 6;
  pointer-events: none;
}

.hint {
  /* Fixed above score — must clear full score block (~6rem) + gap */
  position: fixed;
  left: 50%;
  bottom: calc(12.25rem + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 18;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-60);
  pointer-events: none;
  transition: opacity 480ms var(--easing);
}

.hint.is-hidden { opacity: 0; }

.hint-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--terracotta);
  box-shadow: 0 0 0 4px rgba(196, 113, 74, 0.18);
  animation: pulse 1.8s var(--easing) infinite;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.25); opacity: 0.7; }
}

/* —— live score —— */
.score {
  position: fixed;
  left: 50%;
  /* Clear multi-line mobile footer + home indicator */
  bottom: calc(4.75rem + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  width: min(88vw, 560px);
  z-index: 18;
  pointer-events: none;
  text-align: center;
  flex-shrink: 0;
}

.score-label {
  margin-bottom: 6px;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.16em;
  color: var(--ink-40);
}

/* Note-voice picker — segmented control below the staff */
.voice-picker {
  pointer-events: auto;
  display: inline-flex;
  gap: 2px;
  margin-top: 10px;
  padding: 2px;
  border: 1px solid var(--ink-18);
  border-radius: 999px;
  background: rgba(245, 240, 228, 0.5);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.voice-opt {
  border: 0;
  background: transparent;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 8px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-40);
  padding: 4px 10px;
  border-radius: 999px;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.2s var(--easing), color 0.2s var(--easing);
}
.voice-opt:hover { color: var(--ink-60); }
.voice-opt[aria-checked="true"] { background: #2f6ccb; color: #fff; }
.voice-opt[aria-checked="true"]:hover { color: #fff; }

/* Gentle-breeze toggle — a switch fixed to the top-right, under the header */
.breeze-toggle {
  position: fixed;
  top: 3.6rem;
  right: clamp(16px, 3vw, 36px);
  z-index: 25;
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 4px 6px 8px;
  border: 0;
  background: transparent;
  color: var(--ink-40);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.25s var(--easing);
}
.breeze-toggle:hover { color: var(--ink-60); }
.breeze-toggle:focus-visible { outline: 2px solid var(--sage); outline-offset: 3px; }
/* Paper pinwheel — still outline when off; colored + spinning while on */
.breeze-toggle svg {
  width: 25px;
  height: 25px;
  display: block;
  overflow: visible;
}
.pin-stick {
  stroke: currentColor;
  stroke-width: 3;
  stroke-linecap: round;
  transition: stroke 0.25s var(--easing);
}
.pin-head {
  transform-box: view-box;
  transform-origin: 32px 30px;
}
.pin-blade {
  fill: rgba(245, 240, 228, 0);
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linejoin: round;
  transition: fill 0.25s var(--easing), stroke 0.25s var(--easing);
}
.pin-dot { fill: currentColor; transition: fill 0.25s var(--easing); }
.breeze-toggle:hover .pin-blade { fill: rgba(158, 195, 232, 0.25); }
.breeze-toggle.is-on { color: #2f6ccb; }
.breeze-toggle.is-on .pin-blade { stroke: rgba(47, 108, 203, 0.55); }
.breeze-toggle.is-on .pin-b1 { fill: #f3b8c8; }
.breeze-toggle.is-on .pin-b2 { fill: #f0c96a; }
.breeze-toggle.is-on .pin-b3 { fill: #a3b88a; }
.breeze-toggle.is-on .pin-b4 { fill: #9ec3e8; }
.breeze-toggle.is-on .pin-dot { fill: #2f6ccb; }
.breeze-toggle.is-on .pin-head { animation: pin-spin 5.5s linear infinite; }
@keyframes pin-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .breeze-toggle.is-on .pin-head { animation: none; }
}

/* HARU theme button — the café's house logo, top-left mirror of Breeze.
   Outline when off; fills soft pink (with the door cutout) when on. */
.haru-button {
  position: fixed;
  top: 3.5rem;
  left: clamp(16px, 3vw, 36px);
  z-index: 25;
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 8px 6px 4px;
  border: 0;
  background: transparent;
  color: var(--ink-40);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.25s var(--easing);
}
.haru-button svg {
  width: 24px;
  height: 21px; /* logo trace is 173:154 */
  display: block;
  overflow: visible;
}
.haru-house-path {
  fill: rgba(245, 182, 195, 0); /* transparent pink so the fill fades in */
  stroke: currentColor;
  stroke-width: 8; /* in 173×154 viewBox units ≈ 1px on screen */
  stroke-linejoin: round;
  transition: fill 0.25s var(--easing), stroke 0.25s var(--easing);
}
.haru-button:hover { color: var(--ink-60); }
.haru-button:hover .haru-house-path { fill: rgba(245, 182, 195, 0.25); }
.haru-button:focus-visible { outline: 2px solid var(--sage); outline-offset: 3px; }
.haru-button.is-on { color: #e8899a; }
.haru-button.is-on .haru-house-path { fill: #f5b6c3; stroke: #e8899a; }

#staff {
  width: 100%;
  height: auto;
  max-height: 72px;
  opacity: 0.92;
}

/* —— footer —— */
.bottom-bar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  gap: 12px;
  padding: 10px clamp(16px, 3vw, 36px) 16px;
  pointer-events: none;
  border-top: 1px solid var(--ink-18);
  background: color-mix(in srgb, var(--paper) 78%, transparent);
  backdrop-filter: blur(14px);
}

.credit {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.04em;
  color: var(--ink-40);
  max-width: 36ch;
}

.credit .kr {
  font-family: var(--font-kr);
  font-size: 11px;
  letter-spacing: 0.08em;
}

.venue {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-40);
  text-align: right;
  justify-self: end;
  white-space: nowrap;
}

.venue .kr {
  font-family: var(--font-kr);
  letter-spacing: 0.04em;
  text-transform: none;
}

.venue .dot {
  opacity: 0.45;
  margin: 0 0.35em;
}

.dates {
  display: flex;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* —— responsive —— */
@media (max-width: 720px) {
  body { overflow: hidden; }

  :root {
    /* Mobile chrome is taller: stacked header + multi-line footer + score.
       Bottom reserve trimmed (~25%) so the flower ground is smaller and the
       enlarged building can sit slightly lower. */
    --top-reserve: calc(4.4rem + env(safe-area-inset-top, 0px));
    --bottom-reserve: calc(10.5rem + env(safe-area-inset-bottom, 0px));
  }

  .top-bar {
    grid-template-columns: 1fr;
    justify-items: center;
    gap: 2px;
    padding: max(6px, env(safe-area-inset-top, 0px)) 10px 4px;
  }
  .meta-left, .meta-right { font-size: 8px; }
  .meta-right { text-align: center; }
  .tagline {
    /* Keep the full title on ONE line; size scales with viewport width so it
       fits from ~320px up (Rock Salt renders this title ~27em wide, so the
       vw factor is capped to (vw−20px)/27 ≈ 3.3vw). */
    font-size: clamp(10px, 3.3vw, 15px);
    white-space: nowrap;
    line-height: 1.25;
    max-width: none;
  }

  /* Stacked header is taller — drop the controls into the sky below it */
  .breeze-toggle {
    top: calc(4.35rem + env(safe-area-inset-top, 0px));
    right: 12px;
    padding: 5px 3px 5px 6px;
  }
  .breeze-toggle svg { width: 21px; height: 21px; }
  .haru-button {
    top: calc(4.35rem + env(safe-area-inset-top, 0px));
    left: 12px;
    padding: 5px 6px 5px 3px;
  }
  .haru-button svg { width: 20px; height: 17.8px; }

  .stage {
    height: 100dvh;
    min-height: 100dvh;
    /* Centered in the band; reserves above clear the mobile chrome */
    padding: var(--top-reserve) 0 var(--bottom-reserve);
    justify-content: center;
    gap: 0;
  }

  .stage .installation {
    /*
     * Enlarge the building so its top reaches up near the header and its base
     * sits a little lower, shrinking the empty flower ground. A centered
     * scale() (not a width change) grows the building AND its curtain together
     * — they stay registered — while the empty artboard margins overflow and
     * clip harmlessly; transforming from the center avoids the left-anchor that
     * a wider-than-viewport layout box would cause. Ratio is untouched.
     * translateY lifts the top the last bit to the header line.
     * Scale is stepped down on shorter phones (below) so it never overlaps.
     */
    height: min(100%, calc(94vw * 900 / 720));
    width: auto;
    max-width: 96vw;
    aspect-ratio: 720 / 900;
    margin-inline: auto;
    transform: scale(1.55) translateY(-34px);
  }

  .stage .installation .building-wrap {
    transform: translateY(10px);
  }

  /* Step the enlargement down as viewport height shrinks (largest max-height
     first so the smallest matching rule wins by source order). */
  @media (max-height: 799px) {
    .stage .installation { transform: scale(1.4) translateY(-18px); }
  }
  @media (max-height: 679px) {
    .stage .installation { transform: scale(1.3) translateY(-6px); }
  }
  @media (max-height: 599px) {
    .stage .installation { transform: scale(1.18); }
  }

  /* score clears tall multi-line footer; hint clears score */
  .hint {
    bottom: calc(13.5rem + env(safe-area-inset-bottom, 0px));
    font-size: 9px;
    letter-spacing: 0.12em;
  }

  .score {
    bottom: calc(6.85rem + env(safe-area-inset-bottom, 0px));
    width: min(92vw, 400px);
  }

  .score-label {
    font-size: 9px;
    margin-bottom: 4px;
  }

  #staff {
    height: 58px;
    max-height: 58px;
  }

  /* Short copy now fits on one line — mirror the desktop 3-column footer */
  .bottom-bar {
    grid-template-columns: 1fr auto 1fr;
    align-items: baseline;
    gap: 8px;
    padding: 8px clamp(12px, 4vw, 22px) calc(8px + env(safe-area-inset-bottom, 0px));
  }
  .credit {
    max-width: none;
    font-size: 9px;
  }
  .credit .kr { font-size: 9px; }
  .venue { font-size: 9px; }
  .dates { font-size: 9px; }
}

/*
 * —— short / landscape ——
 * Little vertical room: the building must shrink to the band and the score
 * must stay compact so the two never collide (the old fixed-lift layout let
 * the building clip the top and overrun the staff here).
 */
@media (max-height: 560px) {
  :root {
    --top-reserve: calc(2.6rem + env(safe-area-inset-top, 0px));
    --bottom-reserve: calc(3.4rem + env(safe-area-inset-bottom, 0px));
  }

  .stage {
    height: 100dvh;
    min-height: 100dvh;
    padding: var(--top-reserve) 0 var(--bottom-reserve);
    justify-content: center;
  }

  .stage .installation {
    transform: none;
    height: min(100%, calc(64vw * 900 / 720));
    width: auto;
    max-width: 82vw;
    aspect-ratio: 720 / 900;
  }

  /* Keep the wrap/curtain registration but drop the desktop 10px nudge */
  .stage .installation .building-wrap { transform: none; }

  /* Hide the live score in landscape — no room, and it fought the building */
  .score { display: none; }
  .hint { display: none; }

  .bottom-bar {
    padding: 4px clamp(10px, 3vw, 28px) calc(4px + env(safe-area-inset-bottom, 0px));
  }
}

@media (prefers-reduced-motion: reduce) {
  .hint-dot { animation: none; }
  * { scroll-behavior: auto !important; }
}
