/* =========================================================
   DONDA — brand site
   Mediterranean brutalism. Berlin discipline, Mallorca climate.
   ========================================================= */

:root {
  --ink:        #0b0b0d;          /* warm black */
  --ink-2:      #141518;          /* one step lighter for sections */
  --steel:      #2b2e33;          /* patinated steel */
  --travertine: #e4e7ea;          /* cream limestone */
  --travertine-dim: #a8adb2;
  --amber:      #cfd6db;          /* the neon glow */
  --amber-soft: rgba(207,214,219, 0.55);
  --concrete:   #5c6166;          /* poured concrete */
  --rule:       rgba(228,231,234, 0.30);
  --rule-soft:  rgba(228,231,234, 0.14);
  /* CASA NEGRA mini-studio tokens (amber = emitted light) */
  --ink-3:      #1c1e22;
  --travertine-faint: rgba(228,231,234,0.55);
  --amber-faint: rgba(207,214,219,0.14);
  --danger:     #c8463c;
  --amber-hot:  #ffffff; --amber-mid: #e7ecef; --amber-cool: #9aa1a7; --amber-deep: #565c61;
  --well:       #08090b;
  --metal-top:  rgba(228,231,234,0.08); --metal-bot: rgba(0,0,0,0.6);
  --lift:       0 14px 30px -18px rgba(0,0,0,0.9);
  --slab:       linear-gradient(168deg,#1e2024 0%,#141518 18%,#131417 100%);
  --mono:       'Archivo', ui-monospace, Menlo, monospace;
  --energy:     0;
  /* The Instrument's living light. studio.js overwrites these every frame from the
     audio (silver at rest → cyan → Eclipse sunset on the peak). Silver fallback here
     keeps the pad on-palette when nothing's playing / reduced motion. */
  --glow-rgb:   207,214,219;
  --glow:       #cfd6db;
  --glow-soft:  rgba(207,214,219,0.55);
  --glow-dim:   rgba(207,214,219,0.18);
  /* The eclipse is the ONE warm element: a Mallorcan yellow-pink-gold sunset disc
     against the cool/black room. Everything else stays silver/stone. */
  --eclipse-grad: radial-gradient(circle at 50% 42%, #fff2c8 0%, #ffd368 20%, #fba94f 40%, #f3815a 57%, #e26a8e 71%, #b8482f 86%, #2a120e 100%);
  --eclipse-glow: 255,150,90;
  --eclipse-soft: 240,108,110;
  --eclipse-gold: 255,205,130;
  /* THE MERIDIAN corona hue (set live in script.js from the sun's altitude: white by
     day, gold at the horizon, deep pink at dusk, magenta ember at night). These
     fallbacks are the original warm-gold corona, so no-JS / reduced-motion renders it. */
  --solRGB: 255, 214, 156;
  --solRGB2: 255, 180, 120;
  --solRim: 0.7;
  --solArrive: 0;
  /* Mediterranean brutalism: one grotesque superfamily, no serif. */
  --display: 'Archivo', 'Arial Narrow', sans-serif;
  --serif: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --sans:  'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --ease:  cubic-bezier(0.2, 0.6, 0.2, 1);
}

* { box-sizing: border-box; }

/* <picture> wrappers (AVIF/WebP delivery) must not affect layout: display:contents
   makes the wrapper generate no box, so each <img> lays out exactly as before and
   the scroll-scrub choreography is untouched. */
picture { display: contents; }

/* THE LAST DOOR — a smooth cross-document transition into /tickets/ instead of a
   white-flash navigation (paired with the Speculation Rules prerender in the
   head). Motion-gated; degrades to a normal navigation where the View Transition
   API is unsupported. The eclipse-morph version layers a shared
   view-transition-name on top of this once the tickets hero disc is designed. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}

/* Skip link — keyboard users bypass the cinematic intro to the main landmark.
   Visually hidden until focused (WCAG 2.4.1). z above the nav + play slab. */

html, body {
  margin: 0;
  padding: 0;
  background: var(--ink);
  color: var(--travertine);
  font-family: var(--sans);
  font-weight: 300;
  font-size: 100%;            /* respect the user's browser / iOS Dynamic Type size */
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

/* Two-temperature ambient — mineral-cool at the top, molten-warm as you
   descend the building. Opacity is scroll-driven via --warmth (set in JS). */
body { background: transparent; }
.ambient {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* THE MERIDIAN: scroll warmth OR the night-time floor, whichever is higher.
     --solAmbient is 0 by day (never lightens the page), capped 0.16 at DOORS,
     so the time-of-day signal is luminance only — the palette never washes. */
  opacity: max(var(--warmth, 0), var(--solAmbient, 0));
  background:
    radial-gradient(135% 95% at 50% 116%, rgba(180,188,194,0.20), transparent 56%),
    linear-gradient(to bottom, transparent 0%, rgba(58,63,68,0.08) 55%, rgba(70,76,82,0.17) 100%);
}

::selection { background: var(--amber); color: var(--ink); }

/* ---------- Nav ---------- */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.1rem clamp(1rem, 4vw, 2.5rem);
  background: linear-gradient(to bottom, rgba(10,10,12,0.92), rgba(10,10,12,0.4));
  /* NO backdrop-filter: on iOS Safari a position:fixed element WITH backdrop-filter
     detaches and floats mid-screen during momentum scrolling ("header broken"). The
     near-solid background below carries the look without it. */
  transition: background 0.4s ease, border-color 0.4s ease, opacity 0.45s ease, transform 0.45s ease;
  border-bottom: 1px solid transparent;
  /* hidden on the splash — the header slides in only once you start scrolling */
  opacity: 0;
  transform: translateY(-100%);
  pointer-events: none;
}
.nav.is-scrolled,
.nav.is-menu-open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.nav.is-scrolled {
  background: rgba(10,10,12,0.92);
  border-bottom-color: var(--rule-soft);
}

.nav__mark {
  display: inline-flex;
  align-items: center;
  height: 22px;
  color: var(--travertine);
}
.nav__mark img {
  height: 100%;
  width: auto;
  display: block;
  opacity: 0.95;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 2.2vw, 2rem);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.nav__links a { transition: color 0.2s ease; }
.nav__links a:hover { color: var(--amber); }

.nav__actions {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 1.25rem);
}
/* The Tickets stamp — the travertine label device, not a button box: small,
   filled, mono caps, sitting quiet next to the wordmark. */
.nav__cta {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  padding: 0.42rem 0.75rem 0.38rem;
  background: var(--travertine);
  color: var(--ink) !important;
  border: 0;
  transition: background 0.2s ease, transform 0.2s ease;
}
.nav__cta:hover { background: var(--amber); color: var(--ink) !important; }
.nav__cta:active { transform: translateY(1px); }

.nav__toggle {
  display: none;
  background: transparent;
  border: none;
  padding: 0.5rem;
  margin: -0.5rem;
  cursor: pointer;
  z-index: 2;
}
.nav__toggle span {
  display: block;
  width: 22px;
  height: 1px;
  background: var(--travertine);
  margin: 5px 0;
  transition: transform 0.3s ease, opacity 0.25s ease;
}
.nav__toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.nav__toggle { display: block; }
.nav__links {
  position: fixed;
  top: 100%;
  left: 0;
  right: 0;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  padding: clamp(1.5rem, 3vh, 2.5rem) clamp(1rem, 4vw, 3rem) clamp(2rem, 4vh, 3rem);
  background: rgba(10,10,12, 0.97);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule-soft);
  transform: translateY(-110%);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.35s cubic-bezier(0.2, 0.6, 0.2, 1), opacity 0.25s ease;
}
.nav.is-menu-open .nav__links {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}
.nav__links a {
  display: block;
  padding: 1rem 0;
  border-bottom: 1px solid var(--rule-soft);
  font-size: 0.95rem;
  letter-spacing: 0.22em;
  color: var(--travertine);
}

@media (min-width: 720px) {
  .nav__links {
    padding-block: clamp(2.5rem, 5vh, 4rem);
    padding-inline: clamp(2rem, 6vw, 5rem);
  }
  .nav__links a {
    font-size: 1.05rem;
    padding: 1.15rem 0;
  }
}

/* ---------- Type ---------- */
.display {
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 112%;            /* expanded width axis — architectural, but mobile-legible */
  letter-spacing: -0.02em;
  line-height: 0.98;
  margin: 0;
  font-size: clamp(2.5rem, 8.5vw, 7rem);
}
.display__line { display: block; }
.display--md { font-size: clamp(1.95rem, 5.6vw, 4.4rem); line-height: 1.05; }
.display--sm { font-size: clamp(1.65rem, 3.4vw, 2.7rem); line-height: 1.08; }

.italic { font-style: italic; color: var(--travertine); }
/* display italics render in the narrower Archivo italic — width + style
   contrast against the Expanded roman, not a faux-slanted Expanded. */
.display .italic { font-family: var(--serif); font-weight: 500; font-stretch: 100%; }

.eyebrow,
.section__index {
  font-family: var(--sans);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--travertine);
  font-weight: 600;
}

/* stamped architectural label — filled block, not an airy tracked line */
.section__index {
  color: var(--ink);
  background: var(--travertine);
  margin: 0 0 2.5rem 0;
  display: inline-block;
  padding: 0.35rem 0.7rem 0.3rem;
  border-bottom: none;
}

.lede {
  font-family: var(--serif);
  font-size: clamp(1.1rem, 1.7vw, 1.45rem);
  font-style: italic;
  font-weight: 300;
  color: var(--travertine);
  line-height: 1.45;
  margin: 1.5rem 0 0;
  max-width: 30em;
}

.prose {
  font-size: 1rem;
  line-height: 1.7;
  color: var(--travertine-dim);
  max-width: 38em;
  margin: 1.5rem 0 0;
}

.prose--rule {
  margin-top: 2.25rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule-soft);
  font-family: var(--serif);
  font-size: 1.15rem;
  letter-spacing: 0.01em;
  color: var(--travertine);
  max-width: 32em;
}
.prose--rule .italic { color: var(--amber); }

/* ---------- Hero ---------- */
.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: clamp(5rem, 10vh, 9rem) clamp(1.25rem, 5vw, 4rem) clamp(2.5rem, 5vh, 4rem);
  overflow: hidden;
}

.hero__media {
  position: absolute; inset: 0;
  z-index: 0;
}
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 50%;
  transform: scale(1.04);
  animation: heroDrift 24s ease-in-out infinite alternate;
}
@keyframes heroDrift {
  from { transform: scale(1.04) translate3d(0,0,0); }
  to   { transform: scale(1.10) translate3d(-1.5%, -1%, 0); }
}
.hero__veil {
  position: absolute; inset: 0;
  background:
    linear-gradient(to top, rgba(10,10,12,0.95) 0%, rgba(10,10,12,0.55) 35%, rgba(10,10,12,0.25) 65%, rgba(10,10,12,0.6) 100%),
    radial-gradient(ellipse at 50% 65%, rgba(207,214,219,0.08), transparent 60%);
}

.hero__content {
  position: relative;
  z-index: 1;
  max-width: 1200px;
}

.hero .display {
  margin-top: 1.5rem;
  text-shadow: 0 2px 40px rgba(0,0,0,0.5);
}

.hero__foot {
  position: relative;
  z-index: 1;
  margin-top: 2.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem 0.9rem;
  align-items: center;
  padding-right: 7rem;
  font-size: 0.75rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.hero__foot-mark { color: var(--amber); }

/* =========================================================
   The Eclipse landing — lives as an OVERLAY inside the cosmos pin. At rest it
   covers the deep field (the clean landing); as you scroll, a circular hole
   irises open from the disc's centre onto the cosmos's OWN deep field beneath
   (one image — the field you reveal is the field you fly into, no re-show), and
   the disc zooms + dissolves into the descent. Driven by --portal (0→1) in JS.
   ========================================================= */
.splash {
  position: absolute; inset: 0; z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(1.75rem, 5vh, 3rem);     /* clear the halo bloom; calmer, shorter column at 390px */
  /* the bottom band belongs to the fixed Play-the-set pill: the in-flow
     SCROLL cue must never reach it, even on short collapsed-chrome
     viewports where the centered column grows down (the cue also bobs) */
  padding: clamp(6rem, 14vh, 9rem) clamp(1.5rem, 6vw, 4rem)
    max(clamp(4rem, 9vh, 6rem), calc(env(safe-area-inset-bottom, 0px) + 8.5rem));
  background: radial-gradient(120% 80% at 50% 38%, #0e0f12 0%, var(--ink) 60%);
  text-align: center;
  pointer-events: none;
}
/* base / reduced-motion (no JS scrub): no portal — go straight to the cosmos */
.cosmos:not(.is-live) .splash { display: none; }

/* portal mechanics — the hole opens onto the deep field beneath.
   GATED behind .is-opening (JS adds it once --portal > 0): at scroll 0 there is
   NO mask, so the splash is fully opaque and covers the field. iOS Safari
   renders a 0-radius radial mask as fully TRANSPARENT (Chrome renders it
   opaque), which made the deep field show first on iPhone — the gate fixes it. */
.cosmos.is-live .splash.is-opening {
  /* the hole has a FLOOR (~1.6vmax) so whenever the mask is applied its radius
     is never in the near-zero range iOS Safari renders fully transparent. The
     floor is centred on the dark orb over the dark deep field, so it is
     invisible until the portal genuinely opens. At true rest (portal 0) the
     class is absent → no mask at all → the splash is guaranteed opaque. */
  --holeR: calc((0.02 + var(--portal, 0) * var(--portal, 0)) * 82vmax);
  /* anchored on the disc's MEASURED centre (script.js aimPortal); the old
     hardcoded 50% 44% drifted off-centre across devices */
  -webkit-mask: radial-gradient(circle var(--holeR) at var(--holeX, 50%) var(--holeY, 44%), transparent 0, transparent 64%, #000 100%);
          mask: radial-gradient(circle var(--holeR) at var(--holeX, 50%) var(--holeY, 44%), transparent 0, transparent 64%, #000 100%);
}
.cosmos.is-live .splash .splash__eclipse {
  /* THE MERIDIAN: the disc stays CENTRED and a constant size (owner: don't move it).
     The time of day now reads purely from the CORONA COLOUR. Only the portal zoom
     scales it as the deep field opens through it. --solY / --solScale are still
     written in script.js but no longer used here (harmless). */
  transform: scale(calc(1 + var(--portal, 0) * 3));
  opacity: calc(1 - var(--portal, 0) * 2.3);          /* …dissolving as the field opens through it */
}
.cosmos.is-live .splash .splash__content { opacity: calc(1 - var(--portal, 0) * 4.5); }
/* the descent gate is now a flex sibling of __content, so it gets its own mirror
   of the old cue fade — shaft, SCROLL and chevron clear fast as the iris opens */
.cosmos.is-live .splash .splash__gate { opacity: calc(1 - var(--portal, 0) * 7); }

/* the eclipse — the container is exactly the disc; the halo overflows it
   (absolute) so its bloom never inflates the layout and pushes the name down */
.splash__eclipse {
  position: relative;
  z-index: 1;
  width: clamp(150px, 34vw, 320px);
  aspect-ratio: 1;
}
.splash__halo {
  position: absolute;
  left: 50%; top: 50%;
  width: 240%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%) scale(calc(1 + var(--solArrive, 0) * 0.12));
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--solRGB, 255,214,156),0.20) 0%, rgba(var(--solRGB2, 255,180,120),0.08) 38%, transparent 64%);
  filter: blur(calc(14px + var(--solWarm, 0.4) * 12px));
  /* THE MERIDIAN: the corona blooms as the real sun nears the horizon and
     after dark (full at night), thin and cool by day */
  opacity: calc(0.35 + var(--solWarm, 0.4) * 0.65 + var(--solArrive, 0) * 0.4);
  pointer-events: none;
}
.splash__orb {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  /* dark mirror body + a faint cool silver sheen, upper-left */
  background:
    radial-gradient(circle at 37% 32%, rgba(207,214,219,0.18) 0%, rgba(207,214,219,0.05) 24%, transparent 46%),
    radial-gradient(circle at 50% 55%, #1a1d22 0%, #0e1013 56%, #08090b 100%);
  /* the warm corona: a crisp rim hugging the edge, then soft sunset bloom */
  box-shadow:
    0 0 1px 1px rgba(var(--solRGB, 255,214,156), calc(0.75 * var(--solRim, 0.7))),
    0 0 9px 2px rgba(var(--solRGB, 255,255,255), calc((1 - var(--solWarm, 0.4)) * 0.45)),
    0 0 26px 2px rgba(var(--solRGB2, 255,180,120), calc(0.40 * var(--solRim, 0.7))),
    0 0 90px 22px rgba(var(--solRGB2, 243,129,90), 0.16),
    inset 0 1px 34px rgba(0,0,0,0.55),
    inset 0 0 60px rgba(var(--solRGB, 255,170,110), 0.05);
  animation: eclipseBreathe 9s ease-in-out infinite alternate;
}
/* THE MERIDIAN: a warm corona bloom that grows with --solWarm (molten at
   night, faint by day). The crisp rim stays on the orb itself; this layer
   only adds the variable outer glow, so the disc identity is untouched. */
.splash__orb::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  box-shadow:
    0 0 40px 6px rgba(var(--solRGB2, 255,180,120), calc(var(--solWarm, 0.4) * 0.5)),
    0 0 120px 34px rgba(var(--solRGB2, 243,129,90), calc(var(--solWarm, 0.4) * 0.22));
}

/* the name + place, fading up on load */
.splash__content {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1rem, 2.6vh, 1.5rem);
}
/* THE CYCLE — the wordmark and the answer-word share ONE focal cell (stacked),
   so the loop never shifts the column; script.js shows one beat at a time. */
.splash__cycle {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
}
.splash__cycle > * { grid-area: 1 / 1; }
/* the logo image is now the FALLBACK (reduced motion / no JS); the reels replace it */
.splash__mark { width: clamp(168px, 42vw, 312px); height: auto; }
.splash__cycle.has-reels .splash__mark { display: none; }
/* THE WORDMARK REELS — each DONDA letter on a fixed-box slot-reel (glyphs sliced from
   the logo typeface, assets/dfont). Uniform boxes so spacing is even; only the wide W
   is squished to fit. script.js builds the faces + drives the spin. */
.splash__reels {
  display: flex; align-items: center; justify-content: center;
  gap: 2px; height: 42px;          /* bigger boxes (64) so W only needs a slight squish; everything else sits natural */
}
.splash__reels:empty { display: none; }   /* reduced-motion / no-JS -> the .splash__mark logo shows instead */
.splash__reels .dreel { position: relative; height: 42px; width: 64px; overflow: hidden; flex: 0 0 auto; }
.splash__reels .dstrip { position: absolute; left: 50%; top: 0; width: 64px; transform: translateX(-50%); }
.splash__reels .dface { height: 42px; display: flex; align-items: center; justify-content: center; }
.splash__reels .dface img { height: 42px; width: auto; display: block; }
.splash__reels .dface img.sq { width: 64px; height: 42px; }   /* only W (the lone width outlier) -> ~18% squish */

/* THE DESCENT GATE — SCROLL elevated into the hero invitation of the splash.
   Strictly cool (--travertine), never silver: the silver Play slab stays the only
   luminous/beating object; this reads as "go down", that reads as "sound". In
   flow after __content so it can never reach the fixed Play pill's band. */
.splash__gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: clamp(1.4rem, 5vh, 2.6rem);
}
.splash__shaft {
  position: relative;
  width: 1px;
  height: clamp(88px, 13vh, 140px);
  background: linear-gradient(to bottom, transparent, var(--travertine-dim));
}
.splash__shaft::after {              /* a slow mote falling the length of the shaft */
  content: '';
  position: absolute;
  left: 50%; top: 0;
  width: 3px; height: 3px;
  border-radius: 50%;
  background: var(--travertine);
  transform: translateX(-50%);
  animation: shaftFall 2.6s ease-in-out infinite;
}
.splash__cue {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: 0.5em;
  text-transform: uppercase;
  color: var(--travertine);
  margin: 0.7rem 0 0 0.5em;          /* the 0.5em offsets the trailing tracking so it stays centred */
}
.splash__chevron {
  display: block;
  width: 11px; height: 11px;
  margin-top: 0.5rem;
  border-right: 1px solid var(--travertine);
  border-bottom: 1px solid var(--travertine);
  transform: rotate(45deg);
  animation: gateBeat 1.8s ease-in-out infinite;
}
@keyframes shaftFall {
  0%   { transform: translateX(-50%) translateY(0); opacity: 0; }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { transform: translateX(-50%) translateY(clamp(88px, 13vh, 140px)); opacity: 0; }
}
@keyframes gateBeat {
  0%, 100% { transform: rotate(45deg) translateY(0); }
  50%      { transform: rotate(45deg) translateY(4px); }
}

@keyframes splashRise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes splashBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(3px); }
}

@media (prefers-reduced-motion: reduce) {
  .splash__halo, .splash__orb { animation: none; }
  .splash__mark, .splash__gate, .splash__cue, .splash__shaft {
    opacity: 1; transform: none; animation: none; transition: none;
  }
  /* still frame: the DONDA wordmark carries the brand; the looping word is hidden */
  .splash__word { opacity: 0; }
  .splash__shaft::after { animation: none; opacity: 0; }
  .splash__chevron { animation: none; opacity: 1; transform: rotate(45deg); }
}

/* =========================================================
   Cosmos — descend from orbit to the site via satellite tiles
   ========================================================= */
