/* =========================================================
   Melissa Dutch — main stylesheet
   Phases 1–3: foundation, shared components, static sections
   Palette tokens = Melissa Dutch (cool). Femme Rising overrides in femme-rising.css
   ========================================================= */

/* ---------- Tokens ---------- */
:root {
  /* Core background tones — indigo cosmos (May 2026 palette pivot) */
  --deep-stage: #0a0820;
  --indigo-deep: #1a1755;       /* card/surface */
  --indigo: #2d2b78;            /* borders, mid-depth */
  --stage-blue: #1e3a8a;        /* cool secondary anchor */

  /* Pink accent stack — replaces violet everywhere on MD */
  --electric-pink: #ec4899;     /* primary accent */
  --neon-pink: #f06aff;         /* hottest FR-only glow */
  --blush: #fce7f3;             /* near-white pink-100 — reads on any background */
  --rose: #d97a8e;              /* warm organic accent */

  /* Legacy aliases — old var names still referenced site-wide;
     point them at the new pink palette so triangles/borders/glows shift
     hue without touching every selector. Diana's direction: "triangles
     should look exactly as they do now, just switch the hue." */
  --violet-dark: var(--indigo-deep);
  --electric-violet: var(--electric-pink);

  --parchment: #f0ece4;

  /* Supporting palette */
  --warm-gold: #c9a96e;
  --muted-earth: #6b5b4e;
  --skin-warm: #de8f86;
  --silver: #9ca3af;

  /* Text tones — cool/neutral everywhere except the nav (which uses gold directly) */
  --text-primary: #f0ece4;     /* lightest — headings (parchment) */
  --text-body: #d4cfe0;        /* body copy */
  --text-secondary: #a8a3b8;   /* secondary */
  --text-label: #f4a8c8;       /* pink-tinted labels (was violet-tinted) */
  --text-quiet: #8a87a0;       /* smallest/quietest */
  --divider: rgba(236, 72, 153, 0.15);

  /* Surfaces */
  --surface-overlay: rgba(10, 8, 32, 0.7);
  --surface-modal: rgba(10, 8, 32, 0.85);

  /* Motion */
  --ease-out-expo: cubic-bezier(0.33, 0, 0, 1);
  --dur-micro: 0.3s;
  --dur-medium: 0.5s;
  --dur-palette: 0.8s;

  /* Layout */
  --gutter: clamp(1.25rem, 4vw, 3rem);
  --section-pad-y: clamp(5rem, 13vh, 9rem);
  --header-h: 92px;
}

/* ---------- Reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Dark fallback lives on <html> so <body> can stay fully transparent —
     nebula/starfield canvases paint in front of <html>, not buried under
     an opaque body background. */
  background: var(--deep-stage);
  /* Kill horizontal page scroll across every page. Several sections use
     `width: 100vw; margin-left: calc(50% - 50vw)` to break out of the
     content column — that pattern can trigger a 1-2px overflow that
     spawns a horizontal scrollbar. Clamping at the document root
     prevents it without having to police every section individually. */
  overflow-x: hidden;
  max-width: 100vw;
}
body {
  margin: 0;
  background: transparent;
  color: var(--text-body);
  font-family: var(--body);
  font-weight: 400;
  line-height: 1.7;
  font-size: 0.9rem;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  max-width: 100vw;
}

/* ---------- Custom scrollbar (vertical only — horizontal is hidden) ----
   Brand-colored: deep-stage track, electric-pink thumb with a soft blush
   inner highlight. Falls back gracefully on Firefox via the standard
   scrollbar-color / scrollbar-width properties. */
html {
  scrollbar-width: thin;
  scrollbar-color: rgba(236, 72, 153, 0.55) rgba(10, 8, 32, 0.4);
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track {
  background: rgba(10, 8, 32, 0.5);
  border-left: 1px solid rgba(236, 72, 153, 0.08);
}
::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, rgba(244, 114, 182, 0.85), rgba(236, 72, 153, 0.7) 50%, rgba(219, 39, 119, 0.85));
  border-radius: 6px;
  border: 2px solid rgba(10, 8, 32, 0.5);
  background-clip: padding-box;
  box-shadow: 0 0 8px rgba(236, 72, 153, 0.35);
}
::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, rgba(252, 231, 243, 0.9), rgba(244, 114, 182, 0.85) 50%, rgba(236, 72, 153, 0.9));
  box-shadow: 0 0 14px rgba(236, 72, 153, 0.6);
}
::-webkit-scrollbar-corner { background: transparent; }

/* page-fit mode: body becomes a flex column so the footer pins to viewport bottom
   when content is small (shows/about). Other pages keep default block layout so
   GSAP's ScrollTrigger pin on the gallery works correctly. */
body.page-fit {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
body.page-fit main {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}
body.page-fit main > section {
  min-height: 0;
  flex: 1 1 auto;
  padding: calc(var(--header-h) + 1rem) 0 0.75rem;
}
body.page-fit .section-head { margin-bottom: 1.25rem; }

/* Compact show rows when in page-fit mode so all 5 rows + heading + footer fit */
body.page-fit .show-row { padding: 0.7rem 1rem; }
body.page-fit .show-date__day { font-size: 1.5rem; }
body.page-fit .show-info__name { font-size: 1.05rem; }
body.page-fit .shows__list.content-glass { padding: 0.85rem 1.25rem; }
body.page-fit .site-footer--minimal { padding: 1.25rem var(--gutter); }

/* Compact about page */
body.page-fit .bio__grid { gap: clamp(2rem, 4vw, 3.5rem); align-items: center; }
body.page-fit .bio__media {
  aspect-ratio: 3/4;
  max-height: calc(100vh - 12rem);
  width: auto;
  justify-self: center;
}
body.page-fit .bio__body { gap: 0.9rem; }
body.page-fit .pull-quote { margin: 0.5rem 0; font-size: 1.05rem; }
body.page-fit .bio__socials { margin-top: 0.25rem; padding-top: 0.75rem; }
/* Home (no nebula canvas) gets a subtle static colour wash on the html element so
   the page isn't pure black behind the starfield. Inner pages override this with
   the WebGL nebula, so the gradient is harmless there (fully covered). */
html {
  background:
    radial-gradient(ellipse at 78% 18%, rgba(236, 72, 153, 0.12), transparent 55%),
    radial-gradient(ellipse at 12% 78%, rgba(1, 25, 70, 0.35), transparent 55%),
    var(--deep-stage);
}
img, picture, video, canvas, svg { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
:focus-visible {
  /* 3px outline + contrasting white inner ring ensures visibility on both the
     dark MD palette and the bright magenta FR palette (WCAG 2.4.7 + 2.4.11). */
  outline: 3px solid var(--electric-violet);
  outline-offset: 3px;
  box-shadow: 0 0 0 5px rgba(255, 255, 255, 0.85);
  border-radius: 2px;
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* Skip link — keyboard users' first interaction, must be visibly obvious. */
.skip-link {
  position: absolute; top: -100px; left: 1rem; z-index: 999;
  background: var(--electric-violet); color: var(--deep-stage);
  padding: 0.85rem 1.35rem; font-family: var(--mono);
  font-size: 0.78rem; letter-spacing: 0.2em; text-transform: uppercase;
  font-weight: 500;
  border-radius: 2px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.55);
  transition: top 0.18s var(--ease-out-expo);
}
.skip-link:focus, .skip-link:focus-visible { top: 1rem; outline-offset: 2px; }

/* ---------- Typography utilities ---------- */
.display {
  font-family: var(--display);
  font-weight: 500;
  line-height: 1.15;
  color: var(--text-primary);
  letter-spacing: -0.01em;
}
.display-xl { font-size: clamp(2.5rem, 7vw, 5.5rem); font-weight: 400; }
.display-l  { font-size: clamp(2rem, 4.5vw, 3.4rem); }
.display-m  { font-size: clamp(1.5rem, 2.6vw, 2rem); }

.mono-label {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--text-primary);
  text-shadow: 0 2px 10px rgba(7, 7, 26, 0.7);
}
.mono-meta {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.body-lead {
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.75;
  color: var(--text-body);
  max-width: 52ch;
}
.pull-quote {
  font-family: var(--display);
  font-style: italic;
  font-size: clamp(1.1rem, 1.7vw, 1.3rem);
  line-height: 1.5;
  color: var(--text-primary);
  padding-left: 1.25rem;
  border-left: 2px solid var(--electric-violet);
  max-width: 44ch;
  margin: 1.75rem 0;
}

/* Text-fill-on-scroll quote — starts muted, fills to parchment as the user scrolls.
   The <span> child has its text clipped to a gradient background; JS animates the
   background-size from 0% to 200% via ScrollTrigger. */
.pull-quote.js-fill {
  padding: 0;
  border-left: 0;
  font-size: clamp(1.5rem, 2.6vw, 2.2rem);
  font-weight: 400;
  line-height: 1.3;
  max-width: 38ch;
  letter-spacing: -0.005em;
  margin: 2.25rem 0;
}
.pull-quote.js-fill > span {
  -webkit-background-clip: text;
  background-clip: text;
  background-color: rgba(232, 229, 239, 0.22);
  background-image: linear-gradient(135deg, var(--text-primary) 50%, rgba(232, 229, 239, 0.22) 60%);
  background-position: 0 0;
  background-repeat: no-repeat;
  background-size: 0% 200%;
  color: transparent;
  display: inline;
  will-change: background-size;
}
@media (prefers-reduced-motion: reduce) {
  .pull-quote.js-fill > span { background-size: 200% 200%; }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.95rem 1.75rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  border: 1px solid transparent;
  border-radius: 2px;
  cursor: pointer;
  transition:
    background-color 0.35s var(--ease-out-expo),
    border-color    0.35s var(--ease-out-expo),
    box-shadow      0.35s var(--ease-out-expo),
    color           0.35s var(--ease-out-expo);
}
/* Glass buttons with violet tint; neon bloom on hover. Matches nav/logo language. */
.btn-primary {
  background: rgba(236, 72, 153, 0.22);
  color: var(--text-primary);
  border-color: rgba(236, 72, 153, 0.55);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: inset 0 0 0 1px rgba(236, 72, 153, 0.05);
}
.btn-primary:hover {
  background: rgba(236, 72, 153, 0.38);
  border-color: var(--electric-violet);
  box-shadow:
    0 0 14px  rgba(236, 72, 153, 0.55),
    0 0 32px  rgba(236, 72, 153, 0.28),
    inset 0 0 12px rgba(236, 72, 153, 0.2);
}
.btn-ghost {
  background: rgba(7, 7, 26, 0.35);
  color: var(--text-primary);
  border-color: rgba(255, 255, 255, 0.22);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.btn-ghost:hover {
  border-color: var(--electric-violet);
  background: rgba(236, 72, 153, 0.14);
  box-shadow:
    0 0 12px rgba(236, 72, 153, 0.45),
    0 0 28px rgba(236, 72, 153, 0.22);
}
/* Chip — smaller variant for streaming platforms. Same glass + 2px radius as other buttons. */
.btn-chip {
  padding: 0.55rem 1.1rem;
  font-size: 0.62rem;
  letter-spacing: 0.24em;
  background: rgba(7, 7, 26, 0.4);
  color: var(--text-primary);
  border: 1px solid rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.btn-chip:hover {
  border-color: var(--electric-violet);
  background: rgba(236, 72, 153, 0.18);
  box-shadow:
    0 0 10px rgba(236, 72, 153, 0.5),
    0 0 24px rgba(236, 72, 153, 0.22);
}
/* Primary chip — highlighted version used to lead the eye to the Buy
   action on the home page Skinny feature. Matches the highlighted
   Bandcamp button on /music/ for consistency. */
.btn-chip.is-primary {
  background: rgba(236, 72, 153, 0.4);
  border-color: var(--electric-pink);
  color: var(--parchment);
  box-shadow:
    0 0 12px rgba(236, 72, 153, 0.35),
    inset 0 0 0 1px rgba(236, 72, 153, 0.1);
}
.btn-chip.is-primary:hover {
  background: rgba(236, 72, 153, 0.6);
  box-shadow:
    0 0 18px rgba(236, 72, 153, 0.7),
    0 0 42px rgba(236, 72, 153, 0.35),
    inset 0 0 14px rgba(236, 72, 153, 0.25);
}

/* ---------- Layout helpers ---------- */
.wrap {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.section {
  position: relative;
  min-height: 100vh;
  padding: calc(var(--header-h) + var(--section-pad-y)) 0 var(--section-pad-y);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.section-head {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
}
.section-head .display { margin-top: 0; }
/* Section label gets a larger, more prominent treatment so it reads as an "eyebrow"
   above the display heading — not a tiny hard-to-see line. */
.section-head .mono-label {
  font-size: 0.82rem;
  letter-spacing: 0.38em;
  color: var(--text-primary);
  text-shadow: 0 2px 12px rgba(7, 7, 26, 0.8);
}
.section-head .mono-label { color: var(--text-primary); }

/* ---------- Liquid nebula (WebGL) + star field canvases ----------
   Stacking: body bg (fallback) < nebula (0) < starfield (1) < content (10) < header (90+).
   Nebula must sit ABOVE the body bg or the body's opaque paint hides it. */
.liquid-nebula {
  position: fixed;
  top: 0; left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 0;
  pointer-events: none;
  /* Calmed down — was 0.72, now 0.42 so bright pink peaks don't wash
     out small text and the page reads quieter overall. */
  opacity: 0.42;
}
/* Mobile: keep the nebula but dial opacity down a touch so it doesn't
   compete with the tighter content on small screens (was previously
   display:none, which left mobile feeling flat vs. desktop). */
@media (max-width: 767px) {
  .liquid-nebula { opacity: 0.32; }
}
/* Respect reduced-motion preference everywhere — the shader animates. */
@media (prefers-reduced-motion: reduce) {
  .liquid-nebula { display: none; }
}

/* Top vignette: fixed dark fade behind the header so nav text stays legible no matter
   where the nebula's bright peaks drift to. Sits above canvases (z:0/1) and below
   the header (z:90). */
.top-vignette {
  content: '';
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 180px;
  z-index: 5;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(7, 7, 26, 0.78) 0%,
    rgba(7, 7, 26, 0.5)  35%,
    rgba(7, 7, 26, 0.22) 65%,
    rgba(7, 7, 26, 0)    100%
  );
}
body.femme-rising .top-vignette {
  background: linear-gradient(
    to bottom,
    rgba(26, 8, 32, 0.78) 0%,
    rgba(26, 8, 32, 0.5)  35%,
    rgba(26, 8, 32, 0.22) 65%,
    rgba(26, 8, 32, 0)    100%
  );
}
.starfield {
  position: fixed;
  top: 0; left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 1;
  pointer-events: none;
  opacity: 1;
  mix-blend-mode: screen;
}

/* Content sections are transparent — stars show through on every MD page. */
.music, .shows, .bio, .gallery, .hero {
  background: transparent;
}
/* Main content sits above both canvases */
main > section {
  position: relative;
  z-index: 10;
}
/* Compositor hints */
.gallery__track { will-change: transform; }

/* ---------- Discography (Music page) ----------
   Transparent — the nebula + starfield canvases sit BEHIND this section so
   the cosmos shows through the discography (per the May 2026 restructure).
   The music-hero above is fully opaque, so the cosmos only becomes
   visible once you scroll past the hero. */
.discography {
  padding: clamp(5rem, 10vw, 8rem) 0 clamp(7rem, 12vw, 10rem);
  position: relative;
  z-index: 2;
  background: transparent;
  border-top: 1px solid var(--divider);
}

/* ---------- Vinyl shelf — 2×2 with inner-only neon grooves ----------
   Layout: 2 columns × 2 rows on desktop. Vinyls are larger (max ~400px
   each) with a wide column gap so the slid record has plenty of room.
   Caption sits below each vinyl with streaming links. */
.vinyl-shelf {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Wide gap so the slid record (22% of vinyl width ≈ 88px on a 400px
     vinyl) never reaches the neighbour. */
  column-gap: clamp(5rem, 10vw, 8rem);
  /* Generous vertical room — fits the bigger caption + 3 link buttons +
     visual breathing space between the two rows of releases. */
  row-gap: clamp(11rem, 18vw, 16rem);
  padding: 1rem var(--gutter) 9rem;
  /* Constrain overall width so vinyls don't grow absurd on wide screens. */
  max-width: 920px;
  margin: 0 auto;
}
.vinyl {
  position: relative;
  aspect-ratio: 1 / 1;
  /* Z-index lifts the hovered vinyl above siblings during the slide. */
  transition: z-index 0s 0.6s;
}
.vinyl:hover, .vinyl:focus-within {
  z-index: 5;
  transition: z-index 0s 0s;
}
/* Slot — translates on hover. Sleeve trigger comes from the parent
   so the streaming links inside the caption don't trigger the slide
   when hovered. */
.vinyl__record-slot {
  position: absolute;
  inset: 0;
  z-index: 1;
  transition: transform 0.7s var(--ease-out-expo);
  will-change: transform;
}
.vinyl:hover .vinyl__record-slot { transform: translateX(22%); }
/* Record — base + outer (subdued) grooves. Inner ring of bright pink
   grooves added via ::before so we can mask them to the inner radius. */
.vinyl__record {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  position: relative;
  background:
    /* (3) Pink centre label */
    radial-gradient(circle at 50% 50%, var(--electric-pink) 0 26%, transparent 26.5%),
    /* (2) Subtle gloss highlight on one side */
    radial-gradient(ellipse at 35% 30%, rgba(255,255,255,0.06), transparent 35%),
    /* (1) Outer grooves — muted plum, no neon */
    repeating-radial-gradient(circle at 50% 50%,
      rgba(140, 110, 150, 0.28) 0px 1px,
      #0a0612 1px 5px);
  box-shadow:
    0 14px 28px rgba(0, 0, 0, 0.6),
    0 0 22px rgba(236, 72, 153, 0.18);
  animation: vinyl-spin 4s linear infinite;
  animation-play-state: paused;
}
.vinyl:hover .vinyl__record { animation-play-state: running; }
/* INNER NEON RING — bright pink grooves just outside the label, gradient
   fading outward so the pink dissipates smoothly instead of cutting off
   at a hard edge. Mask is solid black just past the label, then fades
   through a long gradient toward transparent at ~75% radius. */
.vinyl__record::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: repeating-radial-gradient(circle at 50% 50%,
    rgba(240, 106, 255, 0.95) 0px 1px,
    transparent 1px 5px);
  -webkit-mask: radial-gradient(circle at 50% 50%,
    transparent 26%,
    black 29%,
    rgba(0, 0, 0, 0.85) 38%,
    rgba(0, 0, 0, 0.55) 48%,
    rgba(0, 0, 0, 0.25) 60%,
    transparent 75%);
          mask: radial-gradient(circle at 50% 50%,
    transparent 26%,
    black 29%,
    rgba(0, 0, 0, 0.85) 38%,
    rgba(0, 0, 0, 0.55) 48%,
    rgba(0, 0, 0, 0.25) 60%,
    transparent 75%);
  pointer-events: none;
  /* Soft pink glow to make the inner ring read as luminous */
  filter: drop-shadow(0 0 4px rgba(236, 72, 153, 0.5));
}
/* Centre hole — small dark dot inside the pink label */
.vinyl__record::after {
  content: '';
  position: absolute;
  inset: 47%;
  border-radius: 50%;
  background: var(--deep-stage);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.4);
}
@keyframes vinyl-spin { to { transform: rotate(360deg); } }
/* Sleeve — clickable area; carries the click-to-bandcamp on hover-only.
   Stays put while the record slides. */
.vinyl__sleeve {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-color: var(--indigo-deep);
  z-index: 2;
  /* No border — was showing as a thin pink/white line around lighter
     cover arts. Pink halo now lives in the box-shadow only. */
  border: 0;
  box-shadow:
    0 12px 26px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(236, 72, 153, 0.18);
  transition: box-shadow 0.5s var(--ease-out-expo);
  cursor: pointer;
}
.vinyl:hover .vinyl__sleeve {
  box-shadow:
    0 18px 36px rgba(0, 0, 0, 0.7),
    0 0 32px rgba(236, 72, 153, 0.28),
    0 0 0 1px rgba(236, 72, 153, 0.5);
}
/* Hover hint — a small pulsing pink circle with a play-arrow glyph in the
   bottom-right corner of every sleeve. Tells the user "hover me, something
   happens." Glides right + fades out the moment hover actually starts (the
   record takes over from here). */
.vinyl__sleeve::after {
  content: '▸';
  position: absolute;
  bottom: clamp(0.75rem, 1.4vw, 1.1rem);
  right: clamp(0.75rem, 1.4vw, 1.1rem);
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 8, 32, 0.85);
  border: 1px solid rgba(236, 72, 153, 0.7);
  color: var(--electric-pink);
  font-size: 0.85rem;
  font-family: -apple-system, sans-serif;
  line-height: 1;
  padding-left: 2px;  /* optical centre the right-pointing arrow */
  box-shadow: 0 0 0 0 rgba(236, 72, 153, 0.5);
  animation: vinyl-hint-pulse 2.4s ease-in-out infinite;
  transition:
    opacity 0.4s var(--ease-out-expo),
    transform 0.4s var(--ease-out-expo);
  pointer-events: none;
}
.vinyl:hover .vinyl__sleeve::after {
  opacity: 0;
  transform: translateX(10px);
  animation-play-state: paused;
}
@keyframes vinyl-hint-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(236, 72, 153, 0.55); }
  50%      { box-shadow: 0 0 0 10px rgba(236, 72, 153, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .vinyl__sleeve::after { animation: none; }
}
/* Caption block — sits well below each vinyl with generous breathing
   space. Title + italic date + pill-button streaming links. */
.vinyl__caption {
  position: absolute;
  left: -10%; right: -10%;
  /* Pushed further from the sleeve so the photo art has visual breathing
     room before the type begins. */
  bottom: -9rem;
  text-align: center;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
}
.vinyl__caption strong {
  font-family: var(--display);
  font-weight: 400;
  /* Bigger + slightly heavier via stroke so the thin Poiret reads cleanly
     against the dark cosmos background. */
  font-size: clamp(1.5rem, 2.4vw, 1.95rem);
  color: var(--parchment);
  letter-spacing: -0.005em;
  line-height: 1.05;
  -webkit-text-stroke: 0.35px var(--parchment);
}
.vinyl__caption time {
  font-family: var(--display-alt, 'Fraunces', serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.05rem;
  color: var(--blush);
  letter-spacing: 0.015em;
}
.vinyl__links {
  display: inline-flex;
  align-items: center;
  /* More room between buttons — was 0.5rem (squished) → 1rem. */
  gap: 1rem;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 0.95rem;
}
/* Streaming buttons — match the home page .btn-primary glass DNA:
   - 2px corners (no rounding, no pill)
   - rgba(236, 72, 153, 0.22) glass fill (more visible than the prior 14%)
   - pink border for definition
   - backdrop blur
   - mono caps with wide tracking
   On hover: intensified fill + multi-layer pink glow, same hue (no jump
   to neon-pink). */
.vinyl__links a {
  position: relative;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.6rem 1.15rem;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--parchment);
  background: rgba(236, 72, 153, 0.22);
  border: 1px solid rgba(236, 72, 153, 0.55);
  border-radius: 2px;
  text-decoration: none;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: inset 0 0 0 1px rgba(236, 72, 153, 0.05);
  transition:
    background-color 0.35s var(--ease-out-expo),
    border-color    0.35s var(--ease-out-expo),
    box-shadow      0.35s var(--ease-out-expo),
    color           0.35s var(--ease-out-expo),
    transform       0.35s var(--ease-out-expo);
}
.vinyl__links a:hover,
.vinyl__links a:focus-visible {
  color: var(--parchment);
  background: rgba(236, 72, 153, 0.4);
  border-color: var(--electric-pink);
  box-shadow:
    0 0 14px  rgba(236, 72, 153, 0.55),
    0 0 32px  rgba(236, 72, 153, 0.28),
    inset 0 0 12px rgba(236, 72, 153, 0.2);
  transform: translateY(-1px);
  outline: none;
}
/* Hide the old text-separator since buttons now have their own boundary */
.vinyl__links .sep { display: none; }

/* Bandcamp = primary action ("buy" — Melissa's direct revenue). Brighter
   fill + stronger border so it leads the eye of the three. */
.vinyl__links a[href*="bandcamp"] {
  background: rgba(236, 72, 153, 0.4);
  border-color: var(--electric-pink);
  box-shadow:
    0 0 12px rgba(236, 72, 153, 0.35),
    inset 0 0 0 1px rgba(236, 72, 153, 0.1);
}
.vinyl__links a[href*="bandcamp"]:hover,
.vinyl__links a[href*="bandcamp"]:focus-visible {
  background: rgba(236, 72, 153, 0.6);
  box-shadow:
    0 0 18px rgba(236, 72, 153, 0.7),
    0 0 42px rgba(236, 72, 153, 0.35),
    inset 0 0 14px rgba(236, 72, 153, 0.25);
}
/* Spotify + Apple Music = lowlit secondary. Subtler fill + faded border
   so they read as alternates rather than competing with Bandcamp. */
.vinyl__links a[href*="spotify"],
.vinyl__links a[href*="apple.com"] {
  background: rgba(236, 72, 153, 0.1);
  border-color: rgba(236, 72, 153, 0.3);
  color: rgba(240, 236, 228, 0.78);
  box-shadow: inset 0 0 0 1px rgba(236, 72, 153, 0.03);
}
.vinyl__links a[href*="spotify"]:hover,
.vinyl__links a[href*="apple.com"]:hover,
.vinyl__links a[href*="spotify"]:focus-visible,
.vinyl__links a[href*="apple.com"]:focus-visible {
  /* Lift to about the same weight as Bandcamp's REST state on hover —
     reads as "warming up" rather than overpowering the primary. */
  background: rgba(236, 72, 153, 0.28);
  border-color: rgba(236, 72, 153, 0.6);
  color: var(--parchment);
  box-shadow:
    0 0 10px rgba(236, 72, 153, 0.4),
    0 0 22px rgba(236, 72, 153, 0.2);
}
@media (max-width: 760px) {
  .vinyl-shelf {
    grid-template-columns: 1fr;
    column-gap: 0;
    max-width: 460px;
  }
  .vinyl:hover .vinyl__record-slot { transform: translateX(18%); }
}
@media (prefers-reduced-motion: reduce) {
  .vinyl__record { animation: none; }
  .vinyl:hover .vinyl__record-slot { transform: translateX(12%); }
}
.release-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* Six-column grid so we can lay 5 releases out as 3-on-top / 2-on-bottom,
     with the bottom row's two cards centered under the top three. Each card
     spans 2 columns. */
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(1.25rem, 2vw, 1.75rem);
}
/* Top row — three cards, each spanning 2 of the 6 columns */
.release-grid > .release-card:nth-child(1) { grid-column: 1 / 3; }
.release-grid > .release-card:nth-child(2) { grid-column: 3 / 5; }
.release-grid > .release-card:nth-child(3) { grid-column: 5 / 7; }
/* Bottom row — two cards centered (shifted one column inward so they sit
   under the midpoints of the three top cards) */
.release-grid > .release-card:nth-child(4) { grid-column: 2 / 4; }
.release-grid > .release-card:nth-child(5) { grid-column: 4 / 6; }
@media (max-width: 899px) {
  .release-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .release-grid > .release-card:nth-child(n) { grid-column: auto; }
}
@media (max-width: 600px) {
  .release-grid { grid-template-columns: 1fr; }
}
/* Four-up variant — used when the upcoming-EP card is hidden and the four
   archive releases sit in a clean single row. Overrides the 6-col layout. */
.release-grid--four {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.release-grid--four > .release-card:nth-child(n) { grid-column: auto; }
@media (max-width: 1100px) {
  .release-grid--four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
  .release-grid--four { grid-template-columns: 1fr; }
}
.release-card {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: 1.25rem;
  position: relative;
  transform-style: preserve-3d;
  animation: release-breathe 6s ease-in-out infinite;
  transition:
    transform 0.5s var(--ease-out-expo),
    box-shadow 0.4s var(--ease-out-expo),
    border-color 0.4s var(--ease-out-expo);
}
.release-grid { perspective: 1200px; }
/* Stagger each card's breathing so the grid feels alive, not synchronised */
.release-grid > .release-card:nth-child(2) { animation-delay: -1.8s; }
.release-grid > .release-card:nth-child(3) { animation-delay: -3.6s; }
.release-grid > .release-card:nth-child(4) { animation-delay: -4.8s; }
.release-grid > .release-card:nth-child(5) { animation-delay: -2.4s; }
/* Upcoming release gets a brighter violet ring so it stands out */
.release-card--upcoming {
  border-color: rgba(236, 72, 153, 0.55);
  box-shadow:
    0 0 24px rgba(236, 72, 153, 0.25),
    0 0 60px rgba(236, 72, 153, 0.12);
}
.release-card--upcoming .mono-meta {
  color: var(--electric-violet);
}

@keyframes release-breathe {
  0%, 100% {
    box-shadow:
      0 0 18px rgba(236, 72, 153, 0.12),
      0 0 40px rgba(236, 72, 153, 0.05);
  }
  50% {
    box-shadow:
      0 0 26px rgba(236, 72, 153, 0.22),
      0 0 58px rgba(236, 72, 153, 0.1);
  }
}

/* Subtle 3D tilt on hover — card lifts, leans, and glows */
/* Hover: smooth rise + glow bloom. No 3D tilt — it was jumpy and clashed
   with the breathing animation. Just a quiet vertical lift with the violet
   halo intensifying. Same motion language as the content-glass cards. */
.release-card:hover,
.release-card:focus-within {
  transform: translateY(-6px);
  border-color: rgba(236, 72, 153, 0.6);
  box-shadow:
    0 18px 40px rgba(0, 0, 0, 0.45),
    0 0 32px rgba(236, 72, 153, 0.42),
    0 0 70px rgba(236, 72, 153, 0.2);
  animation-play-state: paused;
}
@media (prefers-reduced-motion: reduce) {
  .release-card { animation: none; }
}
.release-card__art {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  background:
    radial-gradient(ellipse at 30% 30%, rgba(255,255,255,0.06), transparent 55%),
    linear-gradient(135deg, var(--art-a, var(--stage-blue)), var(--art-b, var(--violet-dark)));
  border-radius: 2px;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  padding: 1rem;
  border: 1px solid rgba(236, 72, 153, 0.12);
}
.release-card__art-title {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.2rem, 2vw, 1.6rem);
  color: var(--text-primary);
  letter-spacing: -0.01em;
  position: relative;
  z-index: 1;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.65);
}
/* When cover art is present, the <img> sits underneath the title and a
   bottom gradient scrim keeps the title readable. */
.release-card__art img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  z-index: 0;
}
.release-card__art:has(img)::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 55%;
  background: linear-gradient(to bottom, transparent, rgba(10, 8, 32, 0.78));
  z-index: 0;
  pointer-events: none;
}
.release-card__meta {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0 0.25rem 0.25rem;
}
.release-card__title {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.1rem, 1.5vw, 1.35rem);
  line-height: 1.25;
  color: var(--text-primary);
  margin: 0;
  letter-spacing: -0.01em;
}
.release-card__note {
  font-size: 0.85rem;
  color: var(--text-secondary);
  margin: 0;
}
.release-card__links {
  display: flex;
  flex-wrap: nowrap;   /* keep all chips on one line inside the card */
  gap: 0.35rem;
  margin-top: 0.5rem;
  overflow-x: auto;
  scrollbar-width: none;
}
.release-card__links::-webkit-scrollbar { display: none; }
/* Streaming-link CTAs — styled like small chips so they read as actions.
   Same language as .btn-chip on the Skinny listen row. Tight padding so
   three chips fit on one line inside the narrow release card. */
