/* ============================================================
   CONSTANTS (kit: child-of-the-mountain; lineages cinematic + warm)
   One source for colour, type, space and motion. Motion values are
   mirrored once in js/main.js (M), which owns the timed ones.
   ============================================================ */
:root {
  /* colour: sampled from their own photographs (kit.tokens.color) */
  --bg: #120C0B;            /* the dark around the candle ring, warmed */
  --surface: #1C1413;
  --surface-2: #271B19;
  --ink: #EFE6DA;           /* their white robes under warm light */
  --muted: #B3A597;
  --line: rgb(239 230 218 / 0.16);
  --accent: #E8A33D;        /* sunset gold (round 4): the sun in their film, the candle flames: fills, underlines, the meter */
  --accent-hi: #F2B75A;
  --accent-ink: #1A0F0D;
  --day-sky: #DCE3F2;       /* Haleakala sky, for the one daylight room */
  --day-earth: #543026;     /* its red cinder */
  --scrim-rgb: 18 12 11;    /* = --bg, so shadow falls into the page ground */

  /* type: round 3 gives every section title display size, so the statement is no longer the only voice */
  --serif: "EB Garamond", Garamond, "Times New Roman", serif;
  --mono: "DM Mono", ui-monospace, Menlo, Consolas, monospace;
  --t-label: 0.75rem;                                        /* 12px mono, the machine */
  --t-mono: 0.875rem;                                        /* 14px mono values */
  --t-body: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);       /* kit body */
  --t-lead: clamp(1.1875rem, 1.05rem + 0.55vw, 1.5rem);
  --t-h3: clamp(1.5rem, 1.2rem + 1vw, 2.125rem);
  --t-h2: clamp(2rem, 1.4rem + 2vw, 3.25rem);                /* now the sub-title size (Send an inquiry) */
  --t-display: clamp(3.5rem, 8vw, 8.25rem);                  /* section titles: 56 to 132 px */
  --t-song: clamp(2.25rem, 6.5vw, 6.5rem);                   /* the set list: song titles, italic */
  --t-numeral: clamp(2.5rem, 1.5rem + 2.5vw, 4rem);          /* I, II, III on the set panels */
  --t-statement: clamp(3rem, 0.6rem + 7.4vw, 8.5rem);        /* the one huge line */

  /* space: one 8px root; micro fixed, macro carries the viewport */
  --s1: 8px; --s2: 16px; --s3: 24px; --s4: 32px; --s5: 40px; --s6: 48px; --s8: 64px; --s12: 96px;
  --section: clamp(72px, 40px + 6vw, 144px);                 /* the one breath, before the statement */
  --pad: clamp(40px, 24px + 4vw, 88px);                      /* the cut rhythm: half a section everywhere else */
  --t-fests: clamp(2rem, 0.8rem + 4.4vw, 5.25rem);           /* Played at: two drifting rows, the booker proof */
  --gutter: clamp(16px, 4.1vw, 56px);
  --nav-h: 72px;
  --foot-pad: clamp(32px, 6svh, 64px);
  --logo-w: clamp(240px, 21vw, 340px);   /* clears the right-hand player's head in every frame of the film */

  /* the act: the sky pins ~1.3 viewports, then the candle stage holds while it opens */
  --sky-run: 130svh;
  --hold: 70svh;
  --live-overlap: 12svh;                 /* the festival row starts on the stage's own dark floor */
  /* the second pin: the rig scene holds one viewport while its title card arrives */
  --rig-run: 100svh;
  --clip-h: 78svh;                       /* Watch, a static centred row (round 4 fix): each clip this tall */

  /* motion */
  --ease-open: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-settle: cubic-bezier(0.37, 0, 0.63, 1);   /* kit eases.settle: the eclipse light travels its arc evenly */
  --dur-fb: 160ms;                       /* feedback: hover, press, focus */
  --dur-beat: 700ms;
  --dur-open: 1400ms;                    /* a scene opening (mirrors M.DUR_OPEN) */
  --dur-dark: 250ms;                     /* the beat of dark (mirrors M.DUR_DARK) */
  --dur-grain: 333ms;                    /* 8 grain frames at 24 fps */
  --dur-eclipse: 1600ms;                 /* the eclipse opening on first load */
}
@media (max-aspect-ratio: 799/1000) {
  /* the tall film has a deep sky: the name floats mid-sky; the foot lifts to clear the film control */
  :root { --nav-h: 64px; --logo-w: min(72vw, 340px); --foot-pad: 72px; --title-drop: 6svh; }
}
@media (max-aspect-ratio: 5/4) {
  /* a narrow screen cannot hold both women full-bleed: the candle print shows whole, under the nav */
  :root {
    --print-top: calc(var(--nav-h) + env(safe-area-inset-top) + var(--s1));
    --hold: 0svh;                        /* the live text arrives with the flame, right under the print */
    --live-overlap: calc(100svh - var(--print-top) - 100vw / 1.4984 - var(--s3));
  }
}
@media (max-aspect-ratio: 799/1000) {
  /* phones: the cut comes right after the name has gone (no screen of empty sky), and the candle stage holds
     while it ignites, so a flick never carries the flame off screen before it is lit; the live text rises
     into place under it during the hold */
  :root { --sky-run: 75svh; --hold: 40svh; }
}

/* ============================================================
   BASE
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html { background: var(--bg); color: var(--ink); -webkit-text-size-adjust: 100%; }
html.lenis-smooth { scroll-behavior: auto; }
body {
  margin: 0;
  font: 400 var(--t-body)/1.55 var(--serif);
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
img, video { display: block; max-width: 100%; }
a { color: inherit; }
h1, h2, h3 { font-weight: 400; }
h2 { margin: 0; font-size: var(--t-display); line-height: 0.88; letter-spacing: -0.025em; text-wrap: balance; }
p { text-wrap: pretty; }
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }
/* gold fills carry dark ink, so currentColor would vanish on the page: a two-tone ring reads on any ground */
.btn--primary:focus-visible, .skip:focus-visible {
  outline: 2px solid transparent; outline-offset: 2px;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--ink);
}
.nowrap { white-space: nowrap; }
.grid {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--s3);
}
/* the machine voice (kit: DM Mono for labels, set specs, controls): one rule */
.skip, .btn, .textlink, .nav__link, .sound, .film-toggle, .track__play, .track__link, .platforms a,
.clip__ctl button, .band__photo figcaption {
  font: 400 var(--t-label)/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
}
.skip {
  position: fixed; left: var(--gutter); top: -80px; z-index: 200;
  padding: 12px var(--s2); background: var(--accent); color: var(--accent-ink);
  text-decoration: none;
}
.skip:focus { top: var(--s2); }

/* their logo as a mask, so it takes any ink; the name is never typeset */
.logo {
  display: block;
  aspect-ratio: 1420 / 888;
  background-color: currentColor;
  -webkit-mask: url(../media/logo-solid.svg) center / contain no-repeat;
          mask: url(../media/logo-solid.svg) center / contain no-repeat;
}
/* The whole logo, as drawn: their lettering (SVG, crisp) over the crescent from their own files, in the
   same 1420x888 frame (content-originals/typography-2026: BLACK V1 shading on the sky, WHITE V1 lit rim on
   dark). The glow is that same rim, blurred: it swells with the sub. No other shapes. */
