/* ============================================================
   CHERRY DN — her own direction
   "Welcome to the paradise you carry within."
   Palette, fonts and structure specified by Cherry:
   #0C1718 bg · #111E20 panel · #8E1F2D red · #E7DED4 ink · #B9AEA3 muted
   Bodoni Moda titles · Inter UI · Cormorant Garamond italic accents
   ============================================================ */

:root {
  --bg: #0C1718;
  --bg2: #111E20;
  --red: #8E1F2D;
  --red-t: #CE6270;          /* small functional red text: 4.87 on --bg, 4.56 on --bg2,
                                so it clears AA at body size on both grounds. It was
                                #C05263, which measured 4.02 and 3.76 and did not. */
  --red-display: #B03846;    /* display-size red only: 3.04 on --bg, which clears the 3:1
                                bar for large text and nothing else. Anything at body size
                                takes --red-t instead. */
  --ink: #E7DED4;
  --muted: #B9AEA3;
  --line: color-mix(in srgb, var(--muted) 16%, transparent);
  --display: "Bodoni Moda", "Didot", serif;
  --ui: "Inter", "Helvetica Neue", sans-serif;
  --poetic: "Cormorant Garamond", Georgia, serif;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* the clip lives here, not on body: overflow on body makes BODY the scroll
   container, and every view timeline then attaches to something that never
   scrolls, so scroll-driven animations sit inactive forever. */
html { scroll-behavior: smooth; overflow-x: clip; scrollbar-gutter: stable; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--ui);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.7;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
::selection { background: var(--red); color: var(--ink); }
:focus-visible { outline: 1px solid var(--red-t); outline-offset: 3px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ---------- grain, very quiet ---------- */
body::after {
  content: "";
  position: fixed; inset: -50%;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  opacity: 0.035;
  z-index: 99;
}

/* ============================================================
   NAV
   ============================================================ */
.nav {
  position: sticky; top: 0;
  z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem;
  padding: 1.3rem 3rem;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.4s;
}
.nav.is-scrolled { border-bottom-color: var(--line); }

.nav__logo {
  font-family: var(--display);
  font-size: 1.05rem;
  letter-spacing: 0.34em;
  color: var(--ink);
  white-space: nowrap;
}
.nav__links {
  display: flex; gap: 1.7rem;
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.26em;
  text-transform: uppercase;
}
.nav__links a {
  color: var(--muted);
  white-space: nowrap;
  padding: 0.4rem 0;
  border-bottom: 1px solid transparent;
  transition: color 0.3s, border-color 0.3s;
}
.nav__links a:hover { color: var(--ink); }
.nav__links a.is-active { color: var(--ink); border-bottom-color: var(--red); }

.nav__cta {
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--ink);
  border: 1px solid var(--red);
  padding: 0.65rem 1.3rem;
  white-space: nowrap;
  transition: background 0.3s, color 0.3s;
}
.nav__cta:hover { background: var(--red); }

.nav__burger {
  display: none;
  flex-direction: column; gap: 6px;
  align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px;
  background: none; border: 0; cursor: pointer;
}
.nav__burger span { display: block; width: 24px; height: 1px; background: var(--ink); transition: transform 0.35s; }
.nav__burger.is-open span:nth-child(1) { transform: translateY(3.5px) rotate(45deg); }
.nav__burger.is-open span:nth-child(2) { transform: translateY(-3.5px) rotate(-45deg); }

.menu {
  position: fixed; inset: 0; z-index: 30;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: blur(16px);
  display: flex; flex-direction: column; justify-content: center;
  padding: 5rem 2.2rem;
  opacity: 0; visibility: hidden;
  transition: opacity 0.4s, visibility 0.4s;
}
.menu.is-open { opacity: 1; visibility: visible; }
.menu a {
  font-family: var(--display);
  font-size: clamp(1.7rem, 7vw, 2.4rem);
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  letter-spacing: 0.06em;
  transition: color 0.3s, padding-left 0.3s;
}
.menu a:hover { color: var(--red-t); padding-left: 0.5rem; }

/* ============================================================
   LANDING
   ============================================================ */
.hero {
  position: relative;
  min-height: 88svh;
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  overflow: hidden;
  /* parchment fallback until assets/hero.jpg arrives */
  background:
    radial-gradient(ellipse at 30% 20%, color-mix(in srgb, var(--red) 35%, transparent), transparent 40%),
    radial-gradient(ellipse at 72% 14%, rgba(90, 16, 26, 0.5), transparent 34%),
    radial-gradient(ellipse at 55% 45%, color-mix(in srgb, var(--red) 22%, transparent), transparent 45%),
    linear-gradient(180deg, #cfc2ad 0%, #b3a48c 55%, #8a7c66 78%, #6f6350 100%);
}
.hero__img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.hero__veil {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--bg) 42%, transparent), transparent 30%, transparent 55%, var(--bg) 98%);
}
.hero__body { position: relative; z-index: 1; padding: 6rem 1.5rem 7rem; }
.hero__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.8rem, 9vw, 6.5rem);
  letter-spacing: 0.16em;
  color: #F2EAD9;
  text-shadow: 0 2px 30px color-mix(in srgb, var(--bg) 50%, transparent);
}
.hero__roles {
  margin-top: 1rem;
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.6em;
  text-transform: uppercase;
  color: #EFE6D4;
  text-shadow: 0 1px 14px color-mix(in srgb, var(--bg) 60%, transparent);
}
.hero__roles i { font-style: normal; color: var(--red-t); }
.hero__welcome {
  margin-top: 1.3rem;
  font-family: var(--poetic);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.05rem, 2.4vw, 1.3rem);
  letter-spacing: 0.14em;
  color: #EFE7D6;
  text-shadow: 0 1px 14px color-mix(in srgb, var(--bg) 65%, transparent);
}
.hero__row { margin-top: 2.6rem; display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }

.btn-line {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 46px;
  padding: 0.7rem 2rem;
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: #F2EAD9;
  border: 1px solid rgba(242, 234, 217, 0.55);
  background: color-mix(in srgb, var(--bg) 35%, transparent);
  backdrop-filter: blur(3px);
  transition: background 0.3s, border-color 0.3s;
}
.btn-line:hover { background: color-mix(in srgb, var(--bg) 60%, transparent); }
.btn-line--red { border-color: var(--red); }
.btn-line--red:hover { background: var(--red); }

/* portals */
.portals {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.4rem;
  padding: 3.2rem 3rem 1rem;
  max-width: 1380px;
  margin: 0 auto;
}
.portal {
  position: relative;
  aspect-ratio: 5 / 4;
  overflow: hidden;
  border: 1px solid var(--line);
  display: block;
}
.portal img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 1.2s cubic-bezier(0.16, 1, 0.3, 1), filter 0.8s;
  filter: saturate(0.9) brightness(0.85);
}
.portal:hover img { transform: scale(1.04); filter: saturate(1) brightness(1); }
.portal__fallback { position: absolute; inset: 0; }
.portal--word .portal__fallback {
  background: radial-gradient(ellipse at 30% 70%, color-mix(in srgb, var(--red) 30%, transparent), transparent 55%), linear-gradient(165deg, #131d1e, #0a1213);
}
.portal--music .portal__fallback {
  background: radial-gradient(ellipse at 60% 30%, rgba(46, 90, 96, 0.4), transparent 55%), linear-gradient(165deg, #0e1c1e, #091112);
}
.portal--visuals .portal__fallback {
  background: radial-gradient(ellipse at 75% 75%, color-mix(in srgb, var(--red) 40%, transparent), transparent 50%), linear-gradient(165deg, #171719, #0b0e0f);
}
.portal__veil {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(9, 15, 16, 0.85), transparent 55%);
}
.portal__text { position: absolute; left: 1.6rem; right: 1.6rem; bottom: 1.4rem; }
.portal__name {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  letter-spacing: 0.12em;
  color: var(--ink);
}
.portal__name::after {
  content: "";
  display: block;
  width: 34px; height: 1px;
  background: var(--red);
  margin-top: 0.45rem;
}
.portal__desc {
  margin-top: 0.6rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 0.95rem;
  color: var(--muted);
  line-height: 1.5;
}

.strip {
  display: flex; justify-content: center; gap: 3rem; flex-wrap: wrap;
  padding: 2.2rem 1.5rem 3rem;
}
.strip a {
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  padding: 0.5rem 0.1rem;
  transition: color 0.3s, border-color 0.3s;
}
.strip a:hover { color: var(--red-t); border-color: var(--red); }

/* ============================================================
   SUBPAGE SHELL
   ============================================================ */
.page {
  max-width: 1060px;
  margin: 0 auto;
  padding: 4.5rem 3rem 5rem;
}
.page__num {
  font-size: 0.66rem;
  font-weight: 400;
  letter-spacing: 0.4em;
  color: var(--red-t);
}
.page__title {
  margin-top: 0.6rem;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.5rem, 7vw, 4.4rem);
  line-height: 1.05;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--red-display);
}
.page__tag {
  margin-top: 1rem;
  font-size: 0.66rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--muted);
}
.page__head { margin-bottom: 3.2rem; }

/* filter tabs */
.tabs {
  display: flex; gap: 1.8rem; flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
  margin-bottom: 2.2rem;
}
.tab {
  background: none; border: 0; cursor: pointer;
  font-family: var(--ui);
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0.7rem 0.1rem 0.9rem;
  border-bottom: 1px solid transparent;
  margin-bottom: -1px;
  transition: color 0.3s, border-color 0.3s;
}
.tab:hover { color: var(--ink); }
.tab.is-active { color: var(--ink); border-bottom-color: var(--red); }

/* red arrow links */
.rlink {
  display: inline-block;
  background: none; border: 0; cursor: pointer;
  font-family: var(--ui);
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--red-t);
  padding: 0.5rem 0;
  transition: letter-spacing 0.3s, color 0.3s;
}
.rlink:hover { letter-spacing: 0.36em; color: var(--ink); }

/* ============================================================
   MUSIC
   ============================================================ */