.cosmos { position: relative; background: #000; z-index: 3; }   /* above the entrance so the entrance can sit BEHIND it (hidden during its rise), then be revealed — door-aligned — as the cosmos scrolls away */
/* through the doors (walk p ≥ 0.8, JS): the pin has faded out, but the section's
   own black bg (z3 > stage z2) would still scroll out as a hard-edged black
   curtain over the club — release it with the same hand-off */
.cosmos.is-thru { background: transparent; }
.cosmos__pin { position: relative; overflow: hidden; min-height: 100vh; min-height: 100svh; }
/* nightfall: --cosmosEnd (the old end-dip hook, see .is-live ::after below) is
   driven by JS as the doors arrive — the daylight satellite falls into night
   while the façade covers it, so the hand-off reads as a dusk landing. */
.cosmos.is-live { height: 720vh; }   /* the Mallorca satellite zoom gets the long runway (those shots are the hero); the rooftop→door gap is cut from the entrance instead */
.cosmos.is-live .cosmos__pin {
  position: sticky; top: 0;
  /* 100lvh, NOT svh (2026-06-12): with iOS chrome COLLAPSED the visible
     viewport is TALLER than svh, and an svh pin left a strip at the bottom
     showing the stage corridor beneath ("doors overlapping an image"). lvh
     always covers; when chrome is expanded the overflow hides below the fold. */
  height: 100vh; height: 100lvh;
  opacity: var(--cosmosFade, 1);   /* cross-dissolves out over the entrance door at the hand-off */
}

.cosmos__stars {
  position: absolute; inset: 0; z-index: 0;
  opacity: var(--stars, 1);
  background-color: #000;
  background-image:
    radial-gradient(1.5px 1.5px at 15% 22%, #fff, transparent),
    radial-gradient(1px 1px at 28% 64%, rgba(255,255,255,.8), transparent),
    radial-gradient(1.5px 1.5px at 42% 14%, #fff, transparent),
    radial-gradient(1px 1px at 55% 48%, rgba(255,255,255,.7), transparent),
    radial-gradient(1.5px 1.5px at 67% 30%, #fff, transparent),
    radial-gradient(1px 1px at 78% 70%, rgba(255,255,255,.75), transparent),
    radial-gradient(1.5px 1.5px at 88% 18%, #fff, transparent),
    radial-gradient(1px 1px at 9% 80%, rgba(255,255,255,.7), transparent),
    radial-gradient(1px 1px at 35% 88%, rgba(255,255,255,.6), transparent),
    radial-gradient(1.5px 1.5px at 62% 82%, #fff, transparent),
    radial-gradient(1px 1px at 92% 55%, rgba(255,255,255,.7), transparent),
    radial-gradient(1px 1px at 48% 70%, rgba(255,255,255,.6), transparent);
}

/* deep-zoom image layers: galaxy → star field → sun → earth */
.cosmos__layer {
  position: absolute; inset: 0;
  background-position: center; background-repeat: no-repeat; background-size: cover;
  transform-origin: 50% 50%;
  opacity: 0;
  mix-blend-mode: screen; /* the images' black space → transparent, so everything reads as one full-screen scene over the starfield */
  will-change: transform, opacity;
}
/* Hubble Ultra Deep Field — the opening frame, dives into the Milky Way.
   Credit: NASA, ESA, S. Beckwith (STScI) and the HUDF Team. */
.cosmos__hudf { z-index: 1; opacity: 1; background-image: url("assets/cosmos_hudf.jpg?v=2"); }
.cosmos__galaxy { z-index: 1; background-image: url("assets/cosmos_galaxy.jpg"); background-size: contain; transform-origin: 61% 40%; }
.cosmos__field  { z-index: 2; background-image: url("assets/cosmos_field.jpg"); }
.cosmos__earth  { z-index: 4; background-image: url("assets/cosmos_earth.jpg"); background-size: contain; transform-origin: 39% 45%; }
.cosmos__sun {
  position: absolute; left: 50%; top: 54%; z-index: 3;
  width: 64vmax; height: 64vmax; margin: -32vmax 0 0 -32vmax;
  border-radius: 50%;
  background: radial-gradient(circle, #ffffff 0%, #ffffff 7%, #eef2f5 17%, rgba(231,236,239,0.55) 33%, rgba(207,214,219,0.14) 55%, transparent 72%);
  opacity: 0; transform: scale(0.2); transform-origin: 50% 50%;
  mix-blend-mode: screen; will-change: transform, opacity;
}

.cosmos__map { position: absolute; inset: 0; z-index: 5; overflow: hidden; opacity: 0; }
/* THE OCULUS — the chrome ball focal canvas: a childless absolute LEAF at z8
   (above the map z5 / atmos z6 / reticle z7, below the arrival door z9 and the
   splash z10 that dissolves on top). Hidden when the cosmos isn't live or on a
   perf-lite device, so the liked CSS eclipse always carries those paths. The
   anchor vars are the door/spark impact point the ball crashes into. */
.cosmos__ball { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 8; pointer-events: none; opacity: 0; --ballAnchorX: 0.53; --ballAnchorY: 0.56; }
.cosmos:not(.is-live) .cosmos__ball, .perf-lite .cosmos__ball { display: none; }
/* MOBILE OCULUS — on coarse/touch the cosmic-descent focal object is a pure-CSS
   eclipse disc, NOT the WebGL ball (iOS kept killing the WebGL context = the "poof").
   Dark mirror body + a luminous silver rim (so it reads on the dark deep field) + a
   dark contrast pool (so it reads on the bright Milky Way). script.js sets its size /
   position / opacity inline per the descent; this only defines the look. CSS renders
   identically on iOS and desktop, so it can never fail to load or crash. */
.cosmos__disc {
  /* OUTER = positioner only (script.js sets width/height/transform/opacity inline);
     the look + the "alive" behaviour live on the children so they don't fight the
     JS-driven position transform. */
  position: absolute; top: 0; left: 0; width: 110px; height: 110px;
  z-index: 8; pointer-events: none; opacity: 0;
  will-change: transform, opacity;
}
/* THE ORB — the chrome/eclipse body, always breathing (scale + float = never resting) */
.cosmos__disc__orb {
  position: absolute; inset: 0; border-radius: 50%;
  /* a true dark VOID (no metal sheen) — the event horizon */
  background: radial-gradient(circle at 50% 50%, #000 0%, #000 50%, #04050a 72%, #080a11 100%);
  /* the PHOTON RING — light bending around the horizon (the defining black-hole feature)
     + a soft lensed halo + the dark contrast pool for bright backgrounds */
  box-shadow:
    0 0 0 1.5px rgba(238,244,254,0.92),
    0 0 14px 2px rgba(202,218,244,0.62),
    0 0 36px 8px rgba(150,174,214,0.30),
    0 0 54px 30px rgba(2,3,7,0.66),
    inset 0 0 24px 7px rgba(0,0,0,0.92);
  animation: discBreathe 6.5s ease-in-out infinite alternate;
}
/* THE ACCRETION GLOW — a bright arc sweeping the ring (relativistic beaming of a
   spinning hole), masked to a thin annulus so it rides the photon ring */
.cosmos__disc__orb::before {
  content: ''; position: absolute; inset: -3%; border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0%, transparent 32%, rgba(220,232,255,0.55) 50%, transparent 68%, transparent 100%);
  -webkit-mask: radial-gradient(circle, transparent 0 58%, #000 70%, #000 84%, transparent 94%);
  mask: radial-gradient(circle, transparent 0 58%, #000 70%, #000 84%, transparent 94%);
  mix-blend-mode: screen;
  animation: discSpin 9s linear infinite;
}
/* THE WARP — the cosmos dims + blurs in a ring at the rim, so space appears pulled
   toward the hole (a CSS stand-in for the WebGL gravitational lens; true geometric
   bending needs WebGL). Masked to an annulus around the void. */
.cosmos__disc__lens {
  position: absolute; inset: -22%; border-radius: 50%;
  -webkit-backdrop-filter: blur(3px) brightness(0.9) saturate(1.1);
  backdrop-filter: blur(3px) brightness(0.9) saturate(1.1);
  -webkit-mask: radial-gradient(circle, transparent 0 42%, #000 52%, #000 80%, transparent 100%);
  mask: radial-gradient(circle, transparent 0 42%, #000 52%, #000 80%, transparent 100%);
  animation: discBreathe 6.5s ease-in-out infinite alternate;
}
@keyframes discBreathe { 0% { transform: scale(1) translateY(0); } 100% { transform: scale(1.03) translateY(-2px); } }
@keyframes discSpin { to { transform: rotate(360deg); } }
/* the disc is cheap CSS, so unlike the WebGL canvas it is NOT hidden under perf-lite —
   only before the cosmos is live. */
.cosmos:not(.is-live) .cosmos__disc { display: none; }
@media (prefers-reduced-motion: reduce) {
  .cosmos__disc__orb, .cosmos__disc__lens, .cosmos__disc__orb::before { animation: none; }
}
/* if WebGL gives up after repeated context losses, hand the intro back to the liked
   CSS eclipse instead of a black void (script.js adds .oculus-failed on give-up). */
.oculus-failed .cosmos__ball { display: none; }
/* MOBILE GPU RELIEF: do not force-promote the four full-res cosmos JPEGs (and the sun)
   to GPU compositor layers on phones/iPad — that ~50MB of resident GPU memory is part
   of what pushes iOS WebKit to kill the WebGL context. */
@media (pointer: coarse) { .cosmos__layer, .cosmos__sun { will-change: auto; } }
.cosmos__plane {
  position: absolute; inset: 0;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}
.cosmos__plane img {
  position: absolute;
  width: 256px; height: 256px;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}

.cosmos__atmos {
  position: absolute; inset: 0; z-index: 6;
  pointer-events: none;
  opacity: var(--atmos, 0.6);
  background:
    radial-gradient(120% 70% at 50% 122%, rgba(96,156,232,0.20), transparent 55%),
    radial-gradient(150% 105% at 50% 50%, transparent 38%, rgba(5,6,10,0.55) 80%, rgba(5,6,10,0.92) 100%);
}

/* ---------- ARRIVAL — the bright point that blooms into the Eclipse and
   reveals the doors, all inside the cosmos pin (continuous with the zoom).
   --arrive 0→1 (JS): the door is revealed through an aperture that expands
   from the site point at 53% 56%; --sparkR/--sparkA drive the bright
   point/corona that "expands into the eclipse". No black anywhere. ---------- */
.cosmos__arrival { position: absolute; inset: 0; z-index: 9; pointer-events: none; }
/* locked to the viewport once revealed, so the unsticking pin scrolls away
   behind it while the door stays put — aligned with the entrance door for a
   clean cross-fade hand-off */
.cosmos.is-arrived .cosmos__arrival { position: fixed; inset: 0 0 auto 0; height: 100vh; height: 100lvh; }   /* lvh: cover the collapsed-chrome viewport too (iOS strip bug) */
.cosmos__arrival-door {
  position: absolute; inset: 0;
  background: url("assets/entrance_door.jpg?v=2") 53% 56% / cover no-repeat;
  /* reveal zoom settles to 1.0, then --arrivalThru pushes IN through the doors */
  transform: scale(calc(1.22 - var(--arrive, 0) * 0.22 + var(--arrivalThru, 0) * 0.6));
  /* the eclipse aperture: a circle growing from the bright point at the site */
  -webkit-mask: radial-gradient(circle calc(var(--arrive,0) * var(--arrive,0) * 170vmax) at 53% 56%, #000 0 72%, transparent 100%);
          mask: radial-gradient(circle calc(var(--arrive,0) * var(--arrive,0) * 170vmax) at 53% 56%, #000 0 72%, transparent 100%);
}
/* the bright point → eclipse corona: a warm bloom at the aperture, intense as a
   point, expanding and softening as the doors take the frame */
.cosmos__spark {
  position: absolute; left: 53%; top: 56%;
  width: calc(var(--sparkR, 0px) * 2);
  height: calc(var(--sparkR, 0px) * 2);
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255,255,255,0.95) 0%, rgba(255,228,180,0.85) 22%,
    rgba(255,190,120,0.45) 50%, rgba(243,129,90,0.16) 72%, transparent 84%);
  opacity: var(--sparkA, 0);
  mix-blend-mode: screen;
  pointer-events: none;
}
.perf-lite .cosmos__arrival-door { transform: none; }

.cosmos__reticle {
  position: absolute; left: 50%; top: 50%; z-index: 7;
  width: clamp(46px, 14vw, 64px); aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border: 1px solid var(--amber-soft);
  border-radius: 50%;
  pointer-events: none;
  opacity: var(--reticle, 0);
}
.cosmos__reticle::before,
.cosmos__reticle::after {
  content: '';
  position: absolute;
  background: var(--amber-soft);
}
.cosmos__reticle::before { left: 50%; top: -8px; bottom: -8px; width: 1px; margin-left: -0.5px; }
.cosmos__reticle::after { top: 50%; left: -8px; right: -8px; height: 1px; margin-top: -0.5px; }

/* end-of-descent dip to black so the rooftop melts into the doors (no hard cut) */
.cosmos.is-live .cosmos__pin::after {
  content: ''; position: absolute; inset: 0; z-index: 9;
  pointer-events: none; background: #000;
  opacity: var(--cosmosEnd, 0);
}

.cosmos__content {
  position: relative; z-index: 8;
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column;
  padding: clamp(5.5rem, 12vh, 9rem) clamp(1.25rem, 5vw, 4rem) clamp(2.5rem, 6vh, 4rem);
  opacity: calc(1 - var(--cosmosOut, 0));
  pointer-events: none;
}
.cosmos__content .eyebrow {
  margin-bottom: auto;
  color: var(--travertine);
  text-shadow: 0 1px 16px rgba(0,0,0,0.8);
}
.cosmos__line {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(2rem, 7vw, 3.6rem);
  line-height: 1.02;
  margin: 0 0 1.25rem;
  color: var(--travertine);
  text-shadow: 0 2px 30px rgba(0,0,0,0.85);
  opacity: 1;   /* visible by default (reduced motion / no JS) */
}
/* with the scroll engine live, the line reveals once you start to descend */
.cosmos.is-live .cosmos__line { opacity: var(--lineIn, 0); }
.cosmos__cue {
  margin: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.85rem;
  font-size: 0.72rem; letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--amber);
}
/* bobbing down-chevron beneath the label — the scroll prompt, made bold */
.cosmos__cue::after {
  content: '';
  width: 1rem; height: 1rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  animation: cosmosBob 1.5s ease-in-out infinite;
  filter: drop-shadow(0 0 8px rgba(207,214,219,0.5));
}
@keyframes cosmosBob {
  0%, 100% { transform: rotate(45deg) translate(-3px, -3px); opacity: 0.45; }
  50%      { transform: rotate(45deg) translate(4px, 4px);   opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .cosmos__cue::after { animation: none; opacity: 0.85; }
}

/* =========================================================
   Entrance — arrive at the doors, walk in
   Base (no JS / reduced motion): a full-screen door panel.
   .is-walk (JS): pinned, scroll pushes you through the doors.
   ========================================================= */
.entrance { position: relative; background: var(--ink); z-index: 1; }   /* BEHIND the cosmos (z3): hidden while it rises, revealed door-aligned as the cosmos arrival scrolls off */
.entrance__pin { position: relative; overflow: hidden; }

.entrance__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
/* the entrance no longer holds its OWN door image — the single cosmos arrival
   door carries all the way through. The entrance section is just scroll-length
   for the through; hide its door + copy so there is never a second door. */
.entrance.is-walk .entrance__media,
.entrance.is-walk .entrance__content,
.entrance.is-walk .entrance__veil,
.entrance.is-walk .entrance__black { display: none; }
/* night feather over the satellite hand-off — the façade emerges from the
   dark instead of butt-jointing the map tiles */
.entrance__media::after {
  content: '';
  position: absolute; left: 0; right: 0; top: 0;
  height: 24vh;
  background: linear-gradient(to bottom, #000 0%, rgba(0,0,0,0.55) 45%, transparent 100%);
  pointer-events: none;
}
.entrance__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 53% 56%;     /* the doors of the new façade */
  transform: scale(1.02);
  transform-origin: 53% 56%;    /* the warp zooms through the door seam */
  will-change: transform;
}
.entrance__glow {
  position: absolute; inset: 0;
  background: radial-gradient(34% 28% at 53% 56%, rgba(207,214,219,0.38), transparent 70%);
  mix-blend-mode: screen;
  opacity: 0.4;
}
.entrance__veil {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(to top, rgba(10,10,12,0.92) 0%, rgba(10,10,12,0.32) 32%, rgba(10,10,12,0.18) 60%, rgba(10,10,12,0.72) 100%);
}
.entrance__black {
  position: absolute; inset: 0; z-index: 3;   /* above the doors + copy, so it can dip the whole frame */
  background: var(--ink);
  opacity: 0;
}
.entrance__content {
  position: relative; z-index: 2;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  padding: clamp(5.5rem, 12vh, 9rem) clamp(1.25rem, 5vw, 4rem) clamp(2.5rem, 6vh, 4rem);
}
.entrance__content .eyebrow { margin-bottom: auto; }
.entrance__line {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(2.1rem, 7.5vw, 4.25rem);
  line-height: 1;
  margin: 0 0 1.25rem;
  color: var(--travertine);
  text-shadow: 0 2px 40px rgba(0,0,0,0.6);
}
.entrance__cue {
  margin: 0;
  display: inline-flex;
  align-items: center;
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--amber-soft);
}
.entrance__cue::before {
  content: '';
  width: 1.6rem; height: 1px;
  background: var(--amber-soft);
  margin-right: 0.7rem;
}

/* ---- THE WARP — reinvented street-level drop (2026-06-11) ----
   Phases of one scrub (--walk 0→1, JS-eased; numbers written by script.js):
   RUSH    the façade flies at you out of the vanishing point (--doorScale
           0.30→1.02 on an accelerating curve, --doorIn fades it up) while the
           fixed .fx-warp streak canvas blasts radial light around it;
   CATCH   the streaks die, the neon flares (--flare spikes the glow), the
           copy lands (--copyCatch);
   THROUGH straight through the doors (--doorScale →2.1) into the black
           (--enterMask), and the Club rises to meet you (stage overlap). */
.entrance.is-walk { height: 150vh; margin-top: -100vh; }   /* pure scroll-length for the THROUGH (the single cosmos door pushes in + the cosmos fades to reveal the stage). entrance.top = flightEnd; the entrance itself shows nothing (no door). */
.entrance.is-walk .entrance__pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
}
.entrance.is-walk .entrance__content { min-height: 0; height: 100%; }
.entrance.is-walk .entrance__media img {
  transform: scale(var(--doorScale, 1.02));
}
/* THE ECLIPSE IRIS — the façade is revealed through an opening disc anchored
   on the doors (the same portal language the splash uses on the way in, so
   the descent ends the way it began). Feathered edge: never a hard rectangle.
   The mask is dropped entirely (.is-irising removed) once fully open, so the
   catch and the walk-through pay no per-frame mask cost. */
.entrance.is-walk.is-irising .entrance__media {
  -webkit-mask: radial-gradient(circle var(--irisR, 6vmax) at 53% 56%, #000 0 58%, transparent 100%);
          mask: radial-gradient(circle var(--irisR, 6vmax) at 53% 56%, #000 0 58%, transparent 100%);
}
/* the corona — a warm rim riding the iris edge, with an ember fill so the
   eclipse opens OUT OF light (the doors behind it are near-black; without
   the ember the pinhole stage reads as a dead black frame) */
.entrance.is-walk .entrance__pin::after {
  content: '';
  position: absolute; left: 53%; top: 56%;
  width: calc(var(--irisR, 6vmax) * 1.16);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 1.5px solid rgba(var(--eclipse-gold), 0.6);
  background: radial-gradient(circle,
    rgba(var(--eclipse-gold), calc(var(--irisGlow, 0) * 0.5)) 0%,
    rgba(var(--eclipse-glow), calc(var(--irisGlow, 0) * 0.28)) 45%,
    transparent 72%);
  box-shadow:
    0 0 calc(18px + var(--irisGlow, 0) * 46px) 2px rgba(var(--eclipse-glow), calc(0.3 + var(--irisGlow, 0) * 0.35)),
    inset 0 0 36px rgba(var(--eclipse-glow), 0.16);
  opacity: var(--irisRing, 0);
  pointer-events: none;
  z-index: 2;
}
.entrance.is-walk .entrance__glow {
  opacity: calc(0.2 + var(--walk, 0) * 0.4 + var(--flare, 0) * 0.95);
}
.entrance.is-walk .entrance__veil { opacity: calc(0.25 + var(--copyCatch, 0) * 0.55); }
.entrance.is-walk .entrance__black { opacity: var(--enterMask, 0); }
.entrance.is-walk .entrance__content {
  opacity: var(--copyCatch, 0);
  transform: translateY(calc((1 - var(--copyCatch, 0)) * 2vh));
}

/* the warp streak field — fixed, brand-silver with the odd dusk-gold streak;
   the engine wakes it only while the drop is live (opacity set from JS) */
.fx-warp {
  position: fixed; inset: 0;
  z-index: 30;               /* over the flight + the flying façade, under the nav */
  pointer-events: none;
  opacity: 0;
}
.perf-lite .fx-warp { display: none; }

/* =========================================================
   Opening stage — Hero → Eclipse descent
   Base (no JS / reduced motion): two readable full-height panels.
   .is-scrub (added by JS when motion is allowed): one pinned,
   scroll-scrubbed cinematic sequence.
   ========================================================= */
.stage { position: relative; z-index: 2; }   /* above the entrance (z1) so the stage still rises over it */
.stage__pin { position: relative; }

.stage__panel {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.stage__panel--hero {
  justify-content: flex-end;
  padding: clamp(5rem, 10vh, 9rem) clamp(1.25rem, 5vw, 4rem) clamp(2.5rem, 5vh, 4rem);
}
.stage__panel--eclipse {
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(5rem, 14vh, 9rem) clamp(1.25rem, 5vw, 4rem);
  background: radial-gradient(120% 90% at 50% 64%, #1a1c20 0%, #121316 42%, var(--ink) 78%);
  border-top: 1px solid var(--rule-soft);
}
/* BEAT 1 welcome panel — centered, NO background (the corridor photo shows through) */
.stage__panel--arrive {
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(5rem, 14vh, 9rem) clamp(1.25rem, 5vw, 4rem);
}
.stage__arrive {
  position: relative;
  z-index: 4;
  max-width: 34rem;
  padding: clamp(1.5rem, 4vw, 3rem);
  margin-top: -4vh;
  background: radial-gradient(ellipse at 50% 46%, rgba(10,10,12,0.62) 0%, rgba(10,10,12,0.3) 46%, transparent 72%);
}

/* the room */
.stage__room { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.stage__room img {
  position: absolute; inset: 0;          /* the two beats stack and cross-fade */
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 50%;
  transform: scale(1.05);
  animation: heroDrift 24s ease-in-out infinite alternate;
}
/* BEAT 2 — the BOOTH (the Eclipse ring) cross-fades in over the corridor as the
   question takes over (--boothIn). Corridor is the base layer, always beneath. */
.stage.is-scrub .stage__img--booth { opacity: var(--boothIn, 0); }
/* BEAT 3 — the wide club room (Eclipse altar at the far LEFT) cross-fades in over
   the booth; bias the crop left so the altar + stone bar anchor the frame */
/* selector carries img + .stage__room so it OUTRANKS the generic `.stage.is-scrub
   .stage__room img` (0,3,1) — else the room's left-bias crop + push-in lose to it */
.stage.is-scrub .stage__room img.stage__img--room { opacity: var(--roomIn, 0); object-position: 24% 48%; transform: scale(calc(1.04 + var(--roomHold, 0) * 0.10)); }
/* the BOOTH (the Eclipse ring behind the decks) is the HELD image now — a slow
   scroll push-in keeps its linger alive (the generic scrub rule sets animation:none,
   so without this it would freeze). img.stage__img--booth (0,4,1) outranks the generic. */
.stage.is-scrub .stage__room img.stage__img--booth { transform: scale(calc(1.08 + var(--boothHold, 0) * 0.10)); }
/* stacking: images at the bottom, then the three text beats in order */
.stage.is-scrub .stage__room { z-index: 0; }
.stage.is-scrub .stage__panel--arrive { z-index: 2; }
.stage.is-scrub .stage__panel--hero { z-index: 3; }
.stage.is-scrub .stage__panel--eclipse { z-index: 5; }
.stage__veil {
  position: absolute; inset: 0;
  background:
    linear-gradient(to top, rgba(10,10,12,0.95) 0%, rgba(10,10,12,0.55) 35%, rgba(10,10,12,0.25) 65%, rgba(10,10,12,0.6) 100%),
    radial-gradient(ellipse at 50% 65%, rgba(207,214,219,0.08), transparent 60%);
}

/* the opening words */
.stage__hero { position: relative; z-index: 3; max-width: 1200px; }
.stage__hero .display { margin-top: 1.5rem; text-shadow: 0 2px 40px rgba(0,0,0,0.5); }
/* THE BIG QUESTION — through the doors, "¿Dónde?" owns the frame, the lit
   corridor pulling the eye down to the Eclipse that answers it. Larger than the
   base display so the arrival lands as a question, not a caption. */
.stage__title { font-size: clamp(3.4rem, 15vw, 8rem); }
.stage__found {
  margin: 1.1rem 0 0;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.35rem, 3.4vw, 2.1rem);
  letter-spacing: 0.01em;
  color: var(--amber);
  text-shadow: 0 2px 30px rgba(0,0,0,0.6);
}
.stage__title .display__line { display: block; will-change: transform; }
.stage__cue {
  display: inline-flex;
  align-items: center;
  color: var(--amber-soft);
}
.stage__cue::before {
  content: '';
  width: 1.6rem; height: 1px;
  background: var(--amber-soft);
  margin-right: 0.7rem;
}

/* the rising sun + the signature copy */
.stage__sky { z-index: 1; }
.stage__eclipse {
  position: relative;
  z-index: 4;
  max-width: 38rem;
  padding: clamp(1.5rem, 4vw, 3rem);
  margin-top: -8vh;
  background: radial-gradient(ellipse at 50% 42%, rgba(10,10,12,0.6) 0%, rgba(10,10,12,0.28) 45%, transparent 72%);
}

/* ---- scrubbed mode ---- */
/* Overlap the Club up onto the entrance's tail so the room is already rising
   as you pass through the doors — kills the dead-black gap (same trick used to
   slide the entrance onto the cosmos tail). */
.stage.is-scrub { height: 520vh; margin-top: -150vh; }   /* = -(entrance height) top, big tail so the room LINGERS ~1 screen after its statement (the back third of the scrub). Pins full-screen at flightEnd, behind the door, so the cosmos fade has NO black gap. Scrub offset in JS so it starts after the fade. */
.stage.is-scrub .stage__pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100lvh;   /* lvh, not svh — see the cosmos pin note (iOS collapsed-chrome strip) */
  overflow: hidden;
  /* the room photo is gone — a dark eclipse-toned backdrop for the words + the
     rising signature orb */
  background: radial-gradient(120% 95% at 50% 64%, #1a1c20 0%, #121316 44%, var(--ink) 80%);
}
.stage.is-scrub .stage__panel {
  position: absolute;
  inset: 0;
  min-height: 0;
}
.stage.is-scrub .stage__panel--eclipse {
  background: transparent;
  border-top: none;
}

.stage.is-scrub .stage__room img {
  /* HELD — no fly-in zoom. club_arrival.jpg (2026-06-12): the lit corridor with
     the Eclipse glowing small at the far end (center, ~42% up) — the depth IS
     the staging for "¿Dónde?". Frame the corridor so the ring sits above the
     copy; lift brightness (the shot is deep + dark) and darken on descend. */
  animation: none;
  transform: scale(1.08);
  object-position: center 44%;
  filter: brightness(calc(1.28 - var(--descend, 0) * 0.62)) contrast(1.06);
}
.stage.is-scrub .stage__veil { opacity: calc(0.18 + var(--descend, 0) * 0.72); }   /* barely there at the arrival so the club reads, darkens as the Eclipse rises */

/* BEAT 1 — the corridor WELCOME holds first (boothIn 0 -> opacity 1), then fades
   as the booth+question take over. It is the complement of the question's fade-in,
   so the corridor is never wordless. */
.stage.is-scrub .stage__arrive {
  opacity: calc(1 - var(--boothIn, 0));
  transform: translateY(calc(var(--boothIn, 0) * -3vh));
}
/* BEAT 2 — the question rises with the booth (--boothIn) and flies apart as the
   room takes over (--roomIn). opacity = boothIn * (1 - roomIn). */
.stage.is-scrub .stage__hero {
  opacity: calc(var(--boothIn, 0) * (1 - var(--questionOut, 0)));
  transform: translateY(calc((1 - var(--boothIn, 0)) * 4vh));
}
.stage.is-scrub .stage__title [data-line="1"] {
  transform: translate3d(calc(var(--questionOut, 0) * -7vw), calc(var(--questionOut, 0) * -18vh), 0);
}
.stage.is-scrub .stage__title [data-line="2"] {
  transform: translate3d(calc(var(--questionOut, 0) * 7vw), calc(var(--questionOut, 0) * 18vh), 0);
}
.stage.is-scrub .stage__hero .stage__found,
.stage.is-scrub .stage__hero .hero__sub,
.stage.is-scrub .stage__hero .lede,
.stage.is-scrub .stage__hero .hero__foot {
  transform: translateY(calc(var(--questionOut, 0) * 10vh));
}

/* (the rising CSS Eclipse orb was removed — BEAT 3 is now the real room photo,
   whose far wall carries the Eclipse; an abstract orb fought the image-led story) */

/* the statement fades IN with the room (roomIn) and HOLDS, read on the room until
   the stage releases to the thesis. The room is NOT the lingering image now (the
   BOOTH holds the wordless dwell earlier), so there is NO early fade-out and NO
   wordless room frame — the statement just reads and the page moves on as normal. */
.stage.is-scrub .stage__eclipse {
  opacity: var(--roomIn, 0);
  transform: translateY(calc((1 - var(--roomIn, 0)) * 4vh));
}

/* ---------- Custom magnetic cursor ---------- */
.cursor {
  position: fixed;
  top: 0; left: 0;
  z-index: 200;
  pointer-events: none;
  will-change: transform;
}
.cursor__ring {
  position: absolute;
  width: 30px; height: 30px;
  margin: -15px;
  border: 1px solid #fff;
  border-radius: 50%;
  mix-blend-mode: difference;
  transition: width .35s cubic-bezier(.2,.6,.2,1),
              height .35s cubic-bezier(.2,.6,.2,1),
              margin .35s cubic-bezier(.2,.6,.2,1),
              opacity .3s ease;
}
.cursor__dot {
  position: absolute;
  width: 4px; height: 4px;
  margin: -2px;
  border-radius: 50%;
  background: var(--amber);
  transition: opacity .3s ease;
}
.cursor.is-hover .cursor__ring { width: 66px; height: 66px; margin: -33px; }
.cursor.is-hover .cursor__dot { opacity: 0; }
.cursor.is-hidden { opacity: 0; }

.has-cursor,
.has-cursor a,
.has-cursor button,
.has-cursor [data-magnetic],
.has-cursor .menu__group-summary,
.has-cursor summary { cursor: none; }
.has-cursor :is(input, select, textarea) { cursor: auto; }

/* keyboard focus — the custom cursor hides the system one, so a visible focus
   ring is the ONLY affordance for keyboard / assistive-tech users (mouse focus
   stays clean via :focus-visible) */
:focus-visible {
  outline: 2px solid var(--travertine);
  outline-offset: 3px;
  border-radius: 3px;
}
.enquire input:focus-visible,
.enquire select:focus-visible { outline-offset: 6px; }

[data-magnetic] {
  will-change: transform;
  transition: transform .3s cubic-bezier(.2,.6,.2,1);
}

/* ---------- Sections ---------- */
.section {
  padding: clamp(5rem, 12vh, 9rem) clamp(1.25rem, 5vw, 4rem);
  max-width: 1280px;
  margin: 0 auto;
  border-top: 2px solid var(--rule);   /* hard structural rule between sections */
  overflow-x: clip;
}
/* oversized labels + headings hang flush to the edge, off the body inset —
   architectural signage against the grid */
.section > .section__index,
.section > .display {
  margin-left: calc(-1 * clamp(1.25rem, 5vw, 4rem));
}

/* ---------- Three Expressions ---------- */
.expressions {
  border-top: 2px solid var(--rule);
}

/* =========================================================
   THE DECK — the rooms hold the frame and the next slides over.
   Club / Restaurant / Menu / Garden are sticky cards: each pins at the top
   of the viewport while the next room rises over it, receding (scale + dim,
   both driven by --cover) as it is buried. --hold (0→1 while a card owns the
   frame) dollies its image like a slow camera. Scroll length is unchanged:
   the parent is exactly the sum of its cards. JS measures with .is-measuring
   (sticky off) so layout reads are true; taller-than-viewport cards get a
   negative top from JS so they scroll fully before pinning.
   ========================================================= */
.expressions > .expr,
.expressions > .menu {
  position: sticky;
  top: 0;
  transform: scale(calc(1 - var(--cover, 0) * 0.05));
  transform-origin: 50% 38%;
}
.is-measuring .expressions > .expr,
.is-measuring .expressions > .menu { position: relative; }
.expressions > .expr { border-bottom: none; }
.expressions > .menu {
  min-height: 100vh;
  min-height: 100svh;
  max-width: none;             /* opaque full-bleed card... */
  background: var(--ink);
}
.expressions > .menu > * {     /* ...the editorial grid keeps its width inside */
  max-width: 1280px;
  margin-left: auto;
  margin-right: auto;
}
.expressions > .expr::after,
.expressions > .menu::after {
  content: '';
  position: absolute; inset: 0;
  background: #000;
  opacity: calc(var(--cover, 0) * 0.55);
  pointer-events: none;
  z-index: 6;
}

/* ---------- THE GAUGE — where you are in the building ---------- */
.gauge {
  position: fixed;
  right: max(0.9rem, env(safe-area-inset-right));
  top: 50%;
  height: 34vh;
  width: 1px;
  transform: translateY(-50%);
  background: rgba(228,231,234,0.16);
  z-index: 40;                 /* under the nav and the instrument */
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.gauge.is-live { opacity: 1; }
.gauge__dot {
  position: absolute;
  left: 50%; top: calc(var(--depth, 0) * 100%);
  width: 7px; height: 7px;
  transform: translate(-50%, -50%) scale(calc(1 + var(--beat, 0) * 0.5));
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, #fff, var(--glow, #cfd6db));
  box-shadow: 0 0 10px var(--glow-soft, rgba(207,214,219,0.55));
}
.gauge__label {
  position: absolute;
  right: calc(100% + 0.55rem);
  top: calc(var(--depth, 0) * 100%);
  transform: translateY(-50%);
  font-family: var(--mono);
  font-weight: 600;
  font-size: 0.56rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--travertine-dim);
  white-space: nowrap;
  opacity: 0.85;
}
.perf-lite .gauge__dot { transform: translate(-50%, -50%); }
/* THE MERIDIAN: the time-of-day state word at the head of the rail */
.gauge__sol {
  position: absolute;
  right: calc(100% + 0.55rem);
  top: 0; transform: translateY(-50%);
  font-family: var(--mono); font-weight: 600; font-size: 0.5rem;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--travertine-faint); white-space: nowrap; opacity: 0.7;
}

/* Full-bleed cinematic room panels — the image is the room, copy lives in it */
.expr {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  padding: clamp(2.5rem, 9vh, 6rem) clamp(1.25rem, 5vw, 4rem);
  padding-bottom: max(clamp(2.5rem, 9vh, 6rem), calc(env(safe-area-inset-bottom, 0px) + 5rem));   /* bottom-aligned room captions clear the fixed Play pill */
  overflow: hidden;
  border-bottom: 1px solid var(--rule-soft);
}
.expr:last-child { border-bottom: none; }

.expr__media {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: var(--ink);
}
.expr__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* --seam settles the room into place; --vel leans the world with a hard
     flick (velocity skew); --cover sinks the buried room behind the riser */
  transform: scale(calc(1.12 + (1 - var(--seam, 1)) * 0.06)) skewY(calc(var(--vel, 0) * 0.5deg));
  translate: 0 calc(var(--epy, 0px) + var(--cover, 0) * 26px);
  transition: filter 1.6s cubic-bezier(0.2, 0.6, 0.2, 1);
}
.expr__media::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(to top, rgba(10,10,12,0.95) 0%, rgba(10,10,12,0.5) 32%, rgba(10,10,12,0.12) 56%, rgba(10,10,12,0.5) 100%);
}
/* full-bleed: don't iris-clip the background; keep the duotone→colour reveal */
.expr__media.reveal { clip-path: none; }

.expr__body {
  position: relative;
  z-index: 2;
  max-width: 42rem;
  text-shadow: 0 2px 30px rgba(10,10,12,0.7);
}
/* second restaurant frame — a quiet caption, the image does the talking */
.expr__caption {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.15rem, 3.4vw, 1.9rem);
  line-height: 1.3;
  color: var(--travertine);
}
.expr__caption .italic { color: var(--amber); }

/* The Restaurant's third frame rides ONE render in two slides — the crop does
   the storytelling: first the working room, then the glass to the Garden. */
#restaurant-dining .expr__media img { object-position: 35% 55%; }
#restaurant-glass  .expr__media img { object-position: 90% 42%; }
/* Phones: the render is landscape with a dark ceiling across its top half, so
   a plain portrait cover-crop reads as black beams (same trap as the arrival
   corridor). Zoom past the ceiling and bias the lit candle band; keep the
   --seam/--vel terms so the deck motion still breathes. */
@media (max-width: 640px) {
  #restaurant-dining .expr__media img {
    object-position: 26% 67%;
    transform: scale(calc(1.55 + (1 - var(--seam, 1)) * 0.06)) skewY(calc(var(--vel, 0) * 0.5deg));
  }
  #restaurant-glass .expr__media img {
    object-position: 86% 58%;
    transform: scale(calc(1.45 + (1 - var(--seam, 1)) * 0.06)) skewY(calc(var(--vel, 0) * 0.5deg));
  }
}

.expr__roman {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.1rem;
  letter-spacing: 0.4em;
  color: var(--amber);
  margin: 0 0 1rem;
}

.meta {
  list-style: none;
  padding: 0;
  margin: 2rem 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.meta li {
  position: relative;
  padding-left: 1rem;
}
.meta li::before {
  content: '';
  position: absolute;
  left: 0; top: 50%;
  width: 0.45rem; height: 1px;
  background: var(--amber);
}

@media (max-width: 820px) {
  .expr, .expr--reverse { grid-template-columns: 1fr; }
  .expr--reverse .expr__media { order: 0; }
  .expr--reverse .expr__body  { order: 1; }
}

/* ---------- Menu ---------- */
.menu {
  max-width: 1280px;
  margin: 0 auto;
  padding: clamp(4rem, 9vh, 6.5rem) clamp(1.25rem, 5vw, 4rem);
  border-top: 1px solid var(--rule-soft);
}
.menu__head {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--rule-soft);
  margin-bottom: 1.5rem;
}
.menu__head .menu__index { margin: 0; }
.menu__title { margin: 0; }
.menu__index {
  font-family: var(--sans);
  font-size: 0.72rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.menu .prose { margin: 0 0 2.5rem; }

.menu__cols {
  column-count: 2;
  column-gap: clamp(2rem, 5vw, 4.5rem);
}
@media (max-width: 760px) {
  .menu__cols { column-count: 1; }
}

.menu__group {
  break-inside: avoid;
  margin: 0 0 0.5rem;
  display: flow-root;
  border-bottom: 1px solid var(--rule-soft);
}
.menu__group-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 0;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.2s ease;
}
.menu__group-summary::-webkit-details-marker { display: none; }
.menu__group-summary::marker { display: none; }
.menu__group-summary:hover .menu__group-title { color: var(--amber); }
.menu__group-summary::after {
  content: '+';
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.6rem;
  color: var(--amber);
  line-height: 1;
  flex-shrink: 0;
  transition: transform 0.3s cubic-bezier(0.2, 0.6, 0.2, 1);
}
.menu__group[open] > .menu__group-summary::after {
  content: '−';
}

.menu__group-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.55rem;
  margin: 0;
  color: var(--travertine);
  letter-spacing: 0.005em;
  transition: color 0.2s ease;
}
.menu__group-title span {
  font-style: normal;
  color: var(--amber);
  font-size: 0.62em;
  letter-spacing: 0.04em;
  margin-left: 0.4em;
  text-transform: lowercase;
}

.menu__list {
  list-style: none;
  padding: 0 0 1.5rem;
  margin: 0;
}
.menu__list li {
  margin: 0 0 1rem;
  break-inside: avoid;
}
.menu__name {
  font-family: var(--serif);
  font-size: 1.08rem;
  color: var(--travertine);
  margin: 0 0 0.18rem;
  line-height: 1.3;
  font-weight: 400;
}
.menu__name span {
  color: var(--amber-soft);
  font-style: italic;
  font-size: 0.92em;
}
.menu__desc {
  font-size: 0.85rem;
  color: var(--travertine-dim);
  margin: 0;
  line-height: 1.5;
}

/* ---------- Rhythm (Club schedule) ---------- */
.rhythm {
  list-style: none;
  padding: 0;
  margin: 2.25rem 0 0;
  border-top: 1px solid var(--rule-soft);
}
.rhythm li {
  display: flex;
  align-items: baseline;
  gap: clamp(1rem, 3vw, 2rem);
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--rule-soft);
}
.rhythm__time {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.5rem;
  color: var(--amber);
  min-width: 5rem;
  letter-spacing: 0.01em;
  line-height: 1;
}
.rhythm__act {
  font-family: var(--serif);
  font-size: 1rem;
  color: var(--travertine);
  letter-spacing: 0.01em;
}

/* ---------- The Bar — full-bleed, the cocktail in the smoke ---------- */
.cocktails {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  border-top: 1px solid var(--rule-soft);
  text-align: left;
}
.cocktails > .section__index,
.cocktails > .display,
.cocktails > .prose { position: relative; z-index: 2; text-shadow: 0 2px 26px rgba(10,10,12,0.85); }
.cocktails__image {
  position: absolute;
  inset: 0;
  z-index: 0;
  margin: 0;
}
.cocktails__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.12);
  translate: 0 var(--epy, 0px);
  filter: brightness(0.82) contrast(1.06);
}
.cocktails__image::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(10,10,12,0.95) 0%, rgba(10,10,12,0.5) 34%, rgba(10,10,12,0.14) 58%, rgba(10,10,12,0.5) 100%);
}

/* ---------- Hero subline ---------- */
.hero__sub {
  margin: 1.75rem 0 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(0.95rem, 1.25vw, 1.1rem);
  letter-spacing: 0.01em;
  line-height: 1.55;
  color: var(--travertine-dim);
  max-width: 36em;
}

/* ---------- Lineage ---------- */
.lineage {
  border-top: 1px solid var(--rule-soft);
  text-align: left;
}
.lineage__list {
  list-style: none;
  padding: 0;
  margin: 3.5rem 0 0;
  display: grid;
  grid-template-columns: 1fr;
}
.lineage__list li {
  display: grid;
  grid-template-columns: 1fr 1.6fr;
  align-items: baseline;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding: 1.75rem 0;
  border-top: 1px solid var(--rule-soft);
}
.lineage__list li:last-child {
  border-bottom: 1px solid var(--rule-soft);
}
.lineage__name {
  font-family: var(--serif);
  font-size: clamp(1.7rem, 5.5vw, 2.6rem);
  font-style: italic;
  font-weight: 300;
  color: var(--travertine);
  margin: 0;
  line-height: 1.1;
}
.lineage__name span {
  font-style: normal;
  color: var(--amber);
  font-size: 0.62em;
  letter-spacing: 0.04em;
  margin-left: 0.4em;
  text-transform: lowercase;
}
.lineage__line {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--travertine-dim);
}
@media (max-width: 720px) {
  .lineage__list li {
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }
}