.release-card__links a {
  display: inline-flex;
  align-items: center;
  padding: 0.45rem 0.6rem;
  font-family: var(--mono);
  font-size: 0.54rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  flex: 0 0 auto;
  color: var(--text-primary);
  background: rgba(7, 7, 26, 0.4);
  border: 1px solid rgba(236, 72, 153, 0.32);
  border-radius: 2px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition:
    background 0.25s var(--ease-out-expo),
    border-color 0.25s var(--ease-out-expo),
    color 0.25s var(--ease-out-expo),
    box-shadow 0.25s var(--ease-out-expo);
}
.release-card__links a:hover,
.release-card__links a:focus-visible {
  background: rgba(236, 72, 153, 0.2);
  border-color: var(--electric-violet);
  color: #ffffff;
  box-shadow:
    0 0 12px rgba(236, 72, 153, 0.5),
    0 0 28px rgba(236, 72, 153, 0.25);
}

/* Glass containers for text-heavy sections — semi-transparent dark bg + blur
   so content reads cleanly over the nebula without killing the atmosphere. */
.content-glass {
  background: rgba(7, 7, 26, 0.55);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  /* Persistent violet neon halo — the card always reads as "lit". Hover
     intensifies for interactive feedback. Same motion language as the MD
     logo triangles and the gallery tiles. */
  border: 1px solid rgba(236, 72, 153, 0.48);
  border-radius: 4px;
  padding: clamp(1.75rem, 4vw, 3rem);
  box-shadow:
    0 0 24px rgba(236, 72, 153, 0.24),
    0 0 60px rgba(236, 72, 153, 0.12);
  transition:
    border-color 0.45s var(--ease-out-expo),
    box-shadow 0.45s var(--ease-out-expo);
}
.content-glass:hover,
.content-glass:focus-within {
  border-color: rgba(236, 72, 153, 0.7);
  box-shadow:
    0 0 34px rgba(236, 72, 153, 0.38),
    0 0 80px rgba(236, 72, 153, 0.2);
}
/* FR pink variant — persistent, intensifies on hover */
body.femme-rising .content-glass {
  border-color: rgba(240, 106, 255, 0.45);
  box-shadow:
    0 0 24px rgba(240, 106, 255, 0.26),
    0 0 60px rgba(225, 29, 116, 0.14);
}
body.femme-rising .content-glass:hover,
body.femme-rising .content-glass:focus-within {
  border-color: rgba(240, 106, 255, 0.7);
  box-shadow:
    0 0 34px rgba(240, 106, 255, 0.42),
    0 0 80px rgba(225, 29, 116, 0.22);
}
body.femme-rising .content-glass {
  background: rgba(26, 8, 32, 0.58);
  border-color: rgba(255, 139, 184, 0.2);
}

/* ---------- Fixed header ---------- */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 90;
  /* Tall initial header so the landing logo has breathing room; shrinks once you scroll. */
  height: 184px;
  display: flex;
  align-items: center;
  padding: 0 var(--gutter);
  background: transparent;
  transition:
    height 0.55s var(--ease-out-expo),
    background-color 0.35s var(--ease-out-expo),
    backdrop-filter 0.35s var(--ease-out-expo),
    opacity 0.5s var(--ease-out-expo),
    transform 0.55s var(--ease-out-expo);
}
/* Pages whose first paint is a full-bleed immersive hero (home, music,
   about). They opt in via `body.has-hero-overlay` — the header hides
   over the hero and fades + slides in once `body.header-revealed` is
   toggled by ui.js (scroll handler tracks the page's hero element). */
body.has-hero-overlay .site-header {
  opacity: 0;
  pointer-events: none;
  transform: translateY(-24px);
}
body.has-hero-overlay.header-revealed .site-header {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  body.has-hero-overlay .site-header { transform: none; transition: opacity 0.3s linear; }
}
.site-header.is-scrolled {
  height: var(--header-h);
  background: var(--surface-overlay);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
@media (max-width: 767px) {
  .site-header { height: 120px; }
}
.site-header__inner {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.wordmark {
  display: inline-flex;
  align-items: center;
  line-height: 0;
  /* font props kept as fallback if mask fails to load */
  font-family: var(--display);
  font-weight: 400;
  font-size: 1rem;
  letter-spacing: 0.06em;
  color: var(--text-primary);
}
/* Logo is the real color image (mask-flatten approach collapsed triangles into letters).
   Shrinks into nav size once the user scrolls past the hero. */
/* Logo rendered as two layered PNGs: crisp letters on top of softly-blurred triangles.
   This lets the triangles have the website's glowy nebula-adjacent feel without
   blurring the wordmark itself. Glow intensifies only on hover. */
.wordmark__mark {
  display: block;
  position: relative;
  width: 275px;
  height: auto;
  aspect-ratio: 2.233 / 1;
  /* Two layers, each a pseudo-element, so they can be filtered independently:
     ::before = neon triangles (z:-1, behind)
     ::after  = crisp letters (z:1, in front) with a dark halo for readability
     Parent has NO background — prevents filter inheritance issues. */
  transition: width 0.55s var(--ease-out-expo);
}
.wordmark__mark::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background-image: url('../img/logo/md-letters.webp');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: left center;
  /* Dark halo keeps the parchment letters legible where they cross the
     bright neon edge of a triangle. */
  filter:
    drop-shadow(0 0 1px rgba(0, 0, 0, 0.9))
    drop-shadow(0 0 4px rgba(20, 6, 36, 0.65));
  pointer-events: none;
}
/* TRIANGLES layer — sits BEHIND the letters. Uses the SAME formula as the nav
   hover: light blur for the center-dense / edge-fading gradient look, plus a
   halo drop-shadow for the outer glow, at matching 55% effective opacity. */
/* Glass triangles — the triangles shape is used as a MASK, a translucent violet
   tint paints inside the mask, and a backdrop-filter blurs whatever nebula/stars
   are behind the triangle shapes. Crisp edges, see-through body. */
.wordmark__mark::before {
  content: '';
  position: absolute;
  /* Pre-baked neon triangles PNG (built by build-neon-triangles.mjs).
     The image has 160px of transparent padding around the shape in the
     original 1000×447 coordinate space, so we position ::before with
     matching negative insets (16% horizontal, 36% vertical) so the glow
     extends OUTSIDE the wordmark's bounds without clipping. */
  top: -36%;
  bottom: -36%;
  left: -16%;
  right: -16%;
  z-index: -1;
  background-image: url('../img/logo/md-triangles-neon.webp');
  background-size: 100% 100%;
  background-repeat: no-repeat;
  pointer-events: none;
  transition: opacity 0.35s var(--ease-out-expo),
              filter 0.45s var(--ease-out-expo);
}
.wordmark:hover .wordmark__mark::before,
.wordmark:focus-visible .wordmark__mark::before {
  /* Hover slightly intensifies the glow */
  filter: brightness(1.15) saturate(1.1);
}
/* Shrink into nav size once scrolled past the hero. 130w × 1/2.233 ≈ 58h in a 92px
   header → ~17px of vertical padding above and below. */
.site-header.is-scrolled .wordmark__mark { width: 156px; }

@media (max-width: 767px) {
  .wordmark__mark { width: 210px; }
  .site-header.is-scrolled .wordmark__mark { width: 128px; }
}
/* ---------- Mobile hamburger toggle ----------
   Hidden on desktop (≥900px). On mobile it replaces the inline nav; clicking
   it opens a full-screen drawer (see .site-nav.is-open below). 44×44 tap
   target meets WCAG AA. Three bars morph into an X when open. */
.nav-toggle {
  display: none;   /* desktop: hidden */
  position: relative;
  width: 44px;
  height: 44px;
  padding: 10px;
  background: transparent;
  border: 0;
  cursor: pointer;
  z-index: 110;   /* above drawer (100) so the close-X is always clickable */
}
.nav-toggle__bar {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--text-primary);
  border-radius: 2px;
  transform-origin: center;
  transition:
    transform 0.4s var(--ease-out-expo),
    opacity 0.25s var(--ease-out-expo),
    background 0.3s var(--ease-out-expo);
}
.nav-toggle__bar + .nav-toggle__bar { margin-top: 5px; }
/* When the drawer is open, morph the 3 bars into an X: top bar rotates 45°
   down, middle fades, bottom rotates -45° up. */
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* Nav — Option A: a small violet bloom expands out from under the word on hover,
   and the letter-spacing widens so the letters drift apart. Pure CSS, no JS. */