.eclipse { position: relative; display: block; aspect-ratio: 1420 / 888; }
.eclipse > * { position: absolute; inset: 0; }
.eclipse__shade { background: url(../media/logo-crescent-night.webp) center / contain no-repeat; }
.eclipse__glow { background: url(../media/logo-crescent-glow.webp) center / contain no-repeat; opacity: 0; }
.eclipse--hero .eclipse__shade,
.nav[data-ground="sky"] .eclipse__shade,
.nav[data-ground="day"] .eclipse__shade { background-image: url(../media/logo-crescent-sky.webp); }
/* first load: the eclipse opens, its light travelling its own arc (centre of their crescent's circle) */
@property --sweep { syntax: "<angle>"; inherits: false; initial-value: 360deg; }
.motion .eclipse--hero .eclipse__shade,
.motion .eclipse--hero .eclipse__glow {
  -webkit-mask-image: conic-gradient(from 265deg at 50.7% 65.9%, #000 0deg, #000 var(--sweep), transparent calc(var(--sweep) + 28deg));
          mask-image: conic-gradient(from 265deg at 50.7% 65.9%, #000 0deg, #000 var(--sweep), transparent calc(var(--sweep) + 28deg));
  animation: eclipse-open var(--dur-eclipse) var(--ease-settle) both;
}
.motion .eclipse--hero .eclipse__glow { animation: eclipse-open var(--dur-eclipse) var(--ease-settle) both, eclipse-light calc(var(--dur-eclipse) * 1.4) var(--ease-open) both; }
@keyframes eclipse-open { from { --sweep: 0deg; } to { --sweep: 360deg; } }
@keyframes eclipse-light { 0% { opacity: 0; } 40% { opacity: 0.9; } 100% { opacity: 0; } }

/* ============================================================
   LAYERS: the WebGL stage sits under the page; grain over everything
   ============================================================ */
.gl { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; display: none; }
/* the journey in light (Sarah: from the clouds down to the fire and back up): their photo palette spilling in
   from the side edges only, behind everything; the photos stay the light sources */
.journey {
  position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  opacity: calc(var(--journey-a, 0.24) * 1.9);   /* the glows fade to nothing at their rims, so the core carries ~2x the old flat wash (the song lines hold 4.5:1 over it) */
  -webkit-mask-image: linear-gradient(to right, #000, transparent 30%, transparent 70%, #000);
          mask-image: linear-gradient(to right, #000, transparent 30%, transparent 70%, #000);
}
/* a screen without WebGL (a managed phone's policy, an old GPU) still gets the renderer's light: two soft glows in
   opposite corners, in the scroll's colour, that drift and breathe (on a slow 8-beat swell of their ~85 bpm) */
.journey::before, .journey::after {
  content: ""; position: absolute; width: 100vmax; height: 100vmax; border-radius: 50%;
  background: radial-gradient(closest-side, rgb(var(--journey, 217 149 90)), rgb(var(--journey, 217 149 90) / 0.5) 45%, transparent);
}
.journey::before { left: -50vmax; bottom: -50vmax; }
.journey::after { right: -50vmax; top: -50vmax; }
.motion .journey::before { animation: journey-drift-a 23s ease-in-out infinite alternate, journey-breath 5.65s ease-in-out infinite alternate; }
.motion .journey::after { animation: journey-drift-b 31s ease-in-out infinite alternate, journey-breath 5.65s ease-in-out -2.8s infinite alternate; }
@keyframes journey-drift-a { to { transform: translate(10vw, -16vh) scale(1.15); } }
@keyframes journey-drift-b { to { transform: translate(-12vw, 14vh) scale(0.88); } }
@keyframes journey-breath { from { opacity: 0.7; } to { opacity: 1; } }
@media (max-width: 699px) {
  /* phones have no side margin: the glows reach halfway in, like the renderer's phone light */
  .journey {
    -webkit-mask-image: linear-gradient(to right, #000, transparent 50%, #000);
            mask-image: linear-gradient(to right, #000, transparent 50%, #000);
  }
}
/* the third cut's overexposure over the whole screen (see the band room) */
.bloom { position: fixed; inset: 0; z-index: 80; pointer-events: none; background: #F4F6FB; opacity: 0; }
.gl-on .gl { display: block; }
main, .foot { position: relative; z-index: 1; }
.grain {
  position: fixed; inset: -96px; z-index: 90; pointer-events: none;
  background-size: 192px 192px;
  mix-blend-mode: overlay;
  opacity: 0.05;
  animation: grain var(--dur-grain) steps(1, end) infinite;   /* 24 fps, stepped like film */
}
@keyframes grain {
  0% { transform: translate(0, 0); }
  12.5% { transform: translate(-37px, 22px); }
  25% { transform: translate(51px, -64px); }
  37.5% { transform: translate(-80px, -12px); }
  50% { transform: translate(18px, 71px); }
  62.5% { transform: translate(-58px, 43px); }
  75% { transform: translate(77px, 9px); }
  87.5% { transform: translate(-6px, -83px); }
}

/* ============================================================
   CONTROLS (feedback on its own 160 ms clock)
   ============================================================ */
.btn, .nav__link, .film-toggle, .sound, .textlink, .track__play, .clip__ctl button {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 var(--s3);
  text-decoration: none; white-space: nowrap;
  border: 1px solid transparent; border-radius: 0; cursor: pointer;
  transition: background-color var(--dur-fb) ease-out, border-color var(--dur-fb) ease-out,
              color var(--dur-fb) ease-out, transform var(--dur-fb) ease-out;
}
.btn:active { transform: scale(0.97); }
.btn:disabled { cursor: progress; opacity: 0.72; }
.btn--primary { background: var(--accent); color: var(--accent-ink); }
.btn--ghost { background: transparent; color: var(--ink); border-color: rgb(239 230 218 / 0.55); }
.btn--sm { min-height: 40px; padding: 0 var(--s2); }
.textlink {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0;
  background: none; border: 0; cursor: pointer; color: inherit;
  text-decoration: underline; text-decoration-color: var(--accent);
  text-underline-position: from-font; text-decoration-thickness: from-font; text-underline-offset: 6px;
  transition: text-decoration-color var(--dur-fb) ease-out, opacity var(--dur-fb) ease-out;
}
.textlink:active { opacity: 0.7; }
@media (hover: hover) {
  .btn--primary:hover { background: var(--accent-hi); }
  .btn--ghost:hover { border-color: var(--ink); background: rgb(239 230 218 / 0.08); }
  .nav__link:hover { text-decoration-color: currentColor; }
  .film-toggle:hover, .sound:hover { opacity: 0.8; }
  .textlink:hover { text-decoration-color: currentColor; }
}

/* the meter: voice-wave-indicator adapted: 2px bars in sunset gold, driven by the analyser */
.meter { display: inline-flex; align-items: center; gap: 2px; height: 14px; }
.meter i {
  display: block; width: 2px; height: 14px; background: currentColor;
  transform: scaleY(0.3); transform-origin: 50% 50%;
}
.meter i:nth-child(2) { transform: scaleY(0.72); }
.meter i:nth-child(3) { transform: scaleY(0.45); }
.meter i:nth-child(4) { transform: scaleY(0.6); }

/* ============================================================
   NAV (logo left; Sound, Listen, Watch, Book right)
   Its ink and bar follow what is under it: sky, stage, dark, day.
   ============================================================ */
.nav {
  --nav-ink: var(--ink);
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  height: calc(var(--nav-h) + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) calc(var(--gutter) + env(safe-area-inset-right)) 0 calc(var(--gutter) + env(safe-area-inset-left));
  display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  color: var(--nav-ink);
  background: transparent;
  transition: background-color var(--dur-fb) ease-out;
  pointer-events: none;
}
.nav > * { pointer-events: auto; }
.nav[data-ground="sky"] { --nav-ink: var(--bg); }        /* backlit by their sunset, like the harps */
.nav[data-ground="dark"], .nav[data-ground="stage"] { background: var(--bg); }
/* over the candle stage the bar softens into the photo instead of ending on a hard line */
.nav[data-ground="stage"]::after {
  content: ""; position: absolute; inset: 100% 0 auto 0; height: var(--s5); pointer-events: none;
  background: linear-gradient(to bottom, rgb(var(--scrim-rgb) / 1), rgb(var(--scrim-rgb) / 0));
}
.nav[data-ground="day"] { --nav-ink: var(--bg); background: var(--day-sky); }
.nav__logo { display: block; width: 88px; color: var(--nav-ink); visibility: hidden; }
.nav:not([data-ground="sky"]) .nav__logo { visibility: visible; }
.nav__logo .eclipse { color: var(--nav-ink); }
.nav__logo .logo { color: var(--nav-ink); }
.nav__right { display: flex; align-items: center; gap: var(--s2); }
.nav__links { display: flex; align-items: center; gap: var(--s1); margin: 0; padding: 0; list-style: none; }
.nav__link {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 var(--s1);
  color: var(--nav-ink);
  text-decoration: underline; text-decoration-color: transparent;
  text-underline-position: from-font; text-decoration-thickness: from-font; text-underline-offset: 6px;
  transition: text-decoration-color var(--dur-fb) ease-out;
}
.nav__links li:last-child { margin-left: var(--s1); }
.sound {
  display: inline-flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 0 var(--s1);
  background: none; border: 0; cursor: pointer;
  color: var(--nav-ink);
  transition: opacity var(--dur-fb) ease-out;
}
.sound .meter { color: currentColor; opacity: 0.7; }
.sound.is-on .meter { color: var(--accent); opacity: 1; }
.sound__title:empty { display: none; }
.sound[hidden] { display: none; }   /* round 5: it steps aside while the player is docked (one control at a time) */
.sound__title {
  font: italic 400 1rem/1 var(--serif); letter-spacing: 0; text-transform: none;
  max-width: 11ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sound:active { opacity: 0.6; }

/* ============================================================
   1. THE ACT. Still (no JS or reduced motion): two frames stacked.
   Motion: one sticky stage, the sky over a scroll run, then the cut.
   ============================================================ */
.act { position: relative; }
.act__stage { position: relative; }
.scene { position: relative; }
.scene--sky { height: 100svh; overflow: hidden; }
.act__run { display: none; }

.motion .act__stage { position: sticky; top: 0; height: 100svh; overflow: hidden; }
.motion .scene { position: absolute; inset: 0; visibility: hidden; }
.motion[data-scene="sky"] .scene--sky,
.motion[data-scene="night"] .scene--night { visibility: visible; }
.motion .act__run { display: block; position: relative; height: calc(var(--sky-run) + var(--hold)); }
.act__cut { position: absolute; left: 0; top: calc(var(--sky-run) - 100svh); width: 1px; height: 1px; }

/* --- scene 1: above the clouds (their film) --- */
.scene__frame { position: absolute; inset: 0; transform-origin: 50% 45%; }
.scene__media { position: absolute; inset: 0; transform-origin: 50% 45%; }
.scene__frame.is-gl .scene__media { opacity: 0; }       /* the renderer draws the film during the tape stop */
.scene__poster, .scene__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 0%;   /* keep the sky: it holds their name */
}
.scene__video { opacity: 0; }
.scene--sky.is-playing .scene__video { opacity: 1; }   /* swap on the first frame, no fade */
@media (max-aspect-ratio: 799/1000) {
  .scene__poster, .scene__video { object-position: 50% 75%; }
}
/* the ridge already falls into shadow here; the scrim continues it (sibling of the copy) */
.hero__scrim {
  position: absolute; inset: auto 0 0 0; height: 44%;
  background: linear-gradient(to bottom,
    rgb(var(--scrim-rgb) / 0) 0%, rgb(var(--scrim-rgb) / 0.5) 38%,
    rgb(var(--scrim-rgb) / 0.8) 70%, rgb(var(--scrim-rgb) / 0.9) 100%);
  pointer-events: none;
}
.hero {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  text-align: center;
  padding: calc(env(safe-area-inset-top) + var(--nav-h)) var(--gutter) calc(env(safe-area-inset-bottom) + var(--foot-pad));
}
.hero__title { margin: var(--title-drop, 0) 0 0; line-height: 1; }
.hero__logo { width: var(--logo-w); color: var(--bg); }    /* a dark silhouette in their sky */
.hero__foot { display: flex; flex-direction: column; align-items: center; gap: var(--s4); }
.hero__line {
  margin: 0; max-width: 29ch;
  font-size: var(--t-lead); line-height: 1.3;
  color: var(--ink); text-wrap: balance;
}
.hero__ctas { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 12px; }
.hero__play {
  display: inline-flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 var(--s2);
  background: none; border: 0; cursor: pointer; color: var(--ink);
  font: 400 var(--t-label)/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
  text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 6px;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation; user-select: none;
  transition: opacity var(--dur-fb) ease-out;
}
.hero__play .meter { color: var(--accent); }
.hero__play:active { opacity: 0.6; }
@media (hover: hover) { .hero__play:hover { text-decoration-color: currentColor; } }
.film-toggle {
  position: absolute;
  right: calc(var(--gutter) + env(safe-area-inset-right));
  bottom: calc(env(safe-area-inset-bottom) + var(--s2));
  min-height: 44px; min-width: 44px; padding: 0 var(--s1); margin-right: calc(var(--s1) * -1);
  background: none; border: 0; border-radius: 0; cursor: pointer;
  color: var(--muted);
  transition: opacity var(--dur-fb) ease-out;
}
.film-toggle:active { opacity: 0.6; }

/* --- scene 2: the candle stage, frameless (lane 1's compositing) ---
   lighten floors every pixel darker than #120C0B at #120C0B, so their stage
   melts into the page; the edges dissolve; nothing else touches the photo. */
.print { position: relative; margin: 0; overflow: hidden; background: var(--bg); }
.print img { width: 100%; height: 100%; object-fit: cover; mix-blend-mode: lighten; }
.print.is-gl { background: transparent; }
.print.is-gl img { opacity: 0; }                  /* the renderer owns this print */
.print--candle img {
  object-position: 50% 100%;                       /* keep the dark stage floor: the copy sits on it */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent),
                      linear-gradient(to bottom, #000 86%, transparent);
  -webkit-mask-composite: source-in;
          mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent),
                      linear-gradient(to bottom, #000 86%, transparent);
          mask-composite: intersect;
}
.motion .print--candle { position: absolute; inset: 0; }
/* very wide screens crop more off the top: anchor a little higher so both heads clear the nav bar */
@media (min-aspect-ratio: 17/10) { .print--candle img { object-position: 50% 80%; } }
.still .print--candle, html:not(.js) .print--candle {
  width: min(100%, 100svh * 1.4984); aspect-ratio: 1927 / 1286; margin-inline: auto;
}
/* the rig and listen prints get the same feathered edge, so they sit in the dark instead of looking pasted in */
.print--rig img, .print--listen img {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent),
                      linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-composite: source-in;
          mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent),
                      linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
          mask-composite: intersect;
}
@media (max-aspect-ratio: 5/4) {
  .motion .print--candle { inset: var(--print-top) 0 auto 0; aspect-ratio: 1927 / 1286; }
  .print--candle img {
    object-position: 50% 50%;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent),
                        linear-gradient(to bottom, transparent, #000 8%, #000 90%, transparent);
            mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent),
                        linear-gradient(to bottom, transparent, #000 8%, #000 90%, transparent);
  }
}


/* ============================================================
   THE CUT RHYTHM (below the act), round 3
   No two neighbouring sections share a composition:
   drifting credits / one huge line / a pinned full-bleed scene /
   a set list over a dimmed plate / a static centred reel / a centred
   daylight room / three panels and a wide form / the sunset again.
   "Wide" = (min-width: 900px) and (min-aspect-ratio: 5/4): only a
   landscape screen can hold both women whole in a full-bleed crop.
   ============================================================ */

/* round 4: no section slates; the display titles carry the wayfinding */
.num { font-variant-numeric: tabular-nums; }
/* a title that rises out of its own baseline (scrubbed in the rig scene) */
.rise { display: block; overflow: clip; padding-bottom: 0.24em; margin-bottom: -0.24em; }   /* room for a descender (Healy) while it rises */
.rise > span { display: block; }

/* ============================================================
   2. THE LIVE SET: Played at as two drifting rows, then who they are
   ============================================================ */
.live { position: relative; padding: var(--s6) 0 0; overflow-x: clip; }   /* the rows are wider than the screen */
.motion .live {
  margin-top: calc(var(--live-overlap) * -1); padding-top: 0;
  transition: opacity var(--dur-open) var(--ease-open) var(--dur-dark);   /* arrives with the flame */
}
.motion[data-scene="sky"] .live { opacity: 0; visibility: hidden; transition: none; }
.played { padding: 0 var(--gutter); }
.fests { font: 400 var(--t-fests)/1.08 var(--serif); letter-spacing: -0.015em; }
.fests__row { display: flex; width: max-content; margin: 0; padding: 0; list-style: none; white-space: nowrap; }
.fests li { color: var(--ink); transition: color var(--dur-beat) var(--ease-open); }
.fests li:not(:last-child)::after { content: "\00B7"; margin: 0 0.32em; color: var(--muted); }
/* while their music plays, one festival lifts to ink per kick */
.fests.is-listening li { color: var(--muted); }
.fests.is-listening li.is-lit { color: var(--ink); transition-duration: var(--dur-fb); }
/* no drift (reduced motion, no JS): the rows wrap, every name always in view */
.still .fests__row, html:not(.js) .fests__row { flex-wrap: wrap; width: auto; white-space: normal; }
.still .fests li, html:not(.js) .fests li { white-space: nowrap; }
.live__grid { margin-top: var(--s12); padding: 0 var(--gutter); align-items: end; row-gap: var(--s3); }
.live__grid h2 { grid-column: 1 / span 6; }
.live__bio { grid-column: 7 / span 6; margin: 0; max-width: 58ch; font-size: var(--t-lead); line-height: 1.45; }

/* ============================================================
   3. THE STATEMENT: the one breath; lines settle as they cross the centre
   ============================================================ */
/* the statement has a full screen of its own: its light (the Warp) needs the room to move */
.statement { min-height: 100svh; display: grid; align-content: center; padding: var(--section) var(--gutter) var(--pad); overflow-x: clip; }
.statement__line {
  margin: 0;
  font: 400 var(--t-statement)/0.9 var(--serif);
  letter-spacing: -0.02em;
  text-wrap: balance;
}
/* a staggered poster: the claim left, what it sounds like answering from the right */
.statement__line em { display: block; font-style: italic; text-align: right; }
/* bass on the type: with sound on, one word per kick lifts to ink, cycling (like Played at) */
.kw, .tw { display: inline-block; transition: transform var(--dur-beat) var(--ease-open), color var(--dur-beat) var(--ease-open); }
.is-listening .kw { color: var(--muted); }
.is-listening .kw.is-lit { color: var(--ink); transform: translateY(-0.05em); transition-duration: var(--dur-fb); }
/* the playing song stays ink (it is the one playing); its words only lift on the kick */
.track.is-playing.is-listening .tw.is-lit { transform: translateY(-0.05em); transition-duration: var(--dur-fb); }
/* the line's mask clips only its baseline; the settle may run a little wide */
.st-mask { display: block; overflow-x: visible; overflow-y: clip; padding: 0.04em 0 0.16em; margin: -0.04em 0 -0.16em; }
.st-line { white-space: nowrap; }

/* ============================================================
   4. THE ELECTRONIC SET. Stacked: the print whole, the title under it.
   Wide: a full-bleed scene; with motion it pins one viewport while
   its title card rises over a measured scrim on the lower third.
   ============================================================ */
.rig { position: relative; padding: 0 var(--gutter) var(--pad); }
.rig__stage { position: relative; }
.print--rig { margin: 0 calc(var(--gutter) * -1) var(--s5); aspect-ratio: 2100 / 1540; }
.rig__scrim { display: none; }
.rig h2 { margin-bottom: var(--s4); }
.rig__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s5); }
.rig__foot p { margin: 0; max-width: 36ch; font-size: var(--t-lead); line-height: 1.4; }

/* ============================================================
   5. LISTEN: the set list. Titles huge and italic; year and length in mono;
   the playing row is ink, the rest muted; its cover appears beside it.
   ============================================================ */
.listen { position: relative; padding: 0 0 var(--pad); }
.listen__bg { position: relative; }
.print--listen { margin: 0 0 var(--s5); aspect-ratio: 1058 / 789; }
.listen__scrim { display: none; }
.listen__body { position: relative; padding: 0 var(--gutter); }
.listen__head { margin-bottom: var(--s5); }
.tracks { list-style: none; margin: 0; padding: 0; border-bottom: 1px solid var(--line); }
.track {
  display: grid; align-items: center; column-gap: var(--s4);
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  grid-template-areas: "name meta play link" "note note note note";
  padding: var(--s2) 0; border-top: 1px solid var(--line);
}
.track__name {
  grid-area: name; position: relative; justify-self: start; max-width: calc(100% - 1.5em);
  font: italic 400 var(--t-song)/0.95 var(--serif); letter-spacing: -0.02em;
}
.track__title { display: block; color: var(--ink); text-wrap: balance; transition: color var(--dur-fb) ease-out; }
.track__cover {
  position: absolute; left: calc(100% + 0.3em); top: 50%;
  width: min(160px, 1.15em); height: min(160px, 1.15em); object-fit: cover;
  transform: translateY(-50%); opacity: 0; pointer-events: none;
  transition: opacity var(--dur-fb) ease-out;
}
.track.is-playing .track__cover { opacity: 1; }
.tracks.has-playing .track:not(.is-playing) .track__title { color: var(--muted); }
.track__meta {
  grid-area: meta; display: flex; gap: 12px;
  font: 400 var(--t-label)/1 var(--mono); letter-spacing: 0.08em; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.track__elapsed:empty { display: none; }
.track__elapsed { color: var(--ink); min-width: 4ch; }
.track__play {
  grid-area: play;
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px; min-width: 96px; padding: 0 var(--s2);
  background: transparent; color: var(--ink); border: 1px solid rgb(239 230 218 / 0.55); border-radius: 0; cursor: pointer;
  transition: border-color var(--dur-fb) ease-out, background-color var(--dur-fb) ease-out, transform var(--dur-fb) ease-out;
}
.track__play .meter { color: var(--muted); }
.track.is-playing .track__play { border-color: var(--accent); }
.track.is-playing .track__play .meter { color: var(--accent); }
.track__play:active { transform: scale(0.97); }
.track__link {
  grid-area: link; display: inline-flex; align-items: center; min-height: 44px;
  color: var(--muted); text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 6px;
  transition: color var(--dur-fb) ease-out, text-decoration-color var(--dur-fb) ease-out;
}
.track__note { grid-area: note; margin: var(--s1) 0 0; font-size: 1rem; line-height: 1.4; color: var(--muted); }
.track__note:empty { display: none; }
.track__note a { color: var(--ink); text-decoration-color: var(--accent); text-underline-offset: 4px; }
@media (hover: hover) and (pointer: fine) {
  .tracks:hover .track:not(:hover):not(.is-playing) .track__title { color: var(--muted); }
  .track:hover .track__title { color: var(--ink); }
  .track:hover .track__cover { opacity: 1; }
}
@media (hover: hover) {
  .track__play:hover { border-color: var(--ink); background: rgb(239 230 218 / 0.06); }
  .track__link:hover, .platforms a:hover { color: var(--ink); text-decoration-color: currentColor; }
}
.platforms {
  display: flex; flex-wrap: wrap; gap: 0 var(--s3); margin: var(--s4) 0 0; padding: 0; list-style: none;
}
.platforms a {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--muted); text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 6px;
  transition: color var(--dur-fb) ease-out, text-decoration-color var(--dur-fb) ease-out;
}

/* ============================================================
   6. WATCH: three equal clips. Stacked grid below 1024 px (phones: a swipe row);
   at 1024 px and wider, one centred row under the title (round 4: no pin, no travel).
   ============================================================ */
.watch { padding: 0 var(--gutter) var(--pad); }
.watch__track { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--s3); }
.watch__head { grid-column: 1 / span 4; align-self: start; }
.watch__head h2 { margin-bottom: var(--s3); }
.watch__head p { margin: 0; color: var(--muted); max-width: 30ch; text-wrap: balance; }
.clips {
  grid-column: 5 / -1; justify-self: end; width: 100%;
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s3);
  max-width: calc(80svh * 27 / 16 + var(--s3) * 2);
}
/* the clip is the containing block, so its visually-hidden labels stay inside the phone swipe row */
.clip { position: relative; }
.clip__frame {
  aspect-ratio: 9 / 16; overflow: hidden; background: var(--surface);
  transition: opacity var(--dur-fb) ease-out;
}
.clip__frame video { width: 100%; height: 100%; object-fit: cover; }
.clips.has-focus .clip:not(.is-focus) .clip__frame { opacity: 0.4; }
.clip__ctl { display: flex; justify-content: space-between; gap: var(--s2); margin-top: var(--s1); }
.clip__ctl[hidden] { display: none; }
.clip__ctl button {
  min-height: 44px; padding: 0; background: none; border: 0; cursor: pointer;
  color: var(--muted);
  transition: color var(--dur-fb) ease-out;
}
.clip__ctl button[aria-pressed="true"] { color: var(--ink); text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 6px; }
.clip__ctl button:active { opacity: 0.6; }
@media (hover: hover) { .clip__ctl button:hover { color: var(--ink); } }

/* ============================================================
   7. THE BAND: the one daylight room, centred. Haleakala edge to edge
   (anchored at its foot, so hands and feet stay in), then both names
   stacked at one size, then the bio in two columns.
   ============================================================ */
.band { background: var(--day-sky); color: var(--bg); padding: 0 0 var(--s6); }
/* with the renderer on, the room's ground and photo are drawn by it, so they can go dark and bloom */
.band.is-gl { background: transparent; }
.band__photo { margin: 0; }
.band__frame { position: relative; aspect-ratio: 4 / 3; overflow: clip; }   /* the scene-open zoom (up to ~6%) must not widen a phone page */
.band__frame.is-gl img { opacity: 0; }
.band__photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 100%; }
.band__photo figcaption { padding: 12px var(--gutter) 0; color: var(--day-earth); }
.band__text { padding: var(--s6) var(--gutter) 0; text-align: center; }
/* until the bloom has burnt the room white, its dark ink would sit on the dark: it waits, then arrives with the light */
.band.is-dark .band__text { opacity: 0; }
.band__names {
  margin: 0 auto;
  font-size: min(var(--t-display), calc((100vw - 2 * var(--gutter)) / 7.6));   /* the longer name always fits one line */
  line-height: 0.9; color: var(--bg);
}
.band__name { display: block; }
/* two columns across most of the room (about 50 characters each), so the daylight is a room, not a margin */
.band__bio { columns: 2 26ch; column-gap: var(--s8); max-width: min(100%, 1120px); margin: var(--s5) auto 0; text-align: left; }
.band__bio p { margin: 0 0 var(--s2); color: var(--bg); font-size: var(--t-lead); line-height: 1.45; }
@media (min-width: 900px) { .band__frame { aspect-ratio: 16 / 9; } }   /* anchored at their feet, 16:9 keeps their sky above their joined hands */