.player {
  display: flex; align-items: center; gap: 1.2rem;
  border: 1px solid var(--line);
  background: var(--bg2);
  padding: 0.9rem 1.2rem;
  margin-bottom: 1.6rem;
}
.player__btn {
  width: 42px; height: 42px; flex-shrink: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  position: relative;
  transition: border-color 0.3s;
}
.player__btn::after {
  content: "";
  position: absolute; top: 50%; left: 54%;
  transform: translate(-50%, -50%);
  border-style: solid;
  border-width: 5px 0 5px 9px;
  border-color: transparent transparent transparent var(--ink);
}
.player__btn.is-playing::after {
  border-width: 0 2.5px;
  border-color: var(--ink);
  width: 9px; height: 11px;
}
.player__btn:hover { border-color: var(--red); }
.player__meta { flex: 1; min-width: 0; }
.player__now {
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.player__wave {
  margin-top: 0.5rem;
  height: 18px;
  background: repeating-linear-gradient(to right, var(--muted) 0 2px, transparent 2px 5px);
  opacity: 0.35;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 30%, #000 70%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 30%, #000 70%, transparent 100%);
}
.player__time {
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tracklist { list-style: none; border: 1px solid var(--line); }
.trk {
  display: flex; align-items: center; gap: 1.4rem;
  padding: 0.95rem 1.2rem;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  transition: background 0.3s, color 0.3s;
}
.trk:last-child { border-bottom: 0; }
.trk:hover { color: var(--ink); background: var(--bg2); }
.trk.is-current { background: var(--bg2); color: var(--ink); box-shadow: inset 2px 0 0 var(--red); }
.trk__no { font-variant-numeric: tabular-nums; opacity: 0.7; }
.trk__name { flex: 1; }
.trk__len { font-variant-numeric: tabular-nums; }
.trk.is-ghost { cursor: default; }
.trk.is-ghost:hover { background: transparent; color: var(--muted); }

.melodies {
  margin-top: 3.4rem;
  display: grid;
  grid-template-columns: minmax(180px, 240px) 1fr;
  gap: 2.2rem;
  align-items: center;
}
.melodies__art {
  position: relative;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  overflow: hidden;
  background: radial-gradient(ellipse at 40% 60%, color-mix(in srgb, var(--red) 45%, transparent), transparent 60%), linear-gradient(160deg, #16090c, #0b0708);
}
.melodies__art img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.melodies__title {
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  margin-bottom: 0.9rem;
}
.melodies__text {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.05rem;
  line-height: 1.75;
  color: var(--muted);
  margin-bottom: 1rem;
}

/* ============================================================
   WRITTEN WORD
   ============================================================ */
.wlist { list-style: none; }
.wl {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 1.8rem;
  padding: 1.8rem 0;
  border-bottom: 1px solid var(--line);
}
.wl:first-child { border-top: 1px solid var(--line); }
.wl__thumb {
  position: relative;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  overflow: hidden;
  background: radial-gradient(ellipse at 45% 55%, color-mix(in srgb, var(--red) 40%, transparent), transparent 60%), linear-gradient(160deg, #141013, #0b090b);
}
.wl__thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.wl__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.25rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.wl__kind {
  margin-top: 0.2rem;
  font-size: 0.56rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--red-t);
}
.wl__excerpt {
  margin-top: 0.7rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--muted);
  max-width: 52ch;
}
.wl__body {
  display: none;
  margin-top: 1.1rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.15rem;
  line-height: 1.9;
  color: var(--ink);
  max-width: 54ch;
}
.wl.is-open .wl__body { display: block; }
.wl__read { margin-top: 0.8rem; }

/* ============================================================
   SPOKEN WORD
   ============================================================ */
.spoken-intro {
  font-family: var(--poetic);
  font-style: italic;
  font-size: clamp(1.1rem, 2.2vw, 1.35rem);
  line-height: 1.8;
  color: var(--muted);
  max-width: 56ch;
  margin-bottom: 2.6rem;
}
.spoken-intro em { color: var(--ink); }
.spoken-note {
  margin-top: 2rem;
  font-family: var(--poetic);
  font-style: italic;
  color: var(--muted);
}
.spoken-gift {
  margin-top: 2.6rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
}

/* ============================================================
   VISUALS
   ============================================================ */
.vgrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}
.vitem {
  position: relative;
  aspect-ratio: 1;
  border: 1px solid var(--line);
  overflow: hidden;
}
.vitem img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  filter: saturate(0.9);
  transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1), filter 0.6s;
}
.vitem:hover img { transform: scale(1.05); filter: saturate(1.05); }
.vitem__cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 2rem 1rem 0.8rem;
  background: linear-gradient(to top, rgba(9, 15, 16, 0.9), transparent);
  font-size: 0.58rem;
  font-weight: 400;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0;
  transition: opacity 0.5s;
}
.vitem:hover .vitem__cap, .vitem.is-empty .vitem__cap { opacity: 1; }
.vg1 { background: radial-gradient(ellipse at 30% 30%, color-mix(in srgb, var(--red) 50%, transparent), transparent 60%), linear-gradient(160deg, #171114, #0b090b); }
.vg2 { background: radial-gradient(ellipse at 70% 60%, rgba(46, 90, 96, 0.45), transparent 60%), linear-gradient(160deg, #0e191b, #091112); }
.vg3 { background: radial-gradient(ellipse at 50% 80%, color-mix(in srgb, var(--red) 35%, transparent), transparent 55%), linear-gradient(160deg, #141618, #0a0d0e); }
.vg4 { background: radial-gradient(ellipse at 25% 70%, color-mix(in srgb, var(--muted) 18%, transparent), transparent 55%), linear-gradient(160deg, #131315, #0a0b0c); }
.vg5 { background: radial-gradient(ellipse at 65% 25%, color-mix(in srgb, var(--red) 42%, transparent), transparent 50%), linear-gradient(160deg, #120e12, #0a080a); }

/* ============================================================
   FILM
   ============================================================ */
.filmbox {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  overflow: hidden;
  margin-bottom: 1.6rem;
  display: flex; align-items: center; justify-content: center;
  background:
    radial-gradient(ellipse at 50% 70%, color-mix(in srgb, var(--red) 40%, transparent), transparent 55%),
    linear-gradient(170deg, #101a1c, #0a1112);
}
.filmbox img, .filmbox video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.filmbox__play {
  position: relative; z-index: 1;
  width: 68px; height: 68px;
  border: 1px solid color-mix(in srgb, var(--ink) 60%, transparent);
  border-radius: 50%;
  backdrop-filter: blur(4px);
}
.filmbox__play::after {
  content: "";
  position: absolute; top: 50%; left: 55%;
  transform: translate(-50%, -50%);
  border-style: solid;
  border-width: 8px 0 8px 13px;
  border-color: transparent transparent transparent var(--ink);
}
.flist { list-style: none; border-top: 1px solid var(--line); }
.fl {
  display: flex; align-items: baseline; gap: 1.4rem;
  padding: 1.1rem 0.3rem;
  border-bottom: 1px solid var(--line);
}
.fl__name {
  font-size: 0.74rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.fl__kind {
  flex: 1;
  font-family: var(--poetic);
  font-style: italic;
  color: var(--muted);
  font-size: 0.95rem;
}
.fl__len { font-size: 0.7rem; color: var(--muted); font-variant-numeric: tabular-nums; letter-spacing: 0.14em; }

/* ============================================================
   ABOUT
   ============================================================ */
.about-grid {
  display: grid;
  grid-template-columns: minmax(240px, 340px) 1fr;
  gap: 3.4rem;
  align-items: center;
}
.about-photo {
  position: relative;
  aspect-ratio: 4 / 5;
  border: 1px solid var(--line);
  overflow: hidden;
  background:
    radial-gradient(ellipse at 60% 30%, rgba(203, 178, 140, 0.25), transparent 60%),
    radial-gradient(ellipse at 30% 80%, color-mix(in srgb, var(--red) 30%, transparent), transparent 55%),
    linear-gradient(165deg, #1a1512, #0d0b0a);
}
.about-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.about-lines p {
  font-size: 0.95rem;
  font-weight: 300;
  line-height: 1.85;
  color: var(--ink);
  margin-bottom: 1.3rem;
}
.about-sig {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 2.1rem;
  color: var(--red-t);
  margin-top: 0.4rem;
}
.about-tags {
  margin-top: 3rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 0.9rem;
}
.about-tags p {
  font-size: 0.64rem;
  font-weight: 400;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
}
.about-tags i { font-style: normal; color: var(--red-t); padding: 0 0.5rem; }

/* ============================================================
   CONTACT
   ============================================================ */
.cform { display: flex; flex-direction: column; gap: 1.1rem; max-width: 560px; }
.cform input, .cform textarea {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink);
  font-family: var(--ui);
  font-weight: 300;
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  padding: 0.95rem 1.1rem;
  border-radius: 0;
  transition: border-color 0.3s;
}
.cform input::placeholder, .cform textarea::placeholder {
  color: var(--muted);
  text-transform: uppercase;
  font-size: 0.62rem;
  letter-spacing: 0.28em;
}
.cform input:focus, .cform textarea:focus { outline: none; border-color: var(--red); }
.cform textarea { min-height: 150px; resize: vertical; }

.contact-meta {
  margin-top: 3.4rem;
  display: flex; justify-content: space-between; gap: 2rem; flex-wrap: wrap;
  padding-top: 1.8rem;
  border-top: 1px solid var(--line);
}
.contact-meta div { font-size: 0.62rem; letter-spacing: 0.26em; text-transform: uppercase; }
.contact-meta span { display: block; color: var(--muted); margin-bottom: 0.5rem; }
.contact-meta a { color: var(--ink); border-bottom: 1px solid var(--line); padding-bottom: 0.2rem; transition: border-color 0.3s, color 0.3s; }
.contact-meta a:hover { color: var(--red-t); border-color: var(--red); }

.endline {
  margin-top: 4.5rem;
  text-align: center;
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ============================================================
   FOOTER (shared)
   ============================================================ */
.foot {
  border-top: 1px solid var(--line);
  padding: 3.2rem 1.5rem 2.4rem;
  text-align: center;
}
.foot__line {
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.38em;
  text-transform: uppercase;
  color: var(--red-t);
}
.foot__sig {
  font-family: var(--poetic);
  font-style: italic;
  text-transform: none;
  letter-spacing: 0.05em;
  font-size: 1rem;
  padding-left: 0.4rem;
}
.foot__cherry { margin: 1.4rem auto 0; width: 20px; }
.foot__cherry svg { width: 100%; fill: var(--red); }
.foot__meta {
  margin-top: 1.4rem;
  font-size: 0.58rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}
.foot__meta a { border-bottom: 1px solid transparent; transition: color 0.3s, border-color 0.3s; }
.foot__meta a:hover { color: var(--ink); border-color: var(--red); }

/* ---------- reveal, restrained ---------- */
html.js [data-r] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1), transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
html.js [data-r].is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.js [data-r] { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 1080px) {
  .nav__links { display: none; }
  .nav__burger { display: flex; }
}
@media (max-width: 900px) {
  .portals { grid-template-columns: 1fr; padding: 2.4rem 1.4rem 0.5rem; }
  .portal { aspect-ratio: 16 / 10; }
  .about-grid { grid-template-columns: 1fr; gap: 2.2rem; }
  .about-photo { max-width: 320px; }
}
@media (max-width: 780px) {
  .nav { padding: 1rem 1.3rem; }
  .nav__cta { display: none; }
  .page { padding: 3.2rem 1.4rem 3.6rem; }
  .vgrid { grid-template-columns: 1fr 1fr; }
  .wl { grid-template-columns: 86px 1fr; gap: 1.1rem; }
  .melodies { grid-template-columns: 1fr; }
  .melodies__art { max-width: 300px; }
}


/* nav cherry glyph */
.nav__cherry { width: 15px; display: inline-flex; }
.nav__cherry svg { width: 100%; fill: var(--red); }


/* view-all rows */
.viewall { margin-top: 2.4rem; text-align: center; }

/* script signature, like the mock */
.about-lines p.about-sig, .about-sig {
  font-family: "Great Vibes", "Cormorant Garamond", cursive;
  font-style: normal;
  font-size: clamp(3.4rem, 5.5vw, 4.4rem);
  line-height: 1.15;
  color: var(--red-display);
  margin-top: 1.1rem;
}

/* ============================================================
   LANDING — graded like the reference: dark frame, luminous center
   ============================================================ */
.landing .nav {
  position: absolute;
  top: 0; left: 0; right: 0;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom: 0;
}
.landing .nav.is-scrolled { border-bottom-color: transparent; }
.landing .nav__logo {
  font-size: 1.3rem;
  letter-spacing: 0.3em;
  color: #EDE3CF;
  text-shadow: 0 1px 16px rgba(10, 8, 5, 0.6);
}
.landing .nav__links { margin-left: auto; margin-right: 1.6rem; }
.landing .nav__links a {
  color: #D9CFBD;
  text-shadow: 0 1px 10px rgba(10, 8, 5, 0.6);
}
.landing .nav__links a:hover { color: #F5EDDC; }
.landing .nav__links a.is-active { color: #D9CFBD; border-bottom-color: transparent; }
.landing .nav__cta {
  color: #E9DFC9;
  border-color: var(--red);
  background: rgba(9, 13, 14, 0.45);
}
.landing .nav__cta:hover { background: rgba(9, 13, 14, 0.45); color: var(--ink); }
.landing .nav__burger span { background: #E9DFC9; }

.landing .hero {
  min-height: max(64svh, 540px);
  align-items: center;
  justify-content: center;
}
.landing .hero__img {
  filter: brightness(0.85) contrast(1.1) saturate(0.86) sepia(0.32) hue-rotate(-8deg);
}
.landing .hero__veil {
  /* the fade to bg is the TOPMOST layer so the hero's last pixel
     is exactly the page ground — no warm/cool seam at the handoff */
  background:
    linear-gradient(180deg, transparent 50%, rgba(22, 14, 8, 0.5) 72%, var(--bg) 93%),
    linear-gradient(180deg, rgba(26, 15, 8, 0.58), rgba(26, 15, 8, 0.16) 22%, transparent 36%),
    radial-gradient(ellipse 88% 72% at 50% 38%, transparent 24%, rgba(24, 13, 6, 0.4) 60%, rgba(13, 7, 3, 0.86) 100%);
}
.landing .hero__title { text-shadow: 0 2px 34px rgba(15, 8, 3, 0.75); }
.landing .hero__roles { text-shadow: 0 1px 14px rgba(15, 8, 3, 0.7); }
.landing .hero__welcome { text-shadow: 0 1px 14px rgba(15, 8, 3, 0.7); }
.landing .hero__body {
  width: 100%;
  padding: 8.5rem 1.5rem 3.4rem;
}
.landing .hero__title {
  font-size: clamp(3rem, 10.5vw, 8rem);
  letter-spacing: 0.13em;
  color: #EDE3CF;
  opacity: 0.97;
}
.landing .hero__roles {
  margin-top: 0.9rem;
  text-transform: lowercase;
  letter-spacing: 0.52em;
  font-size: 0.82rem;
  font-weight: 300;
  color: #E4D9C2;
}
.landing .hero__welcome { letter-spacing: 0.2em; }
.landing .hero__row { margin-top: 2.1rem; }
.landing .btn-line {
  min-height: 44px;
  padding: 0.65rem 1.9rem;
  color: #E9DFC9;
  background: rgba(9, 13, 14, 0.62);
  border-color: rgba(190, 180, 160, 0.55);
  backdrop-filter: blur(2px);
}
.landing .btn-line:hover { background: rgba(9, 13, 14, 0.85); }
.landing .btn-line--red { border-color: var(--red); }
.landing .btn-line--red:hover { background: rgba(9, 13, 14, 0.62); }

.landing .portals {
  max-width: none;
  padding: 1.2rem 1.1rem 0.4rem;
  gap: 1.15rem;
}
.landing .portal { aspect-ratio: 5 / 4; border: 0; }
.landing .portal img { filter: saturate(0.8) brightness(0.55) contrast(1.05); }
.landing .portal:hover img { filter: saturate(0.95) brightness(0.72) contrast(1.05); }
.landing .portal__veil {
  background:
    linear-gradient(to top, rgba(6, 10, 11, 0.94), rgba(6, 10, 11, 0.3) 42%, rgba(6, 10, 11, 0.18)),
    radial-gradient(ellipse 120% 100% at 50% 0%, transparent 55%, rgba(6, 10, 11, 0.5) 100%);
}
.landing .portal__text { left: 2rem; right: 2rem; bottom: 1.9rem; }
.landing .portal__name { font-size: clamp(1.9rem, 3.1vw, 2.6rem); letter-spacing: 0.1em; color: #EDE3CF; }
.landing .portal__name::after { width: 30px; height: 2px; margin-top: 0.55rem; }
.landing .portal__desc { font-size: 1.02rem; margin-top: 0.7rem; color: #BDB2A0; }

.landing .foot { border-top: 0; padding-top: 1.2rem; }
.landing .foot__meta, .landing .foot__cherry { display: none; }
.landing .foot__line { font-size: 0.66rem; color: var(--red-t); }

@media (max-width: 780px) {
  .landing .hero { min-height: max(70svh, 480px); }
  .landing .portals { grid-template-columns: 1fr; }
  .landing .portal { aspect-ratio: 16 / 11; }
}

/* ============================================================
   MOTION — page breath, staged arrivals, micro-interactions
   ============================================================ */

/* cross-page fade: View Transitions where supported, JS fade otherwise */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation-duration: 0.2s; }
::view-transition-new(root) { animation-duration: 0.35s; }

html.js.fade body { opacity: 0; }
html.js.fade.ready body { opacity: 1; transition: opacity 0.4s ease; }
html.js.fade.leaving body { opacity: 0; transition: opacity 0.2s ease; }
@media (prefers-reduced-motion: reduce) {
  html.js.fade body { opacity: 1 !important; transition: none !important; }
}

main, .foot { position: relative; z-index: 1; }

/* landing hero: ken burns + staged entrance */
@media (prefers-reduced-motion: no-preference) {
  .landing .hero__img { animation: hero-settle 4.5s cubic-bezier(0.22, 1, 0.36, 1) both; }
  @keyframes hero-settle {
    from { transform: scale(1.07); }
    to   { transform: scale(1); }
  }
  .landing .hero__title {
    animation: title-in 1.6s cubic-bezier(0.16, 1, 0.3, 1) 0.25s both;
  }
  @keyframes title-in {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 0.97; transform: none; }
  }
  .landing .hero__roles   { animation: soft-in 1.1s ease 0.9s both; }
  .landing .hero__welcome { animation: soft-in 1.1s ease 1.15s both; }
  .landing .hero__row     { animation: soft-in 1.1s ease 1.4s both; }
  .landing .nav           { animation: soft-in 1.2s ease 0.1s both; }
  @keyframes soft-in {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
  }
}

/* subpage titles: rise out of a baseline mask */
html.js .page__head .page__title {
  clip-path: inset(0 0 100% 0);
  transform: translateY(20px);
  transition: clip-path 1s cubic-bezier(0.16, 1, 0.3, 1) 0.1s,
              transform 1s cubic-bezier(0.16, 1, 0.3, 1) 0.1s;
}
html.js .page__head.is-in .page__title {
  clip-path: inset(-2% 0 -8% 0);
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  html.js .page__head .page__title { clip-path: none; transform: none; transition: none; }
}

/* scroll reveals: gentler, with a scale variant for imagery */
html.js [data-r="scale"] { transform: translateY(14px) scale(0.985); }
html.js [data-r].is-in { transform: none; }
/* the page header container stays put — only its title does the clip reveal */
html.js .page__head[data-r] { opacity: 1; transform: none; transition: none; }

/* --- micro-interactions --- */
.nav__links a { position: relative; border-bottom: 0; }
.nav__links a::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--red);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav__links a:hover::after, .nav__links a.is-active::after { transform: scaleX(1); }

.nav__cta { position: relative; overflow: hidden; z-index: 0; }
.nav__cta::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--red);
  transform: translateY(101%);
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: -1;
}
.nav__cta:hover { background: transparent; }
.nav__cta:hover::before { transform: translateY(0); }

.btn-line { position: relative; overflow: hidden; z-index: 0; }
.btn-line::before {
  content: "";
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--red) 90%, transparent);
  transform: translateY(101%);
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: -1;
}
.btn-line--red:hover { background: rgba(9, 13, 14, 0.62); }
.btn-line--red:hover::before { transform: translateY(0); }

.portal__name::after { transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1); }
.portal:hover .portal__name::after { width: 52px; }

.tab { position: relative; }
.trk { transition: background 0.3s, color 0.3s, padding-left 0.35s; }
.trk:hover { padding-left: 1.5rem; }
.trk.is-current:hover { padding-left: 1.2rem; }
.trk.is-ghost { opacity: 0.45; cursor: default; }
.trk.is-ghost:hover { background: transparent; color: var(--muted); padding-left: 1.2rem; }

.player__btn.is-playing { border-color: var(--red); animation: pulse-red 2.2s ease-in-out infinite; }
@keyframes pulse-red {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 35%, transparent); }
  50%      { box-shadow: 0 0 0 9px transparent; }
}
@media (prefers-reduced-motion: reduce) { .player__btn.is-playing { animation: none; } }

.vitem::after {
  content: "";
  position: absolute; inset: 0;
  border: 1px solid transparent;
  /* inset is not compositable; scale the frame instead so it never
     janks against a scroll-driven animation */
  transition: border-color 0.5s, transform 0.5s;
  transform: scale(1);
  pointer-events: none;
}
.vitem:hover::after { border-color: color-mix(in srgb, var(--red) 55%, transparent); transform: scale(0.955); }

.wl__thumb img { transition: transform 1s cubic-bezier(0.16, 1, 0.3, 1); }
.wl:hover .wl__thumb img { transform: scale(1.05); }
.wl__body { overflow: hidden; }

.about-photo img { transition: transform 1.4s cubic-bezier(0.16, 1, 0.3, 1), filter 0.8s; filter: saturate(0.95); }
.about-photo:hover img { transform: scale(1.03); filter: saturate(1.05); }

/* --- honest waiting states --- */
.media-note, .form-note {
  margin-top: 1.2rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 0.98rem;
  color: var(--muted);
}
.filmbox__note {
  position: absolute; left: 0; right: 0;
  bottom: 2rem;
  text-align: center;
  font-family: var(--poetic);
  font-style: italic;
  color: var(--ink);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.5s, transform 0.5s;
  z-index: 2;
  pointer-events: none;
}
.filmbox.show-note .filmbox__note { opacity: 1; transform: none; }
.filmbox { cursor: pointer; }
.filmbox:hover .filmbox__play { border-color: var(--red); box-shadow: 0 0 30px color-mix(in srgb, var(--red) 35%, transparent); }
.filmbox__play { transition: border-color 0.4s, box-shadow 0.4s, transform 0.4s; }
.filmbox:hover .filmbox__play { transform: scale(1.06); }

/* --- the gift, restored --- */
.giftpanel {
  margin-top: 2.6rem;
  display: grid;
  grid-template-columns: 118px 1fr;
  gap: 2rem;
  align-items: start;
  border: 1px solid var(--line);
  background: var(--bg2);
  padding: 1.9rem;
}
.giftpanel__qr {
  background: var(--ink);
  padding: 10px;
}
.giftpanel__qr svg { display: block; width: 100%; fill: var(--bg); }
.giftpanel__qr--big { width: 100%; }
.giftpanel--tall { grid-template-columns: 170px 1fr; }
.giftpanel__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.15rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.7rem;
}
.giftpanel__text {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.02rem;
  line-height: 1.75;
  color: var(--muted);
  margin-bottom: 1rem;
  max-width: 52ch;
}
.gift-list { margin-top: 1.2rem; }
@media (max-width: 640px) {
  .giftpanel, .giftpanel--tall { grid-template-columns: 96px 1fr; gap: 1.2rem; }
}


/* reduced motion: final word */
@media (prefers-reduced-motion: reduce) {
  html.js [data-r] { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
   THE DUALITY — Cherry & DN, one voice with two names
   ============================================================ */
.duality-intro { text-align: center; margin: 2.8rem 0 2rem; }
.duality-intro__caps {
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.44em;
  text-transform: uppercase;
  color: var(--muted);
}
.duality-intro__line {
  margin-top: 0.5rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.1rem;
  color: var(--red-t);
}

.duality {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 2.4rem;
  align-items: start;
}
.duality__half {
  padding: 2rem 1.7rem;
  border: 1px solid var(--line);
  transition: background 0.7s;
}
.duality__half--cherry {
  background:
    radial-gradient(ellipse at 30% 0%, rgba(203, 178, 140, 0.07), transparent 55%),
    var(--bg2);
}
.duality__half--dn {
  background:
    radial-gradient(ellipse at 70% 0%, rgba(46, 90, 96, 0.1), transparent 55%),
    var(--bg2);
}
.duality__half--cherry:hover { background: radial-gradient(ellipse at 30% 0%, rgba(203, 178, 140, 0.11), transparent 60%), var(--bg2); }
.duality__half--dn:hover { background: radial-gradient(ellipse at 70% 0%, rgba(46, 90, 96, 0.15), transparent 60%), var(--bg2); }

.duality__eyebrow {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 0.95rem;
  color: var(--muted);
}
.duality__name {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.9rem, 4.2vw, 2.8rem);
  letter-spacing: 0.14em;
  margin: 0.3rem 0 0.7rem;
}
.duality__name--cherry { color: var(--red-display); }
.duality__name--dn { color: #A9B7B7; }
.duality__name::after {
  content: "";
  display: block;
  width: 30px; height: 2px;
  margin-top: 0.6rem;
  transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.duality__name--cherry::after { background: var(--red); }
.duality__name--dn::after { background: #5E7476; }
.duality__half:hover .duality__name::after { width: 52px; }
.duality__desc {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--muted);
  margin-bottom: 1.4rem;
}
.duality__half .tracklist { border: 0; border-top: 1px solid var(--line); }
.duality__half .trk { padding-left: 0.4rem; }
.duality__half .trk:hover { padding-left: 0.8rem; }

.duality__divider {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
}
.duality__divider::before, .duality__divider::after {
  content: "";
  width: 1px;
  flex: 1;
  background: linear-gradient(to bottom, transparent, var(--line) 30%, var(--line) 70%, transparent);
}
.duality__divider span {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.3rem;
  color: var(--red-t);
}

@media (max-width: 860px) {
  .duality { grid-template-columns: 1fr; gap: 1.6rem; }
  .duality__divider { flex-direction: row; width: 100%; }
  .duality__divider::before, .duality__divider::after {
    width: auto; height: 1px; flex: 1;
    background: linear-gradient(to right, transparent, var(--line) 30%, var(--line) 70%, transparent);
  }
}

/* ============================================================
   THE DUALITY, ALIVE — mirrored, responsive, one voice at a time
   ============================================================ */

/* they face each other across the spine */
.duality__half--dn { text-align: right; }
.duality__half--dn .duality__name::after { margin-left: auto; }
.duality__half--dn .duality__desc { margin-left: auto; }
.duality__half--dn .tracklist { direction: ltr; text-align: left; }

/* two voices, two temperaments — even the hairlines have a temperature */
.duality__half--cherry { border-color: rgba(203, 178, 140, 0.22); }
.duality__half--dn { border-color: rgba(94, 116, 118, 0.4); }
.duality__half--cherry .duality__name { letter-spacing: 0.18em; }
.duality__half--dn .duality__name { letter-spacing: 0.08em; }
.duality__eyebrow--dn {
  font-family: var(--ui);
  font-style: normal;
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.34em;
  text-transform: uppercase;
}
.duality__half--cherry .trk__no { color: var(--red-t); }
.duality__half--dn .trk__no { color: #7E9496; }
.duality__half--cherry .trk.is-current { box-shadow: inset 2px 0 0 var(--red); }
.duality__half--dn .trk.is-current { box-shadow: inset 2px 0 0 #5E7476; }

/* contradiction: reaching for one, the other recedes */
.duality__half { transition: background 0.7s, opacity 0.7s, filter 0.7s, border-color 0.7s; }
.duality:has(.duality__half--cherry:hover) .duality__half--dn,
.duality:has(.duality__half--dn:hover) .duality__half--cherry {
  opacity: 0.55;
  filter: saturate(0.6);
}

/* the hinge leans toward whoever you reach for, and it breathes */
.duality__divider span {
  display: inline-block;
  transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1), color 0.6s;
}
@media (prefers-reduced-motion: no-preference) {
  .duality__divider span { animation: hinge-breathe 6s ease-in-out infinite alternate; }
  @keyframes hinge-breathe {
    from { opacity: 0.65; }
    to   { opacity: 1; }
  }
}
.duality:has(.duality__half--cherry:hover) .duality__divider span {
  transform: rotate(-12deg) scale(1.15);
  color: var(--red-display);
}
.duality:has(.duality__half--dn:hover) .duality__divider span {
  transform: rotate(12deg) scale(1.15);
  color: #A9B7B7;
}

/* one voice: whoever sings, the world takes their temperature */
body[data-persona] .duality__half { transition: opacity 1.2s, filter 1.2s, border-color 1.2s, background 1.2s; }
body[data-persona="cherry"] .duality__half--dn,
body[data-persona="dn"] .duality__half--cherry { opacity: 0.5; filter: saturate(0.55); }
body[data-persona="cherry"] .player { border-color: color-mix(in srgb, var(--red) 55%, transparent); }
body[data-persona="cherry"] .player__btn { border-color: var(--red); }
body[data-persona="dn"] .player { border-color: rgba(94, 116, 118, 0.65); }
body[data-persona="dn"] .player__btn { border-color: #5E7476; }
body[data-persona="dn"] .player__btn.is-playing { animation: pulse-steel 2.2s ease-in-out infinite; }
@keyframes pulse-steel {
  0%, 100% { box-shadow: 0 0 0 0 rgba(94, 116, 118, 0.4); }
  50%      { box-shadow: 0 0 0 9px rgba(94, 116, 118, 0); }
}

/* the intro carries the spine down into the split */
.duality-intro { position: relative; padding-bottom: 1.6rem; margin-bottom: 0.4rem; }
.duality-intro::after {
  content: "";
  position: absolute; left: 50%; bottom: 0;
  width: 1px; height: 1.4rem;
  background: linear-gradient(to bottom, var(--line), transparent);
}

@media (max-width: 860px) {
  .duality__half--dn { text-align: right; }
}

/* ============================================================
   THE DIPTYCH — one stage, two halves, everything leans
   toward the spine where the & lives
   ============================================================ */
.dstage {
  position: relative;
  margin: 0 calc(50% - 50vw) 2.8rem;   /* full bleed */
  display: grid;
  grid-template-columns: 1fr 1fr;
}
.dstage::before {
  content: "";
  position: absolute;
  left: 50%; top: 0; bottom: 0;
  width: 1px;
  background: linear-gradient(to bottom,
    var(--line), color-mix(in srgb, var(--red) 50%, transparent) 38%, var(--line) 75%, transparent);
  transform: translateX(-0.5px);
}
.dstage__half {
  display: flex;
  padding: 4.4rem 3.4rem 4rem;
  min-height: 540px;
  transition: opacity 0.8s, filter 0.8s, background 0.8s;
}
.dstage__half--cherry {
  justify-content: flex-end;
  text-align: right;
  background:
    radial-gradient(ellipse at 82% 10%, color-mix(in srgb, var(--red) 17%, transparent), transparent 52%),
    radial-gradient(ellipse at 15% 88%, rgba(203, 178, 140, 0.06), transparent 50%),
    linear-gradient(115deg, #150d10 0%, #0e1315 85%);
}
.dstage__half--dn {
  justify-content: flex-start;
  text-align: left;
  background:
    radial-gradient(ellipse at 18% 10%, rgba(70, 110, 115, 0.16), transparent 52%),
    radial-gradient(ellipse at 88% 88%, rgba(28, 44, 46, 0.25), transparent 55%),
    linear-gradient(245deg, #0c1517 0%, #0e1113 85%);
}
.dstage__inner {
  width: min(440px, 100%);
  display: flex;
  flex-direction: column;
}

.dstage__eyebrow--cherry {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1rem;
  color: var(--muted);
}
.dstage__eyebrow--dn {
  font-family: var(--ui);
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--muted);
  padding-top: 0.3rem;
}
.dstage__name {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.7rem, 5.6vw, 4.3rem);
  line-height: 1;
  margin: 0.5rem 0 0;
}
.dstage__name--cherry { color: var(--red-display); letter-spacing: 0.15em; margin-right: -0.15em; }
.dstage__name--dn { color: #AFC0C0; letter-spacing: 0.32em; margin-left: 0; }
.dstage__name::after {
  content: "";
  display: block;
  width: 34px; height: 2px;
  margin-top: 1.1rem;
  transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.dstage__name--cherry::after { background: var(--red); margin-left: auto; }
.dstage__name--dn::after { background: #5E7476; }
.dstage__half:hover .dstage__name::after { width: 58px; }

.dstage__desc {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--muted);
  margin: 1.1rem 0 0;
  min-height: 3.6em;
}

.dlist { list-style: none; margin-top: 1.6rem; border-top: 1px solid var(--line); }
.dlist .trk {
  display: flex;
  align-items: baseline;
  gap: 1.3rem;
  padding: 1rem 0.2rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.3s, background 0.3s;
}
.dlist .trk:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 2%, transparent); padding-left: 0.2rem; }
.dlist .trk__name { flex: 1; }
.dlist--cherry .trk__name { text-align: right; }
.dlist--cherry .trk__no { color: var(--red-t); }
.dlist--dn .trk__no { color: #7E9496; }
.dlist--cherry .trk.is-current { box-shadow: inset -2px 0 0 var(--red); background: color-mix(in srgb, var(--red) 6%, transparent); }
.dlist--dn .trk.is-current { box-shadow: inset 2px 0 0 #5E7476; background: rgba(94, 116, 118, 0.07); }
.dlist .trk.is-ghost { opacity: 0.55; cursor: default; }
.dlist .trk.is-ghost:hover { color: var(--muted); background: transparent; }

/* the hinge, at the heart of the spine */
.dstage__amp {
  --amp-place: translate(-50%, -50%);   /* becomes translate(0,0) when stacked */
  position: absolute;
  left: 50%; top: 44%;
  transform: var(--amp-place);
  font-family: var(--poetic);
  font-style: italic;
  font-size: 2.4rem;
  color: var(--red-t);
  background: var(--bg);
  padding: 0.55rem 0.3rem;
  z-index: 1;
  transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1), color 0.6s;
}
@media (prefers-reduced-motion: no-preference) {
  .dstage__amp { animation: hinge-breathe 6s ease-in-out infinite alternate; }
}

/* contradiction: reach for one, the other steps back into the dark */
.dstage:has(.dstage__half--cherry:hover) .dstage__half--dn,
.dstage:has(.dstage__half--dn:hover) .dstage__half--cherry {
  opacity: 0.5;
  filter: saturate(0.55) brightness(0.85);
}
.dstage:has(.dstage__half--cherry:hover) .dstage__amp {
  transform: var(--amp-place) rotate(-12deg) scale(1.18);
  color: var(--red-display);
}
.dstage:has(.dstage__half--dn:hover) .dstage__amp {
  transform: var(--amp-place) rotate(12deg) scale(1.18);
  color: #AFC0C0;
}

/* one voice: whoever sings, the other half falls dark */
body[data-persona="cherry"] .dstage__half--dn,
body[data-persona="dn"] .dstage__half--cherry {
  opacity: 0.45;
  filter: saturate(0.5) brightness(0.8);
}

/* the shared throat below the two names */
.dstage ~ .player, .player {
  max-width: 780px;
  margin-left: auto;
  margin-right: auto;
}

/* the intro's thread reaches the stage */
.duality-intro { margin-bottom: 0; padding-bottom: 2rem; }
.duality-intro::after { height: 2rem; }

@media (max-width: 860px) {
  .dstage { grid-template-columns: 1fr; }
  .dstage::before {
    left: 10%; right: 10%; top: auto; bottom: auto;
    width: auto; height: 1px;
    top: 50%;
  }
  .dstage__half { min-height: 0; padding: 3rem 1.5rem 2.6rem; }
  /* stacked, an absolutely centred hinge lands on top of a song title.
     Let it flow: the DOM already has it between the two halves. */
  .dstage__amp {
    --amp-place: translate(0, 0);
    position: static;
    justify-self: center;
    background: none;
    padding: 0;
    margin: 0.2rem 0;
  }
  .dstage__inner { width: 100%; }
}

/* ============================================================
   THE DIPTYCH AS WEATHER — full-page stage, diffused seam,
   two atmospheres breathing into each other
   ============================================================ */
.stage-page .nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom: 0;
}
/* after 24px of scroll the veiled bar returns — wayfinding never leaves */
.stage-page .nav.is-scrolled {
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.dstage--hero {
  margin: 0 0 0.5rem;
  min-height: 100svh;
  overflow: hidden;
}
.dstage--hero::before { display: none; }   /* no hard line — the seam is mist */
.dstage--hero .dstage__half {
  min-height: 100svh;
  padding: 15rem 3.4rem 5rem;
  align-items: center;
  position: relative;
  z-index: 1;
}
.dstage--hero .dstage__inner { margin: auto 0; }
.dstage--hero .dstage__half--cherry {
  background:
    radial-gradient(ellipse at 70% 8%, color-mix(in srgb, var(--red) 14%, transparent), transparent 55%),
    linear-gradient(115deg, #150d10 0%, #0d1214 100%);
}
.dstage--hero .dstage__half--dn {
  background:
    radial-gradient(ellipse at 30% 8%, rgba(70, 110, 115, 0.13), transparent 55%),
    linear-gradient(245deg, #0c1517 0%, #0d1113 100%);
}

/* crown */
.dstage__crown {
  position: absolute;
  top: 6.2rem; left: 0; right: 0;
  text-align: center;
  z-index: 3;
  pointer-events: none;
}
.crown__num {
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.44em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--red-t) 72%, var(--ink));
}
.crown__tag {
  margin-top: 0.7rem;
  font-size: 0.66rem;
  font-weight: 400;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ink);
}
.crown__line {
  margin-top: 0.6rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.05rem;
  color: var(--muted);
}
.crown__line::after {
  content: "";
  display: block;
  width: 1px; height: 2.6rem;
  margin: 1rem auto 0;
  background: linear-gradient(to bottom, var(--line), transparent);
}

/* --- the mist: two atmospheres diffusing across the seam --- */
.dstage__mist {
  position: absolute; inset: -12%;
  z-index: 0;
  pointer-events: none;
}
.mist {
  position: absolute;
  top: 0; bottom: 0;
  width: 58%;
  opacity: 0.6;
  will-change: transform, opacity;
  transition: opacity 1.8s ease, transform 2.2s cubic-bezier(0.22, 1, 0.36, 1);
}
.mist::before {
  content: "";
  position: absolute; inset: 0;
  filter: blur(64px);
}
.mist--cherry { left: -4%; }
.mist--cherry::before {
  background:
    radial-gradient(46% 38% at 70% 32%, color-mix(in srgb, var(--red) 34%, transparent), transparent 72%),
    radial-gradient(38% 30% at 58% 72%, rgba(203, 178, 140, 0.1), transparent 70%);
}
.mist--dn { right: -4%; }
.mist--dn::before {
  background:
    radial-gradient(46% 38% at 30% 62%, rgba(74, 118, 124, 0.44), transparent 72%),
    radial-gradient(36% 28% at 42% 24%, rgba(135, 168, 172, 0.18), transparent 70%);
}
@media (prefers-reduced-motion: no-preference) {
  .mist--cherry::before { animation: mist-flow-a 17s ease-in-out infinite alternate; }
  .mist--dn::before { animation: mist-flow-b 21s ease-in-out infinite alternate; }
  @keyframes mist-flow-a {
    0%   { transform: translate3d(0, 0, 0) scale(1) rotate(0deg); }
    50%  { transform: translate3d(3.5%, -2.5%, 0) scale(1.07) rotate(1.2deg); }
    100% { transform: translate3d(1.5%, 2.5%, 0) scale(1.03) rotate(-1deg); }
  }
  @keyframes mist-flow-b {
    0%   { transform: translate3d(0, 0, 0) scale(1.04) rotate(0deg); }
    50%  { transform: translate3d(-3.5%, 3%, 0) scale(1) rotate(-1.2deg); }
    100% { transform: translate3d(-1.5%, -2%, 0) scale(1.08) rotate(0.8deg); }
  }
}

/* attention feeds the weather: the hovered side floods the seam */
.dstage[data-attend="cherry"] .mist--cherry {
  opacity: 1;
  transform: translate3d(2%, 0, 0) scale(1.16);
}
.dstage[data-attend="cherry"] .mist--cherry::before {
  filter: blur(46px);
  background:
    radial-gradient(78% 68% at 26% 48%, rgba(160, 34, 52, 0.72), rgba(130, 28, 42, 0.4) 58%, transparent 84%),
    radial-gradient(54% 46% at 58% 76%, rgba(132, 26, 40, 0.5), transparent 74%);
}
.dstage:has(.dstage__half--cherry:hover) .mist--cherry,
.dstage.sim-cherry .mist--cherry,
body[data-persona="cherry"] .mist--cherry {
  opacity: 0.95;
  transform: translate3d(15%, 0, 0) scale(1.18);
}
.dstage:has(.dstage__half--cherry:hover) .mist--dn,
.dstage.sim-cherry .mist--dn,
body[data-persona="cherry"] .mist--dn {
  opacity: 0.28;
  transform: translate3d(7%, 0, 0) scale(0.94);
}
.dstage:has(.dstage__half--dn:hover) .mist--dn,
.dstage.sim-dn .mist--dn,
body[data-persona="dn"] .mist--dn {
  opacity: 0.95;
  transform: translate3d(-15%, 0, 0) scale(1.18);
}
.dstage:has(.dstage__half--dn:hover) .mist--cherry,
.dstage.sim-dn .mist--cherry,
body[data-persona="dn"] .mist--cherry {
  opacity: 0.28;
  transform: translate3d(-7%, 0, 0) scale(0.94);
}

/* halves themselves keep only a whisper of the old dimming — the mist speaks now */
.dstage--hero:has(.dstage__half--cherry:hover) .dstage__half--dn,
.dstage--hero:has(.dstage__half--dn:hover) .dstage__half--cherry {
  opacity: 0.78;
  filter: saturate(0.75);
}

/* the & floats free in the mist */
.dstage--hero .dstage__amp {
  background: none;
  font-size: 2.7rem;
  top: 47%;
  text-shadow: 0 0 26px color-mix(in srgb, var(--bg) 90%, transparent);
}

/* entrance */
@media (prefers-reduced-motion: no-preference) {
  .dstage__crown { animation: soft-in 1.2s ease 0.2s both; }
  .dstage--hero .dstage__half--cherry .dstage__inner { animation: soft-in 1.3s ease 0.55s both; }
  .dstage--hero .dstage__half--dn .dstage__inner { animation: soft-in 1.3s ease 0.8s both; }
  .dstage__mist { animation: soft-in 2.6s ease 0.1s both; }
}

@media (max-width: 860px) {
  .dstage--hero .dstage__half { min-height: 0; padding: 3.2rem 1.5rem 2.8rem; }
  .dstage--hero .dstage__half--cherry { padding-top: 15rem; }
  .dstage__crown { top: 5.4rem; }
  .mist { width: 120%; height: 58%; top: auto; }
  .mist--cherry { left: -10%; top: 0; }
  .mist--dn { right: -10%; bottom: 0; }
}

/* ============================================================
   TWO RIVERS — the halves paint nothing; one continuous bed,
   three currents of light, merging mid-stream
   ============================================================ */
.dstage--hero {
  /* the bed itself lands on the page ground — no foreign color at the floor */
  background:
    radial-gradient(ellipse 90% 50% at 50% 0%, #10161a 0%, transparent 65%),
    linear-gradient(180deg, #0e1315 0%, #0c1214 68%, var(--bg) 94%);
}
.dstage--hero .dstage__half--cherry,
.dstage--hero .dstage__half--dn {
  background: none;
}

/* wider, stronger currents whose tails cross the middle */
.mist { width: 66%; opacity: 0.72; }
.mist--cherry { left: -6%; }
.mist--dn { right: -6%; }

/* the confluence: where the two waters try to fill each other */
.mist--merge {
  left: 26%; right: 26%;
  top: -12%; bottom: -12%;
  width: auto;
  opacity: 0.6;
}
.mist--merge::before {
  background:
    radial-gradient(40% 32% at 36% 28%, color-mix(in srgb, var(--red) 20%, transparent), transparent 70%),
    radial-gradient(44% 36% at 64% 66%, rgba(74, 118, 124, 0.24), transparent 70%),
    radial-gradient(30% 24% at 50% 46%, rgba(150, 110, 105, 0.1), transparent 68%);
  filter: blur(84px);
}
@media (prefers-reduced-motion: no-preference) {
  .mist--merge::before { animation: merge-swirl 23s ease-in-out infinite alternate; }
  @keyframes merge-swirl {
    0%   { transform: translateY(-4%) scale(1) rotate(0deg); }
    50%  { transform: translateY(3.5%) scale(1.1) rotate(2.2deg); }
    100% { transform: translateY(-2%) scale(1.05) rotate(-1.8deg); }
  }
}

/* floods deepen the confluence rather than erasing it */
.dstage:has(.dstage__half--cherry:hover) .mist--merge,
.dstage:has(.dstage__half--dn:hover) .mist--merge,
body[data-persona] .mist--merge {
  opacity: 0.78;
}

/* ============================================================
   RIVERS v2 — two strong bodies of liquid, churning where they meet
   ============================================================ */

/* each side owns its color, richly */
.mist { width: 60%; opacity: 0.85; }
.mist--cherry::before {
  background:
    radial-gradient(72% 62% at 28% 46%, color-mix(in srgb, var(--red) 52%, transparent), rgba(130, 28, 42, 0.26) 56%, transparent 80%),
    radial-gradient(48% 40% at 60% 74%, rgba(118, 24, 36, 0.34), transparent 72%);
  filter: blur(54px);
  transition: background 1.6s ease, filter 1.6s ease;
}
.mist--dn::before {
  background:
    radial-gradient(72% 62% at 72% 50%, rgba(86, 122, 128, 0.48), rgba(78, 112, 118, 0.22) 56%, transparent 80%),
    radial-gradient(46% 38% at 40% 24%, rgba(126, 156, 162, 0.26), transparent 70%);
  filter: blur(54px);
}

/* the churn: tongues of each liquid pushing across the midline,
   interleaved at different heights so they fill each other's gaps */
.mist::after {
  content: "";
  position: absolute;
  top: -4%; bottom: -4%;
  width: 58%;
  filter: blur(42px);
  pointer-events: none;
}
.mist--cherry::after {
  right: -22%;
  background:
    radial-gradient(30% 15% at 66% 24%, rgba(148, 34, 48, 0.44), transparent 70%),
    radial-gradient(34% 13% at 76% 52%, color-mix(in srgb, var(--red) 38%, transparent), transparent 70%),
    radial-gradient(26% 12% at 62% 79%, rgba(126, 28, 40, 0.32), transparent 70%);
}
.mist--dn::after {
  left: -22%;
  background:
    radial-gradient(30% 14% at 34% 12%, rgba(96, 132, 138, 0.4), transparent 70%),
    radial-gradient(34% 15% at 24% 38%, rgba(88, 124, 130, 0.42), transparent 70%),
    radial-gradient(28% 13% at 38% 65%, rgba(104, 138, 144, 0.34), transparent 70%),
    radial-gradient(24% 11% at 28% 90%, rgba(90, 126, 132, 0.3), transparent 70%);
}
@media (prefers-reduced-motion: no-preference) {
  .mist--cherry::after { animation: tongues-a 13s ease-in-out infinite alternate; }
  .mist--dn::after { animation: tongues-b 16s ease-in-out infinite alternate; }
  @keyframes tongues-a {
    0%   { transform: translate3d(0, -2.5%, 0) scaleY(1); }
    50%  { transform: translate3d(2.5%, 1.5%, 0) scaleY(1.06); }
    100% { transform: translate3d(0.8%, 3%, 0) scaleY(0.98); }
  }
  @keyframes tongues-b {
    0%   { transform: translate3d(0, 2.5%, 0) scaleY(1.04); }
    50%  { transform: translate3d(-2.5%, -1.5%, 0) scaleY(0.97); }
    100% { transform: translate3d(-0.8%, -3%, 0) scaleY(1.05); }
  }
}

/* the old central wash muddied everything — reduce it to a faint glint
   in the churn, nothing more */
.mist--merge { left: 36%; right: 36%; opacity: 0.4; }
.mist--merge::before {
  background:
    radial-gradient(34% 18% at 44% 34%, rgba(150, 60, 62, 0.18), transparent 70%),
    radial-gradient(36% 20% at 56% 62%, rgba(96, 126, 132, 0.2), transparent 70%);
  filter: blur(64px);
}
.dstage:has(.dstage__half--cherry:hover) .mist--merge,
.dstage:has(.dstage__half--dn:hover) .mist--merge,
body[data-persona] .mist--merge { opacity: 0.55; }

/* ============================================================
   FOCUS — the courted side confides; the other becomes
   only its name, larger, sunk in its own river
   ============================================================ */
.dstage__eyebrow, .dstage__desc, .dstage__half .dlist {
  transition: opacity 0.55s ease, transform 0.55s ease;
}
.dstage__name {
  transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1), color 0.6s;
}
.dstage__name--cherry { transform-origin: right center; }
.dstage__name--dn { transform-origin: left center; }

/* THE ATTENDED SIDE
   Reach for one half and it comes forward: its name grows, its letters
   open, it takes a breath of its own colour, and its songs are the only
   songs on the page. The other keeps nothing but its name, and that name
   floats to the middle of its own half.

   One attribute decides all of it. js/cherry.js resolves pointer, keyboard
   focus and the playing persona into .dstage[data-attend="cherry"|"dn"],
   so precedence is settled in one place instead of by specificity accident
   across six selector groups. Adding a state here means adding it once.

   Two things that are easy to get wrong, both learned the hard way:
   · this ran inside out at first, the side you were NOT on rising
     monumental. It has to follow the hand.
   · .dstage__inner cannot be scaled or offset from here. It carries the
     entrance animation with fill-mode both, so its transform is
     animation-owned for the life of the page and any rule loses silently. */
.dstage { --away-scale: 1; }   /* the one she is not on keeps its size; it only moves */

.dstage__name { transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1),
  letter-spacing 0.9s cubic-bezier(0.22, 1, 0.36, 1),
  margin 0.9s cubic-bezier(0.22, 1, 0.36, 1),
  text-shadow 0.8s ease, color 0.6s; }
.dstage__eyebrow { transition: color 0.6s ease, opacity 0.5s ease, transform 0.5s ease; }
.dstage__desc { transition: opacity 0.45s ease, transform 0.55s cubic-bezier(0.22, 1, 0.36, 1); }
.dstage__half .dlist { transition: border-color 0.4s ease; }
.dstage__half .trk { transition: opacity 0.5s ease,
  transform 0.6s cubic-bezier(0.22, 1, 0.36, 1), color 0.3s, background 0.3s; }

/* ---- the one she is on ---- */
.dstage[data-attend="cherry"] .dstage__half--cherry .dstage__name,
.dstage[data-attend="dn"] .dstage__half--dn .dstage__name {
  transform: scale(1.3);
}
.dstage[data-attend="cherry"] .dstage__half--cherry .dstage__name--cherry {
  letter-spacing: 0.19em;
  margin-right: -0.19em;
  text-shadow: 0 0 42px color-mix(in srgb, var(--red-display) 50%, transparent), 0 0 14px color-mix(in srgb, var(--red-display) 28%, transparent);
}
.dstage[data-attend="dn"] .dstage__half--dn .dstage__name--dn {
  letter-spacing: 0.38em;
  text-shadow: 0 0 42px rgba(175, 192, 192, 0.34), 0 0 14px rgba(175, 192, 192, 0.2);
}
.dstage[data-attend="cherry"] .dstage__half--cherry .dstage__name::after,
.dstage[data-attend="dn"] .dstage__half--dn .dstage__name::after {
  width: 74px;
}
.dstage[data-attend="cherry"] .dstage__half--cherry .dstage__eyebrow,
.dstage[data-attend="dn"] .dstage__half--dn .dstage__eyebrow {
  color: var(--ink);
}

/* ---- the one she is not on ----
   The drift is measured in cherry.js and handed here as --drift-x /
   --drift-y: the distance from the name to the middle of its half is a
   measurement, not something a stylesheet can know. With no JS the
   properties are absent, the name shrinks in place, and nothing breaks. */
.dstage[data-attend="cherry"] .dstage__half--dn .dstage__name,
.dstage[data-attend="dn"] .dstage__half--cherry .dstage__name {
  transform: translate(var(--drift-x, 0px), var(--drift-y, 0px)) scale(var(--away-scale));
}
.dstage[data-attend="cherry"] .dstage__half--dn .dstage__name::after,
.dstage[data-attend="dn"] .dstage__half--cherry .dstage__name::after {
  width: 0;
  opacity: 0;
}
.dstage[data-attend="cherry"] .dstage__half--dn .dstage__eyebrow,
.dstage[data-attend="cherry"] .dstage__half--dn .dstage__desc,
.dstage[data-attend="dn"] .dstage__half--cherry .dstage__eyebrow,
.dstage[data-attend="dn"] .dstage__half--cherry .dstage__desc {
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
}

/* Only the attended songs are on the page. The rows carry the fade, not
   the list, so the stagger below has something to move; the list keeps
   the pointer-events so nothing invisible can be clicked. */
.dstage[data-attend="cherry"] .dstage__half--dn .dlist,
.dstage[data-attend="dn"] .dstage__half--cherry .dlist {
  pointer-events: none;
  /* the rows carry the fade, so the list's own hairline has to be told
     separately: otherwise a rule hangs in the air under a lone name */
  border-top-color: transparent;
}
.dstage[data-attend="cherry"] .dstage__half--dn .trk,
.dstage[data-attend="dn"] .dstage__half--cherry .trk {
  opacity: 0;
  transform: translateY(16px);
  transition-delay: 0s;          /* leaving is one movement, not a queue */
}

/* Coming back, the songs arrive one after another, the way a needle finds
   the groove. The delays sit on the resting state, so they apply as the
   rows return and never on the way out. */
.dstage .dstage__half .trk:nth-child(1) { transition-delay: 0.02s; }
.dstage .dstage__half .trk:nth-child(2) { transition-delay: 0.07s; }
.dstage .dstage__half .trk:nth-child(3) { transition-delay: 0.12s; }
.dstage .dstage__half .trk:nth-child(4) { transition-delay: 0.17s; }
.dstage .dstage__half .trk:nth-child(5) { transition-delay: 0.22s; }
.dstage .dstage__half .trk:nth-child(6) { transition-delay: 0.27s; }
.dstage .dstage__half .trk:nth-child(7) { transition-delay: 0.32s; }
.dstage .dstage__half .trk:nth-child(8) { transition-delay: 0.37s; }

/* the hinge leans toward whoever is attended */
.dstage[data-attend="cherry"] .dstage__amp {
  transform: var(--amp-place) rotate(-12deg) scale(1.18);
  color: var(--red-display);
}
.dstage[data-attend="dn"] .dstage__amp {
  transform: var(--amp-place) rotate(12deg) scale(1.18);
  color: #AFC0C0;
}

/* the play control, so a song is a real button and not a listitem
   pretending to be one */
.trk__go {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  background: none; border: 0; padding: 0;
  cursor: pointer; font: inherit; color: inherit;
}
.trk { position: relative; }
.trk__words, .trk__lyrics { position: relative; z-index: 1; }

/* Nothing hides where it cannot be brought back, and nothing floats to
   the middle of a half that is no longer beside anything: on touch, and
   once the two halves stack, the whole mechanic stands down. */
@media (hover: none), (max-width: 860px) {
  .dstage__eyebrow, .dstage__desc, .dstage__half .dlist,
  .dstage__half .trk { opacity: 1 !important; transform: none !important; pointer-events: auto !important; }
  .dstage__name { transform: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .dstage__eyebrow, .dstage__desc, .dstage__half .dlist,
  .dstage__half .trk, .dstage__name { transition: none; }
  .dstage__half .trk { transition-delay: 0s !important; }
  /* the drift itself is zeroed in cherry.js: it writes inline custom
     properties, and inline always beats a stylesheet, so a rule here
     could never win */
}

/* ============================================================
   THE ESTUARY — where the rivers settle into one channel.
   The stage dissolves into the page; the coda below is one
   centered composition, not floating fragments.
   ============================================================ */
.dstage--hero::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 24svh;
  /* eased S-curve: the rivers keep their color, then commit to dark quickly.
     z-index 0 — the veil dissolves the water, never the words: it paints
     after the mist in tree order but under the halves' text (z-index 1). */
  background: linear-gradient(to bottom, transparent, color-mix(in srgb, var(--bg) 10%, transparent) 24%, color-mix(in srgb, var(--bg) 32%, transparent) 46%, color-mix(in srgb, var(--bg) 62%, transparent) 64%, color-mix(in srgb, var(--bg) 88%, transparent) 78%, var(--bg) 90%);
  z-index: 0;
  pointer-events: none;
}
/* the water itself thins to nothing before the floor — no clipped mist
   edge for the scrim to hide, so no line can survive at the boundary */
.dstage--hero .dstage__mist {
  -webkit-mask-image: linear-gradient(to bottom, #000 64%, transparent 87%);
          mask-image: linear-gradient(to bottom, #000 64%, transparent 87%);
}
.dstage--hero { margin-bottom: 0; }

.stage-page--music .page {
  max-width: 860px;
  padding-top: 0;
  padding-bottom: 4.5rem;
  text-align: center;
}
/* the thread returns — the crown's line descends into the shared throat */
.stage-page--music .page::before {
  content: "";
  display: block;
  width: 1px; height: 2.6rem;
  margin: 0 auto 2.6rem;
  background: linear-gradient(to bottom, transparent, var(--line));
}
.stage-page .player { text-align: left; }
.stage-page .media-note { margin-top: 1.4rem; }

.stage-page .melodies {
  margin-top: 4.5rem;
}
/* no cover art yet → the coda reads as one centered poem, no empty frame */
.stage-page .melodies:not(:has(img)) {
  display: block;
}
.stage-page .melodies:not(:has(img)) .melodies__art { display: none; }
.stage-page .melodies:not(:has(img)) .melodies__title { margin-bottom: 1.4rem; }
.stage-page .melodies:not(:has(img)) .melodies__text {
  /* Cormorant's small x-height needs ~1.3x the rem to hold focal weight */
  font-size: clamp(1.28rem, 1.1rem + 0.5vw, 1.45rem);
  line-height: 1.6;
  color: var(--ink);
  margin-bottom: 1.6rem;
}
/* when her cover art arrives, the grid returns — but composed, not floating */
.stage-page .melodies:has(img) { text-align: left; }

/* ============================================================
   THE ARCHIVE ARRIVES — text-only written pieces, full-width
   ============================================================ */
/* Her name holds the left column and her words take the whole right one.
   The old single column left half the page empty beside every poem, which
   read as a page that had run out of things to say. */
.wl--text {
  grid-template-columns: clamp(160px, 21%, 290px) minmax(0, 1fr);
  grid-template-areas:
    "title excerpt"
    "kind  excerpt"
    "read  body";
  column-gap: clamp(1.6rem, 4vw, 3.6rem);
  row-gap: 0;
  align-items: start;
}
.wl--text .wl__title   { grid-area: title; }
.wl--text .wl__kind    { grid-area: kind; }
.wl--text .wl__read    { grid-area: read; margin-top: 1.1rem; }
.wl--text .wl__excerpt { grid-area: excerpt; margin-top: 0; max-width: 62ch; }
.wl--text .wl__body    { grid-area: body; max-width: 66ch; margin-top: 1.4rem; }

@media (max-width: 820px) {
  .wl--text {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "title" "kind" "excerpt" "body" "read";
  }
  .wl--text .wl__excerpt { margin-top: 0.7rem; }
  .wl--text .wl__body { margin-top: 1.1rem; }
}

/* ============================================================
   THE REFERENCE CUT — landing matched to the approved frame:
   serif nav, one-breath hero, near-square smoldering portals
   ============================================================ */
.landing .nav__links a {
  font-family: var(--display);
  font-size: 0.82rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.landing .hero { min-height: max(58svh, 470px); }
.landing .hero__body { padding: 7.5rem 1.5rem 2.6rem; }
.landing .hero__title { font-size: clamp(2.8rem, 7.5vw, 5.6rem); letter-spacing: 0.12em; }
.landing .hero__roles { font-size: 0.95rem; margin-top: 1rem; }
.landing .hero__roles i { color: var(--red-t); font-style: normal; }
.landing .hero__welcome { font-size: 1.15rem; }
.landing .hero__row { margin-top: 1.9rem; }
/* deeper corners, exactly the mock's dark frame; fade layer stays topmost */
.landing .hero__veil {
  background:
    linear-gradient(180deg, transparent 50%, rgba(22, 14, 8, 0.5) 72%, var(--bg) 93%),
    linear-gradient(180deg, rgba(24, 14, 7, 0.74), rgba(26, 15, 8, 0.22) 24%, transparent 38%),
    radial-gradient(ellipse 86% 70% at 50% 38%, transparent 22%, rgba(24, 13, 6, 0.46) 58%, rgba(13, 7, 3, 0.92) 100%);
}
.landing .portal {
  aspect-ratio: 6 / 5;
  border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
}
.landing .portal img { filter: saturate(0.72) brightness(0.5) contrast(1.08); }
.landing .portal:hover img { filter: saturate(0.9) brightness(0.66) contrast(1.08); }
.landing .portal__desc { font-family: var(--poetic); font-style: italic; font-size: 1.06rem; }
/* the quiet strip stays: without it, spoken word, film and contact
   are unreachable from the front door on desktop */

/* ============================================================
   EVERY WORLD GETS ITS WEATHER — one stage system, six climates.
   Atmosphere never blocks UX: pointer-events none, motion gated,
   content peeks above the fold, functional page follows a thread.
   ============================================================ */
.astage {
  position: relative;
  /* clip, not hidden: hidden kills position:sticky in descendants.
     content-visibility is gone for the same reason. */
  overflow: clip;
  min-height: 92svh;
  display: grid;
  place-items: center;
  padding: 10rem 1.5rem 7rem;
  text-align: center;
  background:
    radial-gradient(ellipse 90% 50% at 50% 0%, #10161a 0%, transparent 65%),
    linear-gradient(180deg, #0e1315 0%, #0c1214 68%, var(--bg) 94%);
}
/* the same estuary that closes the music stage */
.astage::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 22svh;
  background: linear-gradient(to bottom, transparent, color-mix(in srgb, var(--bg) 12%, transparent) 26%, color-mix(in srgb, var(--bg) 34%, transparent) 48%, color-mix(in srgb, var(--bg) 64%, transparent) 66%, color-mix(in srgb, var(--bg) 88%, transparent) 80%, var(--bg) 92%);
  /* the veil dissolves the weather, never the words: it must sit under
     .astage__body, which is z-index 1 */
  z-index: 0;
  pointer-events: none;
}
.astage__body { position: relative; z-index: 1; max-width: 900px; }
.astage__display {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.5rem, 6.4vw, 4.8rem);
  letter-spacing: 0.1em;
  line-height: 1.06;
  color: var(--ink);
}
.astage__sub {
  margin-top: 1.3rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.15rem;
  color: var(--muted);
}
@media (prefers-reduced-motion: no-preference) {
  .astage .dstage__crown { animation: soft-in 1.2s ease 0.15s both; }
  .astage__body { animation: soft-in 1.3s ease 0.45s both; }
}
/* the thread carries every world down into its page */
.astage + .page { padding-top: 0.6rem; }
.astage + .page::before {
  content: "";
  display: block;
  width: 1px; height: 2.6rem;
  margin: 0 auto 2.6rem;
  background: linear-gradient(to bottom, transparent, var(--line));
}
@media (max-width: 720px) {
  .astage { min-height: 86svh; padding: 8.5rem 1.2rem 5.5rem; }
}

/* --- 02 · written word: her lines surface and sink like memory --- */
.astage--words {
  background:
    radial-gradient(46% 38% at 22% 30%, color-mix(in srgb, var(--red) 15%, transparent), transparent 70%),
    radial-gradient(42% 36% at 78% 66%, rgba(86, 122, 128, 0.13), transparent 70%),
    radial-gradient(ellipse 90% 50% at 50% 0%, #10161a 0%, transparent 65%),
    linear-gradient(180deg, #0e1315 0%, #0c1214 68%, var(--bg) 94%);
}
.astage__drift { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.astage__drift span {
  position: absolute;
  max-width: 38ch;
  font-family: var(--poetic);
  font-style: italic;
  font-size: clamp(0.95rem, 1.5vw, 1.25rem);
  color: var(--muted);
  opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .astage__drift span { animation: line-surface 27s ease-in-out infinite; }
  .astage__drift span:nth-child(2) { animation-delay: 4.5s; }
  .astage__drift span:nth-child(3) { animation-delay: 9s; }
  .astage__drift span:nth-child(4) { animation-delay: 13.5s; }
  .astage__drift span:nth-child(5) { animation-delay: 18s; }
  .astage__drift span:nth-child(6) { animation-delay: 22.5s; }
  @keyframes line-surface {
    0% { opacity: 0; transform: translateY(14px); }
    6% { opacity: 0.5; }
    16% { opacity: 0.5; transform: translateY(-6px); }
    24% { opacity: 0; transform: translateY(-18px); }
    100% { opacity: 0; }
  }
}
@media (prefers-reduced-motion: reduce) {
  .astage__drift span { opacity: 0.26; }
}

/* --- 03 · spoken word: a voice rings out from one warm ember --- */
.astage__rings { position: absolute; inset: 0; z-index: 0; display: grid; place-items: center; pointer-events: none; }
.astage__rings::before {
  content: "";
  position: absolute;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--red-display);
  box-shadow: 0 0 42px 14px color-mix(in srgb, var(--red) 50%, transparent);
}
/* the voice rises from beneath the words, not through them */
.astage--voice .astage__rings { inset: 18% 0 -18% 0; }
.astage__rings i {
  position: absolute;
  width: 26vmin; height: 26vmin;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--red-t) 32%, transparent);
  transform: scale(0.7);
  opacity: 0.16;
}
.astage__rings i:nth-child(2) { transform: scale(1.5); opacity: 0.11; }
.astage__rings i:nth-child(3) { transform: scale(2.3); opacity: 0.07; }
@media (prefers-reduced-motion: no-preference) {
  .astage__rings::before { animation: ember-breathe 6s ease-in-out infinite alternate; }
  .astage__rings i { animation: ring-out 10s cubic-bezier(0.16, 1, 0.3, 1) infinite; opacity: 0; transform: none; }
  .astage__rings i:nth-child(2) { animation-delay: 3.3s; }
  .astage__rings i:nth-child(3) { animation-delay: 6.6s; }
  @keyframes ring-out {
    0% { transform: scale(0.24); opacity: 0; }
    10% { opacity: 0.45; }
    100% { transform: scale(3.2); opacity: 0; }
  }
  @keyframes ember-breathe {
    from { transform: scale(1); }
    to { transform: scale(1.3); }
  }
}

/* --- 04 · visuals: her works projected on the dark, one by one --- */
.astage__proj { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.astage__proj img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  filter: saturate(0.75) brightness(0.52) contrast(1.05);
}
.astage__proj::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--bg) 66%, transparent), transparent 32%),
    radial-gradient(ellipse 74% 62% at 50% 46%, color-mix(in srgb, var(--bg) 22%, transparent), color-mix(in srgb, var(--bg) 78%, transparent) 96%);
}
.astage__proj img:first-child { opacity: 0.85; }
@media (prefers-reduced-motion: no-preference) {
  .astage__proj img, .astage__proj img:first-child { opacity: 0; animation: proj-cycle 36s linear infinite; }
  .astage__proj img:nth-child(2) { animation-delay: 9s; }
  .astage__proj img:nth-child(3) { animation-delay: 18s; }
  .astage__proj img:nth-child(4) { animation-delay: 27s; }
  @keyframes proj-cycle {
    0% { opacity: 0; }
    5% { opacity: 0.85; }
    25% { opacity: 0.85; }
    32% { opacity: 0; }
    100% { opacity: 0; }
  }
}

/* --- 05 · film: an empty luminous screen, waiting in the dark --- */
.astage__beam {
  position: absolute;
  left: 50%; top: 0;
  width: 120vmin; height: 76%;
  transform: translateX(-50%);
  clip-path: polygon(46.5% 0, 53.5% 0, 97% 100%, 3% 100%);
  background: linear-gradient(180deg, color-mix(in srgb, var(--ink) 11%, transparent), color-mix(in srgb, var(--ink) 4%, transparent) 55%, transparent 92%);
  filter: blur(7px);
  z-index: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .astage__beam { animation: beam-breathe 6.5s ease-in-out infinite alternate; }
  @keyframes beam-breathe { from { opacity: 0.75; } to { opacity: 1; } }
}
.astage__screenlum {
  width: min(74vw, 880px);
  aspect-ratio: 2.39 / 1;
  border: 1px solid var(--line);
  background:
    radial-gradient(ellipse 80% 95% at 50% 46%, color-mix(in srgb, var(--ink) 8.5%, transparent), color-mix(in srgb, var(--bg) 35%, transparent) 80%),
    linear-gradient(160deg, #101718, #0b0f10);
  box-shadow: 0 34px 90px rgba(0, 0, 0, 0.55);
  display: grid;
  place-items: center;
  padding: 1.5rem;
}
.astage__screenlum .astage__display { font-size: clamp(1.7rem, 4vw, 3.1rem); }
.astage__screenlum .astage__sub { margin-top: 0.8rem; }

/* --- 06 · about: she is the whole weather --- */
.astage__her { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.astage__her img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 28%;
  filter: brightness(0.6) saturate(0.82) contrast(1.07);
}
.astage__her::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--bg) 78%, transparent), color-mix(in srgb, var(--bg) 30%, transparent) 22%, transparent 40%),
    radial-gradient(ellipse 82% 72% at 50% 40%, transparent 30%, rgba(10, 16, 17, 0.82) 100%);
}
@media (prefers-reduced-motion: no-preference) {
  .astage__her img { animation: her-drift 34s ease-in-out infinite alternate; }
  @keyframes her-drift { from { transform: scale(1); } to { transform: scale(1.06); } }
}
.stage-page .about-grid { grid-template-columns: 1fr; text-align: center; }
.stage-page .about-lines { max-width: 46ch; margin: 0 auto; }

/* --- 07 · contact: a wax seal breathing in the dark --- */
.astage--letter { min-height: 74svh; }
.astage--letter::before {
  content: "";
  position: absolute;
  left: 50%; top: 58%;
  width: 46vmin; height: 46vmin;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--red) 32%, transparent), color-mix(in srgb, var(--red) 8%, transparent) 46%, transparent 70%);
  filter: blur(22px);
  z-index: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .astage--letter::before { animation: seal-breathe 7s ease-in-out infinite alternate; }
  @keyframes seal-breathe {
    from { transform: translate(-50%, -50%) scale(1); opacity: 0.8; }
    to { transform: translate(-50%, -50%) scale(1.16); opacity: 1; }
  }
}
@media (max-width: 720px) {
  /* narrow screens: the top-zone fragments crowd the crown */
  .astage__drift span:nth-child(2), .astage__drift span:nth-child(5) { display: none; }
}

/* panel-confirmed guards: type must survive any ground */
.dstage__crown { text-shadow: 0 1px 12px color-mix(in srgb, var(--bg) 75%, transparent), 0 0 30px color-mix(in srgb, var(--bg) 50%, transparent); }
.astage--her .astage__display, .astage--her .astage__sub,
.astage--gaze .astage__display, .astage--gaze .astage__sub {
  text-shadow: 0 2px 30px rgba(10, 16, 17, 0.95), 0 1px 6px rgba(10, 16, 17, 0.65);
}
@media (max-width: 720px) {
  /* phones: one still projection (no four resident GPU layers),
     and the cinema screen keeps its 2.39:1 identity */
  .astage__proj img, .astage__proj img:first-child { animation: none; opacity: 0; }
  .astage__proj img:first-child { opacity: 0.85; }
  .astage__screenlum { width: 92vw; padding: 1rem 1.1rem; }
}

/* ============================================================
   THE GRAVITY OF HER ART — five worlds on the landing in her
   order, and the book they all grew out of
   ============================================================ */
.landing .portals { grid-template-columns: repeat(6, 1fr); }
.landing .portal:nth-child(-n+3) { grid-column: span 2; }
.landing .portal:nth-child(n+4) { grid-column: span 3; aspect-ratio: 16 / 9; }
/* The narrow rule for these lives a thousand lines further up, and a media
   query adds no specificity, so this unconditional rule was quietly winning
   and phones were being handed six columns: five of her worlds at 44 by 30
   pixels each. The correction belongs next to the rule it corrects. */
@media (max-width: 780px) {
  .landing .portals { grid-template-columns: 1fr; }
  .landing .portal:nth-child(-n+3),
  .landing .portal:nth-child(n+4) { grid-column: auto; }
  .landing .portal:nth-child(n+4) { aspect-ratio: 16 / 10; }
}
@media (max-width: 1240px) and (min-width: 1081px) {
  .nav__links { gap: 1.25rem; }
  .landing .nav__links a { font-size: 0.76rem; letter-spacing: 0.16em; }
}
@media (max-width: 780px) {
  .landing .portal:nth-child(-n+3),
  .landing .portal:nth-child(n+4) { grid-column: auto; aspect-ratio: 16 / 11; }
}

/* --- 00 · the book: the heart, held up out of the dark --- */
.astage--book::before {
  content: "";
  position: absolute;
  left: 50%; top: 52%;
  width: 58vmin; height: 58vmin;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--red) 26%, transparent), color-mix(in srgb, var(--red) 6%, transparent) 48%, transparent 72%);
  filter: blur(30px);
  z-index: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .astage--book::before { animation: seal-breathe 8s ease-in-out infinite alternate; }
}
.bookobj {
  position: relative;
  width: min(268px, 56vw);
  aspect-ratio: 2 / 3;
  margin: 0 auto 2.6rem;
  border: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
  background:
    radial-gradient(ellipse 90% 60% at 50% 18%, color-mix(in srgb, var(--red) 30%, transparent), transparent 62%),
    linear-gradient(155deg, #17090d 0%, #0e1315 72%);
  box-shadow: 0 42px 90px rgba(0, 0, 0, 0.62);
  display: grid; place-items: center;
  padding: 2rem 1.5rem;
  overflow: hidden;
  transform: perspective(1400px) rotateY(-9deg);
  transition: transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
.bookobj:hover { transform: perspective(1400px) rotateY(0deg) translateY(-5px); }
.bookobj::before {   /* the spine */
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 14px;
  background: linear-gradient(90deg, rgba(0, 0, 0, 0.6), transparent);
  z-index: 2;
}
.bookobj img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 1; }
.bookobj img:not([src]) { display: none; }   /* no photograph yet: the type is the cover */
.bookobj__face { position: relative; z-index: 0; text-align: center; }
.bookobj__title {
  font-family: var(--display);
  font-size: clamp(1.5rem, 4vw, 2rem);
  letter-spacing: 0.09em;
  line-height: 1.14;
  color: var(--ink);
}
.bookobj__rule { display: block; width: 26px; height: 1px; background: var(--red-display); margin: 1.2rem auto; }
.bookobj__by {
  font-size: 0.56rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--muted);
}
.book-page { max-width: 860px; text-align: center; }
.book-lede {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.2rem;
  line-height: 1.7;
  color: var(--ink);
  max-width: 54ch;
  margin: 0 auto 3.6rem;
}
.movements {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.6rem;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 2.6rem 0;
  margin-bottom: 3.6rem;
}
.mv__no {
  font-family: var(--display);
  font-size: 0.72rem;
  letter-spacing: 0.3em;
  color: var(--red-t);
}
.mv__name {
  font-family: var(--display);
  font-size: 1.5rem;
  letter-spacing: 0.06em;
  margin: 0.5rem 0 0.6rem;
}
.mv__theme {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1rem;
  color: var(--muted);
}
.reserve { margin-top: 1rem; }
.reserve__title {
  font-family: var(--display);
  font-size: 1.7rem;
  letter-spacing: 0.06em;
  margin-bottom: 0.9rem;
}
.reserve__text {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.08rem;
  color: var(--muted);
  max-width: 46ch;
  margin: 0 auto 1.7rem;
}
.book-page .giftpanel { text-align: left; margin-bottom: 3.4rem; }
@media (max-width: 720px) {
  .movements { grid-template-columns: repeat(2, 1fr); gap: 2rem 1.2rem; }
}

/* the letter's answer, spoken in place */
.form-status {
  margin-top: 1.1rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.05rem;
  color: var(--ink);
}
.form-status--sent { color: var(--red-display); }
.form-status--error { color: var(--muted); }
.cform.is-sending button[type="submit"] { opacity: 0.5; pointer-events: none; }

/* ============================================================
   THE WALL OPENS — one artwork held up in the dark, with her words
   ============================================================ */
.vitem { cursor: zoom-in; }
.lbox {
  position: fixed; inset: 0;
  z-index: 90;
  display: grid;
  grid-template-columns: auto 1fr auto;
  /* stretch, not centre: the stage needs a definite height of its own so
     the picture can be told to give way to her words */
  align-items: stretch;
  gap: 1rem;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(8, 13, 14, 0.93);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  opacity: 0;
  transition: opacity 0.26s ease;
}
.lbox.is-open { opacity: 1; }
.lbox__stage {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 1.4rem;
  min-width: 0;
  min-height: 0;
  max-height: 100%;
  transform: scale(0.985);
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.lbox.is-open .lbox__stage { transform: scale(1); }
/* What she writes about a picture is never cut off. The picture used to
   hold 72svh whatever the note said, so a long one ran off the bottom of a
   fixed overlay with no way to reach it. The picture yields instead: it
   takes what it can up to 72svh and gives the rest back to her words. */
.lbox__img {
  flex: 0 1 auto;
  min-height: 0;
  max-width: 100%;
  max-height: 72svh;
  object-fit: contain;
  border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
  box-shadow: 0 40px 90px rgba(0, 0, 0, 0.6);
}
.lbox__meta {
  flex: none;                 /* her words are never the thing that shrinks */
  max-width: 58ch;
  text-align: center;
  max-height: 62svh;
  overflow-y: auto;           /* only reachable if a note runs truly long */
  overscroll-behavior: contain;
}
.lbox__title {
  font-family: var(--display);
  font-size: 1.4rem;
  font-weight: 400;
  letter-spacing: 0.07em;
  color: var(--ink);
}
.lbox__note {
  margin-top: 0.7rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.08rem;
  line-height: 1.65;
  color: var(--muted);
}
.lbox__close, .lbox__nav {
  background: none;
  border: 1px solid var(--line);
  color: var(--ink);
  cursor: pointer;
  line-height: 1;
  transition: border-color 0.3s, color 0.3s, background 0.3s;
}
.lbox__close:hover, .lbox__nav:hover { border-color: var(--red); color: var(--red-display); }
.lbox__close {
  position: absolute; top: clamp(1rem, 3vw, 2rem); right: clamp(1rem, 3vw, 2rem);
  width: 44px; height: 44px;
  font-size: 1.4rem;
  border-radius: 50%;
  z-index: 2;
}
.lbox__nav {
  width: 48px; height: 48px;
  font-size: 1.8rem;
  border-radius: 50%;
  flex-shrink: 0;
}
@media (max-width: 720px) {
  .lbox { grid-template-columns: 1fr; grid-template-rows: 1fr auto; padding-top: 4.5rem; }
  .lbox__nav { position: absolute; bottom: 1.2rem; }
  .lbox__nav--prev { left: 1.2rem; }
  .lbox__nav--next { right: 1.2rem; }
  .lbox__img { max-height: 56svh; }
  .lbox__meta { padding-bottom: 4.5rem; }
}
@media (prefers-reduced-motion: reduce) {
  .lbox, .lbox__stage { transition: none; }
}

/* the book announces itself: cover beside the word */
.bookhero {
  display: grid;
  grid-template-columns: minmax(190px, 250px) 1fr;
  gap: clamp(2rem, 5vw, 3.6rem);
  align-items: center;
  text-align: left;
  max-width: 820px;
}
.bookhero .bookobj { margin: 0; }
.bookhero .astage__display { font-size: clamp(2.1rem, 5.4vw, 3.9rem); }
.bookhero .astage__sub { margin-top: 1rem; }
.book-kind {
  margin-top: 1.3rem;
  font-size: 0.62rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--red-t);
}
@media (max-width: 720px) {
  .bookhero { grid-template-columns: 1fr; justify-items: center; text-align: center; }
}

/* the crown never touches the edges of a phone */
.dstage__crown { padding-inline: 1.3rem; }

/* ============================================================
   THE FOUR PHASES — her elemental growth, the same movements
   as the book, so the site reads as evolution not a dump
   ============================================================ */
.phase { margin-top: 4.6rem; }
.phase:first-of-type { margin-top: 1.4rem; }
.phase__head {
  display: grid;
  justify-items: center;
  text-align: center;
  margin-bottom: 1.8rem;
}
.phase__no {
  font-family: var(--display);
  font-size: 0.72rem;
  letter-spacing: 0.4em;
  color: var(--el, var(--red-display));
}
.phase__name {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.4rem, 2.6vw, 1.95rem);
  letter-spacing: 0.18em;
  margin: 0.35rem 0 0.4rem;
  color: var(--ink);
}
.phase__name::after {
  content: "";
  display: block;
  width: 30px; height: 1px;
  margin: 0.6rem auto 0;
  background: var(--el, var(--red-display));
  opacity: 0.7;
}
.phase__theme {
  font-family: var(--poetic);
  font-style: italic;
  font-size: 0.98rem;
  color: var(--muted);
  margin-top: 0.6rem;
}
.phase--water { --el: #6E9BA6; }
.phase--fire  { --el: var(--red-t); }   /* --el paints .phase__no at 0.72rem, which is
                                           body size: --red-display is a display-size red
                                           and measures 3.04 here, so this takes the
                                           text-weight red instead. */
.phase--earth { --el: #C0A275; }
.phase--air   { --el: #C9C2B6; }
.phase .wl:first-child { border-top: 1px solid var(--line); }

.restline {
  margin-top: 3.4rem;
  text-align: center;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.18rem;
  color: var(--ink);
}
.restline + .viewall { margin-top: 0.9rem; text-align: center; }

/* her own frame, at the ratio the film was shot in */
.filmbox--strip {
  aspect-ratio: 691 / 1536;
  max-width: 330px;
  margin: 0 auto;
  background: #000;
}
.filmbox--strip img { object-fit: contain; }
.filmline {
  margin-top: 1.6rem;
  text-align: center;
  font-family: var(--poetic);
  font-style: italic;
  font-size: 1.08rem;
  color: var(--muted);
}

/* ============================================================
   THE DIVE — surface · hold · submerge
   The page stops being a column of content and becomes a body of
   water you descend through. Native scroll is the only transport:
   nothing here intercepts the wheel, so trackpads, keyboards,
   scrollbars and thumbs all behave exactly as the reader expects.

   THE BASE-STATE LAW: every keyframe's `from` is the resting design
   that already ships. Animations may only replay an arrival or add a
   departure, never gate content into existence. Anything whose `to`
   is a "gone" state lives inside @supports, so a browser without
   scroll timelines simply sees the site as it is today.
   ============================================================ */

@property --tide {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

/* the depth gauge: how deep you are, bleeding Cherry red into DN steel */
.gauge {
  position: fixed;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  z-index: 45;
  pointer-events: none;
  background: linear-gradient(to bottom, color-mix(in srgb, var(--muted) 10%, transparent), color-mix(in srgb, var(--muted) 2%, transparent));
}
.gauge__fill {
  position: absolute;
  left: 0; top: 0; right: 0;
  height: 100%;
  transform-origin: top;
  transform: scaleY(0);
  background: linear-gradient(to bottom, var(--red), #5E7476);
}
@media (prefers-reduced-motion: reduce) { .gauge { display: none; } }

@supports (animation-timeline: scroll()) {
  .gauge__fill {
    animation: gauge-fill linear both;
    animation-timeline: scroll(root block);
  }
  @keyframes gauge-fill { to { transform: scaleY(1); } }
}

@supports (animation-timeline: view()) {

  /* ---- the stage holds, then submerges ------------------------------
     The title card does not scroll away like a paragraph. It stays in
     frame while the reader pushes past it, then sinks. */
  /* one row, the full height of the stage: a sticky child can only
     travel as far as its own grid area, so the area must be the dive. */
  .astage {
    min-height: 148svh;
    /* an auto column sizes to its widest child and can exceed the
       viewport; pin the track to the container instead */
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 1fr;
    padding: 0 1.5rem;
    /* the stage's own passage is the clock every layer animates against.
       view() on a layer would be useless: a 100svh layer has a
       zero-length `contain` range. */
    view-timeline: --stage block;
  }
  /* every layer shares that cell so they stack instead of stacking UP.
     ::after is a grid item too and must be named explicitly. */
  .astage > *, .astage::after { grid-area: 1 / 1; align-self: start; }
  /* the stage sets place-items:center, which stops grid items stretching.
     The weather layers hold absolutely-positioned children, so without an
     explicit width they collapse to zero and their lines wrap one word per
     row. Every full-bleed layer must be told to span the cell. */
  .astage__drift, .astage__rings, .astage__proj, .astage__her,
  .astage .dstage__crown, .astage::after {
    justify-self: stretch;
    width: 100%;
  }
  .astage__body { justify-self: center; width: min(900px, 100%); }
  /* the ember rises from beneath the words, expressed for a sticky layer */
  .astage--voice .astage__rings { inset: auto; top: 0; padding-top: 16svh; }
  /* the projector beam keeps its own geometry: it was centred by
     left:50% + translateX(-50%), which a grid item must not inherit */
  .astage__beam {
    justify-self: center;
    left: auto;
    width: min(120vmin, 100%);
    height: 100svh;
    transform: none;
  }
  /* the book's bloom and the wax seal are absolutely positioned, so they
     measure against the whole 148svh stage: pull them back into frame */
  .astage--book::before { top: 34%; }
  .astage--letter::before { top: 40%; }
  /* contact stays the short, still room at the end of the descent */
  .astage--letter { min-height: 92svh; }

  /* film: the body is now the sticky viewport box, so the cinema screen
     moves onto the inner block or it stretches to full height */
  .astage__screenlum {
    width: min(900px, 100%);
    aspect-ratio: auto;
    border: 0;
    background: none;
    box-shadow: none;
    padding: 9rem 0 6rem;
  }
  .astage__screenlum > div {
    width: min(74vw, 880px);
    aspect-ratio: 2.39 / 1;
    border: 1px solid var(--line);
    background:
      radial-gradient(ellipse 80% 95% at 50% 46%, color-mix(in srgb, var(--ink) 8.5%, transparent), color-mix(in srgb, var(--bg) 35%, transparent) 80%),
      linear-gradient(160deg, #101718, #0b0f10);
    box-shadow: 0 34px 90px rgba(0, 0, 0, 0.55);
    display: grid;
    place-items: center;
    padding: 1.5rem;
  }
  @media (max-width: 720px) {
    .astage__screenlum > div { width: 92vw; padding: 1rem 1.1rem; }
  }
  .astage__body {
    position: sticky;
    top: 0;
    min-height: 100svh;
    display: grid;
    place-content: center;
    padding: 9rem 0 6rem;
    animation: submerge linear both;
    animation-timeline: --stage;
    animation-range: contain 12% contain 100%;
  }
  @keyframes submerge {
    0%   { opacity: 1; transform: none; }
    62%  { opacity: 1; transform: translateY(-2vh); }
    100% { opacity: 0; transform: translateY(-12vh) scale(0.965); }
  }

  /* the weather holds with it, and deepens as you go under */
  .astage__drift, .astage__rings, .astage__proj, .astage__her {
    position: sticky;
    /* the shorthand must come FIRST: `inset: auto` after `top: 0` resets
       the offset and a sticky box with no offsets never sticks. */
    inset: auto;
    top: 0;
    height: 100svh;
    animation: weather-deepen linear both;
    animation-timeline: --stage;
    animation-range: contain 0% contain 100%;
  }
  @keyframes weather-deepen {
    from { opacity: 1; transform: scale(1); }
    to   { opacity: 0.25; transform: scale(1.08); }
  }
  .astage__beam { position: sticky; top: 0; }
  .astage .dstage__crown {
    position: sticky;
    top: 0;
    padding-top: 6.2rem;
    height: 100svh;
    animation: crown-lift linear both;
    animation-timeline: --stage;
    animation-range: contain 0% contain 55%;
  }
  @keyframes crown-lift {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: translateY(-2.6rem); }
  }
  /* the estuary floods upward as the stage goes under */
  .astage::after {
    height: 100svh;
    position: sticky;
    top: 0;
    animation: estuary-flood linear both;
    animation-timeline: --stage;
    animation-range: contain 0% contain 100%;
  }
  @keyframes estuary-flood {
    from { opacity: 0.35; transform: translateY(78svh); }
    to   { opacity: 1; transform: translateY(0); }
  }

  /* ---- the acts: each phase pins its name while its work passes ---- */
  .phase__head {
    position: sticky;
    /* Pins at the very top, not below the nav. Pinning at top:5.4rem left a
       band of bare viewport above the plate, and the poems scrolled up
       through it in full view. The nav clearance is padding now, so the
       plate's own background covers the whole band. */
    top: 0;
    z-index: 3;
    padding: calc(var(--nav-h, 5.4rem) + 1rem) 0 1.4rem;
    margin-bottom: 0.6rem;
    background: linear-gradient(to bottom,
      var(--bg) 0 78%, color-mix(in srgb, var(--bg) 96%, transparent) 90%, color-mix(in srgb, var(--bg) 75%, transparent) 96%, transparent);
    animation: plate-settle linear both;
    animation-timeline: view();
    animation-range: entry 60% contain 12%;
  }
  @keyframes plate-settle {
    from { opacity: 0; transform: translateY(26px); }
    to   { opacity: 1; transform: none; }
  }
  /* the element's name, huge and half-drowned, behind her lines only */
  .wlist { position: relative; }
  .phase[data-el] .wlist::before {
    content: attr(data-el);
    position: absolute;
    left: 50%; top: 8%;
    transform: translateX(-50%);
    font-family: var(--display);
    font-size: clamp(6rem, 22vw, 15rem);
    letter-spacing: 0.06em;
    line-height: 1;
    color: var(--el, var(--red-display));
    opacity: 0.06;
    pointer-events: none;
    z-index: 0;
    white-space: nowrap;
    animation: watermark-drift linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
  @keyframes watermark-drift {
    from { transform: translate(-50%, 6vh); }
    to   { transform: translate(-50%, -6vh); }
  }
  .wl, .vitem { position: relative; z-index: 1; }

  /* ---- arrivals scrubbed by scroll, so scrolling back rewinds them --
     staggered by animation-range, never by animation-delay: a delay
     cannot play backwards. */
  .vgrid .vitem {
    animation: surface linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 86%;
  }
  .vgrid .vitem:nth-child(3n+2) { animation-range: entry 0% entry 94%; }
  .vgrid .vitem:nth-child(3n+3) { animation-range: entry 0% entry 100%; }
  @keyframes surface {
    from { opacity: 0; transform: translateY(38px) scale(0.985); }
    to   { opacity: 1; transform: none; }
  }
  .wlist .wl {
    animation: surface linear both;
    animation-timeline: view();
    animation-range: entry 10% entry 92%;
  }
  /* opening a poem makes it taller than the scrollport, which re-resolves
     its entry range and scrubs the arrival BACKWARDS: the reader clicks
     read and the poem ghosts out. Open pieces leave the timeline. */
  html.js .wlist .wl.is-open {
    animation: none;
    opacity: 1;
    transform: none;
  }

  /* one arrival per element. The children scrub on scroll here, so the
     container's time-based reveal must stand down (it stays the arrival in
     browsers without scroll timelines, which is why this is scoped). */
  html.js .wlist[data-r], html.js .vgrid[data-r] {
    opacity: 1;
    transform: none;
    transition: none;
  }

  /* the poem you are level with is the one lit */
  .wl { transition: opacity 0.6s ease; }
  /* animation declarations outrank normal ones; only !important wins back */
  .wlist:has(.wl:hover) .wl:not(:hover) { opacity: 0.45 !important; }

  /* ---- the landing: depth, without touching the approved frame ---- */
  /* the landing frame was matched to an approved reference and keeps its
     shipped hero-settle entrance: a sink here bound view() to .hero, which
     is overflow:hidden and therefore a scroll container with no range. */
  .landing .hero__body {
    animation: submerge linear both;
    animation-timeline: view();
    animation-range: exit 0% exit 100%;
  }
  .landing .portal {
    animation: surface linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 92%;
  }
  .landing .portal:nth-child(2) { animation-range: entry 0% entry 96%; }
  .landing .portal:nth-child(3) { animation-range: entry 0% entry 100%; }

  /* ---- the coda and the closing lines rise out of the dark -------- */
  .stage-page--music .page::before,
  .astage + .page::before {
    animation: thread-draw linear both;
    animation-timeline: view();
    animation-range: entry 20% cover 8%;
  }
  @keyframes thread-draw {
    from { transform: scaleY(0); opacity: 0; }
    to   { transform: scaleY(1); opacity: 1; }
  }
  .restline, .endline, .filmline {
    animation: surface linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 90%;
  }

  /* contact is the one room where nothing moves: after a whole site of
     descent, stillness is the strongest beat available */
  /* contact's stage is exactly one viewport tall, so a `contain` range has
     zero length and fill:both would paint the END state from the first frame,
     erasing the crown entirely. Stillness here is the design anyway. */
  body:has(.astage--letter) .astage__body,
  body:has(.astage--letter) .astage .dstage__crown,
  body:has(.astage--letter) .astage::after { animation: none; }

  @media (prefers-reduced-motion: reduce) {
    .astage { min-height: 92svh; align-content: center; padding: 10rem 1.5rem 7rem; }
    .astage > * { grid-area: auto; }
    .astage__body, .astage__drift, .astage__rings, .astage__proj,
    .astage__her, .astage__beam, .astage .dstage__crown, .astage::after,
    .phase__head, .vgrid .vitem, .wlist .wl, .landing .hero__img,
    .landing .hero__body, .landing .portal, .restline, .endline, .filmline,
    .phase[data-el] .wlist::before, .astage + .page::before {
      animation: none !important;
      position: static;
    }
    .astage__drift, .astage__rings, .astage__proj, .astage__her { position: absolute; }
    .astage::after { position: absolute; height: 22svh; }
    .astage .dstage__crown { position: absolute; height: auto; padding-top: 0; }
    .phase__head { position: static; background: none; }
  }
}

/* ============================================================
   THE PROJECTION ROOM
   Her films, hung like the artworks and played where they hang.
   One frame at a time: the projector stops the last film before it
   starts the next. Nothing from YouTube or Vimeo is fetched until
   somebody actually presses play.
   ============================================================ */
.reel { display: grid; gap: clamp(3.4rem, 8vw, 6.5rem); }
.reel:empty { display: none; }
.film { display: grid; gap: 1.15rem; }

.film__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  overflow: hidden;
  background:
    radial-gradient(ellipse at 50% 70%, color-mix(in srgb, var(--red) 34%, transparent), transparent 58%),
    linear-gradient(170deg, #101a1c, #0a1112);
}
.film__poster {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  filter: saturate(0.86) contrast(1.06) brightness(0.92);
  transition: transform 1.4s cubic-bezier(0.16, 1, 0.3, 1), filter 0.7s ease;
}
.film__poster:not([src]) { display: none; }
.film:hover .film__poster { transform: scale(1.035); filter: saturate(1) contrast(1.06) brightness(1); }

/* the ring, borrowed from the strip above it */
.film__play {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: grid; place-items: center;
  background: none; border: 0; cursor: pointer;
  color: var(--ink);
}
.film__play::before {
  content: "";
  width: clamp(62px, 9vw, 86px); height: clamp(62px, 9vw, 86px);
  border: 1px solid color-mix(in srgb, var(--ink) 60%, transparent);
  border-radius: 50%;
  background: rgba(10, 17, 18, 0.28);
  backdrop-filter: blur(4px);
  transition: border-color 0.45s ease, box-shadow 0.45s ease, transform 0.45s ease;
}
.film__play::after {
  content: "";
  position: absolute;
  border-style: solid;
  border-width: 10px 0 10px 17px;
  border-color: transparent transparent transparent var(--ink);
  transform: translateX(3px);
}
.film:hover .film__play::before,
.film__play:focus-visible::before {
  border-color: var(--red);
  box-shadow: 0 0 34px color-mix(in srgb, var(--red) 38%, transparent);
  transform: scale(1.06);
}
.film__play[disabled] { cursor: default; opacity: 0.35; }

.film__player { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: #000; display: block; }
.film__frame.is-playing .film__play,
.film__frame.is-playing .film__poster { display: none; }
.film__frame.is-empty .film__play::before { border-color: color-mix(in srgb, var(--ink) 20%, transparent); }

.film__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.4rem, 3vw, 2.1rem);
  letter-spacing: 0.06em;
  line-height: 1.2;
}
.film__title:empty { display: none; }
.film__note {
  font-family: var(--poetic);
  font-style: italic;
  font-size: clamp(1.02rem, 1.6vw, 1.2rem);
  color: var(--muted);
  max-width: 56ch;
}
.film__note:empty { display: none; }

@media (prefers-reduced-motion: reduce) {
  .film__poster, .film__play::before { transition: none; }
  .film:hover .film__poster { transform: none; }
}

/* ============================================================
   HER WORDS, UNDER HER SONGS
   The lyric sheet folds out of the track row itself, so a song and
   its words are never in two different places. The row is a flex
   line; the sheet takes a whole line of its own.
   ============================================================ */
.trk { flex-wrap: wrap; }
.trk__words {
  background: none; border: 0; padding: 0.2rem 0.35rem;
  font-family: var(--ui); font-size: 0.6rem; font-weight: 400;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--red-t); cursor: pointer;
  transition: color 0.3s ease;
}
.trk__words:hover { color: var(--ink); }
.trk__lyrics {
  flex-basis: 100%; width: 100%;
  padding: 0.9rem 0 0.3rem;
  font-family: var(--poetic); font-style: italic;
  font-size: clamp(1rem, 1.5vw, 1.12rem); line-height: 1.9;
  letter-spacing: 0; text-transform: none;
  color: var(--muted); cursor: auto;
}
.trk__lyrics[hidden] { display: none; }
.dlist--cherry .trk__lyrics { text-align: right; }

/* the heading over a group of chapters, in her own words */
.chapters { display: grid; gap: clamp(2.2rem, 5vw, 3.4rem); }
.chgroup__name {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.15rem, 2vw, 1.5rem);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--line);
}
.chgroup .tracklist { margin-top: 0; }

/* ============================================================
   HER PAGE — one held frame
   The portrait is the ground. Her name begins in the middle of it and
   travels to the bottom left; the archive rises slowly up the left side
   as it goes. Nothing about the page itself moves: the scroll drives the
   choreography and the frame stays pinned.

   Resting design, which is also every keyframe's `from`: the portrait
   behind, the name in the middle, the words below it in normal flow. A
   browser without scroll-driven animation gets exactly that and loses
   only the travel.
   ============================================================ */
.herstage { position: relative; }
.herstage__pin { position: relative; min-height: 100svh; }

.herstage__ground { position: absolute; inset: 0; overflow: hidden; z-index: 0; }
.herstage__ground img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* her face sits to the right of centre, clear of the column of words
     that rises on the left */
  object-position: 26% 26%;
  filter: saturate(0.82) contrast(1.04);
}
.herstage__veil {
  position: absolute; inset: 0;
  /* Darkened along the left, where her words rise, and along the bottom,
     where her name lands. Nothing across the top: the nav has its own
     ground and should look here exactly as it looks everywhere else. */
  background:
    radial-gradient(90% 78% at 96% 34%, rgba(9, 18, 19, 0.82) 0%, rgba(9, 18, 19, 0.45) 46%, transparent 78%),
    linear-gradient(to left,
      rgba(9, 18, 19, 0.94) 0%, rgba(9, 18, 19, 0.9) 18%, rgba(9, 18, 19, 0.74) 34%,
      rgba(9, 18, 19, 0.42) 52%, color-mix(in srgb, var(--bg) 12%, transparent) 72%, color-mix(in srgb, var(--bg) 44%, transparent) 100%),
    linear-gradient(to bottom, transparent 0%, transparent 52%, color-mix(in srgb, var(--bg) 72%, transparent) 84%, var(--bg) 100%);
}

body:has(.herstage) .nav.is-scrolled {
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom: 0;
}
body:has(.herstage) .nav__logo,
body:has(.herstage) .nav__links a,
body:has(.herstage) .nav__cta {
  text-shadow: 0 1px 3px color-mix(in srgb, var(--bg) 90%, transparent), 0 2px 16px color-mix(in srgb, var(--bg) 85%, transparent);
}

.herstage__crown {
  position: relative; z-index: 2;
  padding-top: 6.2rem;
  text-align: center;
}
/* the band of dark across the top is gone, so these carry their own
   legibility rather than borrowing it from a scrim over the nav */
.herstage__crown .crown__num,
.herstage__crown .crown__tag {
  text-shadow: 0 1px 3px color-mix(in srgb, var(--bg) 95%, transparent), 0 2px 18px color-mix(in srgb, var(--bg) 90%, transparent);
}

.herstage__title {
  position: relative; z-index: 2;
  display: grid;
  place-content: center;
  justify-items: center;
  text-align: center;
  min-height: 62svh;
  padding: 0 1.4rem;
  transform-origin: 50% 50%;
}
.herstage__name {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.9rem, min(6.4vw, 7.2svh), 4.6rem);
  letter-spacing: 0.12em;
  line-height: 1.05;
  color: var(--ink);
  text-shadow: 0 2px 40px color-mix(in srgb, var(--bg) 80%, transparent);
}
.herstage__sub {
  margin-top: 1.1rem;
  font-family: var(--poetic);
  font-style: italic;
  font-size: clamp(1.05rem, 1.8vw, 1.35rem);
  color: var(--muted);
}