.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2rem);
  /* Nudged up so the nav sits visually near the top of the header
     while the wordmark stays vertically centred. Collapses on scroll. */
  transform: translateY(-28px);
  transition: transform 0.55s var(--ease-out-expo);
}
.site-header.is-scrolled .site-nav { transform: translateY(0); }
/* FR has a taller header (240 idle / 108 scrolled) so the flex-centered nav
   ends up lower than it does on MD pages. Nudge it back up to match the
   vertical position of the MD nav visually. */
body.femme-rising .site-nav { transform: translateY(-56px); }
body.femme-rising .site-header.is-scrolled .site-nav { transform: translateY(-8px); }
.site-nav a,
.header-link {
  position: relative;
  isolation: isolate;
  font-family: var(--mono);
  /* Accessibility: 0.82rem ≈ 13px, tightened letter-spacing so uppercase
     words read as word-units (not scattered letters). Wider tap target. */
  font-size: 0.82rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-primary);
  /* Baseline dark text-shadow ensures legibility over any background —
     bright nebula peak, visualizer wash, photo hero, etc. Strengthened
     further on hover. */
  text-shadow: 0 1px 3px rgba(10, 8, 32, 0.7), 0 0 8px rgba(10, 8, 32, 0.45);
  padding: 0.7rem 1rem;
  white-space: nowrap;
  transition:
    letter-spacing 0.55s var(--ease-out-expo),
    color 0.35s var(--ease-out-expo),
    text-shadow 0.35s var(--ease-out-expo);
}
/* Nav hover triangle — pre-baked neon PNG (280×248 with glow padding).
   Sized to match the FR page's moon hover-size (≈51px visible). */
.site-nav a::before,
.header-link::before {
  content: '';
  position: absolute;
  left: 50%; top: 55%;
  /* 36×32 base (aspect ~280:248 preserved) scales up to ~58 × 51 at hover.
     Moon is 32×32 scale(1.6) = 51 visible — we match that. */
  width: 36px; height: 32px;
  transform: translate(-50%, -50%) scale(0.5) rotate(-10deg);
  background-image: url('../img/logo/nav-tri-up-neon.webp');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  background-color: transparent;
  clip-path: none;
  opacity: 0;
  z-index: -1;
  pointer-events: none;
  transition:
    transform 0.7s var(--ease-out-expo),
    opacity 0.55s var(--ease-out-expo);
}
/* Triangles alternate direction across the nav, anchored per-link so each
   stays consistent across pages (doesn't flip when Home is added/removed).
   Pattern: Home ↓, Music ↑, Shows ↓, About ↑, Femme Rising (moon), Contact ↓.
   On the home page (no Home link): Music ↑, Shows ↓, About ↑, FR, Contact ↓
   — still alternates, and every link keeps its own direction. */
/* (Removed: about page white-fill triangle override. Nav triangles are
   transparent everywhere now for consistency. Legibility on bright hero
   backgrounds is handled via nav-link hover text-shadow + the pink halo
   glow on each triangle.) */
.site-nav a[href="/"]::before,
.site-nav a[href="../"]::before,
.site-nav a[href*="/shows/"]::before,
.site-nav a[data-modal-open="contact"]::before {
  background-image: url('../img/logo/nav-tri-down-neon.webp');
  transform: translate(-50%, -50%) scale(0.5) rotate(10deg);
}
.site-nav a[href="/"]:hover::before,
.site-nav a[href="../"]:hover::before,
.site-nav a[href="/"]:focus-visible::before,
.site-nav a[href="../"]:focus-visible::before,
.site-nav a[href*="/shows/"]:hover::before,
.site-nav a[href*="/shows/"]:focus-visible::before,
.site-nav a[data-modal-open="contact"]:hover::before,
.site-nav a[data-modal-open="contact"]:focus-visible::before {
  transform: translate(-50%, -50%) scale(2.0) rotate(0deg);
}

.site-nav a:hover,
.site-nav a:focus-visible,
.header-link:hover,
.header-link:focus-visible {
  letter-spacing: 0.3em;
  /* Stay parchment on hover (was blush — too low contrast against pink
     hover halos). Strong dark text-shadow guarantees the label stays
     readable against any background — including the bright pink moon
     glow on the FR link and bright nebula peaks. */
  color: var(--parchment);
  text-shadow:
    0 1px 4px rgba(10, 8, 32, 0.95),
    0 0 10px rgba(10, 8, 32, 0.65),
    0 0 20px rgba(10, 8, 32, 0.4);
}
.site-nav a:hover::before,
.site-nav a:focus-visible::before,
.header-link:hover::before,
.header-link:focus-visible::before,
.site-nav a:nth-child(even):hover::before,
.site-nav a:nth-child(even):focus-visible::before {
  opacity: 1;
  transform: translate(-50%, -50%) scale(2.0) rotate(0deg);
}

/* Active page indicator — persistent triangle at reduced intensity is the marker. */
.site-nav a[aria-current="page"] {
  color: var(--text-primary);
  letter-spacing: 0.24em;
}
.site-nav a[aria-current="page"]::before,
.site-nav a[aria-current="page"]:nth-child(even)::before {
  /* Same visual size as the hover state (scale 2.0) so the active-page
     indicator reads as "the bloom has settled here" — just at reduced
     opacity so it's distinguishable from an actively hovered link. */
  opacity: 0.55;
  transform: translate(-50%, -50%) scale(2.0) rotate(0deg);
}

/* ===== Femme Rising link EVERYWHERE: swap the triangle for a PINK moon.
   The fr-moon.webp source is white/grayscale; the sepia+saturate+hue-rotate
   filter chain shifts it to electric-pink so the moon reads pink on every
   page (was previously grayscale on non-FR pages). FR page has its own
   bigger persistent neon variant further down. ===== */
.site-nav a[href*="femme-rising"]::before {
  width: 36px; height: 36px;
  background: url('../img/logo/fr-moon.webp') center / contain no-repeat;
  clip-path: none;
  filter:
    sepia(1) saturate(8) hue-rotate(280deg) brightness(1)
    drop-shadow(0 0 8px rgba(236, 72, 153, 0.55))
    drop-shadow(0 0 20px rgba(236, 72, 153, 0.3));
  transform: translate(-50%, -50%) scale(0.5);
}
.site-nav a[href*="femme-rising"]:hover::before,
.site-nav a[href*="femme-rising"]:focus-visible::before {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1.6);
  filter:
    sepia(1) saturate(8) hue-rotate(280deg) brightness(1.1)
    drop-shadow(0 0 12px rgba(236, 72, 153, 0.85))
    drop-shadow(0 0 30px rgba(236, 72, 153, 0.45))
    drop-shadow(0 0 60px rgba(236, 72, 153, 0.22));
}

/* ===== FR page only: every nav link swaps the triangle for the moon motif.
   Idle state uses the SAME pink-neon filter as the hover state (just at
   opacity: 0) so the mouseleave fade-out doesn't visibly pass through a
   grayscale intermediate color — only the opacity and scale animate. ===== */
body.femme-rising .site-nav a::before,
body.femme-rising .header-link::before,
body.femme-rising .site-nav a:nth-child(even)::before {
  width: 32px; height: 32px;
  background: url('../img/logo/fr-moon.webp') center / contain no-repeat;
  clip-path: none;
  filter:
    sepia(1) saturate(7) hue-rotate(260deg) brightness(1.1)
    drop-shadow(0 0 12px rgba(240, 106, 255, 0.95))
    drop-shadow(0 0 30px rgba(225, 29, 116, 0.65))
    drop-shadow(0 0 60px rgba(169, 28, 143, 0.35));
  transform: translate(-50%, -50%) scale(0.5);
}
body.femme-rising .site-nav a:hover::before,
body.femme-rising .site-nav a:focus-visible::before,
body.femme-rising .header-link:hover::before,
body.femme-rising .header-link:focus-visible::before,
body.femme-rising .site-nav a:nth-child(even):hover::before,
body.femme-rising .site-nav a:nth-child(even):focus-visible::before {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1.6);
  /* Pink neon on hover — same sepia + hue-rotate treatment as the FR link */
  filter:
    sepia(1) saturate(7) hue-rotate(260deg) brightness(1.1)
    drop-shadow(0 0 12px rgba(240, 106, 255, 0.95))
    drop-shadow(0 0 30px rgba(225, 29, 116, 0.65))
    drop-shadow(0 0 60px rgba(169, 28, 143, 0.35));
}
body.femme-rising .site-nav a[aria-current="page"]::before,
body.femme-rising .site-nav a[aria-current="page"]:nth-child(even)::before {
  opacity: 0.55;
  transform: translate(-50%, -50%) scale(1.2);
}
/* On the FR page, non-FR nav links turn the brand pink on hover (instead of
   plain white) — a small moment that reinforces the magenta identity. The FR
   link itself stays white (handled in the :nth-child(4) overrides below). */
body.femme-rising .site-nav a:hover,
body.femme-rising .site-nav a:focus-visible,
body.femme-rising .header-link:hover,
body.femme-rising .header-link:focus-visible {
  /* Text stays white on hover (matches the FR link treatment). The pink neon
     moon behind does the color work. Dense dark outline keeps letters crisp. */
  color: #ffffff;
  text-shadow:
     1px  0 0 rgba(20, 6, 36, 1),
    -1px  0 0 rgba(20, 6, 36, 1),
     0  1px 0 rgba(20, 6, 36, 1),
     0 -1px 0 rgba(20, 6, 36, 1),
     1px  1px 2px rgba(20, 6, 36, 0.95),
    -1px -1px 2px rgba(20, 6, 36, 0.85),
     0 0 8px rgba(20, 6, 36, 0.9),
     0 0 18px rgba(240, 106, 255, 0.5),
     0 0 40px rgba(169, 28, 143, 0.3);
}

/* FR link on the FR page: bigger + persistent PINK NEON moon, always visible
   (not only on hover). Uses sepia + hue-rotate to tint the greyscale moon
   disc toward hot magenta, then stacks pink halo drop-shadows around it. */
body.femme-rising .site-nav a[href*="femme-rising"]::before {
  width: 56px; height: 56px;
  filter:
    sepia(1) saturate(6) hue-rotate(260deg) brightness(1)
    drop-shadow(0 0 14px rgba(240, 106, 255, 0.9))
    drop-shadow(0 0 34px rgba(225, 29, 116, 0.6))
    drop-shadow(0 0 70px rgba(169, 28, 143, 0.4));
  opacity: 0.9;
  transform: translate(-50%, -50%) scale(1);
}
body.femme-rising .site-nav a[href*="femme-rising"]:hover::before,
body.femme-rising .site-nav a[href*="femme-rising"]:focus-visible::before {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1.35);
  filter:
    sepia(1) saturate(7) hue-rotate(260deg) brightness(1.1)
    drop-shadow(0 0 18px rgba(240, 106, 255, 1))
    drop-shadow(0 0 42px rgba(225, 29, 116, 0.75))
    drop-shadow(0 0 90px rgba(169, 28, 143, 0.5));
}
body.femme-rising .site-nav a[href*="femme-rising"][aria-current="page"]::before {
  opacity: 0.95;
  transform: translate(-50%, -50%) scale(1.15);
  filter:
    sepia(1) saturate(6.5) hue-rotate(260deg) brightness(1.05)
    drop-shadow(0 0 16px rgba(240, 106, 255, 0.95))
    drop-shadow(0 0 38px rgba(225, 29, 116, 0.7))
    drop-shadow(0 0 80px rgba(169, 28, 143, 0.45));
}
body.femme-rising .site-nav a[aria-current="page"] { color: var(--nebula-pink); }

/* The "Femme Rising" link (4th) gets a persistent soft pink glow on its text
   so it stays legible and feels like it's emanating the same magenta light
   as the moon behind it — regardless of page. The glow intensifies on hover. */
.site-nav a[href*="femme-rising"] {
  text-shadow:
    0 0 10px rgba(240, 106, 255, 0.55),
    0 0 22px rgba(225, 29, 116, 0.38);
  transition:
    letter-spacing 0.55s var(--ease-out-expo),
    color 0.35s var(--ease-out-expo),
    text-shadow 0.4s var(--ease-out-expo);
}
.site-nav a[href*="femme-rising"]:hover,
.site-nav a[href*="femme-rising"]:focus-visible {
  text-shadow:
    0 0 14px rgba(240, 106, 255, 0.9),
    0 0 32px rgba(225, 29, 116, 0.55),
    0 0 60px rgba(169, 28, 143, 0.35);
}
body.femme-rising .site-nav a[href*="femme-rising"],
body.femme-rising .site-nav a[href*="femme-rising"]:hover,
body.femme-rising .site-nav a[href*="femme-rising"]:focus-visible,
body.femme-rising .site-nav a[href*="femme-rising"][aria-current="page"] {
  /* FR link text is ALWAYS white on the FR page (not pink) — the pink neon
     moon behind it does the color work. A dense dark outline keeps the
     letters crisp against the bright moon disc. */
  color: #ffffff;
}
body.femme-rising .site-nav a[href*="femme-rising"] {
  text-shadow:
     1px  0 0 rgba(20, 6, 36, 1),
    -1px  0 0 rgba(20, 6, 36, 1),
     0  1px 0 rgba(20, 6, 36, 1),
     0 -1px 0 rgba(20, 6, 36, 1),
     1px  1px 2px rgba(20, 6, 36, 0.95),
    -1px -1px 2px rgba(20, 6, 36, 0.85),
     0 0 8px rgba(20, 6, 36, 0.9),
     0 0 18px rgba(240, 106, 255, 0.5),
     0 0 40px rgba(169, 28, 143, 0.3);
}
body.femme-rising .site-nav a[href*="femme-rising"]:hover,
body.femme-rising .site-nav a[href*="femme-rising"]:focus-visible {
  text-shadow:
     1px  0 0 rgba(20, 6, 36, 1),
    -1px  0 0 rgba(20, 6, 36, 1),
     0  1px 0 rgba(20, 6, 36, 1),
     0 -1px 0 rgba(20, 6, 36, 1),
     1px  1px 2px rgba(20, 6, 36, 0.95),
    -1px -1px 2px rgba(20, 6, 36, 0.85),
     0 0 10px rgba(20, 6, 36, 0.9),
     0 0 22px rgba(240, 106, 255, 0.9),
     0 0 48px rgba(169, 28, 143, 0.5);
}

/* ---------- Section 1: Hero ---------- */
.hero {
  position: relative;
  height: 100vh;
  /* dvh = dynamic viewport height, accounts for mobile browser chrome so the
     hero doesn't get clipped when the URL bar shows/hides. Supported in
     Safari 15.4+ / Chrome 108+; falls back to 100vh otherwise. */
  height: 100dvh;
  min-height: 640px;
  padding: 0;
  overflow: hidden;
}
.hero__media {
  position: absolute; inset: 0;
  z-index: 0;
}
/* <picture> is the parent of <img> — must be stretched so the img can fill hero */
.hero__media picture {
  display: block;
  width: 100%;
  height: 100%;
}
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* Shows face + chest/hands. Raise this % to reveal more body (lower crop),
     lower to pull the crop up toward the top of the image. */
  object-position: center 40%;
  /* Alpha mask that fades the image into the starfield over the lower 75% of hero.
     Starts the fade very early so there's no perceivable line. */
  --hero-fade-mask:
    linear-gradient(
      to bottom,
      #000 0%,
      #000 55%,
      rgba(0,0,0,0.7)  70%,
      rgba(0,0,0,0.45) 82%,
      rgba(0,0,0,0.2)  92%,
      transparent 100%
    );
  mask-image: var(--hero-fade-mask);
  -webkit-mask-image: var(--hero-fade-mask);
}
.hero__overlay {
  position: absolute; inset: 0;
  /* Soft colour wash only — NO blue blob at bottom, no fade-to-dark, nothing that
     would create a visible horizontal edge at the hero boundary. */
  background:
    radial-gradient(ellipse at 70% 20%, rgba(236, 72, 153, 0.16), transparent 55%),
    radial-gradient(ellipse at 25% 30%, rgba(1, 25, 70, 0.25), transparent 60%);
  z-index: 1;
}
.hero__cta {
  position: absolute;
  bottom: clamp(2.5rem, 6vh, 5rem);
  left: var(--gutter);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--text-primary);
  padding: 0.85rem 1.35rem 0.85rem 0;
}
.hero__cta::before {
  content: '';
  width: 42px; height: 1px;
  background: var(--electric-violet);
  transition: width var(--dur-micro) var(--ease-out-expo);
}
.hero__cta:hover::before { width: 72px; }
.hero__cta-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--electric-violet);
  margin-left: 0.25rem;
  box-shadow: 0 0 12px var(--electric-violet);
}
/* Scroll cue — triangle (points down) echoing the M/D wedges of the wordmark.
   Outer outline + inner filled triangle that pulses softly. Fades on scroll. */