/* ---------- Why this building ---------- */
.why {
  border-top: 1px solid var(--rule-soft);
  text-align: left;
}
.why__pillars {
  list-style: none;
  padding: 0;
  margin: 3.5rem 0 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3.5vw, 2.5rem);
}
.why__pillars li {
  border-top: 1px solid var(--amber-soft);
  padding-top: 1.25rem;
}
.why__pillar-name {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.15rem;
  color: var(--travertine);
  margin: 0 0 0.4rem;
  line-height: 1.25;
}
.why__pillar-name span {
  font-style: normal;
  color: var(--amber);
  font-size: 0.62em;
  letter-spacing: 0.04em;
  margin-left: 0.3em;
  text-transform: lowercase;
}
.why__pillar-line {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--travertine-dim);
}
@media (max-width: 820px) {
  .why__pillars { grid-template-columns: 1fr; }
}

/* ---------- Bites — pinned horizontal gallery ---------- */
/* Base (no JS / reduced motion): a normal stacked grid. */
.bites-stage { border-top: 1px solid var(--rule-soft); }
.bites-pin {
  max-width: 1280px;
  margin: 0 auto;
  padding: clamp(5rem, 12vh, 9rem) clamp(1.25rem, 5vw, 4rem);
}
.bites__head { max-width: 1280px; }
.bites__cue {
  margin: 1.5rem 0 0;
  font-size: 0.72rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--amber-soft);
}
.bites__cue::before {
  content: '';
  display: inline-block;
  width: 1.6rem; height: 1px;
  vertical-align: middle;
  background: var(--amber-soft);
  margin-right: 0.7rem;
}
.bite-row {
  margin-top: 3.5rem;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.5vw, 2rem);
}

/* Track mode (JS adds .is-track when motion is allowed): pin + scrub sideways. */
.bites-stage.is-track { position: relative; height: 320vh; }
.bites-stage.is-track .bites-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100lvh;   /* lvh, not svh — match the other pins (iOS collapsed-chrome strip) */
  max-width: none;
  margin: 0;
  padding: clamp(6rem, 12vh, 8rem) 0 clamp(2.5rem, 6vh, 4rem);
  padding-bottom: max(clamp(2.5rem, 6vh, 4rem), calc(env(safe-area-inset-bottom, 0px) + 5rem));   /* clear the fixed Play pill */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.bites-stage.is-track .bites__head {
  flex: 0 0 auto;
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 5vw, 4rem);
}
.bites-stage.is-track .bites__viewport {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  width: 100%;
  overflow: hidden;
}
.bites-stage.is-track .bite-row {
  margin: 0;
  display: flex;
  flex-wrap: nowrap;
  width: max-content;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  padding: 0 clamp(1.25rem, 5vw, 4rem);
  transform: translateX(var(--shift, 0px));
  will-change: transform;
}
.bites-stage.is-track .bite {
  flex: 0 0 auto;
  width: clamp(240px, 30vw, 360px);
}
.bite {
  margin: 0;
  position: relative;
}
.bite img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--ink-2);
  filter: brightness(0.95) contrast(1.05);
  transition: filter 0.4s ease;
}
.bite:hover img { filter: brightness(1.05) contrast(1.05); }
.bite figcaption {
  margin-top: 1rem;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.bite figcaption span {
  font-family: var(--serif);
  font-style: italic;
  color: var(--amber);
  margin-right: 0.6rem;
  letter-spacing: 0.2em;
}
@media (max-width: 720px) {
  .bite-row { grid-template-columns: 1fr; }
}

/* ---------- Site ---------- */
.site { border-top: 1px solid var(--rule-soft); }

.site__head {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: end;
  margin-bottom: clamp(3rem, 6vh, 4.5rem);
}
.site__head .prose { margin-top: 0; }
@media (max-width: 820px) { .site__head { grid-template-columns: 1fr; } }

.site__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1rem, 2.5vw, 2rem);
  margin-bottom: clamp(2rem, 4vh, 3rem);
}
@media (max-width: 720px) {
  /* full-width stack (2026-06-12). The old alternating 92% left/right offsets
     read as misaligned, not as rhythm — user: "offset and look terrible".
     A bigger row gap keeps each caption visually paired with ITS image. */
  .site__pair { grid-template-columns: 1fr; gap: 2rem; }
}

.site__shot { margin: 0; }
.site__shot img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--ink-2);
  filter: brightness(0.95) contrast(1.05);
}

.site__plan { margin: 0; }
.site__plan img {
  width: 100%;
  background: var(--travertine);
  padding: clamp(1rem, 3vw, 2.25rem);
  border: 1px solid var(--rule-soft);
}

.site__shot figcaption,
.site__plan figcaption,
.site__satellite figcaption {
  margin-top: 1rem;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.site__shot figcaption span,
.site__plan figcaption span,
.site__satellite figcaption span {
  font-family: var(--serif);
  font-style: italic;
  color: var(--amber);
  margin-right: 0.6rem;
  letter-spacing: 0.2em;
}

.site__satellite {
  margin: clamp(2rem, 4vh, 3rem) 0 0;
}
.site__satellite iframe {
  width: 100%;
  height: clamp(340px, 55vh, 520px);
  border: 0;
  display: block;
  filter: brightness(0.92) contrast(1.05);
  transition: filter 0.4s ease;
}
.site__satellite:hover iframe { filter: brightness(1) contrast(1.05); }

.site__foot {
  margin-top: clamp(2.5rem, 5vh, 3.5rem);
  padding-top: clamp(1.5rem, 3vh, 2rem);
  border-top: 1px solid var(--rule-soft);
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 1.5rem;
}
.site__foot .meta { margin: 0; }

.site__map {
  font-size: 0.78rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--travertine);
  border-bottom: 1px solid var(--amber);
  padding-bottom: 0.5rem;
  transition: color 0.2s ease, border-color 0.2s ease;
  white-space: nowrap;
}
.site__map::after {
  content: ' →';
  color: var(--amber);
  margin-left: 0.4em;
  display: inline-block;
  transition: transform 0.25s ease;
}
.site__map:hover { color: var(--amber); }
.site__map:hover::after { transform: translateX(4px); }

/* ---------- Address ---------- */
.address { border-top: 1px solid var(--rule-soft); }
.address__grid {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: start;
}
@media (max-width: 820px) {
  .address__grid { grid-template-columns: 1fr; }
}
.facts {
  margin: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem 2rem;
  border-top: 1px solid var(--rule);
  padding-top: 2rem;
}
.facts > div { display: flex; flex-direction: column; gap: 0.4rem; }
.facts dt {
  font-size: 0.7rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--travertine-dim);
  opacity: 0.7;
}
.facts dd {
  margin: 0;
  font-family: var(--serif);
  font-size: 1.4rem;
  letter-spacing: 0.01em;
  color: var(--travertine);
}

/* ---------- Contact ---------- */
/* ---------- Contact — the closing bookend, back at the doors ---------- */
.contact {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  overflow: hidden;
  border-top: 1px solid var(--rule-soft);
}
.contact > .section__index,
.contact > .display,
.contact > .prose,
.contact > .enquire { position: relative; z-index: 2; }
.contact > .display,
.contact > .prose { text-shadow: 0 2px 28px rgba(10,10,12,0.85); }
.contact__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: var(--ink); }
.contact__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 56%;
  transform: scale(1.12);
  translate: 0 var(--epy, 0px);
  filter: brightness(0.62) contrast(1.04);
}
.contact__media::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(10,10,12,0.92) 0%, rgba(10,10,12,0.55) 38%, rgba(10,10,12,0.35) 70%, rgba(10,10,12,0.7) 100%);
}

.enquire {
  margin-top: 3rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem 2rem;
  max-width: 720px;
}
.enquire__field { display: flex; flex-direction: column; gap: 0.5rem; }
.enquire__field--wide { grid-column: span 2; }
.enquire__field span {
  font-size: 0.7rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.enquire input,
.enquire select {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--rule);
  color: var(--travertine);
  font-family: var(--serif);
  font-size: 1.15rem;
  padding: 0.6rem 0;
  outline: none;
  transition: border-color 0.25s ease;
  border-radius: 0;
}
.enquire input:focus,
.enquire select:focus { border-bottom-color: var(--amber); }
.enquire select option { background: var(--ink); color: var(--travertine); }