.herstage__read {
  position: relative; z-index: 2;
  width: min(50ch, 30vw);
  margin: 0 clamp(1.2rem, 4.5vw, 5rem) 0 auto;
  padding-bottom: 5rem;
}
.herstage__lines p {
  font-family: var(--poetic);
  font-size: clamp(1.02rem, 1.92svh, 1.3rem);
  line-height: 1.72;
  color: var(--ink);
  margin-bottom: 1.05rem;
  text-shadow: 0 1px 3px color-mix(in srgb, var(--bg) 95%, transparent), 0 1px 22px color-mix(in srgb, var(--bg) 90%, transparent);
}
.herstage__lines .about-duality {
  font-style: italic;
  color: var(--red-t);
}
.herstage__lines .about-sig {
  font-family: "Great Vibes", var(--poetic);
  font-size: clamp(2.1rem, 5.2svh, 3.4rem);
  color: var(--red-display);
  margin-top: 1.2rem;
  line-height: 1;
}

@media (max-width: 820px) {
  .herstage__read { width: auto; margin: 0 1.4rem; }
  .herstage__lines { text-align: left; }
  .herstage__ground img { object-position: 50% 22%; }
}

/* ---------- the travel ---------- */
@supports (animation-timeline: view()) {
  /* A held frame needs room for two things at once: all of her words, and
     her name at full size in the corner. Below about 780px of height there
     is not enough for both without them touching, so the frame stands down
     and the page reads in ordinary flow instead. The same judgement as the
     stacked layout: better a plain page than a crowded one. */
  @media (prefers-reduced-motion: no-preference) and (min-height: 820px) {
    .herstage {
      /* three and a bit screens. The travel is deliberately unhurried and
         needs the scroll to spend it in; what is left after everything
         has arrived is time to read, not dead space. */
      height: 330svh;
      view-timeline: --her block;
    }
    .herstage__pin {
      position: sticky;
      top: 0;
      height: 100svh;
      overflow: hidden;
    }

    /* The ground does not move. It was drifting in a slow zoom; it is
       her photograph, and it holds still while everything else travels. */

    .herstage__crown {
      position: absolute; inset: 0 0 auto 0;
      animation: her-crown linear both;
      animation-timeline: --her;
      animation-range: contain 0% contain 22%;
    }
    @keyframes her-crown {
      from { opacity: 1; transform: none; }
      to   { opacity: 0; transform: translateY(-2rem); }
    }

    /* her name leaves the middle and settles into the bottom left corner */
    .herstage__title {
      position: absolute;
      inset: auto;
      left: 50%; top: 50%;
      width: max-content;
      max-width: 92vw;
      min-height: 0;
      padding: 0;
      transform: translate(-50%, -50%);
      animation: her-name cubic-bezier(0.5, 0, 0.18, 1) both;
      animation-timeline: --her;
      animation-range: contain 5% contain 58%;
    }
    @keyframes her-name {
      from { transform: translate(-50%, -50%); }
      to   { transform: translate(-46vw, calc(46svh - 100%)); }
    }
    .herstage__sub {
      animation: her-sub linear both;
      animation-timeline: --her;
      animation-range: contain 5% contain 30%;
    }
    @keyframes her-sub {
      from { opacity: 1; transform: none; }
      to   { opacity: 0; transform: translateY(1.2rem); }
    }

    /* The archive rises through a band down the left centre of the frame,
       and only through that band. It used to rise through the whole
       viewport, which meant her words and her name were in the bottom left
       corner at the same time, on top of each other. The band ends well
       above the corner, and its edges are masked so the words materialise
       and dissolve rather than being cut off by nothing. */
    /* It rises once and then stays. Rolling it endlessly past meant there
       was no moment in the whole scroll when all of it could be read, which
       is the one thing an about page has to allow. */
    .herstage__read {
      position: absolute;
      right: 0; left: auto; top: 14svh;
      margin-right: clamp(1.4rem, 5vw, 6rem);
      margin-left: 0;
      padding: 0;
      animation: her-rise cubic-bezier(0.16, 1, 0.3, 1) both;
      animation-timeline: --her;
      animation-range: contain 10% contain 64%;
    }
    @keyframes her-rise {
      from { transform: translateY(34svh); }
      to   { transform: translateY(0); }
    }

    /* Her paragraphs arrive one after another rather than as a block, each
       a little behind the last, so the archive assembles itself as you
       come down instead of sliding in whole. */
    .herstage__lines p {
      animation: her-line cubic-bezier(0.16, 1, 0.3, 1) both;
      animation-timeline: --her;
    }
    .herstage__lines p:nth-child(1) { animation-range: contain 12% contain 34%; }
    .herstage__lines p:nth-child(2) { animation-range: contain 17% contain 39%; }
    .herstage__lines p:nth-child(3) { animation-range: contain 22% contain 44%; }
    .herstage__lines p:nth-child(4) { animation-range: contain 27% contain 49%; }
    .herstage__lines p:nth-child(5) { animation-range: contain 32% contain 54%; }
    .herstage__lines p:nth-child(6) { animation-range: contain 37% contain 62%; }
    @keyframes her-line {
      from { opacity: 0; transform: translateY(2.2rem); filter: blur(3px); }
      to   { opacity: 1; transform: none; filter: blur(0); }
    }

  }
}