/* ============================================================
   8. BOOK: short and sure. The title, three numbered panels, the form wide.
   ============================================================ */
.book { padding: var(--s6) var(--gutter) var(--pad); }   /* it opens straight on its title: the room above is the pause */
.book__head { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--s3); row-gap: var(--s4); align-items: end; }
.book__title { grid-column: 1 / span 7; }
.book__intro { grid-column: 9 / span 4; }
.book__intro p { margin: 0 0 var(--s1); color: var(--muted); max-width: 44ch; }
.sets { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s3); list-style: none; margin: var(--s8) 0 0; padding: 0; }
.set {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s2);
  padding: var(--s4); background: var(--surface); border-top: 1px solid var(--line);
}
.set__n { font: italic 400 var(--t-numeral)/0.9 var(--serif); letter-spacing: -0.02em; color: var(--muted); }
.set__title { margin: 0; font-size: var(--t-h3); line-height: 1.1; letter-spacing: -0.01em; text-wrap: balance; }
.set p { margin: 0; color: var(--muted); max-width: 42ch; }
.set .btn { margin-top: auto; }

.inquiry {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--s3); row-gap: var(--s4);
  margin-top: var(--s8); padding-top: var(--s6); border-top: 1px solid var(--line);
}
/* the aside travels with the form, so the column beside a long form is never bare */
.inquiry__aside { grid-column: 1 / span 4; align-self: start; position: sticky; top: calc(var(--nav-h) + var(--s4)); }
.form, .form__done { grid-column: 5 / span 8; }
.inquiry__h { margin: 0 0 var(--s2); font-size: var(--t-h2); line-height: 1; letter-spacing: -0.015em; text-wrap: balance; }
.inquiry__alt { margin: 0; color: var(--muted); }
.inquiry__alt a { color: var(--ink); text-decoration-color: var(--accent); text-underline-offset: 4px; overflow-wrap: anywhere; }
.form { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
.form[hidden], .form__done[hidden] { display: none; }
.field { display: flex; flex-direction: column; gap: var(--s1); min-width: 0; }
.field--full { grid-column: 1 / -1; }
.field label { font: 400 var(--t-label)/1.2 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
.field input, .field select, .field textarea {
  width: 100%; min-height: 48px; padding: 12px var(--s2);
  font: 400 1.0625rem/1.4 var(--serif); color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: 0;
  transition: border-color var(--dur-fb) ease-out;
}
.field textarea { resize: vertical; min-height: 144px; }
.field ::placeholder { color: var(--muted); opacity: 1; }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  outline: 2px solid var(--ink); outline-offset: 2px; border-color: var(--ink);
}
@media (hover: hover) { .field input:hover, .field select:hover, .field textarea:hover { border-color: rgb(239 230 218 / 0.4); } }
.field [aria-invalid="true"] { border-color: var(--accent); }
.field__err { margin: 0; font: 400 0.8125rem/1.4 var(--mono); color: var(--ink); }
.field__err.is-on { padding-left: 12px; border-left: 2px solid var(--accent); }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form__foot { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); }
.form__status { margin: 0; padding-left: 12px; border-left: 2px solid var(--accent); max-width: 52ch; }
.form__status a { color: var(--ink); overflow-wrap: anywhere; }
.form__done p { margin: 0 0 var(--s2); font-size: var(--t-lead); line-height: 1.35; max-width: 40ch; }
.form__done:focus { outline: none; }
.form__done:focus-visible { outline: 2px solid var(--ink); outline-offset: 8px; }