.scroll-cue {
  position: fixed;
  bottom: clamp(1.25rem, 3vh, 2.25rem);
  right: clamp(1.25rem, 3vw, 2.25rem);
  width: 36px;
  height: 36px;
  /* Triangle stroke + fill are parchment (white-ish); halo is pink only. */
  color: var(--parchment);
  z-index: 60;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.45s var(--ease-out-expo), transform 0.45s var(--ease-out-expo);
  filter:
    drop-shadow(0 0 8px rgba(236, 72, 153, 0.65))
    drop-shadow(0 0 22px rgba(236, 72, 153, 0.35));
}
.scroll-cue svg { width: 100%; height: 100%; display: block; overflow: visible; }
.scroll-cue__outer {
  transform-origin: 16px 20px;
  animation: scroll-cue-breathe 3.4s ease-in-out infinite;
}
.scroll-cue__inner {
  transform-origin: 16px 20px;
  animation: scroll-cue-drip 2.6s cubic-bezier(0.55, 0, 0.35, 1) infinite;
}
@keyframes scroll-cue-drip {
  0%   { transform: translateY(-3px); opacity: 0; }
  25%  { opacity: 0.95; }
  70%  { transform: translateY(6px);  opacity: 0; }
  100% { transform: translateY(6px);  opacity: 0; }
}
@keyframes scroll-cue-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}
.scroll-cue:hover {
  /* keep the parchment color; glow intensifies, flip handled on the SVG above */
  filter:
    drop-shadow(0 0 14px rgba(236, 72, 153, 0.85))
    drop-shadow(0 0 38px rgba(236, 72, 153, 0.5));
}
.scroll-cue.is-hidden {
  opacity: 0;
  transform: translateY(14px);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .scroll-cue__outer, .scroll-cue__inner { animation: none; }
}
/* FR palette — pink neon glow instead of violet */
body.femme-rising .scroll-cue {
  filter:
    drop-shadow(0 0 10px rgba(240, 106, 255, 0.65))
    drop-shadow(0 0 26px rgba(225, 29, 116, 0.35));
}
body.femme-rising .scroll-cue:hover {
  filter:
    drop-shadow(0 0 14px rgba(240, 106, 255, 0.95))
    drop-shadow(0 0 38px rgba(225, 29, 116, 0.55));
}

/* ---------- Home hero — Skinny visualizer, full viewport ----------
   The video sits absolutely in the hero section. Ambient parallax: the video
   uses transform: translateZ(0) and a slight scale that we shift as the user
   scrolls (handled by ui.js via CSS custom property --hero-scroll). Content
   above the video fades + lifts as user scrolls. */
.home-hero {
  position: relative;
  isolation: isolate;
  height: 100vh;
  height: 100dvh;
  min-height: 640px;
  width: 100%;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 var(--gutter) clamp(4rem, 10vh, 7rem);
  /* JS sets this to a 0→1 value as the user scrolls through the hero */
  --hero-scroll: 0;
  /* Deep-stage backdrop ensures the brief moment before the video paints
     its first frame is dark, not white/flash. */
  background-color: var(--deep-stage);
}
.home-hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 0;
  /* Scale-only parallax. Earlier rev added translateY but that slid the
     video upward inside overflow:hidden, exposing a growing dark gap at
     the bottom of the hero as the user scrolled. Scale alone keeps the
     video fully covering the section while still feeling alive. */
  transform: scale(calc(1.02 + 0.06 * var(--hero-scroll)));
  transition: transform 0.1s linear;
  filter: brightness(calc(0.82 - 0.18 * var(--hero-scroll)))
          contrast(1.04);
  will-change: transform, filter;
  /* Background = deep-stage so any sub-pixel gap during scale interpolation
     paints dark, never the page bg through. */
  background-color: var(--deep-stage);
}
@media (prefers-reduced-motion: reduce) {
  .home-hero__video {
    transform: scale(1.04);
    filter: brightness(0.82) contrast(1.04);
  }
}
.home-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(ellipse at 70% 30%, rgba(236, 72, 153, 0.18), transparent 60%),
    radial-gradient(ellipse at 20% 75%, rgba(30, 58, 138, 0.30), transparent 60%),
    linear-gradient(to bottom, rgba(10, 8, 32, 0.35) 0%, rgba(10, 8, 32, 0.05) 40%, rgba(10, 8, 32, 0.65) 100%);
  opacity: calc(0.9 + 0.1 * var(--hero-scroll));
  transition: opacity 0.1s linear;
}
.home-hero__content {
  position: relative;
  z-index: 2;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  color: var(--text-primary);
  text-shadow: 0 2px 24px rgba(10, 8, 32, 0.9), 0 0 12px rgba(10, 8, 32, 0.6);
  /* Drift up + fade out as user scrolls into the next section */
  transform: translateY(calc(var(--hero-scroll) * -36px));
  opacity: calc(1 - var(--hero-scroll));
  transition: transform 0.1s linear, opacity 0.1s linear;
  will-change: transform, opacity;
}
.home-hero__eyebrow {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--blush);
  margin: 0;
}
.home-hero__title {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(4rem, 12vw, 9rem);
  letter-spacing: -0.025em;
  line-height: 0.92;
  margin: 0;
  color: var(--text-primary);
}
.home-hero__sub {
  font-family: var(--display-alt, 'Fraunces', Georgia, serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1rem, 1.6vw, 1.25rem);
  letter-spacing: 0.04em;
  margin: 0;
  opacity: 0.85;
}

/* ===== Centered hero stack — wordmark + bigger scroll-cue =====
   Per Melissa's feedback: visitors weren't sure how to enter the site.
   Putting the wordmark in the visualizer's center + the scroll triangle
   directly below it (larger) gives an obvious "this is the page, click
   here to scroll in" affordance. Both fade out together as the user
   scrolls into the Skinny section. */
.home-hero__center {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Shifted further down the hero so the logo + subtext + cue stack
     hovers in the lower-middle of the visualizer rather than near top. */
  justify-content: flex-start;
  padding-top: clamp(34vh, 38vh, 42vh);
  /* Negative gap pulls subtext + cue right under the logo since the
     baked PNG carries ~20% transparent padding around the wordmark. */
  gap: 0;
  pointer-events: none;
  /* Inherit the hero scroll fade — same as .home-hero__content. */
  transform: translateY(calc(var(--hero-scroll) * -36px));
  opacity: calc(1 - var(--hero-scroll));
  transition: transform 0.1s linear, opacity 0.1s linear;
  will-change: transform, opacity;
}
.home-hero__intro {
  font-family: var(--display-alt, 'Fraunces', Georgia, serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(0.95rem, 1.4vw, 1.2rem);
  letter-spacing: 0.04em;
  color: var(--blush);
  /* Pull subtext UP into the logo's transparent bottom padding so it
     reads as part of the wordmark stack, not separated from it. */
  margin: clamp(-3.5rem, -4vh, -2rem) 0 clamp(0.75rem, 1.5vh, 1.5rem);
  text-align: center;
  text-shadow:
    0 2px 12px rgba(10, 8, 32, 0.95),
    0 0 18px rgba(10, 8, 32, 0.6);
  pointer-events: auto;
}
/* Single pre-baked PNG combining the parchment letters + pink neon
   triangles. Same logo that appears in the nav, scaled big on the hero. */
.home-hero__logo-img {
  display: block;
  width: clamp(320px, 42vw, 640px);
  height: auto;
  pointer-events: auto;
  user-select: none;
}
@media (max-width: 700px) {
  .home-hero__logo-img { width: 80vw; }
}
/* Same two-layer composition as the header wordmark: ::after carries
   the parchment letters, ::before paints the neon-pink triangles. */
.home-hero__logo-mark {
  position: absolute;
  inset: 0;
  display: block;
}
.home-hero__logo-mark::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background-image: url('../img/logo/md-letters.webp');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  filter:
    drop-shadow(0 0 1px rgba(0, 0, 0, 0.95))
    drop-shadow(0 0 6px rgba(20, 6, 36, 0.7));
  pointer-events: none;
}
.home-hero__logo-mark::before {
  content: '';
  position: absolute;
  top: -36%;
  bottom: -36%;
  left: -16%;
  right: -16%;
  z-index: 0;
  background-image: url('../img/logo/md-triangles-neon.webp');
  background-size: 100% 100%;
  background-repeat: no-repeat;
  pointer-events: none;
}

/* Hero scroll-cue variant — bigger + sits in the centered stack
   instead of fixed in the corner. Negative margin pulls it UP into the
   logo's transparent bottom padding so it tucks directly under the
   wordmark instead of floating below it. */
.scroll-cue--hero {
  position: relative;
  bottom: auto; right: auto;
  width: clamp(48px, 5.5vw, 72px);
  height: clamp(48px, 5.5vw, 72px);
  margin-top: clamp(-5rem, -6vh, -3rem);
  pointer-events: auto;
  color: var(--blush, #fce7f3);
  filter:
    drop-shadow(0 0 8px rgba(236, 72, 153, 0.75))
    drop-shadow(0 0 24px rgba(236, 72, 153, 0.45));
  animation: scroll-cue-bob 2.2s ease-in-out infinite;
}
.scroll-cue--hero svg { width: 100%; height: 100%; }
.scroll-cue--hero:hover {
  filter:
    drop-shadow(0 0 12px rgba(236, 72, 153, 0.9))
    drop-shadow(0 0 36px rgba(236, 72, 153, 0.6));
}
@keyframes scroll-cue-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(8px); }
}
@media (prefers-reduced-motion: reduce) {
  .scroll-cue--hero { animation: none; }
}
@media (max-width: 700px) {
  .home-hero__center { gap: 2rem; }
  .home-hero__logo { width: 72vw; }
}
/* (Home scroll cue now uses the default fixed bottom-right .scroll-cue
   placement — no per-page override.) */

/* ---------- Skinny feature ----------
   Full-viewport release moment — cover art on the left, release info on the
   right. The section claims an entire viewport so it reads as the "album
   page" beat between the visualizer hero and the photo reel. */
.skinny-feature {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding: clamp(3rem, 8vh, 6rem) var(--gutter);
  background:
    radial-gradient(ellipse at 80% 15%, rgba(236, 72, 153, 0.12), transparent 55%),
    radial-gradient(ellipse at 15% 80%, rgba(30, 58, 138, 0.20), transparent 60%),
    var(--deep-stage);
  z-index: 3;
  /* overflow: visible so the first reel photo (margin-up below) can peek
     above the feature's bottom edge as a scroll hint. */
  overflow: visible;
}
.skinny-feature__inner {
  /* Bumped from 1180px so the body column has room to hold all 4
     stream chips on one line at desktop (Soundcloud was wrapping). */
  max-width: 1320px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.2fr);
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
}
.skinny-feature__cover {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  max-width: 480px;
  justify-self: center;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid rgba(236, 72, 153, 0.4);
  box-shadow:
    0 40px 80px rgba(0, 0, 0, 0.55),
    0 0 40px rgba(236, 72, 153, 0.32),
    0 0 100px rgba(236, 72, 153, 0.18);
  /* Slight scroll-driven lift — picks up the parallax from the hero */
  transform: translateY(calc(var(--feature-scroll, 0) * -22px));
  transition: transform 0.1s linear;
}
.skinny-feature__cover img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
.skinny-feature__body {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.skinny-feature__title {
  font-family: var(--display);
  font-weight: 500;
  /* Display-size — matches the scale that used to live on the visualizer
     hero. Big enough to anchor the section as a "release page" moment. */
  font-size: clamp(4.5rem, 12vw, 9rem);
  letter-spacing: -0.025em;
  line-height: 0.9;
  margin: 0;
  color: var(--text-primary);
}
.skinny-feature__lead {
  max-width: 56ch;
  color: var(--text-body);
  font-weight: 300;
}
.skinny-feature__meta {
  margin: 0.5rem 0 0.25rem;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.6rem;
  border-top: 1px solid rgba(236, 72, 153, 0.18);
  border-bottom: 1px solid rgba(236, 72, 153, 0.18);
  padding: 1rem 0;
}
.skinny-feature__meta > div {
  display: grid;
  grid-template-columns: 9rem 1fr;
  gap: 0.75rem;
  align-items: baseline;
}
.skinny-feature__meta dt {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--blush);
  margin: 0;
}
.skinny-feature__meta dd {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: 1rem;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}
.skinny-feature__cta-row {
  display: flex;
  flex-wrap: nowrap;
  gap: 0.65rem;
  margin-top: 0.5rem;
}
.skinny-feature__cta-row .btn { white-space: nowrap; }
@media (max-width: 860px) {
  .skinny-feature__cta-row { flex-wrap: wrap; }
}
/* Grid variant — Showcase Tickets spans full width on top, Pre-save +
   Buy split 50/50 below. Showcase is the primary action so it gets the
   full row. */
.skinny-feature__cta-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.65rem;
  margin-top: 0.5rem;
}
.skinny-feature__cta--wide { grid-column: 1 / -1; }
.skinny-feature__cta-grid .btn {
  width: 100%;
  text-align: center;
  white-space: nowrap;
}
@media (max-width: 500px) {
  .skinny-feature__cta-grid { grid-template-columns: 1fr; }
  .skinny-feature__cta--wide { grid-column: 1; }
}
.skinny-feature__stream {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.75rem;
}
.skinny-feature__stream-label {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--blush);
}
.skinny-feature__stream-row {
  display: flex;
  flex-wrap: wrap;
  /* Tighter gap so all 4 chips fit on one line at desktop widths. */
  gap: 0.5rem;
  align-items: center;
  justify-content: flex-start;
}
.skinny-feature__stream-row .btn-chip {
  /* Size by content so each chip just fits its text + SOON tag, with
     consistent padding. No more flex:1 1 0 — that was squashing the
     wider chips ("Apple Music") so the SOON tag bled into neighbors. */
  flex: 0 0 auto;
  white-space: nowrap;
  padding: 0.55rem 0.85rem;
  font-size: 0.66rem;
  letter-spacing: 0.2em;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.skinny-feature__stream-row .btn-chip .chip-tag {
  /* Tag sits cleanly inside the chip with its own padding + border. */
  margin-left: 0;
  padding: 0.12rem 0.4rem;
  font-size: 0.52rem;
  letter-spacing: 0.16em;
}
@media (max-width: 860px) {
  .skinny-feature__inner { grid-template-columns: 1fr; }
  .skinny-feature__cover { max-width: 360px; }
  .skinny-feature__meta > div { grid-template-columns: 7rem 1fr; }
}

/* ---------- Reveal entrance animations ----------
   `data-reveal="cover"` for the album cover (scale + lift + fade).
   `data-reveal="up"`    for stacked text/meta/CTA blocks (lift + fade,
   staggered via inline `--reveal-delay` custom property).
   ui.js IntersectionObserver toggles `.is-revealed` on the parent section,
   which cascades to all data-reveal descendants. */
[data-reveal] {
  opacity: 0;
  transition:
    opacity 0.8s var(--ease-out-expo),
    transform 0.9s var(--ease-out-expo);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
[data-reveal="cover"] {
  transform: translateY(36px) scale(0.94);
}
[data-reveal="up"] {
  transform: translateY(28px);
}
.is-revealed [data-reveal] { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---------- Skinny photo reel — 3D tilt, near-full-bleed -------------------
   Photos are SHOWN BIG — width: 92vw — and their height is whatever the
   image's natural aspect demands. For portrait photos that means each card
   is taller than the viewport, so the user scrolls through it; the 3D tilt
   animates continuously across that scroll range. No cropping, no shrinking. */
/* ===== skinny-reel — Option F: continuous auto-drift marquee =====
   Replaces the prior vertical-stacked 3D tilt cards. The 3 promo
   photos drift left forever in a seamless loop (the set is duplicated
   in markup so translateX(-50%) wraps without a seam). Soft mask
   fades the edges into the page. Hover any photo to pause the entire
   marquee + scale that photo up + ignite a pink neon glow matched
   to the FR Past Nights gallery (.acc-item:hover) so the hover
   treatment reads consistent across pages.
   ================================================================= */
.skinny-reel {
  position: relative;
  z-index: 2;
  background: transparent;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  /* Was `overflow: hidden` — now horizontally scrollable so the user can
     pan through the photos themselves (touch swipe / wheel / drag). The
     JS-driven auto-scroll in ui.js pauses on user interaction and resumes
     after idle, so the reel still drifts on its own when untouched. */
  overflow-x: auto;
  overflow-y: hidden;
  /* Hide the scrollbar UI — interaction is via touch/wheel/drag, no chrome. */
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* Soft edge fade so the moving strip dissolves into the nebula
     rather than cutting hard against the viewport edge. */
  mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  /* Full-page experience — section takes a full viewport height with
     photos sized to feel like an immersive gallery walkway, not a small
     strip below the Skinny info. */
  height: 100vh;
  min-height: 720px;
  display: flex;
  align-items: center;
  padding: 0;
  /* Pulled up so the reel meets the bottom of the Skinny feature with
     less dead space — felt too vertically spread before. */
  margin-top: clamp(-4rem, -6vh, -2rem);
}
.skinny-reel__track {
  display: flex;
  gap: 2rem;
  width: max-content;
  /* Auto-scroll handled by JS (ui.js setupMarquee) instead of a CSS
     transform animation — that's what allows the user to also scroll
     manually. The track is duplicated in the HTML so JS can wrap
     scrollLeft at half scrollWidth for a seamless loop. */
}
/* Hide the WebKit/Chromium scrollbar for the marquee (we still want it
   functionally scrollable, just no visible scrollbar). */
.skinny-reel::-webkit-scrollbar { display: none; }
.skinny-reel__shot {
  flex: 0 0 auto;
  /* Photos now scale to ~70vh so they dominate the section like a
     proper gallery experience. Width follows from the 3:4 portrait
     aspect. */
  height: clamp(420px, 70vh, 760px);
  aspect-ratio: 3 / 4;
  width: auto;
  object-fit: cover;
  object-position: center 20%;
  border-radius: 4px;
  display: block;
  box-shadow:
    0 30px 70px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(252, 231, 243, 0.06);
  transition:
    transform 0.5s cubic-bezier(.16, 1, .3, 1),
    box-shadow 0.5s cubic-bezier(.16, 1, .3, 1),
    border-color 0.5s cubic-bezier(.16, 1, .3, 1);
  border: 1px solid transparent;
}
.skinny-reel__shot:hover {
  transform: scale(1.04);
  z-index: 2;
  /* Same exact glow as .acc-item:hover on the FR gallery for
     cross-page cohesion (main.css line ~2090). */
  border-color: rgba(236, 72, 153, 0.6);
  box-shadow:
    0 0 30px rgba(236, 72, 153, 0.4),
    0 0 70px rgba(236, 72, 153, 0.2);
}
@keyframes skinny-reel-drift {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-50% - 0.75rem)); }
}
@media (prefers-reduced-motion: reduce) {
  .skinny-reel__track { animation: none; }
}
@media (max-width: 700px) {
  .skinny-reel__shot { width: clamp(220px, 64vw, 320px); }
  .skinny-reel__track { animation-duration: 22s; }
}