.btn {
  grid-column: span 2;
  justify-self: start;
  background: transparent;
  color: var(--travertine);
  border: 1px solid var(--travertine);
  padding: 0.95rem 2.4rem;
  font-family: var(--sans);
  font-size: 0.78rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
.btn:hover {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--ink);
}

.enquire__ack {
  grid-column: span 2;
  margin: 0;
  font-style: italic;
  font-family: var(--serif);
  color: var(--amber);
}

@media (max-width: 620px) {
  .enquire { grid-template-columns: 1fr; }
  .enquire__field--wide,
  .btn,
  .enquire__ack { grid-column: span 1; }
}

/* ---------- Footer ---------- */
.foot {
  margin-top: 0;
  border-top: 1px solid var(--rule-soft);
  padding: 3rem clamp(1.25rem, 5vw, 4rem);
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
  font-size: 0.75rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--travertine-dim);
  background: var(--ink-2);
}
.foot__row,
.foot__fine {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
}
.foot__mark {
  display: inline-flex;
  align-items: center;
  height: 18px;
}
.foot__mark img {
  height: 100%;
  width: auto;
  display: block;
  opacity: 0.85;
}
.foot__fine {
  font-size: 0.68rem;
  opacity: 0.6;
  letter-spacing: 0.2em;
}
.foot__ig {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  color: inherit;
  text-decoration: none;
  opacity: 0.72;
  transition: opacity 0.25s ease;
}
.foot__ig:hover, .foot__ig:focus-visible { opacity: 1; }
.foot__ig-glyph { flex: 0 0 auto; }

/* ---------- Scroll progress ---------- */
.scroll-progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 60;
  pointer-events: none;
  background: transparent;
}
.scroll-progress__bar {
  display: block;
  height: 100%;
  width: 100%;
  transform: scaleX(var(--scroll, 0));
  transform-origin: 0 50%;
  background: linear-gradient(to right, var(--amber-soft), var(--amber));
  box-shadow: 0 0 12px var(--amber-soft);
}

/* ---------- The Eclipse ---------- */
.eclipse {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(5rem, 14vh, 9rem) clamp(1.25rem, 5vw, 4rem);
  overflow: hidden;
  border-top: 1px solid var(--rule-soft);
  background:
    radial-gradient(120% 90% at 50% 64%, #1a1c20 0%, #121316 42%, var(--ink) 78%);
}

.eclipse__sky,
.stage__sky {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  z-index: 1;
}
.eclipse__sky > *,
.stage__sky > * {
  grid-area: 1 / 1;
  border-radius: 50%;
}

/* soft atmospheric bloom behind the orb */
.eclipse__halo {
  width: clamp(420px, 95vw, 1100px);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(var(--eclipse-glow),0.26) 0%, rgba(var(--eclipse-soft),0.10) 34%, transparent 62%);
  filter: blur(8px);
  transform: translateY(calc(21% + var(--p, 0) * 26px));
  animation: eclipseBreathe 9s ease-in-out infinite alternate;
}

/* the rotating corona ring */
.eclipse__corona {
  width: clamp(260px, 50vw, 660px);
  aspect-ratio: 1;
  background:
    conic-gradient(from 0deg,
      rgba(var(--eclipse-gold),0) 0deg,
      rgba(var(--eclipse-gold),0.55) 70deg,
      rgba(var(--eclipse-gold),0) 140deg,
      rgba(var(--eclipse-gold),0) 220deg,
      rgba(var(--eclipse-gold),0.4) 290deg,
      rgba(var(--eclipse-gold),0) 360deg);
  -webkit-mask: radial-gradient(circle, transparent 0 47%, #000 48% 50%, transparent 51%);
          mask: radial-gradient(circle, transparent 0 47%, #000 48% 50%, transparent 51%);
  filter: blur(1px);
  opacity: 0.85;
  transform: translateY(calc(21% + var(--p, 0) * -36px));
  animation: eclipseSpin 60s linear infinite;
}

/* the lit sphere — a full sun */
.eclipse__orb {
  position: relative;
  width: clamp(220px, 42vw, 540px);
  aspect-ratio: 1;
  background: var(--eclipse-grad);
  box-shadow:
    0 0 90px 10px rgba(var(--eclipse-glow),0.5),
    0 0 240px 70px rgba(var(--eclipse-soft),0.26),
    inset 0 0 60px rgba(255,240,205,0.3);
  transform: translateY(calc(21% + var(--p, 0) * -64px));
  animation: eclipseBreathe 9s ease-in-out infinite alternate;
}

@keyframes eclipseBreathe {
  from { filter: brightness(0.96); }
  to   { filter: brightness(1.08); }
}
/* THE MERIDIAN: during DOORS (Fri/Sat 00:00-06:00 Palma) the corona breathes,
   the room is open. Reduced-motion kills it via the .splash__halo rule above. */
[data-sol="doors"] .splash__halo { animation: coronaPulse 3.8s ease-in-out infinite; }
@keyframes coronaPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.68; } }
@keyframes eclipseSpin {
  to { rotate: 360deg; }
}

.eclipse__content {
  position: relative;
  z-index: 1;
  max-width: 38rem;
  margin-top: -15vh;
  padding: clamp(1.5rem, 4vw, 3rem);
  background: radial-gradient(ellipse at 50% 42%, rgba(10,10,12,0.6) 0%, rgba(10,10,12,0.28) 45%, transparent 72%);
}
.eclipse__eyebrow { color: var(--amber-soft); }
/* the concept line is LONGER than the one-word hero, so it gets its own
   comfortable size + relaxed leading (not the giant ¿Dónde? scale) — it must
   read as a confident statement with air, never a cramped wall of giant type.
   .display.eclipse__title (0,2,0) beats .display--md so the mobile size holds. */
.display.eclipse__title {
  margin: 0 auto;
  max-width: 17ch;
  font-size: clamp(1.9rem, 7.4vw, 3.4rem);
  line-height: 1.12;
  letter-spacing: -0.015em;
  text-shadow: 0 2px 60px rgba(10,10,12,0.85);
}
/* BEAT 1 welcome headline — bold, screen-owning, comfortable leading */
.display.stage__welcome {
  margin: 0 auto;
  max-width: 14ch;
  font-size: clamp(2rem, 7.8vw, 3.6rem);
  line-height: 1.1;
  letter-spacing: -0.015em;
  text-shadow: 0 2px 60px rgba(10,10,12,0.85);
}
/* the promotional substance beneath the welcome — smaller, so it reads as a
   subline (headline + subline hierarchy, never a uniform cramped wall) */
.eclipse__sub {
  margin: 1.1rem auto 0;
  max-width: 30ch;
  font-size: clamp(1rem, 4.2vw, 1.4rem);
  line-height: 1.4;
  color: var(--travertine);
  text-shadow: 0 2px 26px rgba(10,10,12,0.9);
}
.eclipse__sub .italic { color: #fff; font-style: italic; }
.eclipse__lede {
  font-family: var(--serif);
  font-size: clamp(1.1rem, 1.8vw, 1.5rem);
  font-style: italic;
  line-height: 1.5;
  color: var(--travertine);
  margin: 1.75rem auto 0;
  max-width: 30em;
  text-shadow: 0 2px 30px rgba(10,10,12,0.8);
}
.eclipse__line {
  font-size: 0.98rem;
  line-height: 1.7;
  color: var(--travertine-dim);
  margin: 1.5rem auto 0;
  max-width: 34em;
  text-shadow: 0 2px 24px rgba(10,10,12,0.8);
}
.eclipse__line .italic { color: var(--travertine); }
.eclipse__mark {
  margin: 2.5rem 0 0;
  font-family: var(--serif);
  font-size: 1.4rem;
  letter-spacing: 0.04em;
  color: var(--travertine);
  text-shadow: 0 2px 22px rgba(10,10,12,0.9), 0 0 8px rgba(10,10,12,0.7);
}
.eclipse__mark .italic { color: #ffffff; }

/* ---------- Reveal ---------- */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 1.1s cubic-bezier(0.2, 0.6, 0.2, 1),
              transform 1.1s cubic-bezier(0.2, 0.6, 0.2, 1);
  will-change: opacity, transform;
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- Editorial image reveal (the three expressions) ----------
   Full-bleed: no iris clip (it letterboxed the background) — the arrival is
   the duotone→colour grade plus the deep zoom settling. */
.expr__media.reveal {
  transition: opacity 1.1s var(--ease),
              transform 1.1s var(--ease);
}
.expr__media.reveal img {
  scale: 1.16;
  filter: grayscale(0.55) brightness(0.8) contrast(1.06) sepia(0.12);
  /* transform is per-frame seam choreography — never transition it */
  transition: scale 1.7s var(--ease),
              filter 1.7s var(--ease);
}
.expr__media.reveal.is-visible img {
  scale: 1;
  filter: none;
}

/* ---------- THE SEAMS — connective tissue between sections ----------
   script.js drives --seam 0→1 as a static section enters (it settles down
   into place over a feathered ink edge), then lifts it away and dims it as
   the next boundary takes the frame. Pinned scenes are never transformed. */
.seamed { position: relative; }
.seamed::before {
  content: '';
  position: absolute; top: -2px; left: 0; right: 0;
  height: 16vh;
  background: linear-gradient(to bottom, var(--ink) 0%, rgba(11,11,13,0) 100%);
  opacity: calc(1 - var(--seam, 1) * 0.72);
  pointer-events: none;
  z-index: 4;
}
.perf-lite .seamed::before { display: none; }

/* photography settles with weight instead of fading in place */
.reveal--media {
  transform: translateY(34px) scale(1.035);
  transition: opacity 1.35s var(--ease), transform 1.55s var(--ease);
}
.reveal--media.is-visible { transform: none; }

/* display headings rise out of a clip below their stamp */
.display-rise {
  opacity: 0;
  clip-path: inset(-0.1em -0.25em 102% -0.05em);
  transform: translateY(0.55em);
  transition: opacity 0.9s var(--ease), transform 1.05s var(--ease), clip-path 1.05s var(--ease);
}
.display-rise.is-risen {
  opacity: 1;
  clip-path: inset(-0.1em -0.25em -0.35em -0.05em);
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .seamed::before { display: none; }
  .reveal--media { transform: none; }
  .display-rise { opacity: 1; clip-path: none; transform: none; transition: none; }
  .typeset .tword { opacity: 1; transform: none; transition: none; font-variation-settings: 'wght' 700, 'wdth' 112; }
  .typeset.italic .tword, .typeset .italic .tword { font-variation-settings: 'wght' 500, 'wdth' 100; }
}

/* ---------- Kinetic headings — wipe up into view ---------- */
.display--md.reveal {
  clip-path: inset(0 0 110% 0);
  transition: opacity 1.1s var(--ease),
              transform 1.1s var(--ease),
              clip-path 1.2s var(--ease);
}
.display--md.reveal.is-visible {
  clip-path: inset(0 0 0 0);
}

/* ---------- THE TYPESET — headings develop into being ---------- */
/* The signature kinetic move: each word resolves from thin + ghosted to the
   architectural expanded-bold final form, cascading word by word, by animating
   the Archivo variable axes. The type builds ITSELF into its brutalist final
   state. Width (wdth) is held at 112 and each word's final advance width is
   reserved in JS (min-width), so the weight develop never reflows the line. */
.typeset .tword {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.5em);
  font-variation-settings: 'wght' 340, 'wdth' 112;
  transition: opacity 0.65s var(--ease),
              transform 0.8s var(--ease),
              font-variation-settings 0.85s var(--ease);
  transition-delay: calc(var(--i, 0) * 55ms);
  will-change: transform, opacity;
}
.typeset.is-set .tword {
  opacity: 1;
  transform: none;
  font-variation-settings: 'wght' 700, 'wdth' 112;
}
/* italic words ride the Archivo italic's narrow band (wght 400-500, wdth 100) */
.typeset.italic .tword,
.typeset .italic .tword { font-variation-settings: 'wght' 400, 'wdth' 100; }
.typeset.is-set.italic .tword,
.typeset.is-set .italic .tword { font-variation-settings: 'wght' 500, 'wdth' 100; }

/* measuring pass: reveal the true final advance width regardless of start state
   (opacity 0 / translateY do not affect width, so the words stay invisible) */
.typeset.is-measuring .tword {
  transition: none !important;
  min-width: 0 !important;
  font-variation-settings: 'wght' 700, 'wdth' 112 !important;
}
.typeset.is-measuring.italic .tword,
.typeset.is-measuring .italic .tword { font-variation-settings: 'wght' 500, 'wdth' 100 !important; }

/* THE QUESTION (Donde? Aqui.) + THE SIGNATURE (The Eclipse.) develop in place:
   a one-shot weight ink-in, no transform (the stage scrub owns transform/opacity
   on these lines). Gated on .is-scrub so no-JS / reduced-motion render full bold. */
.stage.is-scrub .stage__title .display__line {
  font-variation-settings: 'wght' 330, 'wdth' 112;
  transition: font-variation-settings 0.9s var(--ease);
}
.stage.is-scrub .stage__title .display__line.italic { font-variation-settings: 'wght' 400, 'wdth' 100; }
.stage.is-scrub .stage__title.is-set .display__line { font-variation-settings: 'wght' 700, 'wdth' 112; }
.stage.is-scrub .stage__title.is-set .display__line.italic { font-variation-settings: 'wght' 500, 'wdth' 100; }
/* THE SIGNATURE renders at its FINAL weight from the start (NO weight develop):
   it wraps to ~4 lines under max-width:17ch and Archivo's advance grows ~10%
   thin->bold, so animating wght RE-WRAPPED the lines mid-transition = the
   "two formatting styles / glitch" the owner saw. (The QUESTION above is safe:
   each line is ONE word, which can't re-wrap.) The reveal is carried by the stage
   scrub's opacity/transform; the weight stays constant, so the lines never reflow. */
.stage.is-scrub .eclipse__title { font-variation-settings: 'wght' 700, 'wdth' 112; }

/* ---------- Intro loader — the Eclipse forms from black ---------- */
.loader {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(1.4rem, 4.5vh, 2.4rem);
  background: var(--ink);
}
/* JS owns the fade-out (added on dismiss) so the CSS timer can't reveal the splash
   before the asset-aware gate is ready — fixes the old CSS-vs-JS reveal race. */
.loader.is-leaving { animation: loaderOut 0.7s var(--ease) forwards; }
/* the real wordmark, not plain type */
.loader__mark {
  width: clamp(150px, 40vw, 240px);
  height: auto;
  opacity: 0;
  animation: loaderIn 0.9s var(--ease) 0.15s forwards;
}
/* a minimalist sound-level meter, pulsing while the room loads */
.loader__eq {
  display: flex;
  align-items: flex-end;
  gap: 5px;
  height: 28px;
  opacity: 0;
  animation: loaderIn 0.9s var(--ease) 0.4s forwards;
}
.loader__eq span {
  width: 3px;
  height: 100%;
  border-radius: 2px;
  background: linear-gradient(var(--travertine), var(--travertine-dim));
  transform-origin: bottom;
  transform: scaleY(0.22);
  animation: loaderEq 0.9s ease-in-out infinite;
}
.loader__eq span:nth-child(1) { animation-duration: 0.78s; }
.loader__eq span:nth-child(2) { animation-duration: 0.54s; animation-delay: 0.12s; }
.loader__eq span:nth-child(3) { animation-duration: 0.94s; animation-delay: 0.05s; }
.loader__eq span:nth-child(4) { animation-duration: 0.62s; animation-delay: 0.18s; }
.loader__eq span:nth-child(5) { animation-duration: 0.84s; animation-delay: 0.08s; }
@keyframes loaderEq {
  0%, 100% { transform: scaleY(0.22); }
  50%      { transform: scaleY(1); }
}
/* the status line ("Setting the room" -> "Warming the descent" -> "Step inside") and
   a hairline determinate progress bar, beneath the EQ meter. The line fades in via JS
   (~0.55s) and cross-fades on each milestone; the bar fill tracks --load. */
.loader__say {
  margin: 0;
  min-height: 1.1em;
  font-family: var(--mono);
  font-size: clamp(0.6rem, 2.4vw, 0.72rem);
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--travertine-dim);
  opacity: 0;
  transition: opacity 0.22s var(--ease);
}
.loader__bar {
  width: clamp(110px, 40vw, 190px);
  height: 2px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.10);
  overflow: hidden;
  opacity: 0;
  animation: loaderIn 0.9s var(--ease) 0.55s forwards;
}
.loader__fill {
  display: block;
  height: 100%;
  width: calc(var(--load, 0) * 100%);
  background: linear-gradient(90deg, var(--travertine-dim), var(--travertine));
  transition: width 0.35s var(--ease);
}
@keyframes loaderIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes loaderOut {
  to { opacity: 0; visibility: hidden; }
}
.is-loading { overflow: hidden; }

/* ---------- Film grain + vignette ---------- */
.grain {
  position: fixed;
  inset: -22%;
  z-index: 90;
  pointer-events: none;
  opacity: 0.06;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  will-change: transform;
  animation: grain 1s steps(3) infinite;
}
/* pause the grain (and its blend repaint) when the tab is hidden */
.is-hidden .grain { animation-play-state: paused; }
@keyframes grain {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-6%, -4%); }
  40%  { transform: translate(4%, -7%); }
  60%  { transform: translate(-5%, 5%); }
  80%  { transform: translate(7%, 3%); }
  100% { transform: translate(0, 0); }
}
/* vignette dropped — brutalism reads flat, not lens-softened */
.vignette { display: none; }

/* ---------- Eclipse echo — the motif returns (Restaurant & Garden) ---------- */
.expr__eclipse {
  position: absolute;
  top: 26%;
  right: 12%;
  width: clamp(120px, 22%, 220px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgba(255,236,196,0.9) 0%, rgba(var(--eclipse-glow),0.6) 32%, rgba(var(--eclipse-soft),0.2) 58%, transparent 72%);
  mix-blend-mode: screen;
  pointer-events: none;
  filter: blur(2px);
  animation: echoBreathe 7s ease-in-out infinite alternate;
}
@keyframes echoBreathe {
  from { opacity: 0.55; transform: scale(0.97); }
  to   { opacity: 0.85; transform: scale(1.03); }
}

/* ---------- Sound toggle ---------- */
/* The Sound control — an eclipse disc. Echoes the signature motif: dark
   centre, amber rim, sound-wave rings emanating while it is the page's beat.
   JS sets --heroT (1 centred, 0 docked) and the centre->corner transform. */
/* ---------- THE AUDIO BAR ----------
   A pill pinned to the bottom band (the strip the mobile browser chrome leaves
   when it collapses). It is the ONE invitation to the sound now — it never
   blooms to the centre. Idle: ▶ + "Sound journey", breathing to draw the eye.
   Live: the EQ meter + "Take control", plus the corner mute. Sits above the
   safe-area inset. */
/* THE THUMP — the play CTA inverts from dark glass into a SOLID mirror-silver
   slab (the brightest + only BEATING object on the black phone) that punches
   UPWARD on a self-generated ~120 BPM kick and emits a soft ring on the down-
   beat; once live it re-syncs to the real --beat and the disc becomes the EQ.
   Pull = form + contrast + beat (no warmth borrowed; the eclipse stays the one
   warm thing). --pulse is written by a tiny rAF in script.js. */
.sound {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + clamp(0.55rem, 1.8vh, 1rem));
  transform: translateX(-50%) scale(calc(1 + var(--pulse, 0) * 0.055));
  transform-origin: 50% 100%;                /* the punch grows UP off the dock, never re-centres */
  z-index: 80;
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  height: 50px;
  padding: 0 1.3rem 0 0.5rem;
  border-radius: 100px;
  background: linear-gradient(180deg, #eef1f3 0%, #cfd6db 60%, #b9c2c8 100%);
  border: 0;
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
  box-shadow:
    0 6px 26px rgba(0, 0, 0, 0.55),
    0 0 calc(20px + var(--pulse, 0) * 30px) rgba(207, 214, 219, calc(0.15 + var(--pulse, 0) * 0.4));
  transition: box-shadow 0.16s linear, opacity 0.4s ease;
  animation: none;
}
.sound:hover { background: linear-gradient(180deg, #ffffff 0%, #dfe5e9 60%, #c6cfd4 100%); }
.sound:active { filter: brightness(0.94); }
.sound:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }   /* dark ring reads on the light slab */

/* the play disc — a dark recessed well holding the triangle (idle) / EQ (live) */
.sound__disc {
  position: relative;
  flex: 0 0 auto;
  width: 40px; height: 40px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
  background: radial-gradient(circle at 50% 38%, #0e0f12, #1b1d21);
  box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.18), inset 0 -2px 4px rgba(0, 0, 0, 0.7);
}
.sound__play {
  display: inline-flex;
  width: 16px; height: 16px;
  margin-left: 2px;
  color: #eef1f3;
}
.sound__play svg { width: 100%; height: 100%; display: block; }

/* the downbeat ring — one soft silver loop breathing UP off the disc (4-beat loop) */
.sound__ring {
  position: absolute;
  left: 50%; top: 50%;
  width: 40px; height: 40px;
  margin: -20px 0 0 -20px;
  border-radius: 50%;
  border: 1.5px solid rgba(207, 214, 219, 0.85);
  transform-origin: 50% 50%;
  opacity: 0;
  pointer-events: none;
  animation: soundRing 2s var(--ease) infinite;
}
@keyframes soundRing {
  0%        { opacity: 0;   transform: translateY(0) scale(0.55); }
  8%        { opacity: 0.5; }
  60%, 100% { opacity: 0;   transform: translateY(-22px) scale(1.85); }
}

.sound__cue {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink);
}

/* live: the slab reads the REAL kick (--beat) + glows with --energy, disc = EQ */
.sound.is-on {
  transform: translateX(-50%) scale(calc(1 + var(--beat, 0) * 0.05));
  box-shadow:
    0 6px 26px rgba(0, 0, 0, 0.55),
    0 0 calc(14px + var(--energy, 0) * 34px) rgba(207, 214, 219, calc(0.2 + var(--energy, 0) * 0.45));
}
.sound.is-on .sound__play { display: none; }
.sound.is-on .sound__ring { animation: none; opacity: 0; }
.sound.is-on .sound__cue { display: none; }

.sound__bars {
  display: none;
  align-items: flex-end;
  gap: 2.5px;
  height: 16px;
}
.sound.is-on .sound__bars { display: inline-flex; }
.sound__bars i {
  display: block;
  width: 2.5px;
  height: 32%;
  background: #dfe5e9;
  border-radius: 1px;
  transform: scaleY(calc(0.5 + var(--energy, 0) * 1.9));
  transform-origin: bottom;
}
.sound.is-on .sound__bars i { animation: eq 0.85s ease-in-out infinite; }
.sound.is-on .sound__bars i:nth-child(2) { animation-delay: 0.18s; }
.sound.is-on .sound__bars i:nth-child(3) { animation-delay: 0.36s; }
.sound.is-on .sound__bars i:nth-child(4) { animation-delay: 0.54s; }
@keyframes eq {
  0%, 100% { height: 26%; }
  50%      { height: 100%; }
}

/* THE BAR MUTE — a small circle in the bottom-right of the audio band. Hidden
   until sound is live (journey scored OR the bar shows the meter); hides with
   the bar (.is-hidden, nav menu / instrument open). Same [data-mute] hook as
   the instrument header — studio.js mirrors aria-pressed across both. */
.soundmute {
  position: fixed;
  right: calc(env(safe-area-inset-right, 0px) + 0.9rem);
  bottom: calc(env(safe-area-inset-bottom, 0px) + clamp(0.55rem, 1.8vh, 1rem));
  z-index: 80;
  width: 44px; height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: linear-gradient(180deg, rgba(20,21,24,0.94), rgba(10,10,12,0.96));   /* solid, no backdrop-filter (it's fixed; backdrop-filter floats fixed elements mid-screen during iOS momentum scroll) */
  border: 1px solid var(--amber-soft);
  color: var(--amber);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease, border-color 0.25s ease, background 0.25s ease;
}
.is-scored .soundmute,
.sound.is-on + .soundmute { opacity: 1; pointer-events: auto; }
.sound.is-hidden + .soundmute { opacity: 0; pointer-events: none; }
.soundmute svg {
  width: 19px; height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* state: one speaker icon at a time; muted = filled-bright button */
.soundmute .soundmute__ico--off { display: none; }
.soundmute[aria-pressed="true"] .soundmute__ico--on { display: none; }
.soundmute[aria-pressed="true"] .soundmute__ico--off { display: block; }
.soundmute[aria-pressed="true"] {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--ink);
}