/* ============================================================
   9. SIGNUP AND FOOTER: the journey closes where it began. The top of their
   sunset film (sky, the cloud horizon, the sun on it; never the two of them,
   who stand below this strip) as a low, dimmed band behind the signup and the logo.
   ============================================================ */
.foot { position: relative; overflow: hidden; padding: var(--pad) var(--gutter) calc(var(--s6) + env(safe-area-inset-bottom)); }
.foot__sun { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
/* 540% tall: the band only ever shows the top 18.5% of the frame, above both harps and both heads; the sun sits at 80% across */
.foot__sun img {
  position: absolute; top: 0; left: 80%;
  width: auto; height: 540%; min-width: 100%; max-width: none;
  object-fit: cover; object-position: 50% 0;
  transform: translateX(-78%);
}
.foot__scrim {
  position: absolute; inset: 0; pointer-events: none;
  /* dark where the pale upper sky would read grey, lighter over the orange horizon; every line of copy on it is ink */
  background: linear-gradient(to bottom, rgb(var(--scrim-rgb) / 1) 0%, rgb(var(--scrim-rgb) / 0.8) 30%,
    rgb(var(--scrim-rgb) / 0.58) 70%, rgb(var(--scrim-rgb) / 0.5) 100%);
}
.foot__grid { position: relative; row-gap: var(--s8); align-items: end; }
.signup__form { grid-column: 1 / span 6; }
.signup__label { display: block; margin-bottom: var(--s2); font-size: var(--t-lead); line-height: 1.3; text-wrap: balance; }
.signup__row { display: flex; gap: 12px; }
.signup__row input {
  flex: 1 1 auto; min-width: 0; min-height: 48px; padding: 12px var(--s2);
  font: 400 1.0625rem/1.4 var(--serif); color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: 0;
}
.signup__row input::placeholder { color: var(--muted); opacity: 1; }
.signup__row input:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-color: var(--ink); }
.signup__row input[aria-invalid="true"] { border-color: var(--accent); }
.signup__msg { margin: var(--s1) 0 0; min-height: 1.4em; font: 400 0.8125rem/1.4 var(--mono); }
.signup__msg.is-on { padding-left: 12px; border-left: 2px solid var(--accent); }
.signup__msg a { color: var(--ink); overflow-wrap: anywhere; }
.foot__meta { grid-column: 8 / span 5; display: flex; flex-direction: column; gap: var(--s1); }
.foot__logo { display: block; width: 160px; margin-bottom: var(--s2); color: var(--ink); }
.foot__mail { margin: 0; }
.foot__links { display: flex; flex-wrap: wrap; gap: 0 var(--s3); margin: 0; padding: 0; list-style: none; }
.foot__mail a, .foot__links a {
  display: inline-flex; align-items: center; min-height: 44px;
  font: 400 var(--t-label)/1 var(--mono); letter-spacing: 0.08em; color: var(--ink);
  text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 6px;
  overflow-wrap: anywhere; white-space: nowrap;
}
.foot__mail a { white-space: normal; }
/* ink, not muted: the small print can sit over the sun's glow */
.foot__small { margin: 0; font: 400 var(--t-label)/1.6 var(--mono); letter-spacing: 0.08em; color: var(--ink); }