/* Standalone footer (home page only, post-reel) — sits over the cosmos.
   site-footer--home base styles already make the inner composition; this
   modifier just removes any flex-shrink from when it lived inside .gallery
   and lets the nebula bleed through underneath. */
.site-footer--standalone {
  position: relative;
  z-index: 2;
  /* Semi-transparent throughout so the nebula + starfield bleed through
     under the footer instead of getting masked by a solid deep-stage. */
  background:
    radial-gradient(ellipse at 90% 0%, rgba(236, 72, 153, 0.08), transparent 55%),
    linear-gradient(to bottom, rgba(10, 8, 32, 0.55) 0%, rgba(10, 8, 32, 0.35) 100%);
}

/* ---------- Section 2: Gallery — accordion (hover to expand) ---------- */
.gallery {
  position: relative;
  height: 100vh;
  min-height: 720px;
  padding: clamp(4rem, 8vh, 6rem) 0 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 3rem;
}
/* Editorial section head for the home gallery — "From the shoot" eyebrow +
   "Skinny — in frame" display heading. Tracks with the rest of the page. */
.gallery__head {
  padding: 0 var(--gutter);
  max-width: 1280px;
  margin: 0 auto;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.gallery__title { margin: 0; }
.gallery__accordion {
  flex: 1 1 auto;
  display: flex;
  gap: 10px;
  padding: 0 var(--gutter);
  min-height: 0;
}
.acc-item {
  flex: 1;
  min-width: 0;
  height: 100%;
  background-size: cover;
  background-position: center;
  border-radius: 2px;
  border: 1px solid rgba(236, 72, 153, 0.22);
  filter: saturate(0.8) brightness(0.72);
  cursor: pointer;
  transition:
    flex 0.85s var(--ease-out-expo),
    filter 0.6s var(--ease-out-expo),
    border-color 0.6s var(--ease-out-expo),
    box-shadow 0.6s var(--ease-out-expo);
}
.acc-item:hover,
.acc-item:focus-visible {
  flex: 5;
  filter: saturate(1) brightness(1);
  border-color: rgba(236, 72, 153, 0.6);
  box-shadow:
    0 0 30px rgba(236, 72, 153, 0.4),
    0 0 70px rgba(236, 72, 153, 0.2);
  outline: none;
}
@media (max-width: 767px) {
  .gallery { height: auto; min-height: 0; padding: calc(var(--header-h) + 2rem) 0 2rem; }
  .gallery__accordion { flex-direction: column; height: auto; gap: 1rem; padding: 0 var(--gutter); }
  .acc-item { flex: 0 0 auto; aspect-ratio: 4/5; filter: saturate(1) brightness(1); }
  .acc-item:hover { flex: 0 0 auto; box-shadow: none; }
}

/* ---------- Section 3: Music ---------- */
.music {
  /* bg intentionally transparent — nebula + starfield show through */
}
.music__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
.music__art {
  position: relative;
  aspect-ratio: 1/1;
  width: 100%;
  max-width: 520px;
  justify-self: end;
  background:
    radial-gradient(ellipse at 30% 30%, rgba(236, 72, 153, 0.5), transparent 60%),
    radial-gradient(ellipse at 70% 70%, rgba(1, 25, 70, 0.8), transparent 55%),
    linear-gradient(135deg, var(--stage-blue), var(--violet-dark));
  display: flex;
  align-items: flex-end;
  padding: 2.5rem;
  border: 1px solid rgba(236, 72, 153, 0.2);
  box-shadow: 0 20px 60px -20px rgba(0,0,0,0.7),
              0 0 40px -10px rgba(236, 72, 153, 0.3);
}
.music__art::after {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(circle at 80% 20%, rgba(212,184,196,0.15), transparent 40%);
}
.music__art-title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.5rem, 5vw, 4rem);
  color: var(--text-primary);
  letter-spacing: -0.02em;
  position: relative;
  z-index: 1;
  line-height: 1;
}
.music__body {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  max-width: 520px;
}
.music__title {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(2.5rem, 5vw, 4rem);
  line-height: 1;
  color: var(--text-primary);
  margin: 0;
  letter-spacing: -0.01em;
}
.music__cta-row {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}
/* Stream-on row — small label + chip buttons for each service */
.music__stream {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  margin-top: 0.5rem;
}
.music__stream-label {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.music__stream-row {
  display: flex;
  flex-wrap: nowrap;   /* keep all platform chips on one line */
  gap: 0.4rem;
  overflow-x: auto;
  scrollbar-width: none;
}
.music__stream-row::-webkit-scrollbar { display: none; }
.music__stream-row .btn-chip {
  padding: 0.5rem 0.75rem;
  font-size: 0.56rem;
  letter-spacing: 0.18em;
  white-space: nowrap;
  flex: 0 0 auto;
}
@media (max-width: 600px) {
  /* On narrow phones, allow wrap — forcing 4 chips on one line gets too squeezed */
  .music__stream-row { flex-wrap: wrap; overflow-x: visible; }
}

/* ---------- About page — editorial magazine feature -----------------------
   Mix of pinned cinematic moments + reading flow sections + a pinned
   italic quote pause + a pinned FR trailer close. Each section has its
   own scroll-driven --p (0 → 1) that drives reveals + parallax. */

/* Wrapper — strip the bio-page header-clearance padding so the pinned
   hero starts flush at the top of the viewport. */
.about-magazine {
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  position: relative;
  z-index: 1;
  /* Transparent fallback so the fixed nebula + starfield canvases bleed
     through reading sections (where there's no opaque media in front).
     Pinned sections still cover with their own video/photo. */
  background:
    radial-gradient(ellipse at 20% 15%, rgba(236, 72, 153, 0.06), transparent 55%),
    radial-gradient(ellipse at 80% 60%, rgba(30, 58, 138, 0.08), transparent 55%);
}

/* ===== text-fill-on-scroll effect ============================================
   Inspired by the GSAP scrollytelling pattern: text starts in a muted
   parchment colour, and as the user scrolls a gradient sweeps across it
   filling the letters with full parchment. Tied to the parent section's
   --p (0 → 1) so it scrubs with real scroll position. No GSAP needed. */
/* Text-fill v2: starts with text readable-but-muted (so the layout never
   feels empty), and as you scroll a sharp-edged gradient sweeps left→
   right across each letter and the bright parchment "writes in" behind
   the muted base. Slower mapping so the sweep is visible across the
   whole scroll, not done by mid-section. */
.text-fill {
  /* Base — readable-but-muted parchment. Higher than v1 (0.32 → 0.55)
     so the text is clearly present at rest, not "appearing from nothing." */
  background-color: rgba(240, 236, 228, 0.55);
  /* Gradient: sharp edge between bright parchment fill and muted base.
     Transition span tightened from 12% to 3% so the sweeping edge is
     visible as a clean writing line, not a smooth blur. */
  background-image: linear-gradient(105deg,
    var(--parchment) 0%,
    var(--parchment) 48%,
    rgba(240, 236, 228, 0.55) 51%,
    rgba(240, 236, 228, 0.55) 100%);
  /* Slower sweep — at p=0 size is 0% (fully muted); at p=1 size is 220%
     (well past the right edge, fully filled). The fill completes at the
     END of the scroll instead of mid-way. */
  background-size: calc(var(--p, 0) * 220%) 100%;
  background-position: 0 0;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent !important;
  filter:
    drop-shadow(0 2px 6px rgba(10, 8, 32, 0.95))
    drop-shadow(0 0 18px rgba(10, 8, 32, 0.85))
    drop-shadow(0 0 36px rgba(10, 8, 32, 0.55));
}
.text-fill em {
  background-color: rgba(244, 168, 200, 0.55);
  background-image: linear-gradient(105deg,
    var(--blush) 0%,
    var(--blush) 48%,
    rgba(244, 168, 200, 0.55) 51%,
    rgba(244, 168, 200, 0.55) 100%);
  background-size: calc(var(--p, 0) * 220%) 100%;
  background-position: 0 0;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent !important;
}
/* Paragraph variant — same sweep DNA, finer drop-shadow, body color
   instead of pure parchment. */
p.text-fill {
  background-color: rgba(212, 207, 224, 0.55);
  background-image: linear-gradient(105deg,
    var(--text-body) 0%,
    var(--text-body) 48%,
    rgba(212, 207, 224, 0.55) 51%,
    rgba(212, 207, 224, 0.55) 100%);
  filter:
    drop-shadow(0 1px 4px rgba(10, 8, 32, 0.95))
    drop-shadow(0 0 12px rgba(10, 8, 32, 0.8))
    drop-shadow(0 0 28px rgba(10, 8, 32, 0.5));
}
/* Stagger consecutive paragraphs so the second starts filling after the
   first — gives the reading rhythm a "line by line" feel. */
p.text-fill + p.text-fill {
  background-size: calc(var(--p, 0) * 220% - 30%) 100%;
}
@media (prefers-reduced-motion: reduce) {
  .text-fill, .text-fill em, p.text-fill, p.text-fill + p.text-fill { background-size: 220% 100%; }
}

/* 1 — Hero portrait. Natural 1-viewport flow (was 200vh pinned). */
.hero-pin {
  position: relative;
  height: 100vh;
  --p: 0;
  overflow: hidden;
  background-color: var(--deep-stage);
}
.hero-pin__sticky {
  position: relative;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background-color: var(--deep-stage);
}
.hero-pin__media {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center 25%;  /* bias upward so heads aren't cropped */
  background-color: var(--indigo-deep);
  transform: scale(calc(1.02 + 0.06 * var(--p, 0)));
  transition: transform 0.1s linear;
}
.hero-pin__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(10, 8, 32, 0.92) 0%, rgba(10, 8, 32, 0.15) 45%, transparent 70%);
}
.hero-pin__content {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: clamp(3rem, 9vh, 7rem) clamp(2rem, 7vw, 5rem);
  max-width: 880px;
}
.hero-pin__eyebrow {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--blush);
  text-shadow:
    0 0 6px rgba(249, 168, 212, 0.95),
    0 0 18px rgba(249, 168, 212, 0.75),
    0 0 36px rgba(236, 72, 153, 0.55);
  margin-bottom: 1rem;
  display: inline-block;
}
.hero-pin__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(3rem, 7vw, 5.5rem);
  line-height: 0.95;
  letter-spacing: -0.015em;
  margin: 0 0 1rem;
  color: #fff;
}
.hero-pin__title em { font-family: var(--display-alt, 'Fraunces', serif); font-style: italic; color: var(--electric-pink); font-weight: 300; text-shadow: 0 0 14px rgba(236, 72, 153, 0.7), 0 0 36px rgba(236, 72, 153, 0.45); }

/* 3-row left-aligned title variant (about page hero). */
.hero-pin__title--rows {
  line-height: 0.95;
  text-align: left;
}
.hero-pin__title--rows > span {
  display: block;
}
.hero-pin__lead {
  font-size: 1.15rem;
  line-height: 1.65;
  color: #fff;
  max-width: 56ch;
  font-weight: 300;
  margin: 0;
}

/* 2 — Reading flow: text + sticky parallax image OR video */
.reading {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: clamp(3rem, 7vw, 6rem);
  padding: clamp(7rem, 14vh, 11rem) clamp(2rem, 7vw, 5rem);
  align-items: center;
  max-width: 1320px;
  margin: 0 auto;
  position: relative;
}
.reading--reverse > :first-child { order: 2; }
/* About page: "The voice" copy column matches the hero photo height exactly.
   The frame's base 78vh was taller than the actual tilted photo (which is
   height:auto, max-height:70vh, aspect 4/5) — so the glass stretched past the
   image and looked over-stretched. Letting the frame size to the real photo
   makes it the row-height driver, and the glass stretches to match it. */
.page-about .reading { align-items: stretch; }
.page-about .reading__image-frame { height: auto; }
.page-about .reading__copy { justify-content: center; }
/* Inline pull-quote variant — sits in the image column of the reading
   grid instead of a photo. Big italic Fraunces, centered, with pink
   open/close quotation marks. No backdrop card. */
.reading__pull {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(2rem, 5vw, 4rem);
  min-height: 60vh;
}
.reading__pull-text {
  font-family: var(--display-alt, 'Fraunces', serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.75rem, 3.5vw, 2.75rem);
  line-height: 1.3;
  color: var(--parchment);
  text-align: center;
  max-width: 22ch;
  margin: 0;
  position: relative;
}
.reading__pull-text::before,
.reading__pull-text::after {
  content: '\201C';
  color: var(--electric-pink);
  font-size: 1.4em;
  line-height: 0;
  vertical-align: -0.15em;
  margin: 0 0.1em;
}
.reading__pull-text::after { content: '\201D'; }
/* Variant for the landscape video reading section — wider video column,
   shorter sticky frame because the video is 16:9. */
.reading--video {
  grid-template-columns: 1fr 1.2fr;
  align-items: center;
}
/* Frosted glass behind the reading copy — backdrop-filter blurs the
   nebula behind the text just enough to quiet bright peaks, but stays
   visually transparent (no grey rectangle, no hard edge). */
.reading__copy {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  padding: 2.5rem;
  background: rgba(15, 12, 38, 0.18);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  border-radius: 4px;
}
/* No more dark scrim box behind the text column — felt grey and odd
   against the nebula. Text legibility now handled by subtle text-shadows
   on the headings + paragraphs themselves (below). */
.reading__eyebrow {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--blush);
}
.reading__h {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.25rem, 4vw, 3.25rem);
  line-height: 1;
  margin: 0;
  color: var(--parchment);
}
.reading__h em { font-family: var(--display-alt, 'Fraunces', serif); font-style: italic; color: var(--electric-pink); font-weight: 300; }
.reading__copy p {
  font-size: 1.05rem;
  line-height: 1.75;
  color: var(--text-body);
  max-width: 52ch;
  margin: 0;
}
.reading__copy p.lead {
  font-size: 1.2rem;
  color: var(--parchment);
  font-weight: 300;
}
.reading__cta-row { margin-top: 0.75rem; display: flex; gap: 0.85rem; }
.reading__image-frame {
  position: relative;
  height: 78vh;
  --p: 0;
}
.reading__image {
  position: relative;
  top: 0;
  height: 78vh;
  border-radius: 4px;
  overflow: hidden;
  background-size: cover;
  background-position: center 25%;  /* bias up so portrait faces stay visible */
  background-color: var(--indigo-deep);
  box-shadow: 0 30px 60px rgba(0,0,0,0.5);
}
/* Landscape video frame override — the visualizer is 1920x1080 (16:9),
   so we use a 16:9 frame without pinning. */
.reading--video .reading__image-frame { height: auto; aspect-ratio: 16 / 9; }
.reading--video .reading__image {
  height: auto;
  aspect-ratio: 16 / 9;
  top: 0;
  border-radius: 6px;
  background: var(--deep-stage);
  box-shadow:
    0 30px 70px rgba(0, 0, 0, 0.6),
    0 0 50px rgba(236, 72, 153, 0.18);
}
/* Tilted image with pink offset frame + corner triangle accent — used
   wherever we want a Memphis/editorial photo treatment in a reading
   flow (about page Voice section, FR about section, etc.). */