/* ============================================================
   SPOKEN WORD, READ AS MUSIC
   Her words: spoken word is a different form of music, so this should
   look more like the music page. It does now. The bordered box is gone
   for the same open hairline list the songs use, each group carries a
   display-face name the way CHERRY and DN do, and groups sit side by
   side rather than stacked, so there is a place here and a place here
   to put her files.
   ============================================================ */
.chapters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
  gap: clamp(2rem, 4.5vw, 4.2rem) clamp(2rem, 5vw, 5rem);
  align-items: start;
}

.chgroup__name {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.5rem, 2.8vw, 2.2rem);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  padding-bottom: 0;
  border-bottom: 0;
  margin-bottom: 0;
}
.chgroup__name::after {
  content: "";
  display: block;
  width: 34px; height: 2px;
  margin-top: 0.9rem;
  background: var(--red);
  opacity: 0.85;
  transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.chgroup:hover .chgroup__name::after { width: 58px; }

/* the open list, not a box */
.chapters .tracklist {
  border: 0;
  border-top: 1px solid var(--line);
  margin-top: 1.5rem;
}
.chapters .trk {
  align-items: baseline;
  padding: 1rem 0.2rem;
  border-bottom: 1px solid var(--line);
  transition: color 0.3s, background 0.3s, padding-left 0.35s;
}
.chapters .trk:last-child { border-bottom: 1px solid var(--line); }
.chapters .trk:hover {
  color: var(--ink);
  background: color-mix(in srgb, var(--ink) 2%, transparent);
  padding-left: 0.6rem;
}
.chapters .trk__no { color: var(--red-t); }
.chapters .trk.is-current { box-shadow: inset 2px 0 0 var(--red); }

/* ============================================================
   ONE GIFT PAGE, ANY BOOK
   The code inside a cover carries the book it belongs to, so the
   page can say which book it just opened.
   ============================================================ */
.page__book {
  font-family: var(--poetic);
  font-style: italic;
  font-size: clamp(1.15rem, 2.2vw, 1.6rem);
  color: var(--red-t);
  margin-top: 0.5rem;
  letter-spacing: 0.01em;
}

/* ============================================================
   THE READING DESK
   A bar for the long recordings. It only exists on pages that
   carry chapters, and only once something is playing.
   ============================================================ */
body.has-adesk { padding-bottom: 5.6rem; }

.adesk {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
  animation: adesk-rise 0.34s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes adesk-rise { from { transform: translateY(100%); } to { transform: none; } }

.adesk__in {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0.85rem 1.4rem;
}
.adesk__b {
  flex: none;
  width: 2.3rem; height: 2.3rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  display: grid; place-items: center;
  position: relative;
  font: inherit;
  transition: border-color 0.2s, color 0.2s;
}
.adesk__b:hover { border-color: var(--red-t); color: var(--red-t); }
.adesk__b span { font-size: 0.56rem; letter-spacing: 0.02em; }

/* the two skips carry a curved arrow drawn in CSS, and their number inside */
.adesk__back::before, .adesk__fwd::before {
  content: ""; position: absolute; inset: 0.32rem;
  border: 1px solid currentColor; border-radius: 50%;
  border-top-color: transparent;
  opacity: 0.55;
}
.adesk__fwd::before { transform: scaleX(-1); }

.adesk__play { width: 2.9rem; height: 2.9rem; border-color: var(--red); }
.adesk__play::before {
  content: ""; width: 0; height: 0;
  border-left: 0.62rem solid currentColor;
  border-top: 0.4rem solid transparent;
  border-bottom: 0.4rem solid transparent;
  margin-left: 0.18rem;
}
.adesk.is-playing .adesk__play::before {
  width: 0.62rem; height: 0.72rem; border: 0;
  margin-left: 0;
  background: linear-gradient(to right,
    currentColor 0 34%, transparent 34% 66%, currentColor 66% 100%);
}

.adesk__mid { flex: 1; min-width: 0; }
.adesk__now {
  font-family: var(--display);
  font-size: 0.86rem;
  letter-spacing: 0.06em;
  color: var(--ink);
  margin: 0 0 0.4rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.adesk__line {
  height: 14px;                 /* a thumb-sized target around a hairline */
  display: flex; align-items: center;
  cursor: pointer;
  touch-action: none;
}
.adesk__line::before {
  content: ""; position: absolute; left: 0; right: 0;
  height: 2px; background: var(--line);
}
.adesk__line { position: relative; }
.adesk__fill {
  position: absolute; left: 0;
  height: 2px; width: 0;
  background: var(--red-t);
}
.adesk__fill::after {
  content: ""; position: absolute; right: -4px; top: 50%;
  width: 9px; height: 9px; margin-top: -4.5px;
  border-radius: 50%; background: var(--red-t);
}
.adesk__line:focus-visible { outline: 1px solid var(--red-t); outline-offset: 4px; }

.adesk__t {
  flex: none; margin: 0;
  font-size: 0.72rem; color: var(--muted);
  font-variant-numeric: tabular-nums;
  display: flex; gap: 0.4rem;
}
.adesk__t span + span::before { content: "/ "; opacity: 0.5; }
.adesk__shut { font-size: 1.1rem; line-height: 1; border-color: transparent; color: var(--muted); }

@media (max-width: 720px) {
  .adesk__in { gap: 0.55rem; padding: 0.7rem 0.9rem; flex-wrap: wrap; }
  .adesk__mid { order: -1; flex-basis: 100%; }
  .adesk__t { margin-left: auto; }
  body.has-adesk { padding-bottom: 8rem; }
}