/* the nav mark's crescent travels its own arc with the page: 0 at the top, whole at the end */
.motion .nav__logo .eclipse__shade,
.motion .nav__logo .eclipse__glow {
  -webkit-mask-image: conic-gradient(from 265deg at 50.7% 65.9%, #000 0deg, #000 var(--sweep), transparent calc(var(--sweep) + 14deg));
          mask-image: conic-gradient(from 265deg at 50.7% 65.9%, #000 0deg, #000 var(--sweep), transparent calc(var(--sweep) + 14deg));
}

/* ============================================================
   WIDE: landscape screens, 900 px and up
   ============================================================ */
@media (min-width: 900px) and (min-aspect-ratio: 5/4) {
  /* 4. the rig as a full-bleed scene; heads clear of the nav, both women uncropped side to side */
  .rig { padding: 0; }
  .rig__stage { height: 100svh; overflow: hidden; }
  .print--rig { position: absolute; inset: 0; margin: 0; aspect-ratio: auto; }
  .print--rig img {
    object-position: 50% 6%;
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 4%);
            mask-image: linear-gradient(to bottom, transparent, #000 4%);
  }
  /* measured scrim, sibling of the copy: 0.88 or more behind every line of it; equal across both women */
  .rig__scrim {
    display: block; position: absolute; inset: auto 0 0 0; height: 58%; pointer-events: none;
    background: linear-gradient(to bottom, rgb(var(--scrim-rgb) / 0) 0%, rgb(var(--scrim-rgb) / 0.62) 30%,
      rgb(var(--scrim-rgb) / 0.88) 52%, rgb(var(--scrim-rgb) / 0.92) 100%);
  }
  .rig__text { position: absolute; left: var(--gutter); right: var(--gutter); bottom: var(--s8); }
  .motion .rig { height: calc(100svh + var(--rig-run)); }
  .motion .rig__stage { position: sticky; top: 0; }

  /* 5. the harp-candles plate, dimmed full-bleed behind the list (sticky while the list passes over it) */
  .listen { min-height: 100svh; padding: 0; overflow: clip; }
  .listen__bg { position: absolute; inset: 0; }
  /* the list pulls up over the plate (never the plate down past the list): a sticky box with a negative bottom
     margin may travel past its section, and the renderer draws its full rect, unclipped */
  .motion .listen__bg { position: sticky; top: 0; height: 100svh; }
  .motion .listen__body { margin-top: -100svh; }
  .print--listen { position: absolute; inset: 0; margin: 0; aspect-ratio: auto; }
  .print--listen img {
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
            mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
  }
  /* measured scrim: 0.66 behind the huge titles (large text), 0.86 behind the small mono columns on the right */
  .listen__scrim {
    display: block; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(to left, rgb(var(--scrim-rgb) / 0.86) 0, rgb(var(--scrim-rgb) / 0.86) calc(var(--gutter) + 480px),
      rgb(var(--scrim-rgb) / 0.66) calc(var(--gutter) + 600px));
  }
  .listen__body { padding: calc(var(--pad) + var(--nav-h)) var(--gutter) var(--pad); }
  /* small text over the plate's left half is ink, never muted */
  .track__note, .platforms a { color: var(--ink); }
}

/* Watch, 1024 px and wider (round 4 fix): the three clips always fit the width as ONE centred row under the title,
   so there is no pin and no sideways travel, and no resting frame ever cuts a clip. They stand 78svh tall where
   that fits (1280 and up), a little shorter where it does not (about 68svh at 1024), always equal. */
@media (min-width: 1024px) and (min-aspect-ratio: 5/4) {
  :root { --clip-h: min(78svh, calc(100svh - var(--nav-h) - 128px), calc((100vw - 2 * var(--gutter) - 2 * var(--s5) - 24px) * 16 / 27)); }
  .watch__track { display: block; }
  .watch__head { margin-bottom: var(--s6); }
  .clips { display: flex; justify-content: center; gap: var(--s5); width: 100%; max-width: none; }
  .clip { flex: 0 0 auto; width: calc(var(--clip-h) * 9 / 16); }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 899px) {
  .live__grid { margin-top: var(--s8); }
  .live__grid h2, .live__bio { grid-column: 1 / -1; }
  .watch__head { grid-column: 1 / -1; margin-bottom: var(--s4); }
  .clips { grid-column: 1 / -1; justify-self: stretch; max-width: none; }
  .book__title, .book__intro { grid-column: 1 / -1; }
  .sets { grid-template-columns: 1fr; margin-top: var(--s6); }
  .inquiry__aside, .form, .form__done { grid-column: 1 / -1; }
  .inquiry__aside { position: static; }
  .signup__form, .foot__meta { grid-column: 1 / -1; }
}
@media (max-width: 699px) {
  .grid { column-gap: var(--s2); }
  .form { grid-template-columns: 1fr; }
  /* phones: Played at wraps (no drift), every festival in view */
  .fests__row { flex-wrap: wrap; width: auto; white-space: normal; }
  .fests li { white-space: nowrap; }
  /* phones: the three clips become one swipe row, equal widths, instead of three screens of scroll */
  .clips {
    display: flex; gap: var(--s2); overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory; scrollbar-width: none;
    margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter);
    scroll-padding-inline: var(--gutter);
  }
  .clips::-webkit-scrollbar { display: none; }
  .clip { flex: 0 0 72vw; scroll-snap-align: start; }
  /* each clip's controls sit together at its left edge, so the next clip's Play never reads as part of this row */
  .clip__ctl { justify-content: flex-start; gap: var(--s3); }
  /* phones: the type sizes to the width, so the longest line (heavy, hypnotic, alive.) always clears the gutter */
  :root { --t-statement: clamp(2.25rem, 11.2vw, 3rem); }
  .statement { min-height: 88svh; padding-block: var(--s8); }
  /* phones have no hover, so a cover that waits for one never showed: each row leads with its cover, always on,
     the title, year and Play stacked beside it; while a song plays the other covers step back with their titles */
  .track {
    grid-template-columns: 112px minmax(0, 1fr) auto;
    grid-template-areas: "cover name name" "cover meta meta" "cover play link" "note note note";
    column-gap: var(--s2); row-gap: 10px; align-items: center;
  }
  .track__name { display: contents; }
  .track__title { grid-area: name; align-self: end; }
  .track__cover {
    grid-area: cover; position: static; align-self: start;
    width: 112px; height: 112px; transform: none; opacity: 1;
  }
  .tracks.has-playing .track:not(.is-playing) .track__cover { opacity: 0.45; }
  .track__link { justify-self: end; }
  .track__play { justify-self: start; min-width: 88px; }
  /* phones: the panels run nearly edge to edge, so they let the journey light through (72%) instead of covering it */
  .set { padding: var(--s3); background: rgb(28 20 19 / 0.72); }
  .nav { gap: var(--s1); }
  .nav__right { gap: 12px; }
  .nav__links { gap: 10px; }
  .nav__link { padding: 0 4px; letter-spacing: 0.08em; }
  .nav__links li:last-child { margin-left: 0; }
  .nav .btn--sm { padding: 0 12px; letter-spacing: 0.08em; }
  .nav__logo { width: 56px; }
  .sound { padding: 0 4px; gap: 6px; letter-spacing: 0.08em; }
  .sound__title { display: none; }
}

/* ============================================================
   REDUCED MOTION: instant swaps, posters, still grain
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .grain { animation: none; }
  .btn, .nav, .nav__link, .film-toggle, .textlink, .clip__frame, .fests li, .kw, .tw,
  .track__title, .track__cover { transition: none; }
}
@media (forced-colors: active) {
  .logo { background-color: CanvasText; }
  .btn, .track__play { border-color: ButtonText; }
  .field__err.is-on, .form__status, .signup__msg.is-on { border-left-color: CanvasText; }
}

/* ============================================================
   ROUND 4
   ============================================================ */
/* Played at keeps its label as a line of copy, not a numbered mono eyebrow */
.played__label { margin: 0 0 var(--s1); font: italic 400 var(--t-lead)/1.2 var(--serif); color: var(--muted); }

/* THE ENTER SCREEN. Still (reduced motion, no WebGL): warm black, their logo, two controls.
   With the renderer: the canvas rises above the page and draws the ground and the living logo in the
   logo's box; this layer keeps only the controls. */
.gate { display: none; }
.gated { overflow: hidden; }
.gated .gate {
  position: fixed; inset: 0; z-index: 170;
  display: grid; place-content: center; justify-items: center; gap: var(--s8);
  padding: var(--gutter); background: var(--bg); color: var(--ink);
}
/* the gate logo sits in the hero logo's exact box (main.js measures it); this is its place before that runs */
.gate__logo { position: fixed; left: 50%; top: calc(var(--nav-h) + var(--title-drop, 0px)); width: var(--logo-w); transform: translateX(-50%); }
.hero:focus { outline: none; }   /* focus after Enter: the top of the content, no ring */
.gate__logo .eclipse { color: var(--ink); }
.gate__ctl { display: flex; flex-direction: column; align-items: center; gap: var(--s1); }
.gate__enter { min-width: 208px; }
.gate__quiet { color: var(--muted); }
.gl-gate .gl { z-index: 160; }
.gl-gate .gate { background: transparent; }
.gl-gate .gate__logo .eclipse { visibility: hidden; }        /* the renderer's logo stands in this box */
/* leaving: the controls go at once with the click's feedback, the dark lifts off the sunset */
.gate.is-leaving .gate__ctl { opacity: 0; transition: opacity var(--dur-fb) ease-out; }
.gl-leaving .gl { opacity: 0; transition: opacity 1100ms var(--ease-open); }
/* their eclipse waits behind the gate and opens as it lifts */
.gate-hold .eclipse--hero .eclipse__shade,
.gate-hold .eclipse--hero .eclipse__glow { animation-play-state: paused; }
/* the journey light is drawn by the renderer when it can be (a grain gradient); this is its CSS stand-in */
.paper-on:not(.journey-css) .journey { display: none; }   /* journey-css: the renderer's journey drew blank on this GPU */

/* round 4 fix: the footer logo, alive. The renderer copies its GemSmoke logo into this canvas each frame;
   the DOM logo steps aside only once the living one has drawn (no WebGL: the DOM logo stays). */
.foot__logo { position: relative; }
.foot__gl { position: absolute; left: -2.632%; top: -2.632%; width: 105.263%; height: 105.263%; pointer-events: none; }
.foot__logo.gl-logo .eclipse { visibility: hidden; }
/* the journey light reaches the footer: their sunset strip fades out at the sides, where the moving sunset-gold
   light takes over under the same scrim (the copy's contrast is measured over it) */
.paper-on .foot__sun {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 28%, #000 72%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 28%, #000 72%, transparent);
}
/* the Enter screen on tall screens: the logo stays at the hero logo's place (the dissolve needs it there),
   the two controls sit in the lower third so the screen balances */
@media (max-aspect-ratio: 3/4) {
  .gated .gate { align-content: end; padding-bottom: calc(env(safe-area-inset-bottom) + 18svh); }
}
/* Enter's focus ring: kept for keyboard users, one thin ink ring instead of two thick ones */
.gate__enter:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; box-shadow: none; }