.reading__image.fr-tilted-image {
  position: relative;
  transform: rotate(-3deg);
  transition: transform 0.6s var(--ease-out-expo);
  aspect-ratio: 4 / 5;
  height: auto;
  max-height: 70vh;
  box-shadow:
    0 30px 60px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(244, 168, 200, 0.25);
}
.reading__image.fr-tilted-image:hover { transform: rotate(-1.5deg); }
.reading__image.fr-tilted-image::before {
  content: '';
  position: absolute;
  inset: 22px -22px -22px 22px;
  border: 2px solid var(--electric-pink, #ec4899);
  border-radius: 2px;
  z-index: -1;
  box-shadow: 0 0 24px rgba(236, 72, 153, 0.45);
  pointer-events: none;
}
.reading__image.fr-tilted-image::after {
  content: '';
  position: absolute;
  top: -14px;
  left: -14px;
  width: 32px;
  height: 32px;
  background: var(--electric-pink, #ec4899);
  clip-path: polygon(0 0, 100% 0, 0 100%);
  box-shadow: 0 0 18px rgba(236, 72, 153, 0.6);
  pointer-events: none;
}

.reading__image--video { background: var(--deep-stage); }

/* ===== Off the Stage — 3-card editorial layout (about page) =====
   Three frosted-glass cards in a 2×2 grid:
     row 1: title + first paragraph (left), landscape video (right)
     row 2: Rising Studios paragraph + CTA spanning full width
   The frosted-glass treatment matches the reading copy style so the
   section reads cohesively with the rest of the about page. */
.off-stage {
  padding: clamp(7rem, 14vh, 11rem) clamp(2rem, 7vw, 5rem);
  max-width: 1320px;
  margin: 0 auto;
}
.off-stage__grid {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  align-items: stretch;
}
.off-stage__card {
  position: relative;
  padding: clamp(2rem, 4vw, 3rem);
  border-radius: 6px;
  background: rgba(15, 12, 38, 0.32);
  backdrop-filter: blur(18px) saturate(1.15);
  -webkit-backdrop-filter: blur(18px) saturate(1.15);
  border: 1px solid rgba(252, 231, 243, 0.08);
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.off-stage__card--intro { grid-column: 1; grid-row: 1; }
.off-stage__video {
  grid-column: 2; grid-row: 1;
  border-radius: 6px;
  overflow: hidden;
  background: #050410;
  aspect-ratio: 16 / 9;
  align-self: stretch;
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(236, 72, 153, 0.18);
}
.off-stage__video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.off-stage__card--studios { grid-column: 1 / -1; grid-row: 2; }

/* v2 layout — text cards 50/50 on top, video full-width below with
   CTA pinned on top of it. */
.off-stage__grid--v2 {
  grid-template-columns: 1fr 1fr;
}
.off-stage__grid--v2 .off-stage__card--fr { grid-column: 1; grid-row: 1; }
.off-stage__grid--v2 .off-stage__card--studios { grid-column: 2; grid-row: 1; }
.off-stage__grid--v2 .off-stage__video {
  grid-column: 1 / -1;
  grid-row: 2;
  /* Original 16:9 landscape — letterboxing the trailer to 21:9
     was cropping the singer's head. */
  aspect-ratio: 16 / 9;
  position: relative;
}
.off-stage__video-cta {
  position: absolute;
  bottom: clamp(1.25rem, 3vh, 2rem);
  right: clamp(1.25rem, 3vw, 2rem);
  z-index: 2;
}
@media (max-width: 900px) {
  .off-stage__grid--v2 { grid-template-columns: 1fr; }
  .off-stage__grid--v2 .off-stage__card--fr,
  .off-stage__grid--v2 .off-stage__card--studios,
  .off-stage__grid--v2 .off-stage__video { grid-column: 1; grid-row: auto; }
  .off-stage__grid--v2 .off-stage__video { aspect-ratio: 16 / 10; }
}
.off-stage__para {
  font-family: var(--body);
  font-weight: 300;
  font-size: 1.05rem;
  line-height: 1.75;
  color: var(--text-body);
  margin: 0;
}
.off-stage__para strong {
  color: var(--parchment);
  font-weight: 500;
}
.off-stage__cta-row {
  display: flex;
  gap: 1rem;
  margin-top: auto;       /* pin CTA to card bottom so both cards align */
  padding-top: 1rem;
}
/* Coming-soon variant of a btn — muted, no hover. */
.btn.is-disabled {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
  font-style: italic;
}
@media (max-width: 900px) {
  .off-stage__grid { grid-template-columns: 1fr; }
  .off-stage__card--intro,
  .off-stage__video,
  .off-stage__card--studios { grid-column: 1; grid-row: auto; }
  .off-stage__video { aspect-ratio: 16 / 10; }
}
.reading__image--video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* 3 — Italic pull-quote moment. Pulled tight up under "The Voice" so
   it reads as that section's closing beat, then a big bottom margin
   creates breathing room before On Stage so Melissa's visualizer feels
   like it's reaching up into open space. */
.quote-pin {
  position: relative;
  --p: 0;
  /* Sits cleanly BELOW the hero and ABOVE "The voice" — natural-height
     band (no negative margin overlap, no empty starfield void). Bottom
     padding is intentionally tighter so the quote leads into "The voice". */
  padding: clamp(4.375rem, 11.25vh, 8.125rem) 8vw clamp(0.375rem, 1.125vh, 0.75rem);
}
.quote-pin__sticky {
  position: relative;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
}
.quote-pin__text {
  font-family: var(--display-alt, 'Fraunces', serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(2rem, 5vw, 4rem);
  line-height: 1.25;
  color: var(--parchment);
  text-align: center;
  max-width: 38ch;
  margin: 0;
  /* Strong multi-stop text-shadow so the quote stays readable on any
     nebula peak behind it. Was opacity-faded which made it worse. */
  text-shadow:
    0 2px 18px rgba(10, 8, 32, 0.95),
    0 0 10px rgba(10, 8, 32, 0.7),
    0 0 30px rgba(10, 8, 32, 0.5);
}
.quote-pin__text::before, .quote-pin__text::after {
  content: '\201C';
  color: var(--electric-pink);
  font-size: 1.4em;
  line-height: 0;
  vertical-align: -0.15em;
  margin: 0 0.1em;
}
.quote-pin__text::after { content: '\201D'; }

/* ── Neon Breath entrance (mockup Idea 05) ───────────────────────────────
   The three words fade up ONE AT A TIME (first, then second, then third),
   and once landed each keeps a slow pink glow that breathes in and out.
   Triggered by .is-revealed, added by the entrance IntersectionObserver
   in ui.js when the quote scrolls into view. */
.quote-pin__word {
  display: inline-block;
  opacity: 0;
  transform: translateY(16px);
}
.quote-pin.is-revealed .quote-pin__word {
  animation:
    quote-word-in 0.7s var(--ease-out-expo) forwards,
    quote-breath 3.6s ease-in-out infinite;
}
/* Sequential fade-in: each word starts ~0.65s after the previous, so they
   land one at a time rather than together. The breath (2nd delay value)
   kicks in only after all three have settled. */
.quote-pin.is-revealed .quote-pin__word:nth-child(1) { animation-delay: 0s,    1.9s; }
.quote-pin.is-revealed .quote-pin__word:nth-child(2) { animation-delay: 0.65s, 2.1s; }
.quote-pin.is-revealed .quote-pin__word:nth-child(3) { animation-delay: 1.3s,  2.3s; }
@keyframes quote-word-in {
  to { opacity: 1; transform: translateY(0); }
}
@keyframes quote-breath {
  0%, 100% { text-shadow: 0 2px 18px rgba(10, 8, 32, 0.95); }
  50%      { text-shadow: 0 0 22px rgba(240, 106, 255, 0.85), 0 0 50px rgba(236, 72, 153, 0.5); }
}
@media (prefers-reduced-motion: reduce) {
  .quote-pin__word { opacity: 1; transform: none; animation: none; }
}
@media (max-width: 700px) {
  /* Stack the three words on top of each other on mobile so each one gets
     its own line — reads better at narrow widths than a wrapped single line. */
  .quote-pin__word { display: block; }
  /* Quote marks (::before/::after on .quote-pin__text) sit on their own
     lines too; tighten the line-height so the stack feels intentional. */
  .quote-pin__text { line-height: 1.15; }
}
.quote-pin__attr {
  position: absolute;
  bottom: clamp(3rem, 6vh, 5rem);
  left: 0; right: 0;
  text-align: center;
  font-family: var(--mono);
  font-size: 0.65rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--blush);
}

/* 4 — FR trailer with overlay copy (natural 1-viewport, was 180vh pinned) */
.fr-pin {
  position: relative;
  height: 100vh;
  --p: 0;
}
.fr-pin__sticky {
  position: relative;
  top: 0;
  height: 100vh;
  overflow: hidden;
  /* No dark background — the masked video fades into the nebula above
     instead of sitting on top of a dark stage. */
  background-color: transparent;
}
.fr-pin__video {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Bias the crop UPWARD so the singer's head stays in frame even when
     the 9:16 portrait video is cropped to a 16:9 viewport. */
  object-position: center 18%;
}
/* Landscape variant — the pink visualizer is 16:9 so it fills a 16:9 hero
   without needing the singer-head crop bias. Top of the video fades to
   transparent so it bleeds into the nebula above instead of cutting hard. */
.fr-pin__video--landscape {
  object-position: center center;
  /* Very long translucent fade — video stays partly translucent across
     nearly its entire height so the nebula above and below bleeds
     through. Mix-blend-mode: lighten makes dark video pixels (mostly
     stage black) defer to whatever's brighter underneath (nebula),
     so the transition is chromatic, not just a hard alpha cut. */
  mix-blend-mode: lighten;
  -webkit-mask-image: linear-gradient(to bottom,
    transparent 0%,
    rgba(0,0,0,0.08) 18%,
    rgba(0,0,0,0.25) 35%,
    rgba(0,0,0,0.55) 55%,
    rgba(0,0,0,0.85) 80%,
    #000 100%);
          mask-image: linear-gradient(to bottom,
    transparent 0%,
    rgba(0,0,0,0.08) 18%,
    rgba(0,0,0,0.25) 35%,
    rgba(0,0,0,0.55) 55%,
    rgba(0,0,0,0.85) 80%,
    #000 100%);
}
/* Stage variant of the pin — central dark vignette for text legibility,
   but TOP is fully transparent so the masked visualizer can blend into
   the nebula without a hard scrim edge cutting across the top. */
.fr-pin--stage .fr-pin__scrim {
  background:
    linear-gradient(to bottom,
      transparent 0%,
      transparent 25%,
      rgba(10, 8, 32, 0.55) 55%,
      rgba(10, 8, 32, 0.7) 100%),
    radial-gradient(ellipse at center 65%, rgba(10, 8, 32, 0.65) 0%, transparent 60%);
}
/* Portrait video variant in the reading frame — the FR trailer clip is
   720×1280 (9:16), so frame matches aspect; sticky height adjusted. */
/* FR trailer — tilted with a hot-pink geometric accent (offset frame).
   The accent is an empty pink-outlined rectangle pushed behind and down-
   right, like a Memphis/editorial poster offset. */
.reading__image--portrait {
  aspect-ratio: 9 / 16;
  height: auto;
  max-height: 62vh;
  max-width: 340px;
  margin: 0 auto;
  position: relative;
  isolation: isolate;
  transform: rotate(-4deg);
  transition: transform 0.6s var(--ease-out-expo);
  box-shadow:
    0 30px 60px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(244, 168, 200, 0.25);
}
.reading__image--portrait:hover { transform: rotate(-2deg); }
/* Offset pink-outlined frame behind the video. */
.reading__image--portrait::before {
  content: '';
  position: absolute;
  inset: 22px -22px -22px 22px;
  border: 2px solid var(--electric-pink);
  border-radius: 2px;
  z-index: -1;
  box-shadow: 0 0 24px rgba(236, 72, 153, 0.45);
  pointer-events: none;
}
/* Small pink triangle accent in the upper-left for editorial spice. */
.reading__image--portrait::after {
  content: '';
  position: absolute;
  top: -14px;
  left: -14px;
  width: 28px;
  height: 28px;
  background: var(--electric-pink);
  clip-path: polygon(0 0, 100% 0, 0 100%);
  box-shadow: 0 0 18px rgba(236, 72, 153, 0.6);
  z-index: 3;
  pointer-events: none;
}
.reading__image--portrait video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 22%;
  display: block;
  position: relative;
  z-index: 1;
}
.fr-pin__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(10, 8, 32, 0.55) 0%, rgba(10, 8, 32, 0.15) 30%, rgba(10, 8, 32, 0.6) 100%);
}
.fr-pin__content {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 0 clamp(2rem, 8vw, 6rem);
}
.fr-pin__eyebrow {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--blush);
  margin: 0 0 1rem;
}
.fr-pin__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.75rem, 6vw, 4.75rem);
  line-height: 0.95;
  letter-spacing: -0.01em;
  margin: 0 0 1.5rem;
  max-width: 18ch;
  color: #fff;
}
.fr-pin__title em { font-family: var(--display-alt, 'Fraunces', serif); font-style: italic; color: var(--electric-pink); font-weight: 300; }
.fr-pin__lead {
  font-size: 1.1rem;
  line-height: 1.65;
  max-width: 52ch;
  margin: 0 0 1.75rem;
  font-weight: 300;
  color: #fff;
}
.fr-pin__cta {
  display: inline-block;
  padding: 0.95rem 1.75rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--parchment);
  background: rgba(236, 72, 153, 0.4);
  border: 1px solid rgba(236, 72, 153, 0.6);
  border-radius: 2px;
  text-decoration: none;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: all 0.35s var(--ease-out-expo);
}
.fr-pin__cta:hover { background: rgba(236, 72, 153, 0.6); box-shadow: 0 0 18px rgba(236, 72, 153, 0.55); }

/* Reduce-motion: kill sticky pinning */
@media (max-width: 900px) {
  .hero-pin, .fr-pin { height: auto; }
  .hero-pin__sticky, .fr-pin__sticky { position: relative; top: 0; height: 100vh; }
  /* Quote stays a compact band on mobile — not a full-viewport gap. */
  .quote-pin__sticky { position: relative; top: 0; height: auto; }
  .reading { grid-template-columns: 1fr; }
  .reading--reverse > :first-child { order: 0; }
  .reading__image-frame { height: 60vh; }
  .reading__image { position: relative; top: 0; height: 60vh; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-pin, .fr-pin { height: auto; }
  .hero-pin__sticky, .fr-pin__sticky { position: relative; top: 0; height: 100vh; }
  .quote-pin__sticky { position: relative; top: 0; height: auto; }
}

/* FR section's media slot styled as video. The FR trailer is portrait
   (720x1280 = 9:16) so we use that aspect on the container and
   object-fit: contain so the whole frame is visible — no cropping. */
.bio-founding__media--video {
  position: relative;
  overflow: hidden;
  border-radius: 4px;
  aspect-ratio: 9 / 16;
  background: var(--deep-stage);
  border: 1px solid rgba(236, 72, 153, 0.18);
}
.bio-founding__media--video video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* ---------- Music page hero — editorial full-bleed photo ----------
   Replaces the previous visualizer hero. The nebula + starfield canvases
   live behind this section in the document, but the photo + scrim are
   opaque so the canvases only show through subsequent sections (discography
   below), per the brief. */
.music-hero {
  position: relative;
  isolation: isolate;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  min-height: 640px;
  overflow: hidden;
}
.music-hero__media {
  position: absolute;
  inset: 0;
  display: block;
  z-index: 0;
}
.music-hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  background-color: var(--deep-stage);
}
/* Cover-art variant: full-bleed crop. The square cover fills the
   landscape viewport (top/bottom cropped via object-fit: cover + center
   focus — the model is centred so the crop is forgiving). The whole
   hero fades out as the user scrolls into the discography. */
.music-hero--cover {
  /* --hero-scroll is written by ui.js (0 → 1 as the hero scrolls out).
     Fades the hero contents to ~30% opacity by the time it's left the
     viewport — gives a soft hand-off to the section below. */
  --hero-scroll: 0;
  opacity: calc(1 - var(--hero-scroll) * 0.7);
  transition: opacity 0.1s linear;
}
.music-hero--cover .music-hero__media {
  background: var(--deep-stage);
}
.music-hero--cover .music-hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* Subtle scale-up tied to scroll for ambient parallax. */
  transform: scale(calc(1.02 + 0.05 * var(--hero-scroll)));
  transition: transform 0.1s linear;
}
/* Bottom-right callout — sits in the lower quadrant, close to the scroll
   cue. Soft type, no boxes, no heavy chrome. */
.music-hero__callout {
  position: absolute;
  z-index: 2;
  right: clamp(2rem, 5vw, 4rem);
  bottom: clamp(5rem, 12vh, 8rem);
  max-width: min(420px, 70vw);
  text-align: right;
  color: var(--parchment);
  text-shadow:
    0 2px 18px rgba(10, 8, 32, 0.78),
    0 0 10px rgba(10, 8, 32, 0.5);
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  align-items: flex-end;
}
.music-hero__eyebrow {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--blush);
  margin: 0;
}
.music-hero__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(3.5rem, 8vw, 6.5rem);
  line-height: 0.95;
  letter-spacing: -0.005em;
  margin: 0;
  color: var(--parchment);
}
.music-hero__sub {
  font-family: var(--display-alt, 'Fraunces', Georgia, serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(0.95rem, 1.4vw, 1.15rem);
  margin: 0;
  opacity: 0.92;
  max-width: 28ch;
}
/* Hero CTAs — Buy + Stream sit directly under the sub-text. Match the
   home page .btn-primary / .btn-ghost glass DNA exactly so the hero
   buttons read as the same brand language as everything else. Hover
   stays in the SAME pink hue (no jump to neon-pink) — only the fill +
   glow intensify. */
.music-hero__ctas {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  margin-top: 1.25rem;
  justify-content: flex-end;
}
.music-hero__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.95rem 1.75rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--parchment);
  text-decoration: none;
  border: 1px solid rgba(236, 72, 153, 0.55);
  border-radius: 2px;
  cursor: pointer;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition:
    background-color 0.35s var(--ease-out-expo),
    border-color    0.35s var(--ease-out-expo),
    box-shadow      0.35s var(--ease-out-expo),
    color           0.35s var(--ease-out-expo),
    transform       0.35s var(--ease-out-expo);
}
/* Primary — slightly more saturated glass fill to lead the eye. */
.music-hero__cta--primary {
  background: rgba(236, 72, 153, 0.4);
  box-shadow:
    0 0 14px rgba(236, 72, 153, 0.4),
    inset 0 0 0 1px rgba(236, 72, 153, 0.1);
}
.music-hero__cta--primary:hover,
.music-hero__cta--primary:focus-visible {
  background: rgba(236, 72, 153, 0.6);
  border-color: var(--electric-pink);
  box-shadow:
    0 0 18px rgba(236, 72, 153, 0.7),
    0 0 42px rgba(236, 72, 153, 0.35),
    inset 0 0 14px rgba(236, 72, 153, 0.25);
  transform: translateY(-1px);
  outline: none;
}
/* Ghost — quieter glass for the secondary action. */
.music-hero__cta--ghost {
  background: rgba(236, 72, 153, 0.12);
  box-shadow: inset 0 0 0 1px rgba(236, 72, 153, 0.05);
}
.music-hero__cta--ghost:hover,
.music-hero__cta--ghost:focus-visible {
  background: rgba(236, 72, 153, 0.32);
  border-color: var(--electric-pink);
  box-shadow:
    0 0 14px rgba(236, 72, 153, 0.55),
    0 0 32px rgba(236, 72, 153, 0.25),
    inset 0 0 10px rgba(236, 72, 153, 0.18);
  transform: translateY(-1px);
  outline: none;
}
@media (max-width: 700px) {
  .music-hero__ctas { justify-content: flex-start; }
}
@media (max-width: 700px) {
  .music-hero__callout {
    right: 1.25rem;
    left: 1.25rem;
    text-align: left;
    align-items: flex-start;
    max-width: 100%;
  }
}
.music-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(ellipse at 25% 30%, rgba(236, 72, 153, 0.12), transparent 60%),
    radial-gradient(ellipse at 80% 75%, rgba(30, 58, 138, 0.22), transparent 60%),
    /* Bottom edge now fades to fully opaque deep-stage over the lower
       half — gives a soft hand-off into the discography below instead
       of the abrupt cut the user flagged. */
    linear-gradient(to bottom,
      rgba(10, 8, 32, 0) 0%,
      rgba(10, 8, 32, 0.1) 40%,
      rgba(10, 8, 32, 0.45) 65%,
      rgba(10, 8, 32, 0.85) 85%,
      rgba(10, 8, 32, 1) 100%);
}
.music-hero__content {
  position: absolute;
  left: 0; right: 0; bottom: clamp(5rem, 12vh, 8rem);
  z-index: 2;
  padding: 0 var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  max-width: 1180px;
  margin: 0 auto;
  color: var(--text-primary);
  text-shadow: 0 2px 24px rgba(10, 8, 32, 0.85);
}
.music-hero__eyebrow {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--blush);
}
.music-hero__title {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(3.5rem, 9vw, 7rem);
  letter-spacing: -0.025em;
  line-height: 0.92;
  margin: 0;
  color: var(--text-primary);
}
.music-hero__sub {
  font-family: var(--display-alt, 'Fraunces', Georgia, serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1rem, 1.6vw, 1.25rem);
  margin: 0.25rem 0 0;
  opacity: 0.85;
  max-width: 38ch;
}

/* Pending-link chip + chip-tag (used by both home Skinny feature + any other
   "link coming soon" placeholders) */
.btn-chip.is-pending {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}
.btn-chip .chip-tag {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.1rem 0.45rem;
  font-size: 0.55rem;
  letter-spacing: 0.18em;
  background: rgba(244, 168, 200, 0.18);
  border: 1px solid rgba(244, 168, 200, 0.35);
  border-radius: 2px;
  color: var(--blush);
}

/* ---------- Section 4: Shows ---------- */
.shows {
  /* bg transparent — nebula + starfield show through. Override the
     .section min-height:100vh — the shows list is short content and
     shouldn't reserve a full viewport of empty space below the dates. */
  min-height: 0;
  padding-bottom: clamp(2rem, 5vh, 3.5rem);
}
.shows__list {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  margin-top: 1rem;
}
/* "Shows coming soon" empty-state — shown in place of the shows list when
   there are no confirmed dates yet. */