/* ---------- The Instrument — Kaoss-style XY performance pad ---------- */
.kaoss {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: clamp(0.75rem, 3vw, 1.75rem);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s var(--ease);
}
.kaoss::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: rgba(6,7,8, 0.5);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.4s var(--ease);
}
/* THE ECLIPSE OPEN: a lit mirror-eclipse disc that the sheet blooms up out of.
   transform + opacity only (NO radial mask), so the iOS near-zero radial-mask
   transparency bug can never bite. Sits behind the sheet, above the backdrop. */
.kaoss::after {
  content: "";
  position: absolute;
  left: 50%; bottom: 6%;
  width: 70vmin; aspect-ratio: 1;
  transform: translate(-50%, 50%) scale(0.18);
  border-radius: 50%; pointer-events: none; z-index: 1; opacity: 0;
  background: radial-gradient(circle at 50% 50%, rgba(207,214,219,0.18) 0%, rgba(207,214,219,0.07) 32%, rgba(207,214,219,0.02) 50%, transparent 64%);
  transition: transform 0.55s var(--ease), opacity 0.5s var(--ease);
}
.kaoss.is-open { opacity: 1; pointer-events: auto; }
.kaoss.is-open::before { opacity: 1; }
.kaoss.is-open::after { transform: translate(-50%, 50%) scale(1); opacity: 1; }

.kaoss__sheet {
  position: relative;
  z-index: 2;                 /* above the eclipse-open disc (::after, z1) and backdrop (::before, z0) */
  width: 100%;
  max-width: 30rem;
  max-height: 100%;            /* never taller than the (padded) viewport */
  overflow-y: auto;           /* scroll internally on short phones */
  padding: clamp(1rem, 4vw, 1.6rem);
  background: linear-gradient(180deg, rgba(18,19,22,0.96), rgba(10,10,12,0.98));
  border: 1px solid var(--rule);
  box-shadow: 0 -8px 60px rgba(0,0,0,0.6), 0 0 90px rgba(207,214,219,0.06);
  transform: translateY(20px) scale(0.965);   /* blooms up out of the eclipse disc */
  transform-origin: 50% 100%;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.kaoss.is-open .kaoss__sheet { transform: translateY(0) scale(1); }
/* reduced motion: no bloom, no disc — the sheet just appears */
@media (prefers-reduced-motion: reduce) {
  .kaoss__sheet { transform: none; transition: none; }
  .kaoss::after { display: none; }
}

.kaoss__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.9rem;
}
.kaoss__title {
  margin: 0.2rem 0 0;
  font-family: var(--serif);
  font-weight: 300;
  font-style: italic;
  font-size: clamp(1.5rem, 6vw, 1.9rem);
  line-height: 1;
  color: var(--travertine);
}
.kaoss__close {
  flex: none;
  width: 2.1rem;
  height: 2.1rem;
  margin: -0.2rem -0.2rem 0 0;
  background: none;
  border: 1px solid var(--rule);
  border-radius: 50%;
  color: var(--travertine-dim);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.25s ease, color 0.25s ease;
}
.kaoss__close:hover { border-color: var(--amber); color: var(--travertine); }

/* header actions — mute toggle + close, kept top-right so they're reachable
   without scrolling to the OFF button at the bottom */
.kaoss__head-actions { flex: none; display: inline-flex; align-items: center; gap: 0.45rem; margin: -0.2rem -0.2rem 0 0; }
.kaoss__head-actions .kaoss__close { margin: 0; }
.kaoss__mute {
  flex: none;
  width: 2.1rem; height: 2.1rem;
  display: inline-flex; align-items: center; justify-content: center;
  background: none;
  border: 1px solid var(--rule);
  border-radius: 50%;
  color: var(--travertine-dim);
  cursor: pointer;
  transition: border-color 0.25s ease, color 0.25s ease, background 0.25s ease;
}
.kaoss__mute:hover { border-color: var(--amber); color: var(--travertine); }
.kaoss__ico { width: 1.05rem; height: 1.05rem; display: block; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.kaoss__ico--off { display: none; }
/* muted = engaged: filled silver with the speaker-off glyph (no red — that's record-only) */
.kaoss__mute[aria-pressed="true"] { background: var(--travertine); border-color: var(--travertine); color: var(--ink); }
.kaoss__mute[aria-pressed="true"]:hover { border-color: var(--travertine); color: var(--ink); }
.kaoss__mute[aria-pressed="true"] .kaoss__ico--on { display: none; }
.kaoss__mute[aria-pressed="true"] .kaoss__ico--off { display: block; }

/* the pad — a near-square performance surface */
.kaoss__pad {
  --px: 0.5;
  --py: 0.5;
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  max-height: 38vh;
  margin: 0 auto;
  overflow: hidden;
  border: 1px solid var(--rule);
  background:
    radial-gradient(120% 120% at 50% 120%, rgba(180,188,194,0.10), transparent 60%),
    radial-gradient(100% 100% at 50% -10%, rgba(228,231,234,0.04), transparent 55%),
    #08090b;
  box-shadow: inset 0 0 calc(18px + var(--level, 0) * 70px) rgba(207,214,219, calc(0.04 + var(--level, 0) * 0.16)); /* pad breathes with the beat */
  cursor: crosshair;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.kaoss__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--rule-soft) 1px, transparent 1px),
    linear-gradient(90deg, var(--rule-soft) 1px, transparent 1px);
  background-size: 12.5% 12.5%;
  opacity: 0.7;
}
.kaoss__edge {
  position: absolute;
  font-family: var(--sans);
  font-size: 0.66rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--travertine-dim);
  opacity: 0.5;
  pointer-events: none;
}
.kaoss__edge--x { left: 0; right: 0; bottom: 0.55rem; text-align: center; }
.kaoss__edge--y { left: 0.6rem; top: 0.7rem; transform: rotate(180deg); writing-mode: vertical-rl; }

/* crosshairs track the finger */
.kaoss__cross {
  position: absolute;
  background: var(--amber-soft);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.kaoss__cross--h { left: 0; right: 0; height: 1px; top: calc(var(--py) * 100%); }
.kaoss__cross--v { top: 0; bottom: 0; width: 1px; left: calc(var(--px) * 100%); }
.kaoss__pad.is-touch .kaoss__cross { opacity: 0.5; }

/* the eclipse orb — follows the finger, pulses to the live level */
.kaoss__orb {
  position: absolute;
  left: calc(var(--px) * 100%);
  top: calc(var(--py) * 100%);
  width: clamp(46px, 14vw, 64px);
  aspect-ratio: 1;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(calc(0.6 + var(--level, 0) * 0.5));
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e7ecef 24%, #cfd6db 50%, #9aa1a7 70%, #3a3e42 86%, rgba(10,11,13,0) 100%);
  box-shadow: 0 0 40px 6px rgba(207,214,219,0.4), 0 0 120px 30px rgba(207,214,219,0.16);
  /* warm + dim when the tone is dark (X low), bright + cool as it opens (X high) */
  filter: brightness(calc(0.72 + var(--orbtone, 0.5) * 0.55)) saturate(calc(1.35 - var(--orbtone, 0.5) * 0.5));
  opacity: 0;
  transition: opacity 0.3s ease;
}
.kaoss__pad.is-touch .kaoss__orb { opacity: 1; }
.kaoss__pad.has-sel .kaoss__orb { opacity: 0.72; }   /* stays put, showing the saved spot */
.kaoss__pad.has-sel .kaoss__cross { opacity: 0.3; }
.kaoss__hint {
  position: absolute;
  left: 50%;
  top: 50%;
  margin: 0;
  transform: translate(-50%, -50%);
  font-size: 0.8rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--travertine-dim);
  opacity: 0.55;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.kaoss__pad.is-touch .kaoss__hint,
.kaoss__pad.has-sel .kaoss__hint { opacity: 0; }

/* controls */
.kaoss__controls {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.9rem;
}
.kaoss__btn,
.kaoss__instr {
  flex: none;
  padding: 0.62rem 0.5rem;
  background: rgba(10,10,12,0.5);
  border: 1px solid var(--rule);
  color: var(--travertine-dim);
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
}
.kaoss__btn:hover,
.kaoss__instr:hover { border-color: var(--amber); color: var(--travertine); }
.kaoss__instr.is-active,
.kaoss__btn.is-active {
  border-color: var(--amber-soft);
  color: var(--ink);
  background: var(--amber);
}
/* the instrument currently being shaped by the pad */
.kaoss__instr.is-selected {
  outline: 1px solid var(--travertine);
  outline-offset: -3px;
  box-shadow: 0 0 12px var(--amber-soft);
}
.kaoss__instr { flex: 1; padding: 0.55rem 0.2rem; }

/* status line + layer lamps */
.kaoss__status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 0.7rem;
}
.kaoss__status-text {
  font-family: var(--sans);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.kaoss__layers { display: inline-flex; gap: 5px; flex: none; }
.kaoss__layers i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1px solid var(--rule);
  background: transparent;
  transition: background 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}
.kaoss__layers i.on {
  background: var(--amber);
  border-color: var(--amber-soft);
  box-shadow: 0 0 8px var(--amber-soft);
}

/* loop selector (4 choices per instrument) */
.kaoss__variants {
  display: flex;
  flex-wrap: wrap;             /* 8 loops → two rows of four */
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.5rem;
}
.kaoss__variants.is-hidden { display: none; }
.kaoss__var-label {
  flex-basis: 100%;           /* label sits on its own line above the chips */
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--travertine-dim);
}
.kaoss__var { flex: 1 1 calc(25% - 0.3rem); padding: 0.45rem 0.2rem; }

/* looper transport */
.kaoss__transport {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.5rem;
}
.kaoss__transport .kaoss__btn { flex: 1; padding: 0.55rem 0.2rem; }
/* COPY GROOVE LINK — the quiet secondary share below the film/transport row.
   The film (the video) is the headline; the link is a low-key text option. */
.kaoss__linkbtn {
  display: block;
  width: 100%;
  margin: 0.45rem 0 0;
  min-height: 38px;
  padding: 0.5rem;
  background: none;
  border: 0;
  color: var(--travertine-dim);
  font: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.kaoss__linkbtn:hover { color: var(--travertine); }
.kaoss__linkbtn:active { opacity: 0.6; }
/* Teaser → full studio */
.kaoss__teaser {
  margin: 0.7rem 0 0;
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--travertine-dim);
  text-align: center;
}
.kaoss__btn:disabled { opacity: 0.4; cursor: default; }
.kaoss__btn:disabled:hover { border-color: var(--rule); color: var(--travertine-dim); }
/* Surprise — the accent action */
.kaoss__btn--surprise {
  flex: 2 !important;
  border-color: var(--amber-soft);
  color: var(--amber);
  letter-spacing: 0.14em;
}
.kaoss__btn--surprise:hover { background: var(--amber); color: var(--ink); border-color: var(--amber); }
.kaoss__btn--surprise:active { background: var(--amber); color: var(--ink); }

/* REC: amber pulse while armed, solid red-amber while recording */
.kaoss__btn--rec.is-armed {
  border-color: var(--amber);
  color: var(--amber);
  animation: kaoss-arm 0.7s steps(1) infinite;
}
.kaoss__btn--rec.is-rec {
  border-color: #e8736b;
  background: #c8463c;
  color: #fff;
  animation: kaoss-rec 1s ease-in-out infinite;
}
@keyframes kaoss-arm { 50% { border-color: var(--rule); color: var(--travertine-dim); } }
@keyframes kaoss-rec { 50% { box-shadow: 0 0 16px 2px rgba(200,70,60,0.7); } }

/* the pad itself signals the looper state */
.kaoss__pad.is-arming { animation: kaoss-pad-arm 0.6s ease-in-out infinite; }
.kaoss__pad.is-recording { border-color: #c8463c; box-shadow: inset 0 0 40px rgba(200,70,60,0.35); }
@keyframes kaoss-pad-arm {
  0%, 100% { border-color: var(--rule); }
  50%      { border-color: var(--amber); box-shadow: inset 0 0 30px rgba(207,214,219,0.25); }
}

@media (prefers-reduced-motion: reduce) {
  .kaoss__btn--rec.is-armed, .kaoss__btn--rec.is-rec, .kaoss__pad.is-arming { animation: none; }
  .kaoss, .kaoss::before, .kaoss__sheet, .kaoss__orb, .kaoss__cross { transition: none; }
}

/* ---------- Audio-reactive — the page breathes with the live engine.
   studio.js writes --energy (loudness 0..1) and --beat (kick impulse) on
   :root every frame; the signature eclipses swell with the loudness and
   tick to the kick. ---------- */
.scroll-progress__bar {
  box-shadow: 0 0 calc(10px + var(--energy, 0) * 26px + var(--beat, 0) * 20px) var(--amber-soft);
}
.stage__sky .eclipse__orb,
.stage__sky .eclipse__halo {
  scale: calc(1 + var(--energy, 0) * 0.045 + var(--beat, 0) * 0.05);
}
.expr__eclipse {
  scale: calc(1 + var(--energy, 0) * 0.18 + var(--beat, 0) * 0.14);
}
.perf-lite .scroll-progress__bar { box-shadow: none; }

/* ---------- Desktop gate — ENABLED: mobile-only while desktop performance is poor ----------
   To re-open desktop, comment out the media query below (leave .desktop-gate display:none). */
.desktop-gate { display: none; }
/* Desktop gate REMOVED (2026-06-19): the site is now adapted for desktop + iPad
   (see the DESKTOP + iPad ADAPTATION block at the end of this file). The base
   `.desktop-gate { display:none }` above keeps the old overlay hidden at all widths. */
.desktop-gate__inner { max-width: 32rem; }
.desktop-gate__sun {
  display: block;
  width: clamp(96px, 9vw, 140px);
  aspect-ratio: 1;
  margin: 0 auto 2.75rem;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e7ecef 26%, #cfd6db 52%, #9aa1a7 72%, #3a3e42 88%, #181a1e 100%);
  box-shadow: 0 0 80px 8px rgba(207,214,219,0.45), 0 0 200px 50px rgba(207,214,219,0.18);
  animation: eclipseBreathe 9s ease-in-out infinite alternate;
}
.desktop-gate__mark {
  display: block;
  height: 24px;
  margin: 0 auto 2rem;
}
.desktop-gate__mark img { height: 100%; width: auto; margin: 0 auto; opacity: 0.95; }
.desktop-gate__line {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.7rem, 3vw, 2.5rem);
  line-height: 1.1;
  margin: 0;
  color: var(--travertine);
}
.desktop-gate__sub {
  margin: 1.4rem 0 0;
  font-size: 0.72rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  line-height: 1.9;
  color: var(--travertine-dim);
}
.desktop-gate__sub strong { color: var(--amber); font-weight: 400; }

/* ---------- Transition FX — smoke dissolve + drifting embers ---------- */
.fx-smoke {
  position: fixed;
  inset: -18%;
  z-index: 46;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  mix-blend-mode: screen;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='700' height='700'%3E%3Cfilter id='s'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.011' numOctaves='3' seed='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='700' height='700' filter='url(%23s)'/%3E%3C/svg%3E");
  background-size: 220% 220%;
  filter: blur(12px) contrast(1.5) brightness(1.04) sepia(0.7) saturate(2.3) hue-rotate(-12deg);
  will-change: opacity, background-position, transform;
}
.fx-smoke.is-active {
  visibility: visible;
  opacity: var(--fxsmoke, 0);
  animation: smokeDrift 24s ease-in-out infinite alternate;
}
@keyframes smokeDrift {
  from { background-position: 0% 18%; transform: scale(1.05) rotate(-1deg); }
  to   { background-position: 100% 72%; transform: scale(1.26) rotate(1.4deg); }
}

.fx-particles {
  position: fixed;
  inset: 0;
  z-index: 47;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0.8;
}
/* soften the slides while the smoke passes — dissolves the crisp seam edge */
/* smoke blur: ENTRANCE ONLY. The map was in this list and the stage's overlap
   margins moved stage.top into the middle of the satellite flight, so the
   smoke window blurred the WHOLE street-level zoom up to ~4px ("so poor
   quality i cant see anything"). The cosmos→doors handoff is a clean
   dip-to-black now — the satellite must never be filtered. */
.entrance__media { filter: blur(calc(var(--fxsmoke, 0) * 6px)); }

/* ---------- EQ — the soundtrack made visible (reacts to the music) ---------- */
.eq {
  position: relative;
  margin-top: clamp(2.75rem, 7vh, 4.5rem);
  display: flex;
  align-items: flex-end;
  gap: clamp(2px, 0.8vw, 5px);
  height: clamp(64px, 15vh, 120px);
}
.eq__label {
  position: absolute;
  top: -1.6rem; left: 0;
  font-size: 0.7rem; letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--amber-soft);
}
.eq i {
  flex: 1 1 0;
  min-width: 2px;
  height: 100%;                 /* full height; we scale it (compositor-only, no layout) */
  background: linear-gradient(to top, var(--amber), rgba(207,214,219,0.18));
  border-radius: 2px 2px 0 0;
  transform-origin: bottom;
  transform: scaleY(0.1);
}
.eq.is-live { opacity: calc(0.6 + var(--level, 0) * 0.4); }
.eq:not(.is-live) i { animation: eqIdle 1.6s ease-in-out infinite alternate; }
.eq.is-off:not(.is-live) i { animation-play-state: paused; }  /* don't animate off-screen */
@keyframes eqIdle { from { transform: scaleY(0.06); } to { transform: scaleY(0.26); } }

/* ---------- Kinetic marquee — the mantra, moving ---------- */
.marquee {
  overflow: hidden;
  border-top: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
  background: var(--ink-2);
  padding: clamp(1rem, 3vh, 1.9rem) 0;
  transform: skewX(calc(var(--vel, 0) * 5deg));
  will-change: transform;
}
.marquee__row {
  display: inline-flex;
  white-space: nowrap;
  animation: marq 26s linear infinite;
  will-change: transform;
}
.marquee__group {
  display: inline-block;
  white-space: nowrap;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.7rem, 5.5vw, 3.1rem);
  letter-spacing: 0.01em;
  color: var(--travertine);
}
.marquee__group i { font-style: normal; color: var(--amber); margin: 0 0.34em; }
@keyframes marq { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.marquee--rev .marquee__row { animation-direction: reverse; }
.marquee__group i { text-shadow: 0 0 calc(var(--energy, 0) * 16px) var(--amber); }
.perf-lite .marquee__group i { text-shadow: none; }

/* Lineage — kinetic slide-in (overrides the generic fade) */
.lineage__list li.reveal { transform: translateX(-26px); }
.lineage__list li.reveal.is-visible { transform: none; }

/* Site shots — parallax within the frame */
.site__shot { overflow: hidden; }
.site__shot img { transform: scale(1.1); translate: 0 var(--epy, 0px); }

/* Beat-reactive accents — amber details glow on the kick when sound is on */
.expr__roman,
.rhythm__time,
.lineage__name span,
.prose--rule .italic,
.menu__group-title span { text-shadow: 0 0 calc(var(--energy, 0) * 13px) var(--amber-soft); }
.perf-lite .menu__group-title span { text-shadow: none; }

/* EQ used as a section divider — a slim frequency line running through the page */
.eq--rail {
  height: clamp(30px, 6vh, 48px);
  max-width: 1280px;
  margin: clamp(2rem, 7vh, 4rem) auto;
  padding: 0 clamp(1.25rem, 5vw, 4rem);
  opacity: 0.5;
}
.eq--rail i { background: linear-gradient(to top, var(--amber-soft), rgba(207,214,219,0.08)); }

/* Mobile — shorten the pinned scrubs so they feel punchy on a flick-scroll */
@media (max-width: 640px) {
  .cosmos.is-live { height: 1000vh; }   /* LONG descent so a phone flick can't blow through it (iOS ignores the JS scroll-clamp during native fling momentum, so scroll DISTANCE is the only reliable pacer). The choreography is scroll-progress-normalized so it scales cleanly; entrance.top still tracks the cosmos bottom = flightEnd. Tune here for descent pace. */
  .entrance.is-walk { height: 140vh; margin-top: -100vh; }   /* scroll-length for the through */
  .stage.is-scrub { height: 440vh; margin-top: -140vh; }     /* = -(entrance height) top, big tail for the ~1-screen room linger; full-screen behind the door, no black gap */
  /* SPLASH compact — the long shaft pushed the SCROLL chevron under the fixed Play pill
     on iOS's short visible viewport (the centred column overflows). Shorten the shaft +
     tighten so the full arrow always clears the pill. */
  .splash { gap: clamp(1.1rem, 3.5vh, 2.1rem); }
  .splash__shaft { height: clamp(26px, 5vh, 44px); }
  .splash__shaft::after { animation: none; opacity: 0; }
  .splash__gate { margin-top: clamp(0.5rem, 2.5vh, 1.3rem); }
  /* THE ARRIVAL FRAME (retuned 2026-06-12 for club_arrival.jpg) — the corridor
     vanishing point + Eclipse are dead-center horizontally, so a portrait
     cover-crop keeps the ring in view. A little extra zoom tightens onto the
     corridor (crops the dark stone ceiling + foreground) and makes the Eclipse
     read bigger at the end. Brightness lifted for the deep dark shot. */
  .stage.is-scrub .stage__room img {
    transform: scale(1.18);
    object-position: center 43%;
    filter: brightness(calc(1.32 - var(--descend, 0) * 0.64)) contrast(1.06);
  }
  /* The Club card — club_room.jpg is the wide room study with the Eclipse
     altar at the far LEFT (x ~8–20%); a centered portrait crop loses it.
     Bias the window left so the ring + stone bar anchor the card. */
  #club .expr__media img { object-position: 20% 52%; }
  /* the club-room beat: bias left so the Eclipse altar + stone bar anchor the
     portrait frame, and ease the zoom (vs the 1.18 hero crop) so the ROOM reads
     spacious, not cramped — the concept is the size of the place */
  .stage.is-scrub .stage__room img.stage__img--room { object-position: 24% 50%; transform: scale(calc(1.05 + var(--roomHold, 0) * 0.10)); }
  /* the BOOTH is the held image: keep the mobile crop (1.18 / center 43%) and add
     the same slow push-in so the linger breathes on the phone too */
  .stage.is-scrub .stage__room img.stage__img--booth { transform: scale(calc(1.18 + var(--boothHold, 0) * 0.10)); }
  .bites-stage.is-track { height: 260vh; }
}

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .expr__media.reveal,
  .display--md.reveal { clip-path: none; }
  .expr__media.reveal img { scale: 1; filter: none; }
  .hero__media img,
  .stage__room img { animation: none; }
  [data-magnetic] { transition: none; }
  .eclipse__halo,
  .eclipse__corona,
  .eclipse__orb { animation: none; transform: none; }
  .scroll-progress { display: none; }
  .grain { animation: none; }
  .expr__eclipse { animation: none; }
  .loader { display: none; }
  .sound { transform: translateX(-50%); animation: none; }
  .sound__ring { animation: none; opacity: 0.4; }
  .sound.is-on { animation: none; transform: translateX(-50%); }
  .sound.is-on .sound__bars i { animation: none; height: 50%; transform: none; }
  .fx-smoke { animation: none; }
  .fx-particles { display: none; }
  .cosmos__galaxy { opacity: 1; }   /* static opening image when motion is reduced */
  .marquee__row { animation: none; }
  .marquee { transform: none; }
  .eq:not(.is-live) i { animation: none; transform: scaleY(0.16); }
}
.is-hidden .fx-smoke { animation-play-state: paused; }

/* Adaptive lite mode — drop the heaviest always-on effects on weak devices */
.perf-lite .grain,
.perf-lite .fx-particles { display: none; }
.perf-lite .fx-smoke { animation: none; }

/* =========================================================
   CASA NEGRA — the mini-studio inside the .kaoss pop-up.
   (Scoped to .kaoss; powered by instrument/studio.js.)
   ========================================================= */