/* ============================================================
   ROUND 5: THE PLAYER. Warm near-black glass, one ink hairline, radius 0.
   The cover at 48 px under their own crescent (logo-crescent-night.webp, the logo's arc): its lit part
   is the song's progress, swept with the same conic mask as the nav mark. Docked bottom left on wide
   screens, a slim full-width bar on phones; while Book is on screen it tucks away (main.js) and the
   nav's Sound meter stands in for it.
   ============================================================ */
.player {
  --player-glass: rgb(28 20 19 / 0.86);   /* 0.86: muted mono text holds 4.5:1 even over the day room */
  position: fixed; z-index: 95;
  left: calc(var(--gutter) + env(safe-area-inset-left)); bottom: calc(var(--s3) + env(safe-area-inset-bottom));
  width: min(488px, calc(100vw - 2 * var(--gutter)));
  display: grid; grid-template-columns: 48px minmax(0, 1fr) auto; grid-template-areas: "art now transport" "more more more";
  column-gap: var(--s3); align-items: center;
  padding: var(--s3) var(--s2) 0 var(--s3);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 0;
  opacity: 0; visibility: hidden; transform: translateY(var(--s3));
  transition: opacity var(--dur-open) var(--ease-open), transform var(--dur-open) var(--ease-open), visibility 0s linear var(--dur-open);
}
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .player { background: var(--player-glass); -webkit-backdrop-filter: blur(16px) saturate(1.1); backdrop-filter: blur(16px) saturate(1.1); }
}
.player[data-state="on"] { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.player p { margin: 0; }
.player__art { grid-area: art; position: relative; width: 48px; height: 48px; }
.player__cover { position: relative; width: 48px; height: 48px; object-fit: cover; background: var(--surface-2); }
/* their crescent, scaled so its inner rim (366 of 1420 px) clears the cover's corners; its circle's centre
   (50.7%, 65.9% of the frame) sits on the cover's centre */
.player__ring { position: absolute; left: -46.81px; top: -33.56px; width: 139.67px; height: 87.34px; pointer-events: none; --ring: 0deg; }
.player__ring > span {
  position: absolute; inset: 0;
  -webkit-mask: url(../media/logo-crescent-night.webp) 0 0 / 100% 100% no-repeat,
                radial-gradient(circle at 50.7% 65.9%, transparent 35px, #000 35.5px, #000 43.5px, transparent 44px);
          mask: url(../media/logo-crescent-night.webp) 0 0 / 100% 100% no-repeat,
                radial-gradient(circle at 50.7% 65.9%, transparent 35px, #000 35.5px, #000 43.5px, transparent 44px);
  -webkit-mask-composite: source-in; mask-composite: intersect;
}
.player__ring-track { background: rgb(239 230 218 / 0.22); }
.player__ring > .player__ring-fill {
  background: var(--ink);
  -webkit-mask: url(../media/logo-crescent-night.webp) 0 0 / 100% 100% no-repeat,
                radial-gradient(circle at 50.7% 65.9%, transparent 35px, #000 35.5px, #000 43.5px, transparent 44px),
                conic-gradient(from 325deg at 50.7% 65.9%, #000 0deg, #000 var(--ring), transparent calc(var(--ring) + 3deg));
          mask: url(../media/logo-crescent-night.webp) 0 0 / 100% 100% no-repeat,
                radial-gradient(circle at 50.7% 65.9%, transparent 35px, #000 35.5px, #000 43.5px, transparent 44px),
                conic-gradient(from 325deg at 50.7% 65.9%, #000 0deg, #000 var(--ring), transparent calc(var(--ring) + 3deg));
  -webkit-mask-composite: source-in, source-in; mask-composite: intersect;
}
.player__now { grid-area: now; min-width: 0; }
.player__title { font: italic 400 1.25rem/1.2 var(--serif); letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.player__time {
  display: flex; gap: var(--s1); margin-top: var(--s1);
  font: 400 var(--t-label)/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* the ring and the Full song toggle already say which: the word is for the screen reader */
.player__mode { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.player__transport { grid-area: transport; display: flex; align-items: center; }
.player__btn, .player__full, .player__on {
  font: 400 var(--t-label)/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
}
.player__btn, .player__full {
  -webkit-tap-highlight-color: transparent; touch-action: manipulation; -webkit-user-select: none; user-select: none;
}
.player__btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s1);
  min-width: 44px; min-height: 44px; padding: 0 var(--s1);
  background: none; color: var(--muted); border: 1px solid transparent; border-radius: 0; cursor: pointer;
  transition: color var(--dur-fb) ease-out, border-color var(--dur-fb) ease-out, transform var(--dur-fb) ease-out;
}
.player__play { min-width: 96px; margin: 0 var(--s1); padding: 0 var(--s2); color: var(--ink); border-color: rgb(239 230 218 / 0.55); }
.player__play .meter { color: var(--muted); }
.player__play.is-on { border-color: var(--accent); }         /* gold only on the active control */
.player__play.is-on .meter { color: var(--accent); }
.player__btn:active, .player__full:active { transform: scale(0.97); }
.player__more {
  grid-area: more; display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  margin-top: var(--s2); border-top: 1px solid var(--line);
}
.player__full {
  display: inline-flex; align-items: center; gap: var(--s1); min-height: 44px; padding: 0;
  background: none; border: 0; color: var(--muted); cursor: pointer;
  transition: color var(--dur-fb) ease-out, transform var(--dur-fb) ease-out;
}
.player__full::before { content: ""; width: 8px; height: 8px; border: 1px solid currentColor; transition: background-color var(--dur-fb) ease-out; }
.player__full[aria-pressed="true"] { color: var(--ink); }
.player__full[aria-pressed="true"]::before { background: var(--accent); border-color: var(--accent); }
.player__on { display: flex; align-items: center; gap: var(--s2); color: var(--muted); letter-spacing: 0.08em; }
.player__on a {
  display: inline-flex; align-items: center; min-height: 44px; color: var(--ink);
  text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 6px;
  transition: text-decoration-color var(--dur-fb) ease-out;
}
@media (hover: hover) {
  .player__btn:hover, .player__full:hover { color: var(--ink); }
  .player__play:hover { border-color: var(--ink); }
  .player__play.is-on:hover { border-color: var(--accent-hi); }
  .player__on a:hover { text-decoration-color: currentColor; }
}
/* phones: a slim full-width bar above the safe area; the words "Listen on" go to the screen reader only */
@media (max-width: 699px) {
  .player {
    left: 0; right: 0; bottom: 0; width: auto;
    padding: 20px var(--s2) env(safe-area-inset-bottom) var(--s2);
    border-width: 1px 0 0; column-gap: var(--s3);
  }
  .player__title { font-size: 1.0625rem; }
  .player__play { min-width: 44px; margin: 0; padding: 0; }
  .player__play-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .player__more { margin-top: var(--s1); }
  .player__on-words { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
/* phones: the cover is their moon, round, and a thin gold ring around it fills with the song
   (the crescent's offset geometry needs the desktop bar's room; on the slim bar it floated off the cover) */
@media (max-width: 699px) {
  .player__cover { border-radius: 50%; }
  .player__ring { left: -6px; top: -6px; width: 60px; height: 60px; }
  .player__ring > span {
    -webkit-mask: radial-gradient(circle closest-side, transparent 27.5px, #000 28px, #000 29.5px, transparent 30px);
            mask: radial-gradient(circle closest-side, transparent 27.5px, #000 28px, #000 29.5px, transparent 30px);
  }
  .player__ring-track { background: rgb(239 230 218 / 0.16); }
  .player__ring > .player__ring-fill {
    background: var(--accent);
    -webkit-mask: radial-gradient(circle closest-side, transparent 27.5px, #000 28px, #000 29.5px, transparent 30px),
                  conic-gradient(#000 calc(var(--p, 0) * 360deg), transparent 0);
            mask: radial-gradient(circle closest-side, transparent 27.5px, #000 28px, #000 29.5px, transparent 30px),
                  conic-gradient(#000 calc(var(--p, 0) * 360deg), transparent 0);
    -webkit-mask-composite: source-in; mask-composite: intersect;
  }
}
@media (prefers-reduced-motion: reduce) {
  .player, .player__btn, .player__full, .player__full::before, .player__on a { transition: none; }
}
@media (forced-colors: active) {
  .player { border-color: CanvasText; }
  .player__ring > .player__ring-fill { background: CanvasText; }
  .player__full[aria-pressed="true"]::before { background: Highlight; }
}