.shows__empty {
  margin-top: 1.5rem;
  padding: clamp(2rem, 5vw, 3.5rem);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
.shows__empty-lede {
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.5rem, 3vw, 2.2rem);
  color: var(--text-primary);
  margin: 0;
  letter-spacing: -0.01em;
}
.shows__empty .body-lead {
  max-width: 52ch;
  margin: 0 auto;
}
.shows__empty-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  margin-top: 0.75rem;
}
.show-row {
  display: grid;
  grid-template-columns: 120px 1fr auto;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 3rem);
  padding: 1.85rem 1.5rem;
  border-radius: 4px;
  border: 1px solid transparent;
  transition:
    background-color 0.35s var(--ease-out-expo),
    border-color 0.35s var(--ease-out-expo),
    box-shadow 0.35s var(--ease-out-expo);
}
.show-row:hover {
  background: rgba(236, 72, 153, 0.08);
  border-color: rgba(236, 72, 153, 0.25);
  box-shadow: 0 0 22px rgba(236, 72, 153, 0.15);
}
/* Featured/next-show variant — visually claims the top of the list. */
.show-row.is-featured {
  position: relative;
  background: linear-gradient(135deg, rgba(236, 72, 153, 0.16), rgba(236, 72, 153, 0.04));
  border-color: rgba(236, 72, 153, 0.45);
  box-shadow:
    0 0 32px rgba(236, 72, 153, 0.22),
    inset 0 0 0 1px rgba(252, 231, 243, 0.08);
  padding: 2.5rem 1.75rem;
}
.show-row.is-featured::before {
  content: 'Next';
  position: absolute;
  top: -10px;
  left: 1.5rem;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  background: var(--electric-pink, #ec4899);
  color: #fff;
  padding: 4px 10px;
  border-radius: 2px;
  box-shadow: 0 0 14px rgba(236, 72, 153, 0.55);
}
.show-row.is-featured .show-date__day { font-size: 3.4rem; color: var(--electric-pink, #ec4899); }
.show-row.is-featured .show-date__month { color: var(--blush); }
.show-row.is-featured .show-info__name { font-size: clamp(1.5rem, 2vw, 1.85rem); }
.show-row.is-sold-out { opacity: 0.5; }
.show-row.is-sold-out:hover {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}
.show-date {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  line-height: 1;
}
.show-date__month {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--text-label);
}
.show-date__day {
  font-family: var(--display);
  font-weight: 500;
  font-size: 2.5rem;
  color: var(--text-primary);
  letter-spacing: -0.02em;
}
.show-info__name {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.25rem, 1.7vw, 1.5rem);
  color: var(--text-primary);
  margin: 0 0 0.4rem 0;
  line-height: 1.25;
}
.show-info__venue {
  /* DM Mono in blush so the address reads as a tagged location label
     rather than body copy — pairs with the mono-label "Shows" eyebrow
     above and the mono CTAs on the right. */
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  color: var(--blush);
  margin: 0 0 0.5rem;
}
/* "Free show" pill — small pink chip nested inside the show name. */
.show-info__free {
  display: inline-block;
  margin-left: 0.6rem;
  padding: 0.18rem 0.55rem;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #fff;
  background: var(--electric-pink, #ec4899);
  border-radius: 2px;
  vertical-align: middle;
  box-shadow: 0 0 12px rgba(236, 72, 153, 0.45);
}

/* Optional descriptive blurb between the show name and the venue line —
   used for the skinny release-party note, FR lineups, etc. */
.show-info__note {
  font-family: var(--body);
  font-weight: 300;
  font-size: 0.95rem;
  color: var(--text-body);
  margin: 0 0 0.4rem;
  max-width: 62ch;
  line-height: 1.55;
}
.show-info__note em {
  font-family: var(--display-alt, 'Fraunces', serif);
  font-style: italic;
  color: var(--blush);
}

/* Shows page — header sits lighter than other pages. The page is
   sparse and the giant Melissa Dutch wordmark was overwhelming the
   modest list of dates below. */
body.page-shows .site-header { height: 132px; }
body.page-shows .wordmark__mark { width: 200px; }
body.page-shows .site-header.is-scrolled { height: var(--header-h); }
body.page-shows .site-header.is-scrolled .wordmark__mark { width: 130px; }
@media (max-width: 767px) {
  body.page-shows .site-header { height: 96px; }
  body.page-shows .wordmark__mark { width: 156px; }
}

/* Shows page — intro line between the page title and the show list.
   Editorial framing sentence in body type, soft parchment. Forced to a
   single line on desktop (>=720px) so the sentence reads as one
   continuous statement; allowed to wrap below 720px where it would
   otherwise overflow horizontally. */
.shows__intro {
  font-family: var(--body);
  font-weight: 300;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--text-body);
  margin: 0.75rem 0 0;
  white-space: nowrap;
}
@media (max-width: 720px) {
  .shows__intro { white-space: normal; font-size: 0.95rem; }
}
.shows__intro em {
  font-family: var(--display-alt, 'Fraunces', serif);
  font-style: italic;
  color: var(--blush);
}

/* Shows page — booking CTA. No card backdrop — instead the copy carries
   a multi-stop dark text-shadow so it stays readable even when the
   nebula behind has a bright pink moment. Same trick used elsewhere
   (FR section heads, hero text). */
/* Cinematic booking moment — full-bleed stage photo backdrop with
   centered booking copy on top. Sits between the shows list and the
   footer so it grounds the page closing with a visual beat instead of
   dumping text on the nebula. */
.shows-cta {
  position: relative;
  isolation: isolate;
  padding: 0;
  min-height: 100vh;
  height: 100vh;
  display: grid;
  /* Reserve a narrower right column (≈30% of viewport) for the booking
     copy — that's the empty dark-blue space in the band photo, far right.
     The left 70% is the band's performance space, untouched. */
  grid-template-columns: 1fr 30vw;
  overflow: hidden;
  margin-top: clamp(2rem, 5vh, 4rem);
  margin-bottom: 0;
}
.shows-cta::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -2;
  background-image: url('../img/femme-rising/gallery/fr-gal-06.webp');
  background-size: cover;
  background-position: center 40%;
}
.shows-cta::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Right-side dark column scrim: the right 30% of the section gets a
     soft dark wash so the booking copy reads cleanly against the dark-
     blue stage area. Left 70% (band photo) stays untouched. */
  background:
    linear-gradient(to left,
      rgba(10, 8, 32, 0.75) 0%,
      rgba(10, 8, 32, 0.55) 22%,
      rgba(10, 8, 32, 0.05) 35%,
      transparent 50%);
}
.shows-cta__inner {
  grid-column: 2;
  /* Anchor near the top of the right column instead of vertical center
     so the booking copy sits up in the dark-blue space, leaving room
     for the band's instruments + heads below. */
  align-self: start;
  justify-self: stretch;
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
  padding: clamp(4rem, 10vh, 7rem) clamp(1.5rem, 3vw, 3rem) clamp(2rem, 5vh, 4rem);
}
.shows-cta__inner .mono-label {
  color: var(--blush);
  /* Bigger, more prominent — this IS the hero of this section. */
  font-size: 0.95rem;
  letter-spacing: 0.5em;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid rgba(252, 231, 243, 0.35);
  text-shadow:
    0 2px 12px rgba(10, 8, 32, 0.85),
    0 0 24px rgba(236, 72, 153, 0.45);
}
.shows-cta__inner .display {
  margin: 0;
  font-size: clamp(2.25rem, 4.5vw, 3.75rem);
  line-height: 1.05;
  color: var(--parchment);
  text-shadow:
    0 2px 18px rgba(10, 8, 32, 0.9),
    0 0 12px rgba(10, 8, 32, 0.65);
}
.shows-cta__btn {
  margin-top: 0.75rem;
}
@media (max-width: 800px) {
  /* On mobile, anchor the copy to the TOP of the section so it sits over
     the dark sky above the band photo instead of overlapping the band's
     instruments + heads in the lower third. The right-side scrim from
     desktop doesn't help here, so swap to a top-down dark wash. */
  .shows-cta { grid-template-columns: 1fr; grid-template-rows: 1fr; min-height: 70vh; height: auto; }
  .shows-cta__inner {
    grid-column: 1;
    justify-self: stretch;
    align-self: start;
    text-align: center;
    align-items: center;
    max-width: 100%;
    padding: clamp(2rem, 6vh, 4rem) 1.5rem clamp(2rem, 5vh, 4rem);
  }
  .shows-cta::after {
    background: linear-gradient(to bottom,
      rgba(10, 8, 32, 0.85) 0%,
      rgba(10, 8, 32, 0.55) 30%,
      rgba(10, 8, 32, 0.15) 50%,
      transparent 65%);
  }
}
/* Ticket button — glass-chip style matching the streaming chips on /music/ */
.show-cta {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-primary);
  padding: 0.65rem 1.25rem;
  background: rgba(7, 7, 26, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 2px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  white-space: nowrap;
  transition:
    background-color 0.3s var(--ease-out-expo),
    border-color 0.3s var(--ease-out-expo),
    box-shadow 0.3s var(--ease-out-expo),
    color 0.3s var(--ease-out-expo);
}
.show-cta:hover {
  background: rgba(236, 72, 153, 0.22);
  border-color: var(--electric-violet);
  box-shadow:
    0 0 12px rgba(236, 72, 153, 0.5),
    0 0 26px rgba(236, 72, 153, 0.22);
}
.show-cta--sold {
  background: transparent;
  border-color: transparent;
  color: var(--text-quiet);
  backdrop-filter: none;
  cursor: default;
}

/* ---------- Section 5: Bio ---------- */
/* ========================================================
   About page — editorial asymmetric layout
   Four cards stacked vertically, each with its OWN width and
   its OWN asymmetric grid, so the eye bounces left/right down
   the page instead of reading one long slab.
   ======================================================== */
.bio-page {
  /* Clear the IDLE header height (184px on MD, 240px on FR) — not just
     --header-h (92px, which is the scrolled state). */
  padding: calc(184px + 2.5rem) 0 var(--section-pad-y);
  display: flex;
  flex-direction: column;
  gap: clamp(3rem, 6vw, 5rem);
}
body.femme-rising .bio-page { padding-top: calc(240px + 2.5rem); }
@media (max-width: 767px) {
  .bio-page { padding-top: calc(120px + 1.75rem); }
  body.femme-rising .bio-page { padding-top: calc(180px + 1.75rem); }
}
/* About page now uses .about-magazine layout (no bio-page padding needed). */
.bio-card {
  padding: 0 var(--gutter);
  max-width: 1400px;
  margin: 0 auto;
  width: 100%;
}

/* ---------- CARD 1 · Hero intro (45/55) ---------- */
.bio-intro__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: clamp(2rem, 4.5vw, 4rem);
  align-items: center;
}
.bio-intro__media {
  position: relative;
  aspect-ratio: 3/4;
  overflow: hidden;
  border-radius: 4px;
  margin: 0;
  box-shadow:
    0 26px 50px rgba(0, 0, 0, 0.5),
    0 0 32px rgba(236, 72, 153, 0.22),
    0 0 80px rgba(236, 72, 153, 0.12);
  --tilt-x: 0deg;
  --tilt-y: 0deg;
  --tilt-lift: 0;
  transform: perspective(1000px)
             rotateX(var(--tilt-x))
             rotateY(var(--tilt-y))
             translateZ(calc(var(--tilt-lift) * 1px));
  transform-style: preserve-3d;
  transition: transform 0.8s var(--ease-out-expo);
  will-change: transform;
}
.bio-intro__media.is-tilting { transition: transform 0.08s linear; }
.bio-intro__media picture,
.bio-intro__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 30%;
  display: block;
}
.bio-intro__body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 640px;
}
.bio-intro__body .mono-meta {
  color: var(--electric-violet);
  font-size: 0.72rem;
  letter-spacing: 0.3em;
  margin-bottom: 0.25rem;
}
.bio-intro__body .display-xl {
  font-size: clamp(2.75rem, 6vw, 4.5rem);
  line-height: 0.98;
  margin: 0;
}
.bio-intro__tagline {
  font-family: var(--display-alt, var(--display));
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.2rem, 1.9vw, 1.5rem);
  color: var(--text-body);
  margin: 0.25rem 0 0.75rem 0;
  max-width: 32ch;
  line-height: 1.4;
}
.bio-intro__socials {
  list-style: none;
  padding: 0;
  margin: 1rem 0 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 1.2rem;
  align-items: center;
}
.bio-intro__socials li { position: relative; }
.bio-intro__socials li + li::before {
  content: '';
  position: absolute;
  left: -0.6rem;
  top: 50%;
  width: 3px; height: 3px;
  background: var(--electric-violet);
  border-radius: 50%;
  transform: translateY(-50%);
  opacity: 0.7;
}
.bio-intro__socials a {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-body);
  padding: 0.3rem 0;
  transition: color 0.25s var(--ease-out-expo);
}
.bio-intro__socials a:hover,
.bio-intro__socials a:focus-visible {
  color: var(--electric-violet);
}

/* ---------- CARD 2 · Pull-quote strip ----------
   The full 54-char quote on ONE line, centered. Uses a compound selector
   `.bio-quote .pull-quote.bio-quote__line` to override the earlier
   `.pull-quote.js-fill` rule (equal specificity was letting max-width 38ch
   win and keeping the quote narrow + left-leaning). */
.bio-quote {
  max-width: 1480px;
  padding: clamp(1rem, 3vw, 2.5rem) var(--gutter);
  text-align: center;
}
.bio-quote .pull-quote.bio-quote__line {
  display: block;
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
  padding: 1.25rem 2rem;
  border-left: 0;
  /* Larger editorial scale. Still fits on one line at desktop widths. */
  font-size: clamp(1.7rem, 2.5vw, 2.8rem);
  line-height: 1.25;
  font-weight: 400;
  letter-spacing: -0.005em;
  text-align: center;
  white-space: nowrap;
  /* Subtle dark inner backdrop + violet halo so the italic serif pops away
     from the nebula instead of getting lost against bright peaks. */
  position: relative;
  isolation: isolate;
}
.bio-quote .pull-quote.bio-quote__line::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(ellipse at center,
              rgba(7, 7, 26, 0.6) 0%,
              rgba(7, 7, 26, 0.35) 55%,
              transparent 100%);
  filter: blur(10px);
  border-radius: 20px;
}
/* Bright parchment fill + dark halo for readability. Override any
   transparent/background-clip trickery from the .pull-quote class in case
   .js-fill gets re-applied later. */
.bio-quote .pull-quote.bio-quote__line > span {
  color: var(--text-primary);
  background: none;
  background-image: none;
  background-color: transparent;
  -webkit-background-clip: unset;
  background-clip: unset;
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.85),
    0 0 18px rgba(7, 7, 26, 0.75),
    0 0 36px rgba(236, 72, 153, 0.25);
}
@media (max-width: 900px) {
  .bio-quote .pull-quote.bio-quote__line {
    white-space: normal;
    font-size: clamp(1.4rem, 4.5vw, 2rem);
    width: auto;
    max-width: 26ch;
    padding: 1rem 1.5rem;
  }
}

/* ---------- CARD 3 · Live/press (55/45) — text left, wide photo right ---------- */
.bio-live {
  max-width: 1320px;
}
.bio-live__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: center;
}
.bio-live__body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.bio-live__body .mono-label {
  color: var(--electric-violet);
  margin-bottom: 0.25rem;
}
.bio-live__body .display-m { margin: 0 0 0.5rem 0; }
.bio-live__list {
  list-style: none;
  padding: 0;
  margin: 0.75rem 0 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  color: var(--text-body);
  border-left: 2px solid rgba(236, 72, 153, 0.35);
  padding-left: 1.25rem;
}
.bio-live__list strong { color: var(--text-primary); font-weight: 500; letter-spacing: 0.2em; }
.bio-live__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.25rem;
}
.bio-live__media {
  position: relative;
  aspect-ratio: 4/5;    /* portrait — matches Cards 1 and 4 */
  overflow: hidden;
  border-radius: 4px;
  margin: 0;
  transform: rotate(-0.8deg);
  box-shadow:
    0 26px 50px rgba(0, 0, 0, 0.5),
    0 0 40px rgba(236, 72, 153, 0.15);
  transition: transform 0.6s var(--ease-out-expo);
}
.bio-live__media:hover { transform: rotate(0deg) scale(1.015); }
.bio-live__media picture,
.bio-live__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

/* ---------- CARD 4 · Femme Rising founding (40/60) — photo left, body right ---------- */
.bio-founding {
  max-width: 1320px;
}
.bio-founding__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: center;
}
.bio-founding__media {
  position: relative;
  aspect-ratio: 4/5;
  overflow: hidden;
  border-radius: 4px;
  margin: 0;
  transform: rotate(0.8deg);
  box-shadow:
    0 26px 50px rgba(0, 0, 0, 0.5),
    0 0 40px rgba(240, 106, 255, 0.18),
    0 0 80px rgba(225, 29, 116, 0.08);
  transition: transform 0.6s var(--ease-out-expo);
}
.bio-founding__media:hover { transform: rotate(0deg) scale(1.015); }
.bio-founding__media picture,
.bio-founding__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.bio-founding__cap {
  position: absolute;
  bottom: 0.75rem; left: 0.85rem;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-primary);
  background: rgba(20, 6, 36, 0.65);
  padding: 0.3rem 0.55rem;
  border-radius: 2px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.bio-founding__body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.bio-founding__body .mono-label {
  /* Was the off-hue neon-pink; switched to brand blush so all eyebrow
     labels across the site sit in the same pink family. */
  color: var(--blush);
  margin-bottom: 0.25rem;
}
.bio-founding__body .display-m { margin: 0 0 0.5rem 0; }
.bio-founding__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.75rem;
}

/* ---------- Responsive: collapse to single column on narrow viewports ---------- */
@media (max-width: 900px) {
  .bio-intro__grid,
  .bio-live__grid,
  .bio-founding__grid {
    grid-template-columns: 1fr;
    gap: 2rem;
  }
  .bio-intro__media,
  .bio-live__media,
  .bio-founding__media {
    aspect-ratio: 4/5;
    max-width: 520px;
    margin-left: auto;
    margin-right: auto;
  }
  .bio-live__media, .bio-founding__media { transform: none; }
}

/* Legacy .bio__* selectors still used by page-fit compact mode — kept minimal */
.bio__grid { display: grid; }
.bio__body { display: flex; flex-direction: column; gap: 1rem; }
.bio__media { position: relative; overflow: hidden; }
.bio__ctas { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1rem; }
.bio__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.25rem;
}
.bio__socials {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-top: 1rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--divider);
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.bio__socials a:hover { color: var(--electric-violet); }

/* ---------- Footer ---------- */
.site-footer {
  position: relative;
  z-index: 1;
  padding: 1.5rem var(--gutter);
  background: transparent;
  text-align: center;
}
.site-footer--minimal { padding: 1.5rem var(--gutter); }
.site-footer__line {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--text-quiet);
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 0.9rem;
}
.site-footer__line a {
  color: var(--text-secondary);
  transition:
    color 0.3s var(--ease-out-expo),
    text-shadow 0.3s var(--ease-out-expo);
}
.site-footer__line a:hover {
  color: var(--electric-violet);
  text-shadow:
    0 0 6px  rgba(236, 72, 153, 0.85),
    0 0 14px rgba(236, 72, 153, 0.55),
    0 0 28px rgba(236, 72, 153, 0.35);
}
.site-footer__line .sep {
  color: var(--text-quiet);
  opacity: 0.6;
}
/* On narrow screens, let it stack into 2-3 lines cleanly */
@media (max-width: 600px) {
  .site-footer__line { font-size: 0.55rem; gap: 0.35rem 0.65rem; }
}
/* Solid dark-blue footer — used on music page so it continues the discography's
   opaque colour band, no nebula peeking through the footer. */