.sound.is-hidden { opacity: 0 !important; pointer-events: none !important; visibility: hidden; }
.kaoss::before { background: rgba(6,7,8,0.86); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
.kaoss__sheet {
  max-width: 30rem;
  padding: clamp(0.9rem, 3.5vw, 1.4rem);
  background: var(--slab);
  border: 1px solid #000;
  border-top: 2px solid var(--amber);
  border-radius: 6px 6px 0 0;
  box-shadow: inset 0 1px 0 var(--metal-top), inset 0 0 0 1px rgba(0,0,0,0.5), 0 -8px 60px rgba(0,0,0,0.7);
}
.kaoss__head { margin-bottom: 0.7rem; }
.kaoss__title { font-family: var(--display); font-weight: 700; }
/* the title slot now reads the CURRENT GENRE: a clear brutalist stamp, not the
   old italic line. Lights with the eclipse glow once a specific genre is on. */
/* THE HEADER, two clean strips: row one is the small label + beat dots +
   mute/close, row two is the genre, full width, ONE line, never wrapping.
   display:contents lets the eyebrow and title sit directly in the head's
   flex flow so the title can break to its own full-width row. */
.kaoss__head { flex-wrap: wrap; align-items: center; row-gap: 0; }
.kaoss__titles { display: contents; }
.kaoss__titles .eyebrow { order: 0; margin: 0; align-self: center; }
.kaoss__head .beatdots { order: 1; margin-left: auto; padding-top: 0; }
.kaoss__head-actions { order: 2; margin: 0 0 0 0.7rem; }
.kaoss__title.is-genre {
  order: 3; flex-basis: 100%; min-width: 0;
  white-space: nowrap; overflow: hidden;
  margin: 0.1rem 0 0;
  font-style: normal;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: clamp(1.4rem, 6.4vw, 1.8rem);
  line-height: 1.1;
  color: var(--glow, var(--travertine));
  text-shadow: 0 0 18px rgba(var(--glow-rgb, 207, 214, 219), 0.4);
}

/* part keys */
.kaoss .parttabs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.4rem; margin-bottom: 0.6rem; }
.kaoss .parttab {
  position: relative;
  display: flex; align-items: center; justify-content: center; gap: 0.35rem; min-width: 0; min-height: 42px; cursor: pointer;
  font-family: var(--display); font-weight: 600; font-size: 0.84rem; color: var(--travertine-dim);
  background: #15171b; border: 1px solid #000; border-radius: 8px; padding: 0.4rem 0.3rem;
  box-shadow: inset 0 1px 0 rgba(228,231,234,0.06), inset 0 -2px 3px rgba(0,0,0,0.6); transition: transform 0.1s var(--ease), color 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.kaoss .parttab__dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: radial-gradient(circle at 35% 35%,#2b2e33,#08090b); box-shadow: inset 0 0 2px #000; transition: all 0.18s; }
.kaoss .parttab.is-live .parttab__dot { background: radial-gradient(circle at 38% 35%,#fff,var(--glow)); box-shadow: 0 0 8px var(--glow-soft), inset 0 0 2px #fff; }
.kaoss .parttab__name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kaoss .parttab__loop { flex: 0 0 auto; font-family: var(--mono); font-weight: 500; font-size: 0.54rem; letter-spacing: 0.06em; color: var(--amber-soft); }
.kaoss .parttab.is-live { color: var(--travertine); }
/* a PLAYING section pulses colour: a ring + outer glow in the live spectrum
   (--glow-rgb), breathing with overall loudness (--energy) and ticking on the
   kick (--beat). No transition on the pseudo, so the pulse stays sharp; idle
   tabs stay flat. Independent of is-current so the selected+playing tab keeps it. */
.kaoss .parttab.is-live::after {
  content: ""; position: absolute; inset: -1px; border-radius: 9px; pointer-events: none;
  border: 1px solid rgba(var(--glow-rgb, 207, 214, 219), calc(0.22 + var(--energy, 0) * 0.4 + var(--beat, 0) * 0.42));
  box-shadow: 0 0 calc(5px + var(--energy, 0) * 13px + var(--beat, 0) * 13px) rgba(var(--glow-rgb, 207, 214, 219), calc(0.16 + var(--energy, 0) * 0.3 + var(--beat, 0) * 0.4));
}
/* the SELECTED section (the part filling the pad) is filled GREEN so "where am
   I" is unmistakable, vs the spectrum pulse that means "this is playing" */
.kaoss .parttab.is-current {
  color: #07140c;
  background: #46ff8a;            /* the one locked green (was off-spec #5bffa0/#2fe07f) */
  border-color: #46ff8a;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.45), inset 0 -2px 5px rgba(0,0,0,0.25), 0 0 14px rgba(70,255,138,0.5);
}
.kaoss .parttab.is-current .parttab__name { color: #07140c; }
.kaoss .parttab.is-current .parttab__loop { color: rgba(7,20,12,0.65); }

/* the Kaoss pad — X = loop, Y = tone */
.kaoss .gridpad {
  --energy: 0; --px: 0.5; --py: 0.5; --orbtone: 0.5;
  position: relative; width: 100%; height: clamp(170px, 24vh, 240px); overflow: hidden; cursor: crosshair;
  border: 1px solid #000; border-radius: 12px;
  background: radial-gradient(120% 90% at 50% 0%, rgba(207,214,219,0.05), transparent 60%), var(--well);
  box-shadow: inset 0 2px 7px rgba(0,0,0,0.85), inset 0 0 0 1px rgba(228,231,234,0.05), inset 0 0 calc(14px + var(--energy)*38px + var(--beat,0)*16px) rgba(var(--glow-rgb),calc(0.05 + var(--energy)*0.16 + var(--beat,0)*0.10));
  touch-action: none; user-select: none; -webkit-user-select: none;
}
/* THE PIT: the render canvas under everything in the pad. The drawLoop paints
   haze, ghost glints, touch glints and the cue tracer into it; under reduced
   motion the loop never starts and the pit stays this static dark well. */
.kaoss .gridpad__pit { position: absolute; inset: 0; display: block; width: 100%; height: 100%; pointer-events: none; }
.kaoss .gridpad::after { content: ""; position: absolute; top: 0; bottom: 0; left: calc(var(--px)*100%); width: 1px; background: var(--glow-soft); opacity: 0.45; pointer-events: none; }
.kaoss .pad__edge--y { position: absolute; right: 0.5rem; top: 0.55rem; writing-mode: vertical-rl; font-family: var(--mono); font-weight: 500; font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--travertine-dim); opacity: 0.55; pointer-events: none; }
.kaoss .pad__orb {
  position: absolute; left: calc(var(--px)*100%); top: calc(var(--py)*100%);
  width: clamp(44px,13vw,58px); aspect-ratio: 1; border-radius: 50%; transform: translate(-50%,-50%); pointer-events: none;
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, var(--glow) 38%, var(--glow-dim) 72%, rgba(10,11,13,0) 100%);
  box-shadow: 0 0 28px 4px var(--glow-soft), 0 0 80px 18px var(--glow-dim);
  filter: brightness(calc(0.7 + var(--orbtone)*0.6)) saturate(calc(1.3 - var(--orbtone)*0.4)); transition: opacity 0.2s;
}
.kaoss .gridpad:not(.has-live) .pad__orb { opacity: 0.4; }
.kaoss .padscale {
  display: flex; gap: 5px; margin-top: 7px; padding: 4px; border-radius: 11px; position: relative;
  background: linear-gradient(180deg, #0a0b0d, #060708);
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.85), inset 0 0 0 1px rgba(228,231,234,0.04);
}
/* the loop selectors are DOMED RUBBER PADS: a silicone key lit along the
   eclipse spectrum (--hue per slot, cyan to coral). No numbers. The dome is a
   radial highlight up top + a recessed inner shadow; pressing sinks it in. */
.kaoss .padnum {
  flex: 1 1 0; min-width: 0; min-height: 34px;
  border: 1px solid #000; border-radius: 9px; cursor: pointer;
  background:
    radial-gradient(125% 90% at 50% 26%,
      hsl(var(--hue, 220) 22% 26%), hsl(var(--hue, 220) 26% 13%) 62%, hsl(var(--hue, 220) 30% 8%));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 -4px 7px rgba(0, 0, 0, 0.55),
    0 1px 2px rgba(0, 0, 0, 0.6);
  transition: background 0.12s, border-color 0.12s, box-shadow 0.12s, transform 0.06s;
}
/* the PLAYING pad blooms with the live audio glow, dome lit from within */
.kaoss .padnum.is-on {
  border-color: hsl(var(--hue, 220) 80% 60%);
  background:
    radial-gradient(125% 95% at 50% 30%,
      hsl(var(--hue, 220) 92% 72%), hsl(var(--hue, 220) 85% 52%) 55%, hsl(var(--hue, 220) 80% 34%));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.4),
    inset 0 -3px 8px rgba(0, 0, 0, 0.35),
    0 0 16px hsl(var(--hue, 220) 85% 58% / 0.7);
}
/* press: the rubber sinks */
.kaoss .padnum:active {
  transform: translateY(1px) scale(0.97);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.kaoss .padnum.is-preview { border-color: hsl(var(--hue, 220) 60% 55%); box-shadow: inset 0 0 0 1px hsl(var(--hue, 220) 60% 55% / 0.7), inset 0 -4px 7px rgba(0, 0, 0, 0.5); }

/* ===== THE CRATE (2026-06-13 rebuild): readable faces + the DEAL ===== */
/* each pad reads its loop — musical KEY big, crate number small, tinted to the
   pad's own --hue. Five anonymous lozenges become a readable deck. */
.kaoss .padnum { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; line-height: 1; overflow: hidden; }
.kaoss .padnum__key {
  font-family: var(--display); font-weight: 700; font-size: 0.84rem; letter-spacing: 0.01em;
  color: hsl(var(--hue, 220) 48% 74%); text-shadow: 0 1px 1px rgba(0, 0, 0, 0.65);
}
.kaoss .padnum__n {
  font-family: var(--mono); font-style: normal; font-weight: 500; font-size: 0.5rem;
  letter-spacing: 0.06em; color: hsl(var(--hue, 220) 22% 56%); opacity: 0.85;
}
.kaoss .padnum.is-on .padnum__key { color: #fff; text-shadow: 0 0 9px hsl(var(--hue, 220) 92% 72%); }
.kaoss .padnum.is-on .padnum__n { color: rgba(255, 255, 255, 0.82); }

/* THE DEAL: the fresh five THROW in, left to right, out of one green wipe.
   transform/opacity only (60fps-cheap); --i staggers each pad. The blanket
   reduced-motion rule below neutralises it, so the LED + repainted faces carry
   the change without motion. */
.kaoss .padscale.is-dealing .padnum {
  animation: dealThrow 0.34s cubic-bezier(0.34, 1.25, 0.64, 1) both;
  animation-delay: calc(var(--i, 0) * 55ms);
}
@keyframes dealThrow {
  0% { transform: translateY(3px) scale(0.9); opacity: 0; }
  45% { opacity: 1; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}
.kaoss .padscale.is-dealing::after {
  content: ""; position: absolute; inset: 0; border-radius: 11px; pointer-events: none; z-index: 2;
  background: linear-gradient(90deg, transparent 0%, rgba(70, 255, 138, 0.5) 50%, transparent 100%);
  mix-blend-mode: screen; opacity: 0; animation: dealWipe 0.5s ease-out 1;
}
@keyframes dealWipe {
  0% { opacity: 0; transform: translateX(-35%); }
  30% { opacity: 0.6; }
  100% { opacity: 0; transform: translateX(35%); }
}
/* the strip is the BLACKOUT door (phase 3B): 44px touch target, pointer-armed,
   hardened so the press-and-hold can never become a scroll or a callout */
.kaoss .gridpad__viz {
  display: block; width: 100%; height: 44px; margin: 7px 0 0; border-radius: 7px;
  background: #060708; box-shadow: inset 0 1px 3px rgba(0,0,0,0.85), inset 0 0 0 1px rgba(228,231,234,0.05);
  pointer-events: auto; cursor: pointer;
  touch-action: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}

/* THE STRIKE: quadrant press overlays, corner stamps, pooled hit ripples and
   the roll-rate ruler. All absolutely positioned inside the pad, zero new rows. */
.kaoss .padzone {
  position: absolute; width: 50%; height: 50%; border-radius: 10px; pointer-events: none;
  background: transparent;
  transition: transform 0.12s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.25s;
}
.kaoss .padzone--0 { left: 0; top: 50%; }
.kaoss .padzone--1 { left: 50%; top: 50%; }
.kaoss .padzone--2 { left: 0; top: 0; }
.kaoss .padzone--3 { left: 50%; top: 0; }
.kaoss .padzone.is-hit { transform: scale(calc(0.97 - var(--vel, 0.5) * 0.07)); background: rgba(var(--glow-rgb), calc(0.04 + var(--vel, 0.5) * 0.10)); transition: none; }
.kaoss .padstamp {
  position: absolute; pointer-events: none;
  font-family: var(--display); font-weight: 600; font-size: 0.65rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--travertine-dim);
  opacity: 1; transition: opacity 1.4s ease;
}
.kaoss .padstamp--0 { left: 0.6rem; bottom: 0.5rem; }
.kaoss .padstamp--1 { right: 0.6rem; bottom: 0.5rem; }
.kaoss .padstamp--2 { left: 0.6rem; top: 0.55rem; }
.kaoss .padstamp--3 { right: 1.55rem; top: 0.55rem; }   /* clears the vertical tone label */
.kaoss .gridpad.is-learned .padstamp { opacity: 0.15; }
.kaoss .padripple {
  position: absolute; left: 0; top: 0; width: 58px; height: 58px; margin: -29px 0 0 -29px;
  border-radius: 50%; pointer-events: none; opacity: 0; will-change: transform, opacity;
  background: radial-gradient(circle, var(--glow) 0%, rgba(var(--glow-rgb), 0.5) 42%, transparent 70%);
}
.kaoss .padripple.is-live { animation: strikeRipple 0.42s ease-out; }
/* the ripple reads --vel (written by strikeFeel): a feather-tap makes a small
   dim ring, a slam throws a wide bright one — the dynamics made visible */
@keyframes strikeRipple {
  0% { opacity: calc(0.45 + var(--vel, 0.6) * 0.55); transform: scale(0.25); }
  100% { opacity: 0; transform: scale(calc(0.85 + var(--vel, 0.6) * 1.35)); }
}
.kaoss .padruler {
  position: absolute; left: 0.45rem; top: 0.45rem; bottom: 0.45rem;
  display: flex; flex-direction: column; justify-content: space-between;
  pointer-events: none; opacity: 0; transition: opacity 0.18s;
}
.kaoss .gridpad.is-rolling .padruler { opacity: 1; }
.kaoss .padruler i {
  font-style: normal; font-family: var(--mono); font-weight: 500; font-size: 0.5rem;
  letter-spacing: 0.12em; color: var(--travertine-dim); opacity: 0.5;
}
.kaoss .padruler i.is-rate { color: var(--glow, var(--travertine)); opacity: 1; text-shadow: 0 0 8px var(--glow-soft); }

/* wrapped loop scale: parts with more than 10 loops break into two rows so
   each target roughly doubles in width; total height stays under 64px */
.kaoss .padscale.is-wrap { flex-wrap: wrap; }
.kaoss .padscale.is-wrap .padnum { min-height: 30px; }

/* touch hardening: every control is an instrument surface, never a browser
   gesture (no long-press menus, no text selection, no scroll-cancelled holds) */
.kaoss .parttab, .kaoss .padnum, .kaoss .btn, .kaoss .punchkey, .kaoss__mute, .kaoss__close {
  touch-action: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.kaoss .gridpad { -webkit-touch-callout: none; }

/* (the Level/Tone balance sliders were REMOVED 2026-06-12 — the pad is the
   control: Y = tone, parts ride their preset/score levels. DJ surface.) */

/* the viz strip wrapper + STATUS FLASH: the ribbon row is gone (the punch row
   took it), so status lines flash transiently over the dot-matrix strip */
.kaoss .vizrow { position: relative; margin-top: 7px; }
.kaoss .vizrow .gridpad__viz { margin: 0; }
/* the LED readout: the strip's resting text IS the current genre (the header
   carries no words any more); statuses flash over it and fall back */
.kaoss .status-flash {
  position: absolute; left: 6px; right: 6px; top: 50%; transform: translateY(-50%); margin: 0;
  font-family: var(--mono); font-weight: 600; font-size: 0.6rem; letter-spacing: 0.22em;
  text-transform: uppercase;
  line-height: 1.3; text-align: center; color: var(--glow, var(--travertine));
  text-shadow: 0 0 9px rgba(var(--glow-rgb, 207, 214, 219), 0.55);
  background: rgba(6,7,8,0.82); border-radius: 5px; padding: 0.28rem 0.5rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 0; transition: opacity 0.35s ease; pointer-events: none;
}
.kaoss .status-flash.is-on { opacity: 1; }
/* the header is iconography only: wordmark left, eclipse + controls right */
.kaoss__logo { display: block; height: 15px; width: auto; opacity: 0.94; }
.kaoss__head { align-items: center; }

/* PUNCH ROW: four momentary performance keys (hold is on, release snaps back
   on the grid). Brutalist stamps; pressed = the stamp inverts. */
.kaoss .punchrow { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.4rem; margin-top: 0.6rem; }
.kaoss .punchkey {
  min-height: 44px; min-width: 0; cursor: pointer; line-height: 1;
  font-family: var(--mono); font-weight: 600; font-size: 0.56rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--travertine-dim); background: linear-gradient(180deg,#191b1f,#0e0f12);
  border: 1px solid #000; border-radius: 8px; padding: 0.4rem 0.15rem;
  box-shadow: inset 0 1px 0 rgba(228,231,234,0.06), inset 0 -2px 3px rgba(0,0,0,0.55);
  transition: color 0.12s, background 0.12s, box-shadow 0.12s, transform 0.08s var(--ease);
}
.kaoss .punchkey.is-held {
  color: #0b0b0d; background: linear-gradient(180deg, var(--travertine), #b8c0c6);
  border-color: var(--travertine); transform: translateY(1px);
  box-shadow: inset 0 2px 4px rgba(0,0,0,0.35), 0 0 14px rgba(var(--glow-rgb), 0.35);
}
/* a captured lane lives behind the CYCLE key: a quiet lit edge */
.kaoss .punchkey.has-lane:not(.is-held) {
  box-shadow: inset 0 -2px 0 rgba(var(--glow-rgb), 0.55), inset 0 1px 0 rgba(228,231,234,0.06);
}
/* THE GENRE KEY: lives with the performance keys, but it is a tap-cycle, not
   a hold, and it PULSES in luminous green (user-locked: the ONE green in the
   palette, so the sound-changing key is unmistakable) */
.kaoss .punchkey--genre {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  color: #46ff8a;
  border-color: rgba(70, 255, 138, 0.6);
  text-shadow: 0 0 8px rgba(70, 255, 138, 0.45);
  animation: genrePulse 2.2s ease-in-out infinite;
}
/* the circular re-deal arrow: makes the key unmistakably a "deal again" control */
.kaoss .punchkey__deal { width: 17px; height: 17px; display: block; filter: drop-shadow(0 0 4px rgba(70, 255, 138, 0.5)); transition: transform 0.5s var(--ease); }
.kaoss .punchkey__label { font-size: 0.5rem; }
.kaoss .punchkey--genre:active .punchkey__deal { transform: rotate(140deg); }       /* nudges on press */
.kaoss .punchkey--genre.is-dealt .punchkey__deal { animation: dealSpin 0.55s var(--ease); }  /* full spin per deal */
@keyframes dealSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.kaoss .punchkey--genre:active { transform: translateY(1px) scale(0.98); background: rgba(70, 255, 138, 0.12); }
@keyframes genrePulse {
  0%, 100% { border-color: rgba(70, 255, 138, 0.45); box-shadow: inset 0 1px 0 rgba(228,231,234,0.06), 0 0 5px rgba(70, 255, 138, 0.2); }
  50% { border-color: rgba(70, 255, 138, 1); box-shadow: inset 0 1px 0 rgba(228,231,234,0.1), 0 0 18px rgba(70, 255, 138, 0.6); }
}
@media (prefers-reduced-motion: reduce) {
  .kaoss .punchkey--genre { animation: none; border-color: rgba(70, 255, 138, 0.85); }
}

/* transport keys */
/* 2×2 transport: Start / The Drop on top, Share / Off beneath */
.kaoss__transport { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-top: 0.7rem; }

/* THE DROP — armed = the build is running, the button burns until the slam */
.kaoss .btn--drop { color: var(--amber); border-color: var(--amber-soft); }
.kaoss .btn--drop.is-armed {
  color: #0b0b0d;
  background: linear-gradient(180deg, var(--amber-mid), var(--amber) 60%, #b8c0c6);
  border-color: var(--amber-hot);
  animation: dropArm 0.5s ease-in-out infinite alternate;
}
@keyframes dropArm {
  from { box-shadow: 0 0 6px var(--amber-soft); }
  to   { box-shadow: 0 0 22px var(--amber); }
}

/* the beat dots — the bar made visible in the panel header, accent on the 1 */
/* THE PULSE: the four dots are gone (user: uncool). The beat indicator is
   the brand's own motif, a small mirror eclipse that breathes on the kick,
   driven by the live --beat impulse exactly like the stage eclipse. */
.beatdots { display: inline-flex; gap: 8px; align-items: center; }
.kaoss__sun {
  display: none;   /* header beat-eclipse removed (user: no purpose, distracting) */
  width: 30px; height: 30px; border-radius: 50%;
  background: radial-gradient(circle at 36% 30%, #2c2f33, #0b0c0e 72%);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.16),
    0 0 0 1px rgba(var(--glow-rgb, 207, 214, 219), calc(0.30 + var(--beat, 0) * 0.65)),
    0 0 calc(7px + var(--beat, 0) * 16px) rgba(var(--glow-rgb, 207, 214, 219), calc(0.22 + var(--beat, 0) * 0.5));
  transform: scale(calc(1 + var(--beat, 0) * 0.1));
}
/* THE TURN: bar 1 of every 4 is the phrase head — the eclipse rings full */
.beatdots.is-phrase .kaoss__sun {
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.22),
    0 0 0 1.5px rgba(242, 245, 248, 0.95),
    0 0 calc(12px + var(--beat, 0) * 16px) rgba(238, 241, 244, 0.7);
}
@media (prefers-reduced-motion: reduce) {
  .kaoss__sun { transform: none; box-shadow: inset 0 1px 1px rgba(255,255,255,0.16), 0 0 0 1px rgba(var(--glow-rgb,207,214,219), 0.5), 0 0 9px rgba(var(--glow-rgb,207,214,219), 0.3); }
}

/* a CUED loop number — committed, waiting for the beat boundary */
.kaoss .padnum.is-cued { animation: cueBlink 0.22s steps(2, start) infinite; border-color: var(--glow, var(--amber)); }
@keyframes cueBlink { to { color: var(--glow, var(--amber)); } }

/* harmonic kinship — this loop is in key with what's already playing */
.kaoss .padnum.is-kin { border-color: rgba(var(--glow-rgb, 207, 214, 219), 0.55); box-shadow: inset 0 0 6px rgba(var(--glow-rgb, 207, 214, 219), 0.18); }
.kaoss .btn { font-family: var(--mono); font-weight: 500; font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--travertine-dim); background: linear-gradient(180deg,#191b1f,#0e0f12); border: 1px solid #000; border-radius: 8px; padding: 0.6rem 0.8rem; cursor: pointer; line-height: 1; min-height: 42px; display: inline-flex; align-items: center; justify-content: center; box-shadow: inset 0 1px 0 rgba(228,231,234,0.06), inset 0 -2px 3px rgba(0,0,0,0.55); transition: transform 0.1s var(--ease), color 0.15s, border-color 0.15s; }
.kaoss .btn:active { transform: translateY(1px); }
.kaoss .btn--amber { flex: 1 1 auto; color: #0b0b0d; background: linear-gradient(180deg,var(--amber-mid),var(--amber) 60%,#b8c0c6); border-color: var(--amber-hot); box-shadow: inset 0 1px 0 rgba(255,255,255,0.55), inset 0 -2px 3px rgba(70,76,82,0.5), 0 3px 0 var(--amber-deep), 0 6px 12px -6px rgba(0,0,0,0.7); }
.kaoss .btn--amber:active { transform: translateY(2px); box-shadow: inset 0 1px 0 rgba(255,255,255,0.55), 0 1px 0 var(--amber-deep); }
@media (prefers-reduced-motion: reduce) { .kaoss *, .kaoss *::before, .kaoss *::after { transition: none !important; animation: none !important; } }

/* =========================================================
   MOBILE POLISH (audit pass) — appended last so it wins.
   Safe-area aware, >=44px tap targets, no sideways scroll.
   ========================================================= */

/* no sideways scroll anywhere (clip keeps sticky pins working) */
html, body { overflow-x: clip; }

/* fixed/edge elements respect the notch + home indicator */
.nav {
  /* sit the logo right below the notch, not a band beneath it: take the LARGER of the
     base padding and the safe-area inset, don't ADD them (the old calc(1.1rem + inset)
     left a tall dark gap above the header on notched iPhones). */
  padding: max(1.1rem, env(safe-area-inset-top)) clamp(1rem, 4vw, 2.5rem) 1.1rem;
  padding-left: max(clamp(1rem, 4vw, 2.5rem), env(safe-area-inset-left));
  padding-right: max(clamp(1rem, 4vw, 2.5rem), env(safe-area-inset-right));
}
.foot {
  padding: 3rem clamp(1.25rem, 5vw, 4rem) calc(3rem + env(safe-area-inset-bottom));
  padding-left: max(clamp(1.25rem, 5vw, 4rem), env(safe-area-inset-left));
  padding-right: max(clamp(1.25rem, 5vw, 4rem), env(safe-area-inset-right));
}
.contact { padding-bottom: calc(clamp(5rem, 12vh, 9rem) + env(safe-area-inset-bottom)); }

/* tap targets >= 44px */
.nav__toggle {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0.5rem; margin: -0.5rem -0.25rem;
}
.nav__mark { min-height: 44px; padding: 11px 0; margin: -11px 0; box-sizing: content-box; }
.nav__mark img { height: 22px; width: auto; }
.site__map { display: inline-flex; align-items: center; min-height: 44px; }
.btn { min-height: 48px; display: inline-flex; align-items: center; justify-content: center; }

/* full-screen menu: bound height + scroll + safe-area, never trap links off-screen */
.nav__links {
  max-height: calc(100svh - 100%);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: calc(clamp(2rem, 4vh, 3rem) + env(safe-area-inset-bottom));
}

/* enquiry select: match the bespoke underline inputs (no native grey control) + 44px row */
.enquire input,
.enquire select { -webkit-appearance: none; appearance: none; min-height: 44px; }
.enquire select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23cfd6db' fill='none' stroke-width='1.2'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 2px center; padding-right: 1.5rem;
}

/* reduced-motion users still need to reach the whole bites tray (no scroll-scrub) */
@media (prefers-reduced-motion: reduce) {
  .bites__viewport { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

@media (max-width: 640px) {
  /* keep section signage inside the phone inset (no clipped overhang) */
  .section > .section__index,
  .section > .display { margin-left: 0; }
  /* keep the screen-blended eclipse off the body copy */
  .expr__eclipse { top: 10%; right: 8%; width: clamp(96px, 30%, 150px); }
  /* deepen the cocktails overlay so the heading reads over the bright dome */
  .cocktails__image::after {
    background: linear-gradient(to top,
      rgba(10,10,12,0.95) 0%, rgba(10,10,12,0.66) 40%, rgba(10,10,12,0.5) 70%, rgba(10,10,12,0.6) 100%);
  }
  /* drop the heavy blur/contrast smoke stack on phones (battery + jank); lighten grain */
  .fx-smoke { display: none; }
  .grain { opacity: 0.04; }
  /* club schedule: tighter time column, less ragged act text */
  .rhythm__time { min-width: 3.6rem; font-size: 1.25rem; }
  .rhythm li { gap: 0.9rem; }
  /* readable dish labels */
  .bite figcaption { font-size: 0.84rem; letter-spacing: 0.12em; }
  /* bigger food photography on the tray */
  .bites-stage.is-track .bite { width: min(72vw, 300px); }
  /* menu group titles: keep the +/- on the first line */
  .menu__group-summary { align-items: flex-start; }
  .menu__group-title { font-size: 1.3rem; }
}

@media (max-width: 620px) {
  .btn { width: 100%; justify-self: stretch; }
  .foot__row, .foot__fine {
    flex-direction: column; align-items: flex-start; justify-content: flex-start; gap: 0.75rem;
  }
}

@media (max-width: 600px) {
  .hero__foot { padding-right: 0; }            /* Sound disc is centred now, not parked here */
  /* the arrival foot (Summer 2027 · Opening · Scroll to descend) is bottom-aligned;
     the fixed Play pill OWNS the bottom-centre band, so reserve clearance above it */
  .stage__panel--hero { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 6rem); }
  .stage__title { font-size: clamp(2.9rem, 12vw, 7rem); }   /* lift the SIGNATURE HERO (¿Dónde?) on phones — scoped so it never inflates the longer concept line */
}

@media (max-width: 480px) {
  .facts { grid-template-columns: 1fr; gap: 1.25rem; }
  .stage__hero .lede br { display: none; }      /* avoid a ragged third line */
  .display--md { font-size: clamp(1.7rem, 7.5vw, 4.4rem); }
  .cosmos__content .eyebrow { font-size: 0.82rem; letter-spacing: 0.05em; }
}

@media (max-width: 430px) {
  .section { padding-block: clamp(3rem, 9vh, 5rem); }   /* reclaim vertical space on small phones */
}

/* compact the homepage pop-up so the WHOLE mini-studio fits a phone (Off + Full
   studio were below the fold). Bottom safe-area so the last row clears the home bar. */
.kaoss__sheet { padding-bottom: calc(clamp(0.9rem, 3.5vw, 1.4rem) + env(safe-area-inset-bottom)); }
@media (max-width: 560px) {
  /* row budget (375x667, Safari chrome EXPANDED, wrapped 20-loop Drums scale
     showing): re-summed ~530px <= ~535px available (559 innerHeight minus
     the 24px .kaoss inset) AFTER the strip grew 30->44px; parttabs margin
     0.5->0.35rem and padscale margin 7->5px bought the headroom back. Punch
     keys hold their 44px floor; the pad gives 150 to 130 and the head
     tightens instead. overflow-y:auto on the sheet stays the safety net. */
  .kaoss__sheet { padding: 0.85rem 0.9rem calc(0.85rem + env(safe-area-inset-bottom)); }
  .kaoss__head { margin-bottom: 0.3rem; }
  .kaoss__titles .eyebrow { font-size: 0.55rem; margin: 0 0 0.1rem; }
  .kaoss__title { font-size: 1.1rem; line-height: 1.15; }
  .kaoss .parttabs { gap: 0.35rem; margin-bottom: 0.35rem; }
  .kaoss .parttab { min-height: 38px; font-size: 0.82rem; padding: 0.4rem 0.3rem; }
  /* the strip holds its 44px BLACKOUT-door floor on phones; the pad, head,
     row gaps and the two margins above/below the pad give ~13.8px back so
     the sheet clears the 375x667 budget with real margin, not sub-pixel luck */
  .kaoss .gridpad { height: clamp(130px, 20vh, 200px); }
  .kaoss .padscale { margin-top: 5px; }
  .kaoss .padnum { min-height: 30px; font-size: 0.54rem; }
  .kaoss .padscale.is-wrap .padnum { min-height: 26px; }
  .kaoss .gridpad__viz { height: 44px; }
  .kaoss .vizrow { margin-top: 4px; }
  .kaoss .status-flash {
    font-size: 0.6rem; padding: 0.22rem 0.45rem;
    white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  }
  .kaoss .punchrow { margin-top: 0.2rem; gap: 0.35rem; }
  .kaoss .punchkey { min-height: 44px; font-size: 0.52rem; }
  .kaoss__transport { margin-top: 0.2rem; gap: 0.4rem; }
  .kaoss .btn { min-height: 38px; padding: 0.5rem 0.55rem; font-size: 0.6rem; }
}

/* =========================================================
   BLACKOUT (phase 3B): hold the dot-matrix strip and the
   sheet dissolves into a full-viewport club render. ONE
   canvas + ONE 44px exit stamp appended to body; the sheet
   chrome fades to 0 underneath (nothing unmounts). 400ms
   pure morph in place, no scroll, no layout cost.
   ========================================================= */
.kaoss__sheet { transition: transform 0.45s var(--ease), opacity 0.4s ease; }
.kaoss.is-blackout .kaoss__sheet { opacity: 0; pointer-events: none; }
.kaoss.is-blackout::before { opacity: 0; }
/* the drop shake drives transform raw from the rAF: the transition stands down */
.kaoss__sheet.is-shake { transition: none; }

.blackout-stage {
  position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; height: 100dvh;
  z-index: 400; display: block; background: #000;
  opacity: 0; pointer-events: none; transition: opacity 0.4s ease;
  touch-action: none; overscroll-behavior: none;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.blackout-stage.is-on { opacity: 1; pointer-events: auto; }
.blackout-exit {
  position: fixed; z-index: 401;
  top: calc(env(safe-area-inset-top, 0px) + 8px);
  right: calc(env(safe-area-inset-right, 0px) + 8px);
  min-width: 44px; min-height: 44px; padding: 0 0.8rem; cursor: pointer; line-height: 1;
  font-family: var(--mono); font-weight: 600; font-size: 0.56rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--travertine); background: rgba(0,0,0,0.55);
  border: 1px solid rgba(228,231,234,0.4); border-radius: 8px;
  opacity: 0; pointer-events: none; transition: opacity 0.4s ease;
  touch-action: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.blackout-exit.is-on { opacity: 1; pointer-events: auto; }
/* reduced motion: entry is a JS no-op, but belt and braces: the stage and
   its exit can never present a dead black input-eating plane */
@media (prefers-reduced-motion: reduce) {
  .blackout-stage, .blackout-exit { display: none !important; }
}

/* =========================================================
   THE PRESS (phase 4A): hold the Share key 500ms and the
   last 8 bars leave as a 9:16 film. Tap stays the groove
   link. The overlay morphs over the pad while pressing,
   then over pad + scale + viz for the preview. No new rows.
   ========================================================= */
.kaoss .btn[data-share] { position: relative; overflow: hidden; }
/* the hold made visible: a fill sweeps the key across the 500ms arm
   (transform only; under reduced motion the hold still fires, unanimated) */
.kaoss .btn[data-share].is-arming::after {
  content: ''; position: absolute; inset: 0; border-radius: 8px; pointer-events: none;
  background: rgba(var(--glow-rgb, 207, 214, 219), 0.30);
  transform-origin: left center; transform: scaleX(0);
  animation: pressArm 0.5s linear forwards;
}
@keyframes pressArm { to { transform: scaleX(1); } }
/* reduced motion: the hold still fires; the kaoss-wide kill flattens the
   sweep, so the fill snaps to full and the ARMED state still reads */
@media (prefers-reduced-motion: reduce) {
  .kaoss .btn[data-share].is-arming::after { transform: scaleX(1); }
}
/* PEAK heat: the drop just landed, or 4+ parts ran 8 straight bars. The
   take is already on the tape; the key glows. Opacity pulse only. */
.kaoss .btn[data-share].is-hot {
  color: var(--glow, var(--travertine));
  border-color: rgba(var(--glow-rgb, 207, 214, 219), 0.6);
}
.kaoss .btn[data-share].is-hot::before {
  content: ''; position: absolute; inset: 0; border-radius: 8px; pointer-events: none;
  box-shadow: inset 0 0 14px rgba(var(--glow-rgb, 207, 214, 219), 0.4);
  animation: pressHot 1.1s ease-in-out infinite alternate;
}
@keyframes pressHot { from { opacity: 0.25; } to { opacity: 1; } }

/* the press overlay: a black slab absolutely positioned inside the
   (position:relative) sheet. JS sets top/left/width/height from the live
   zone rects, so nothing underneath ever moves. The plate canvas stays
   visible throughout: WebKit starves captureStream on hidden canvases. */
.kaoss .press-stage {
  position: absolute; z-index: 40;
  display: flex; gap: 0.7rem; align-items: stretch; justify-content: center;
  background: rgba(5, 6, 7, 0.97);
  border: 1px solid rgba(228, 231, 234, 0.14);
  border-radius: 10px;
  padding: 0.55rem;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.6);
}
.kaoss .press-plate {
  height: 100%; width: auto; aspect-ratio: 9 / 16; max-width: 60%;
  background: #000; object-fit: cover;
  border: 1px solid rgba(228, 231, 234, 0.18); border-radius: 6px;
  flex: 0 0 auto; align-self: center;
}
.kaoss .press-side {
  display: flex; flex-direction: column; justify-content: flex-start;
  min-width: 96px; max-width: 170px; flex: 0 1 150px;
}
.kaoss .press-label {
  margin: 0 0 0.45rem;
  font-family: var(--mono); font-weight: 600; font-size: 0.56rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--travertine-dim);
}
.kaoss .press-keys { display: flex; flex-direction: column; gap: 0.4rem; margin-top: auto; }
.kaoss .press-stage.is-pressing .press-keys { display: none; }   /* keys arrive with the preview */
.kaoss .press-key {
  min-height: 44px; min-width: 0; cursor: pointer; line-height: 1;
  font-family: var(--mono); font-weight: 600; font-size: 0.58rem;
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--travertine-dim); background: linear-gradient(180deg, #191b1f, #0e0f12);
  border: 1px solid #000; border-radius: 8px; padding: 0.5rem 0.6rem;
  box-shadow: inset 0 1px 0 rgba(228, 231, 234, 0.06), inset 0 -2px 3px rgba(0, 0, 0, 0.55);
  touch-action: manipulation; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.kaoss .press-key:active { transform: translateY(1px); }
.kaoss .press-key--share {
  color: var(--glow, var(--travertine));
  border-color: rgba(var(--glow-rgb, 207, 214, 219), 0.55);
}

/* LIVE FILM rec bar — sits over the transport while recording so the PAD
   stays fully playable. Only this bar is interactive during the take. */
.kaoss .press-live {
  position: absolute; z-index: 40;
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.45rem 0.55rem;
  background: rgba(5, 6, 7, 0.97);
  border: 1px solid rgba(228, 231, 234, 0.16);
  border-radius: 10px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.6);
}
.kaoss .press-live__plate {
  width: 38px; height: 67px; flex: 0 0 auto;
  background: #000; border: 1px solid rgba(228, 231, 234, 0.18); border-radius: 5px;
}
.kaoss .press-live__meta { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.kaoss .press-live__line { display: flex; align-items: center; gap: 0.4rem; }
.kaoss .press-live__dot { width: 9px; height: 9px; border-radius: 50%; background: #ff3b30; flex: 0 0 auto; animation: recPulse 1s steps(2, end) infinite; }
.kaoss .press-live__cd { font-family: var(--mono); font-weight: 700; font-size: 0.72rem; letter-spacing: 0.08em; color: var(--mirror, #cfd6db); }
.kaoss .press-live__hint { font-size: 0.6rem; line-height: 1.25; color: var(--travertine-dim); overflow: hidden; }
.kaoss .press-live__stop {
  flex: 0 0 auto; min-height: 40px; padding: 0 0.95rem; cursor: pointer;
  font-family: var(--mono); font-weight: 700; font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: #0b0b0d; background: var(--mirror, #cfd6db); border: 0; border-radius: 9px;
  touch-action: manipulation; -webkit-user-select: none; user-select: none;
}
.kaoss .press-live__stop:active { transform: translateY(1px); }
@keyframes recPulse { 0% { opacity: 1; } 50% { opacity: 0.25; } 100% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .kaoss .press-live__dot { animation: none; } }

/* =========================================================
   PHASE 4B: TONIGHT'S SET + CHAIN + THE STAMP chrome.
   The header eyebrow is the kit door, the padscale morphs
   into four full-width kit keys, locked parent tabs dim and
   shake, GEN rides inside the beatdots dead zone. Zero new
   rows; every surface is a morph of an existing zone.
   ========================================================= */
/* the eyebrow becomes the daily-kit door: a REAL 44px thumb floor without
   moving the header. The box grows to 44px, the calc margins (1.55em = the
   inherited 1.55 line box at any font size, incl. the 0.55rem phone size)
   give every grown pixel back, and flex centring keeps the painted text
   exactly where static layout had it. position:relative lets the grown hit
   box win taps over the inert title text below it. */
/* THE NIGHT SELECTOR is a REAL control, not a caption: a bordered pill that
   names the genre and shows a cycle arrow, so it reads as "tap to change the
   sound" at a glance. It draws the eye on open (a few attention pulses), then
   settles. Lives in the eyebrow slot, no new row, no scroll. */
.kaoss__titles .eyebrow.is-setkit {
  cursor: pointer;
  position: relative; z-index: 2;
  display: inline-flex; align-items: center; gap: 0.4em;
  min-height: 30px;
  box-sizing: border-box;
  padding: 0 0.5rem;
  margin: 0 0 0.3rem;
  font-size: 0.62rem; letter-spacing: 0.16em;
  border: 1px solid rgba(var(--glow-rgb, 207, 214, 219), 0.4);
  border-radius: 6px;
  background: rgba(var(--glow-rgb, 207, 214, 219), 0.06);
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  touch-action: manipulation;
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
  animation: nightHint 1.6s ease-in-out 3;
}
/* the cycle affordance: a chevron that says this advances on every tap */
.kaoss__titles .eyebrow.is-setkit::after {
  content: "\25B8"; /* black right-pointing small triangle */
  font-size: 0.85em; opacity: 0.7; margin-left: 0.1em;
}
.kaoss__titles .eyebrow.is-setkit:active {
  background: rgba(var(--glow-rgb, 207, 214, 219), 0.14);
  border-color: rgba(var(--glow-rgb, 207, 214, 219), 0.7);
}
.kaoss__titles .eyebrow.is-setkit.is-kit-on {
  color: var(--glow, var(--travertine));
  border-color: rgba(var(--glow-rgb, 207, 214, 219), 0.85);
  text-shadow: 0 0 10px rgba(var(--glow-rgb, 207, 214, 219), 0.35);
}
@keyframes nightHint {
  0%, 100% { border-color: rgba(var(--glow-rgb, 207, 214, 219), 0.4); box-shadow: none; }
  50% { border-color: rgba(var(--glow-rgb, 207, 214, 219), 0.95); box-shadow: 0 0 14px rgba(var(--glow-rgb, 207, 214, 219), 0.4); }
}
@media (prefers-reduced-motion: reduce) {
  .kaoss__titles .eyebrow.is-setkit { animation: none; }
}
/* kit mode: four loops, four real 44px keys across the full scale row */
.kaoss .padscale.is-kit .padnum { min-height: 44px; font-size: 0.72rem; }
/* THE NIGHT SELECTOR: a thin pack backfills from the full library and the
   borrowed numbers ride dimmer than the pack's own (a lit guest stays full) */
.kaoss .padnum.is-guest:not(.is-on) { opacity: 0.5; }
/* CHAIN: the parent's parts play on behind glass */
.kaoss .parttab.is-locked { opacity: 0.45; }
.kaoss .parttab.is-locked .parttab__dot { box-shadow: none; }
.kaoss .parttab.is-shake { animation: lockShake 0.15s linear 1; }
@keyframes lockShake {
  0% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  55% { transform: translateX(4px); }
  80% { transform: translateX(-2px); }
  100% { transform: translateX(0); }
}
/* GEN stamp rides inside the beatdots dead zone (never rendered while the
   kit date owns the eyebrow; studio.js gates the display) */
.beatdots .genstamp {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 0.54rem;
  letter-spacing: 0.12em;
  color: var(--travertine-dim);
  padding-left: 7px;
  white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
  .kaoss .parttab.is-shake { animation: none; }
}

/* =========================================================
   THE PASEO (next-level Pass 1) — the back half turns sideways.
   .paseo is the vertical scroll runway (one screen per panel);
   .paseo__pin sticks for the duration (never transformed — sticky
   pins break inside transformed ancestors); JS pans .paseo__track
   left via --pan. Each panel is one lit window down the waterfront,
   the reverse marquee the road beneath. Appended last so it wins over
   the .section / mobile-polish rules these ids carried before.
   Reduced motion + perf-lite fall back to a clean vertical stack.
   ========================================================= */
.paseo {
  position: relative;
  /* runway scales to the real track width (JS sets --paseo-screens = trackW/vw,
     so a wide gallery panel gets proportionally more vertical scroll) */
  height: calc(var(--paseo-screens, 5) * 100vh);
  background: var(--ink);
  border-top: 2px solid var(--rule);
}
.paseo__pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100lvh;                      /* iOS collapsed-chrome safe (never 100svh) */
  overflow: hidden;
}
.paseo__track {
  display: flex;
  height: 100%;
  width: max-content;                  /* sums the panels (mix of 100vw + wide) */
  will-change: transform;
  transform: translate3d(var(--pan, 0px), 0, 0);
}
.paseo__panel {
  position: relative;                  /* containing block for the bar backdrop */
  flex: 0 0 100vw;
  height: 100%;
  display: flex;
  align-items: center;
  overflow: hidden;
  border-right: 1px solid var(--rule-soft);   /* the frame between windows */
}
/* THE SITE is a wide horizontal gallery: as wide as its content (lead + five
   full-size frames + end), so the pan tracks past the rooms like a dolly */
.paseo__panel--wide { flex: 0 0 auto; align-items: center; }
.paseo__inner {
  width: min(1180px, 90vw);
  margin: 0 auto;
  padding: clamp(3.5rem, 8vh, 6rem) clamp(1.25rem, 5vw, 4rem) clamp(7rem, 15vh, 10rem);
  box-sizing: border-box;
}
/* oversized signage hangs flush like the old .section did */
.paseo__panel .section__index,
.paseo__panel > .paseo__inner > .display {
  margin-left: calc(-1 * clamp(1.25rem, 5vw, 4rem));
}
/* neutralise the old per-section block layout now that they are panels */
.paseo .cocktails,
.paseo .lineage,
.paseo .site,
.paseo .address {
  min-height: 0; max-width: none; border: 0; text-align: left;
}

/* iii THE BAR: the smoking-dome shot is the full-bleed backdrop, copy over it */
.paseo .cocktails .cocktails__image { position: absolute; inset: 0; z-index: 0; }
.paseo .cocktails .section__index,
.paseo .cocktails .display,
.paseo .cocktails .prose {
  position: relative; z-index: 2; text-shadow: 0 2px 26px rgba(10,10,12,0.85);
}
.paseo .cocktails .prose { max-width: 42em; }

/* v THE SITE — the wide gallery. A horizontal row you pan through: the lead
   copy, then five full-size frames, then the coordinates + Maps link. The
   construction images are the point, so they are big and never collapsed. */
.paseo__inner--wide {
  width: auto; max-width: none;
  display: flex; flex-direction: row; align-items: center;
  gap: clamp(1.25rem, 4vw, 2.75rem);
  padding-left: clamp(1.25rem, 6vw, 4rem);
  padding-right: clamp(1.25rem, 6vw, 4rem);
}
.site__lead { flex: 0 0 min(82vw, 480px); }
.site__lead .prose { max-width: none; }
.site__frame { flex: 0 0 min(78vw, 460px); margin: 0; }
.site__frame img {
  width: 100%; height: min(58vh, 560px);
  object-fit: cover; background: var(--ink-2);
  filter: brightness(0.95) contrast(1.05);
}
.site__frame--plan img {
  object-fit: contain; background: var(--travertine);
  padding: clamp(0.9rem, 2vw, 1.6rem); height: min(58vh, 560px);
}
.site__frame figcaption {
  margin-top: 0.9rem; font-size: 0.78rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--travertine-dim);
}
.site__frame figcaption span {
  font-family: var(--serif); font-style: italic; color: var(--amber);
  margin-right: 0.6rem; letter-spacing: 0.2em;
}
.site__end { flex: 0 0 min(80vw, 380px); }
.site__end .meta { margin: 0 0 1.5rem; }

/* iii THE BAR fix: the copy sits at the BOTTOM (over the dome + drink), so the
   fade can be dark there for legibility and CLEAR at the top — the hand reads
   in full (was: top fade cut the top of the hand). */
.paseo__panel.cocktails { align-items: flex-end; }
.paseo .cocktails .cocktails__image img { object-position: 50% 32%; transform: scale(1.04); }
.paseo .cocktails .cocktails__image::after {
  background: linear-gradient(to top,
    rgba(10,10,12,0.95) 0%, rgba(10,10,12,0.62) 24%,
    rgba(10,10,12,0.16) 52%, rgba(10,10,12,0.04) 100%);
}

/* the road: the reverse marquee runs along the bottom of every panel */
.paseo__road {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
  margin: 0; background: var(--ink-2);
}

/* ---- fallback: reduced motion / perf-lite → today's vertical stack ---- */
@media (prefers-reduced-motion: reduce) {
  .paseo { height: auto; }
  .paseo__pin { position: static; height: auto; overflow: visible; }
  .paseo__track { flex-direction: column; width: auto; transform: none !important; }
  .paseo__panel {
    flex: none; height: auto; min-height: 78vh; border-right: 0;
    border-bottom: 1px solid var(--rule-soft);
  }
  .paseo__panel--wide { min-height: 0; }
  .paseo__inner--wide { flex-direction: column; align-items: stretch; width: auto; }
  .paseo__inner--wide .site__lead,
  .paseo__inner--wide .site__frame,
  .paseo__inner--wide .site__end { flex: none; width: 100%; }
  .paseo__inner--wide .site__frame img,
  .paseo__inner--wide .site__frame--plan img { height: auto; aspect-ratio: 4 / 3; }
  .paseo__road { position: static; }
}
.perf-lite .paseo { height: auto; }
.perf-lite .paseo__pin { position: static; height: auto; overflow: visible; }
.perf-lite .paseo__track { flex-direction: column; width: auto; transform: none !important; }
.perf-lite .paseo__panel {
  flex: none; height: auto; min-height: 78vh; border-right: 0;
  border-bottom: 1px solid var(--rule-soft);
}
.perf-lite .paseo__panel--wide { min-height: 0; }
.perf-lite .paseo__inner--wide { flex-direction: column; align-items: stretch; width: auto; }
.perf-lite .paseo__inner--wide .site__lead,
.perf-lite .paseo__inner--wide .site__frame,
.perf-lite .paseo__inner--wide .site__end { flex: none; width: 100%; }
.perf-lite .paseo__inner--wide .site__frame img,
.perf-lite .paseo__inner--wide .site__frame--plan img { height: auto; aspect-ratio: 4 / 3; }
.perf-lite .paseo__road { position: static; }

/* ---- phones: top-align (tall panels must show their heading, not centre-clip
   it) + tighter type so each window holds one screen above the road ---- */
@media (max-width: 640px) {
  /* the standard (one-screen) panels top-align + go full width; the WIDE
     gallery keeps its row layout (NOT width:100%) and stays vertically centred */
  .paseo__panel:not(.paseo__panel--wide) { align-items: flex-start; }
  .paseo__panel:not(.paseo__panel--wide) .paseo__inner {
    width: 100%; position: relative; z-index: 6;   /* lift the panel content above the road marquee */
    padding: clamp(4.25rem, 10vh, 5.5rem) clamp(1.1rem, 5vw, 1.6rem) clamp(6rem, 13vh, 7.5rem);
  }
  .paseo__inner--wide {
    position: relative; z-index: 6;
    padding-top: clamp(4.25rem, 10vh, 5.5rem);
    padding-bottom: clamp(6rem, 13vh, 7.5rem);   /* reserve the road band so the last line never hides */
    gap: clamp(1rem, 4vw, 1.75rem);
  }
  .paseo__road { opacity: 0.55; }                 /* a background ticker, not a competing line */
  .paseo__road .marquee__group { font-size: clamp(1.05rem, 4vw, 1.5rem); }
  .paseo__panel .section__index,
  .paseo__panel > .paseo__inner > .display { margin-left: 0; }
  .paseo .section__index { margin-bottom: 0.6rem; }
  /* paseo headings use the one global size now (type scale unified) */
  .paseo .prose { font-size: 0.92rem; line-height: 1.5; }
  .paseo .lineage .prose { margin-top: 1rem; }
  .paseo .lineage__list { margin-top: 1rem; }
  .paseo .lineage__list li { padding: 0.5rem 0; }
  .paseo .lineage__name { font-size: clamp(1.2rem, 5.5vw, 1.6rem); }
  .paseo .lineage__line { font-size: 0.86rem; line-height: 1.4; }
  /* the wide gallery on a phone: near-full-width lead + frames, tall images */
  .site__lead { flex-basis: 84vw; }
  .site__frame { flex-basis: 80vw; }
  .site__frame img, .site__frame--plan img { height: min(62vh, 540px); }
  .site__frame figcaption { margin-top: 0.6rem; font-size: 0.66rem; letter-spacing: 0.12em; }
  .site__end { flex-basis: 84vw; }
  .site__end .meta { margin-bottom: 1.1rem; }
  /* the address panel is the densest (long heading + two paragraphs + six
     facts): shrink its heading and tighten the facts so all six rows hold */
  .paseo #address .display { font-size: clamp(1.5rem, 6.4vw, 2.1rem); }
  .paseo #address .prose { margin-top: 0.6rem; font-size: 0.88rem; line-height: 1.45; }
  .paseo .facts { gap: 0.5rem 1.2rem; padding-top: 0.9rem; margin-top: 1.1rem; }
  .paseo .facts dt { font-size: 0.58rem; letter-spacing: 0.16em; }
  .paseo .facts dd { font-size: 0.9rem; }
  .paseo .facts > div { gap: 0.2rem; }
}

/* =========================================================
   THE RETURN (next-level Pass 3) — the ending rhymes with the open.
   On submit the page irises SHUT down to the eclipse. .return-veil is the
   masked ink (the closing iris); .return-stage is a SEPARATE unmasked layer
   on top (disc + ack + Tickets), so the content is never masked away. JS
   drives --retR (hole 150vmax -> 16vmax) then drops the mask (iOS-safe, never
   radius 0). --retIn fades the stage in over the second half.
   ========================================================= */
.return-wrap {
  position: fixed; inset: 0; z-index: 350;
  pointer-events: auto;
  opacity: 1;
}
.return-wrap.is-gone { opacity: 0; transition: opacity 0.6s var(--ease); pointer-events: none; }
.return-veil {
  position: absolute; inset: 0;
  background: var(--ink);
  -webkit-mask: radial-gradient(circle var(--retR, 150vmax) at 50% 44%, transparent 0, transparent 60%, #000 80%);
          mask: radial-gradient(circle var(--retR, 150vmax) at 50% 44%, transparent 0, transparent 60%, #000 80%);
}
.return-wrap.is-closed .return-veil { -webkit-mask: none; mask: none; }
.return-stage {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(1.1rem, 3vh, 1.8rem);
  padding: clamp(2rem, 6vw, 4rem);
  text-align: center;
  opacity: var(--retIn, 0);
}
.return-wrap.is-closed .return-stage { opacity: 1; }
/* the eclipse, the same motif the site opened on (corona rides THE MERIDIAN) */
.return-eclipse { position: relative; width: clamp(140px, 40vw, 280px); aspect-ratio: 1; }
.return-halo {
  position: absolute; left: 50%; top: 50%; width: 240%; aspect-ratio: 1;
  transform: translate(-50%, -50%); border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--solRGB, 255,214,156),0.20) 0%, rgba(var(--solRGB2, 255,180,120),0.08) 38%, transparent 64%);
  filter: blur(calc(14px + var(--solWarm, 0.5) * 12px));
  opacity: calc(0.4 + var(--solWarm, 0.5) * 0.6);
  pointer-events: none;
}
.return-orb {
  position: absolute; inset: 0; border-radius: 50%;
  background:
    radial-gradient(circle at 37% 32%, rgba(207,214,219,0.18) 0%, rgba(207,214,219,0.05) 24%, transparent 46%),
    radial-gradient(circle at 50% 55%, #1a1d22 0%, #0e1013 56%, #08090b 100%);
  box-shadow:
    0 0 1px 1px rgba(var(--solRGB, 255,214,156), calc(0.75 * var(--solRim, 0.7))),
    0 0 9px 2px rgba(var(--solRGB, 255,255,255), calc((1 - var(--solWarm, 0.5)) * 0.45)),
    0 0 26px 2px rgba(var(--solRGB2, 255,180,120), calc(0.40 * var(--solRim, 0.7))),
    0 0 90px 22px rgba(var(--solRGB2, 243,129,90), 0.16),
    inset 0 1px 34px rgba(0,0,0,0.55);
  animation: eclipseBreathe 9s ease-in-out infinite alternate;
}
.return-ack {
  margin: 0; max-width: 22em;
  font-style: italic; font-weight: 340;
  font-size: clamp(1.15rem, 5vw, 1.7rem); letter-spacing: 0.04em;
  color: var(--travertine);
}
.return-cta { margin-top: 0.4rem; }
.return-close {
  margin-top: 0.2rem; background: none; border: 0; cursor: pointer;
  font-family: var(--mono); font-weight: 500; font-size: 0.6rem;
  letter-spacing: 0.3em; text-transform: uppercase; color: var(--travertine-dim);
  min-height: 44px; padding: 0 1rem;
}
.return-close:hover { color: var(--travertine); }
@media (prefers-reduced-motion: reduce) {
  .return-orb { animation: none; }
  .return-wrap .return-veil { -webkit-mask: none; mask: none; }
  .return-wrap .return-stage { opacity: 1; }
}

/* ============================================================================
   DESKTOP + iPad ADAPTATION (2026-06-19) — fill wide LANDSCAPE screens; the phone
   (<=640px) stays byte-identical, 641-767 degrades to the fluid base.
   Tiers: iPad-portrait 768-1023; PRIMARY-WIDE 1024+ (desktop + iPad-landscape).
   Hover gated (hover:hover)+(pointer:fine). Art-directs pin DESCENDANTS ONLY —
   never transform/filter/overflow on a pin ancestor (that kills sticky).
   ============================================================================ */

/* ---- FOUNDATION: generic type (NOT .stage/.eclipse__title — sized per scene) ---- */
@media (min-width: 1024px) {
  .display { font-size: clamp(2.5rem, 7vw, 9rem); }
  .display--md { font-size: clamp(1.95rem, 4.4vw, 5rem); }
  .display--sm { font-size: clamp(1.65rem, 2.6vw, 3.1rem); }
  .lede { font-size: clamp(1.1rem, 1.5vw, 1.7rem); }
  .prose { font-size: 1.0625rem; max-width: 42em; }
  .section__index { font-size: 0.74rem; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .display { font-size: clamp(2.5rem, 8vw, 5.5rem); }
  .lede { font-size: 1.3rem; }
}

/* ---- FOUNDATION: fixed controls (THUMP dock locked, size only) + nav + loader ---- */
@media (min-width: 1024px) {
  .sound { height: 58px; padding: 0 1.6rem 0 0.6rem; min-width: 240px; }
  .gauge { right: max(1.4rem, env(safe-area-inset-right, 0px)); height: 42vh; }
  .soundmute { right: calc(env(safe-area-inset-right, 0px) + 1.4rem); width: 48px; height: 48px; }
  .nav { padding: 1.1rem clamp(2rem, 4vw, 3.5rem); }
  .nav__toggle { display: none; }
  .nav__links {
    position: static; flex-direction: row; align-items: center;
    gap: clamp(1.2rem, 2vw, 2.2rem);
    transform: none; opacity: 1; pointer-events: auto;
    background: none; backdrop-filter: none; -webkit-backdrop-filter: none; border: 0; padding: 0;
  }
  .nav__links a { display: inline; padding: 0; border-bottom: 0; font-size: 0.8rem; letter-spacing: 0.18em; }
  .loader__mark { width: clamp(150px, 18vw, 300px); }
  .loader__eq { height: 34px; }
}

/* ---- SPLASH ---- */
@media (min-width: 1024px) {
  .splash__eclipse { width: clamp(260px, 20vw, 360px); }   /* mirror mobile: a gateway disc, not a billboard (was 26vw/460) */
  .splash__mark { width: clamp(280px, 22vw, 400px); }
  .splash__content { max-width: 640px; }
  .splash__say { font-size: clamp(2.4rem, 4vw, 3.4rem); }
  .splash__cue { font-size: 0.9rem; }
  .splash { gap: clamp(2.5rem, 4vh, 3.5rem); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .splash__eclipse { width: clamp(300px, 40vw, 400px); }
  .splash__mark { width: clamp(280px, 38vw, 380px); }
  .splash__say { font-size: clamp(2.2rem, 6vw, 2.9rem); }
}

/* ---- COSMOS DESCENT + arrival-door anchor (re-aimed to landscape centre) ---- */
@media (min-width: 1024px) {
  .cosmos__galaxy { background-size: cover; transform-origin: 55% 42%; }
  .cosmos__earth { background-size: cover; transform-origin: 45% 46%; }
  .cosmos__arrival-door {
    background-position: 50% 50%;
    -webkit-mask: radial-gradient(circle calc(var(--arrive, 0) * var(--arrive, 0) * 170vmax) at 50% 50%, #000 0 72%, transparent 100%);
            mask: radial-gradient(circle calc(var(--arrive, 0) * var(--arrive, 0) * 170vmax) at 50% 50%, #000 0 72%, transparent 100%);
  }
  .cosmos__spark { left: 50%; top: 50%; }
  .cosmos__line { font-size: clamp(3rem, 4.5vw, 5rem); max-width: 18ch; }
  .cosmos__content { padding: clamp(6rem, 12vh, 9rem) clamp(3rem, 6vw, 6rem) clamp(3rem, 6vh, 4rem); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .cosmos__arrival-door { background-position: 52% 54%; }
  .cosmos__line { font-size: clamp(2.4rem, 5.5vw, 3.8rem); }
}

/* ---- ENTRANCE corona anchor (MUST match the cosmos door anchor above) ---- */
@media (min-width: 1024px) {
  .entrance.is-walk .entrance__pin::after { left: 50%; top: 50%; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .entrance.is-walk .entrance__pin::after { left: 52%; top: 54%; }
}

/* ---- STAGE scrub images (corridor base / booth / room) ---- */
@media (min-width: 1024px) {
  .stage.is-scrub .stage__room img { transform: scale(1.02); object-position: center 50%; filter: brightness(calc(1.28 - var(--descend, 0) * 0.62)) contrast(1.06); }
  .stage.is-scrub .stage__room img.stage__img--room { object-position: 24% 48%; transform: scale(calc(1.02 + var(--roomHold, 0) * 0.06)); }   /* mirror mobile: hard-left so the Eclipse altar anchors the frame (was 32%) */
  .stage.is-scrub .stage__room img.stage__img--booth { transform: scale(calc(1.06 + var(--boothHold, 0) * 0.10)); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .stage.is-scrub .stage__room img { transform: scale(1.06); object-position: center 46%; filter: brightness(calc(1.30 - var(--descend, 0) * 0.62)) contrast(1.06); }
  .stage.is-scrub .stage__room img.stage__img--room { object-position: 28% 48%; transform: scale(calc(1.05 + var(--roomHold, 0) * 0.08)); }
  .stage.is-scrub .stage__room img.stage__img--booth { transform: scale(calc(1.10 + var(--boothHold, 0) * 0.10)); }
}

/* ---- STAGE text panels — MIRROR MOBILE: centred text over the images (the
   left-editorial desktop split was reverted 2026-06-22; only type sizes + a
   centred max-width remain so copy doesn't span a 1440px line edge-to-edge) ---- */
@media (min-width: 1024px) {
  .stage__arrive, .stage__eclipse { max-width: min(46rem, 62vw); margin-left: auto; margin-right: auto; }
  .stage__title { font-size: clamp(5rem, 9vw, 9.5rem); }
  .display.eclipse__title { max-width: 24ch; margin-left: auto; margin-right: auto; font-size: clamp(2.6rem, 4vw, 4.4rem); }
  .display.stage__welcome { max-width: 20ch; margin-left: auto; margin-right: auto; font-size: clamp(2.8rem, 4.4vw, 4.8rem); }
  .eclipse__sub { max-width: 42ch; margin-left: auto; margin-right: auto; font-size: clamp(1.1rem, 1.6vw, 1.6rem); }
  .stage__found { font-size: clamp(1.5rem, 2.2vw, 2.4rem); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .stage__title { font-size: clamp(4rem, 11vw, 7rem); }
  .display.eclipse__title { max-width: 20ch; font-size: clamp(2.2rem, 5vw, 3.4rem); }
  .stage__welcome { max-width: 18ch; }
}

/* ---- THESIS — MIRROR MOBILE: one centred single column (the 2-col grid was
   reverted 2026-06-22; only the heading size bump remains) ---- */
@media (min-width: 1024px) {
  .thesis .display--md { font-size: clamp(2.6rem, 4.2vw, 5.2rem); line-height: 1.0; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .thesis .prose { max-width: 40em; }
  .thesis .display--md { font-size: clamp(2.3rem, 5vw, 3.4rem); }
}

/* ---- THE DECK — MIRROR MOBILE: full-bleed cards with bottom-left copy (the
   left-sidebar split — border-left + narrowed body — was reverted 2026-06-22;
   the body inherits the mobile 42rem, bottom-aligned via base .expr). Only type
   sizes + a 2-col menu (mobile) remain. ---- */
@media (min-width: 1024px) {
  .expr .display--sm { font-size: clamp(2.2rem, 3.2vw, 3.4rem); }
  .expr .prose { font-size: 1.05rem; max-width: 40em; }
  .expr__roman { font-size: 1.25rem; }
  .expr__caption { font-size: clamp(1.6rem, 2.4vw, 2.4rem); line-height: 1.28; }
  .menu { padding: clamp(5rem, 9vh, 7.5rem) clamp(2rem, 5vw, 4rem); }
  .menu > * { max-width: 1400px; margin-left: auto; margin-right: auto; }
  .menu__cols { column-count: 2; column-gap: clamp(2.5rem, 4vw, 4.5rem); }
  .menu__title { font-size: clamp(2.2rem, 3vw, 3.2rem); }
  .menu .prose { max-width: 46em; }
}
@media (min-width: 1024px) and (hover: hover) {
  .menu__group-summary:hover .menu__group-title span { opacity: 1; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .expr__body { max-width: 40rem; }
  .expr__body--caption { max-width: 38rem; }
  .menu__cols { column-count: 2; }
  .menu__title { font-size: clamp(1.9rem, 4vw, 2.6rem); }
}

/* ---- PASEO (lateral track) + LINEAGE ---- */
@media (min-width: 1024px) {
  .paseo__panel:not(.paseo__panel--wide) { align-items: center; }
  .paseo__panel:not(.paseo__panel--wide) .paseo__inner { width: min(46rem, 52vw); margin: 0; padding-left: clamp(3rem, 8vw, 7rem); padding-right: clamp(2rem, 5vw, 4rem); position: relative; z-index: 6; padding-bottom: clamp(7rem, 16vh, 11rem); }
  .paseo .display--md { font-size: clamp(2.4rem, 4.2vw, 4.2rem); }
  .paseo .cocktails { align-items: flex-end; }
  .paseo .cocktails .cocktails__image img { object-position: 50% 42%; transform: scale(1.06); }
  .paseo .cocktails .cocktails__image::after { background: linear-gradient(to top, rgba(10,10,12,0.92) 0%, rgba(10,10,12,0.5) 34%, rgba(10,10,12,0.08) 66%, transparent 100%); }
  .paseo__road { opacity: 0.6; }
  .paseo__road .marquee__group { font-size: clamp(1.6rem, 2.4vw, 2.4rem); }
  .paseo__panel.lineage .paseo__inner { width: min(64rem, 72vw); }
  .lineage__list { display: grid; grid-template-columns: 1fr 1fr; column-gap: clamp(3rem, 6vw, 6rem); }
  .lineage__list li { grid-template-columns: auto 1fr; column-gap: clamp(1.5rem, 3vw, 2.5rem); }
  .lineage__name { font-size: clamp(2rem, 2.6vw, 2.8rem); }
}
@media (min-width: 1024px) and (hover: hover) and (pointer: fine) {
  .lineage__list li:hover .lineage__name { color: var(--travertine); }
  .lineage__list li:hover { border-top-color: var(--rule); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .paseo__panel:not(.paseo__panel--wide) { align-items: flex-start; }
  .paseo__panel:not(.paseo__panel--wide) .paseo__inner { width: 100%; position: relative; z-index: 6; padding: clamp(5rem, 11vh, 7rem) clamp(2rem, 6vw, 4rem) clamp(7rem, 15vh, 9rem); }
  .paseo__road { opacity: 0.55; }
  .paseo__panel.lineage .lineage__list { display: block; }
}

/* ---- BITES tray ---- */
@media (min-width: 1024px) {
  .bites-stage.is-track .bite { width: clamp(360px, 26vw, 460px); }
  .bites-stage.is-track .bite-row { gap: clamp(2rem, 3vw, 3.5rem); }
  .bites-stage.is-track .bites__head { max-width: 1280px; margin: 0 auto; padding: 0 clamp(2rem, 5vw, 4rem); }
  .bites .display--md { font-size: clamp(2.4rem, 3.6vw, 4.4rem); }
  .bites-stage.is-track .bite figcaption { font-size: 0.85rem; margin-top: 1.1rem; }
}
@media (hover: hover) and (pointer: fine) {
  .bite img { transition: filter 0.4s ease; }
  .bite:hover img { filter: brightness(1.08) contrast(1.06); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .bites-stage.is-track .bite { width: clamp(300px, 40vw, 360px); }
}

/* ---- MARQUEE signage ---- */
@media (min-width: 1024px) {
  .marquee__group { font-size: clamp(2.4rem, 3.4vw, 4.2rem); }
  .marquee { padding: clamp(1.6rem, 3.2vh, 2.6rem) 0; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .marquee__group { font-size: clamp(2rem, 4.4vw, 3.4rem); }
}

/* ---- CONTACT + FOOTER — MIRROR MOBILE: one stacked, left-aligned column
   (the copy-left / form-right split was reverted 2026-06-22; the form sits
   below the reading column, left-aligned, like the phone) ---- */
@media (min-width: 1024px) {
  .contact__media img { object-position: center 42%; transform: scale(1.06); }
  .contact > .section__index, .contact > .display, .contact > .prose { max-width: 40rem; }
  .contact > .prose { font-size: 1.05rem; line-height: 1.6; }
  .contact .display--md { font-size: clamp(3rem, 5.6vw, 5.2rem); }
  .enquire { max-width: 600px; margin-top: 2.5rem; }
  .foot { padding: 3.5rem clamp(2rem, 6vw, 5rem) calc(3.5rem + env(safe-area-inset-bottom, 0px)); font-size: 0.82rem; gap: 1.6rem; }
  .foot__fine { font-size: 0.72rem; }
}
@media (min-width: 1024px) and (hover: hover) and (pointer: fine) {
  .enquire input:hover, .enquire select:hover { border-bottom-color: var(--travertine-dim); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .contact__media img { object-position: center 50%; transform: scale(1.09); }
  .enquire { max-width: 640px; margin-left: 0; }
  .contact > .prose { max-width: 46ch; }
}

/* =========================================================
   MOBILE COMPOSITE RELIEF (2026-06-22) — backdrop-filter on
   moving/fixed layers is a per-frame framebuffer blur that janks
   the compositor (worst on Android Chrome; the codebase already
   bans it on fixed mobile elements per the .nav/.soundmute note —
   these three were leftovers). Drop it on COARSE pointers; near-
   solid backgrounds carry the look. NB coarse = iPhone too, so this
   also lightens the phone — the descent disc loses its blur "warp"
   (kept as a faint dim ring); owner to confirm the iPhone descent.
   ========================================================= */
@media (pointer: coarse) {
  .nav__links { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(10,10,12,0.985); }
  .kaoss::before { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(6,7,8,0.95); }
  .cosmos__disc__lens { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(0,0,0,0.16); }
}

/* =========================================================
   POWER UP (2026-06-22) — a bar over the pad while the heavy
   loops decode, so the instrument opens ready instead of
   janking mid-play (built for Android/5G). Blocks the pad only
   while loading; fades out the instant it's warm.
   ========================================================= */
.kaoss__power {
  position: absolute; z-index: 30;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.95rem;
  background: rgba(6,7,8,0.92);
  border-radius: 12px;
  transition: opacity 0.34s ease;
}
.kaoss__power.is-done { opacity: 0; pointer-events: none; }
.kaoss__power-mark {
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.34em; text-transform: uppercase;
  color: var(--travertine-dim);
}
.kaoss__power-track {
  width: 58%; max-width: 220px; height: 3px; border-radius: 3px;
  background: rgba(228,231,234,0.14); overflow: hidden;
}
.kaoss__power-track i {
  display: block; height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--mirror, #cfd6db), #eef1f3);
  box-shadow: 0 0 8px rgba(207,214,219,0.5);
  transition: width 0.3s ease;
}

/* =========================================================
   PERF-ULTRA — the BUDGET tier (2026-06-23, set at boot by the
   device probe for data-tier=budget: low-RAM / 2G / saveData
   Androids). It INCLUDES .perf-lite and ALSO cuts the costs the
   descent pays every frame WITHOUT breaking the picture: freeze
   ambient animations, drop the per-frame image filter, and clamp
   the descent so there are simply fewer heavy frames to render.
   The cosmos mix-blend-mode:screen is LOAD-BEARING (it composites
   the layers transparently) so it STAYS. Budget-gated only — the
   iPhone is 'flagship' and never matches any of this.
   ========================================================= */
.perf-ultra .cosmos__disc__orb,
.perf-ultra .cosmos__disc__lens,
.perf-ultra .cosmos__sun,
.perf-ultra .splash__orb,
.perf-ultra .splash__halo,
.perf-ultra .eclipse__orb { animation: none !important; }
.perf-ultra .stage.is-scrub .stage__room img { filter: none !important; }   /* skip the per-frame brightness/contrast recalc */
.perf-ultra .cosmos.is-live { height: 700vh !important; }                    /* a shorter descent = fewer heavy frames + faster to the lighter content (budget only) */