.site-footer--dark {
  position: relative;
  z-index: 10;
  background: var(--deep-stage);
}
/* When the footer lives inside the gallery section on the home page. */
.site-footer--gallery {
  flex-shrink: 0;
  padding: 3rem var(--gutter) 2rem;
  position: relative;
  z-index: 4;
}
.site-footer__credit {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-quiet);
}
.site-footer__credit a:hover { color: var(--electric-violet); }

/* ---------- Editorial footer — home page ----------
   Three-column composition: brand block / social-listening links / contact.
   Base line below for copyright + credit. Replaces the generic pipe-separated
   mono row used everywhere else. */
.site-footer--home {
  flex-shrink: 0;
  padding: clamp(3rem, 6vw, 4.5rem) var(--gutter) clamp(1.5rem, 2.5vw, 2.5rem);
  position: relative;
  z-index: 4;
  text-align: left;
  border-top: 1px solid rgba(236, 72, 153, 0.15);
  background:
    radial-gradient(ellipse at 90% 0%, rgba(236, 72, 153, 0.08), transparent 55%),
    transparent;
}
.site-footer--home .site-footer__inner {
  max-width: 1280px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.4fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
  padding-bottom: clamp(2rem, 4vw, 3rem);
}
.site-footer__brand {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.site-footer__name {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.5rem, 2.4vw, 1.85rem);
  letter-spacing: -0.01em;
  color: var(--text-primary);
  line-height: 1;
}
.site-footer__tagline {
  font-family: var(--mono);
  font-size: 0.65rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--blush);
}
.site-footer__nav {
  display: flex;
  /* Keep on one line at desktop — five social links should fit horizontally
     without YouTube/Apple Music dropping below. Wraps only on narrow screens. */
  flex-wrap: nowrap;
  align-items: center;
  justify-content: center;
  gap: 0.4rem 1.1rem;
  white-space: nowrap;
}
.site-footer__nav a {
  font-family: var(--mono);
  /* Slightly tighter type so all five links breathe on one line at the
     middle column width. */
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-body);
  padding: 0.2rem 0;
  transition: color 0.3s var(--ease-out-expo), text-shadow 0.3s var(--ease-out-expo);
}
@media (max-width: 860px) {
  /* Stacked layout below 860px — allow wrap again so links don't run off-screen */
  .site-footer__nav {
    flex-wrap: wrap;
    justify-content: flex-start;
  }
}
.site-footer__nav a:hover {
  color: var(--electric-pink);
  text-shadow:
    0 0 6px  rgba(236, 72, 153, 0.85),
    0 0 16px rgba(236, 72, 153, 0.4);
}
.site-footer__contact {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  align-items: flex-end;
  text-align: right;
}
.site-footer__contact a {
  font-family: var(--display);
  font-weight: 400;
  font-size: 0.95rem;
  letter-spacing: -0.005em;
  color: var(--text-primary);
  transition: color 0.3s var(--ease-out-expo);
}
.site-footer__contact a + a {
  font-size: 0.78rem;
  color: var(--blush);
}
.site-footer__contact a:hover { color: var(--electric-pink); }
.site-footer__base {
  max-width: 1280px;
  margin: 0 auto;
  padding-top: clamp(1.25rem, 2.5vw, 1.75rem);
  border-top: 1px solid rgba(236, 72, 153, 0.08);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-quiet);
}
.site-footer__base a {
  color: var(--text-secondary);
  transition: color 0.3s var(--ease-out-expo);
}
.site-footer__base a:hover { color: var(--electric-pink); }
@media (max-width: 860px) {
  .site-footer--home .site-footer__inner {
    grid-template-columns: 1fr;
    gap: 2rem;
  }
  .site-footer__contact { align-items: flex-start; text-align: left; }
  .site-footer__base { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
}

/* ========================================================
   Contact modal — nebula glass
   A floating glass card that feels like it's suspended in the
   same cosmos as the rest of the site. Soft backdrop lets the
   nebula continue animating behind; the card itself uses
   backdrop-filter + violet (or magenta on FR) corner glows.
   ======================================================== */
.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 3vw, 2rem);
  /* Soft backdrop — keeps the nebula visible (not a full blackout).
     Uses the FR pink-tinted backdrop everywhere so the contact modal looks
     identical on every page (per launch request: MD modal == FR modal). */
  background: rgba(20, 6, 36, 0.55);
  backdrop-filter: blur(8px) saturate(0.9);
  -webkit-backdrop-filter: blur(8px) saturate(0.9);
}
.modal.is-open {
  display: flex;
  animation: modal-fade 0.35s var(--ease-out-expo);
}
@keyframes modal-fade {
  from { opacity: 0; transform: scale(0.99); }
  to   { opacity: 1; transform: scale(1); }
}
.modal__card {
  position: relative;
  width: 100%;
  max-width: 720px;
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
  background: rgba(20, 6, 36, 0.55);
  backdrop-filter: blur(22px) saturate(1.1);
  -webkit-backdrop-filter: blur(22px) saturate(1.1);
  border: 1px solid rgba(240, 106, 255, 0.35);
  border-radius: 8px;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  box-shadow:
    0 30px 90px rgba(0, 0, 0, 0.6),
    0 0 110px rgba(240, 106, 255, 0.25),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
  animation: modal-card-rise 0.4s var(--ease-out-expo);
}
@keyframes modal-card-rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* Corner glows painted on a ::before so they can't clip the scroll content */
.modal__card::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: 8px;
  background:
    radial-gradient(circle at 0% 0%, rgba(240, 106, 255, 0.28), transparent 40%),
    radial-gradient(circle at 100% 100%, rgba(225, 29, 116, 0.22), transparent 40%);
  z-index: -1;
}
.modal__close {
  position: absolute;
  top: 0.85rem; right: 0.85rem;
  width: 36px; height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  color: var(--text-secondary);
  background: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: color var(--dur-micro) var(--ease-out-expo),
              background var(--dur-micro) var(--ease-out-expo);
  z-index: 2;
}
.modal__close:hover,
.modal__close:focus-visible {
  color: var(--text-primary);
  background: rgba(240, 106, 255, 0.2);
}
.modal__eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: #f06aff;
  margin-bottom: 0.5rem;
}
.modal__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.75rem, 3vw, 2.3rem);
  color: var(--text-primary);
  margin: 0 0 1.5rem 0;
  letter-spacing: -0.01em;
  line-height: 1.05;
}
.modal__lede {
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--text-body);
  margin: 0 0 1.5rem 0;
  font-weight: 300;
  max-width: 42ch;
}

/* ----- Reason chips ----- */
.field-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-bottom: 1.25rem;
}
.reason-chip {
  padding: 0.6rem 1rem;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  border: 1px solid rgba(240, 106, 255, 0.32);
  background: rgba(20, 6, 36, 0.4);
  color: var(--text-body);
  /* Match the sharp rectangular language of .btn and the rest of the site
     (2px radius) — pill shape was out of step with the aesthetic. */
  border-radius: 2px;
  cursor: pointer;
  transition:
    border-color 0.25s var(--ease-out-expo),
    background 0.25s var(--ease-out-expo),
    color 0.25s var(--ease-out-expo);
}
.reason-chip:hover,
.reason-chip:focus-visible {
  border-color: #f06aff;
  color: var(--text-primary);
}
.reason-chip.is-selected {
  /* Bright fuchsia fill (matches .btn-primary on FR pages) — applied
     site-wide so the contact modal is identical everywhere. */
  background: #f06aff;
  border-color: #f06aff;
  color: #2a0f1e;
}

/* ----- Floating label fields ----- */
.float-field {
  position: relative;
  margin-bottom: 0.85rem;
}
.float-field input,
.float-field textarea {
  width: 100%;
  padding: 1.25rem 1rem 0.55rem;
  background: rgba(20, 6, 36, 0.4);
  color: var(--text-primary);
  border: 1px solid rgba(240, 106, 255, 0.28);
  border-radius: 3px;
  font-family: var(--body);
  font-size: 0.95rem;
  transition:
    border-color 0.22s var(--ease-out-expo),
    background 0.22s var(--ease-out-expo);
}
.float-field textarea {
  min-height: 110px;
  resize: vertical;
  padding-top: 1.65rem;
}
.float-field input::placeholder,
.float-field textarea::placeholder { color: transparent; }
.float-field label {
  position: absolute;
  left: 1rem;
  top: 1rem;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-secondary);
  pointer-events: none;
  transition: all 0.2s var(--ease-out-expo);
}
.float-field input:not(:placeholder-shown) + label,
.float-field input:focus + label,
.float-field textarea:not(:placeholder-shown) + label,
.float-field textarea:focus + label {
  top: 0.4rem;
  font-size: 0.54rem;
  color: #f06aff;
}
.float-field input:focus,
.float-field textarea:focus {
  outline: none;
  border-color: #e11d74;
  background: rgba(20, 6, 36, 0.65);
}

/* ----- Submit ----- */
.modal__submit {
  width: 100%;
  padding: 1rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  /* Bright fuchsia fill matching .btn-primary on FR pages — used site-wide
     so the contact modal looks identical on every page. */
  background: #f06aff;
  color: #2a0f1e;
  border: 0;
  border-radius: 2px;
  cursor: pointer;
  margin-top: 0.5rem;
  box-shadow: 0 8px 30px rgba(240, 106, 255, 0.42);
  transition: background 0.25s var(--ease-out-expo),
              box-shadow 0.25s var(--ease-out-expo);
}
.modal__submit:hover,
.modal__submit:focus-visible {
  background: transparent;
  color: #f06aff;
  box-shadow: 0 10px 40px rgba(240, 106, 255, 0.45);
  outline: 1px solid #f06aff;
}

/* ----- Divider + direct-contact info ----- */
.modal__divider {
  margin: 1.5rem 0 1rem;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--text-quiet);
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.modal__divider::before,
.modal__divider::after {
  content: '';
  flex: 1;
  border-top: 1px solid rgba(240, 106, 255, 0.22);
}
.modal__info {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.12em;
}
.modal__info a {
  color: var(--text-primary);
  text-decoration: underline;
  text-decoration-color: rgba(240, 106, 255, 0.5);
  text-underline-offset: 4px;
  transition: text-decoration-color 0.2s var(--ease-out-expo);
}
.modal__info a:hover,
.modal__info a:focus-visible { text-decoration-color: #f06aff; }

/* ----- Conditional field (FR "submit music" only) ----- */
.float-field[data-conditional] { display: none; }
.float-field[data-conditional].is-shown { display: block; }

/* ----- Honeypot + success ----- */
.form-hp { position: absolute; left: -9999px; visibility: hidden; }
.form-success {
  display: none;
  font-family: var(--display);
  font-style: italic;
  font-size: 1.1rem;
  color: var(--text-primary);
  line-height: 1.5;
  padding: 2rem 0;
  text-align: center;
}
form.is-sent .form-success { display: block; }
form.is-sent .float-field,
form.is-sent .field-chips,
form.is-sent .modal__submit,
form.is-sent .form-hp { display: none; }

/* ---------- Responsive ---------- */
@media (max-width: 1024px) {
  .music__grid,
  .bio__grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .music__art { justify-self: start; max-width: 100%; }
  .bio__media { aspect-ratio: 4/5; }
}

/* Mobile: gallery reverts to a vertical stack — horizontal scroll is desktop-only per spec */
@media (max-width: 899px) {
  /* ===== Hamburger drawer nav ===== */
  .nav-toggle { display: inline-flex; align-items: center; justify-content: center; flex-direction: column; }

  /* Drawer slides in from the right, ABOVE the header (z-index 100) so links
     are never hidden behind the fixed header. Only the toggle (z-index 110)
     stays on top of the drawer. */
  .site-nav {
    position: fixed;
    top: 0; right: 0; bottom: 0;
    width: min(420px, 88vw);
    padding: 5.5rem 2rem 2rem;   /* clears the toggle X button at top-right */
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 0.5rem;
    background: rgba(7, 7, 26, 0.96);
    backdrop-filter: blur(24px) saturate(1.1);
    -webkit-backdrop-filter: blur(24px) saturate(1.1);
    border-left: 1px solid rgba(236, 72, 153, 0.3);
    box-shadow: -30px 0 80px rgba(0, 0, 0, 0.65);
    transform: translateX(100%);
    opacity: 0;
    pointer-events: none;
    transition:
      transform 0.45s var(--ease-out-expo),
      opacity 0.35s var(--ease-out-expo);
    z-index: 100;
    overflow-y: auto;
  }
  body.femme-rising .site-nav {
    background: rgba(20, 6, 36, 0.96);
    border-left-color: rgba(240, 106, 255, 0.28);
  }
  /* The desktop rule `.site-header.is-scrolled .site-nav { transform:
     translateY(0) }` has higher specificity than `.site-nav.is-open`, so
     when the user scrolled the drawer's translateX was being overridden
     by translateY — leaving links invisible. Force the correct translateX
     states with !important so this can't be re-broken by any other rule. */
  .site-header.is-scrolled .site-nav,
  .site-nav { transform: translateX(100%) !important; }
  .site-header.is-scrolled .site-nav.is-open,
  .site-nav.is-open {
    transform: translateX(0) !important;
    opacity: 1 !important;
    pointer-events: auto !important;
  }
  /* Nav items in the drawer — large, readable, stacked */
  .site-nav a,
  .header-link {
    display: block;
    width: 100%;
    padding: 1.1rem 0.5rem;
    font-size: 1.1rem;
    letter-spacing: 0.18em;
    border-bottom: 1px solid rgba(236, 72, 153, 0.12);
  }
  body.femme-rising .site-nav a { border-bottom-color: rgba(240, 106, 255, 0.14); }
  .site-nav a:last-child { border-bottom: 0; }
  /* Drawer nav triangles/moon — right-aligned beside each link label.
     `!important` on the position properties because the FR moon rules that
     sit further down the stylesheet have higher specificity and would
     otherwise keep the moon centered (translate(-50%, -50%)). */
  .site-nav a::before,
  .header-link::before {
    left: auto !important;
    right: 0 !important;
    top: 50% !important;
    width: 44px !important;
    height: 40px !important;
    transform: translate(30%, -50%) scale(0.5) !important;
  }
  .site-nav a:hover::before,
  .site-nav a:focus-visible::before,
  .site-nav a[aria-current="page"]::before {
    transform: translate(30%, -50%) scale(1.2) !important;
  }
  /* The FR link's own special moon sizing needs the same treatment so it
     doesn't pop to 56px and drift off the edge of the drawer row. */
  body.femme-rising .site-nav a[href*="femme-rising"]::before {
    width: 44px !important;
    height: 40px !important;
  }

  /* When drawer is open, lock body scroll */
  body.nav-open { overflow: hidden; }

  /* Critical: ANY CSS property that creates a "containing block" on the
     fixed-position header (backdrop-filter, transform, filter, perspective,
     will-change) makes its position:fixed descendants resolve against the
     header's box instead of the viewport. That clips the drawer to the
     shrunk header height (~76px) and leaves the lower nav items invisible.
     When the drawer is open, kill ALL of these on the header + its inner so
     the drawer escapes back to viewport-sized. */
  body.nav-open .site-header,
  body.nav-open .site-header.is-scrolled,
  body.nav-open .site-header__inner {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    transform: none !important;
    filter: none !important;
    perspective: none !important;
    will-change: auto !important;
    transition: none !important;
    /* has-hero-overlay pages render the header at opacity:0 until the
       user scrolls past the hero. That makes the drawer (a child of the
       header) invisible too — when the user opens the menu before
       scrolling past the hero, they see nothing. Force the header back
       to fully visible whenever the drawer is open. */
    opacity: 1 !important;
    pointer-events: auto !important;
  }
  /* Backdrop behind the drawer */
  body.nav-open::after {
    content: '';
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(3px);
    z-index: 80;
    animation: nav-backdrop-fade 0.3s var(--ease-out-expo);
  }
  @keyframes nav-backdrop-fade { from { opacity: 0; } to { opacity: 1; } }
}

@media (max-width: 767px) {
  :root { --header-h: 76px; }
  /* Hero min-height reduced on mobile so landscape phones (can be only 400px
     tall) don't get a huge empty hero. 100dvh takes over as viewport height. */
  .hero, .fr-hero { min-height: 520px; }
  .hero__media img { object-position: center 14%; }
  .hero__cta { left: 50%; transform: translateX(-50%); padding-right: 0; }
  .hero__cta::before { display: none; }
  /* Shows rows — stacked card layout on mobile. 3-col grid gets too cramped
     on phones, so we restructure: date sits as a small eyebrow up top,
     name + venue fill the middle, CTA spans the full width below. */
  .show-row {
    grid-template-columns: 1fr;
    grid-template-areas:
      "date"
      "info"
      "cta";
    gap: 0.6rem;
    padding: 1.25rem 1.1rem;
    border: 1px solid rgba(236, 72, 153, 0.15);
    border-radius: 4px;
    background: rgba(7, 7, 26, 0.35);
    text-align: left;
  }
  .show-row .show-date  { grid-area: date; }
  .show-row .show-info  { grid-area: info; }
  .show-row .show-cta   { grid-area: cta; }
  .show-date {
    display: inline-flex;
    flex-direction: row;
    align-items: baseline;
    gap: 0.45rem;
  }
  .show-date__month {
    font-size: 0.7rem;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: var(--electric-violet);
  }
  .show-date__day {
    font-size: 1.15rem;
    font-weight: 400;
    color: var(--text-primary);
    letter-spacing: 0.05em;
  }
  .show-info__name {
    font-size: 1.1rem;
    line-height: 1.3;
    margin: 0 0 0.25rem 0;
  }
  .show-info__venue {
    font-size: 0.85rem;
    color: var(--text-body);
    margin: 0;
  }
  .show-row .show-cta {
    justify-self: start;
    margin-top: 0.25rem;
    padding: 0.55rem 1rem;
    border: 1px solid rgba(236, 72, 153, 0.4);
    border-radius: 2px;
    font-size: 0.62rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--text-primary);
    background: transparent;
  }
  .shows__list.content-glass { padding: 1rem; gap: 0.75rem; }

  /* Gallery stack fallback */
  .gallery {
    height: auto;
    min-height: 0;
    padding: calc(var(--header-h) + 2rem) 0 var(--section-pad-y);
    overflow: visible;
  }
  .gallery__track {
    position: relative;
    flex-direction: column;
    gap: 1rem;
    padding: 0 var(--gutter);
    height: auto;
    align-items: stretch;
    transform: none !important; /* GSAP may leave inline transforms on resize */
  }
  .gallery__item,
  .gallery__item--portrait-tall,
  .gallery__item--portrait,
  .gallery__item--landscape,
  .gallery__item--landscape-wide {
    height: auto;
    width: 100%;
    aspect-ratio: 4/5;
  }
  .gallery__progress { display: none; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
