/* ──────────────────────────────────────────────────────────────────────────
   Crowdsurf landing — single-screen hero + NTS-style discovery grid.

   Hero: one 100vh screen (poster-collage of real covers behind a veil), the
   circle mark, the eyebrow "Music discovery lives on", and a BROKE-RECORDS-
   scale "Crowdsurf" wordmark. One scroll reveals the discovery grid. intro.js
   adds a light parallax + fade on scroll; everything renders statically with
   no JS (progressive enhancement).
   ────────────────────────────────────────────────────────────────────────── */

/* ── Hero — mark centred + big wordmark; both snap to the corner on scroll ── */
/* .cs-hero is just a short scroll runway (spacer). The brand itself is FIXED so
   that after the snap it stays locked in the corner for the rest of the page
   (persistent brand awareness). The grid that follows pops up as the snap ends. */
/* Auto-intro: the grid is the top content; a fixed light backdrop covers it
   while the logos play their opening, then intro.js fades the backdrop out. */
.cs-hero { position: relative; height: 0; }
.cs-hero-veil {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--bg);
  will-change: opacity;
  transition: opacity 0.7s ease;
}
/* Logo cycle → corner lockup. All four logos are fixed and centred (intro.js
   sets each transform), one opaque at a time during the fast cycle. After ~2
   loops the circular mark slides left, the wordmark joins it (the lockup), then
   both snap to the top-left corner and hold for the rest of the page. Difference
   blend keeps them legible over the light backdrop. */
.cs-cyc {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 50;
  height: auto;
  opacity: 0;
  pointer-events: none;
  transform-origin: top left;
  will-change: transform, opacity;
  mix-blend-mode: difference;
}
/* Smaller cycle sizes; the wordmark is width-driven (it's wide), the icons sized to match. */
.cs-cyc-script,
.cs-cyc-triangle,
.cs-hero-mark { width: clamp(64px, 9vw, 104px); }
.cs-hero-word { width: clamp(150px, 24vw, 260px); }

/* ── Floating artist canvas + one info panel — LIGHT MODE, Apple-clean ── */
@font-face {
  font-family: 'Times Now';
  src: url('/fonts/times-now/TimesNowSemiBold.otf') format('opentype');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* Light palette scoped to the intro + discovery sections (children read these
   vars). The lower legacy sections keep their own colours. */
.cs-hero,
.cs-disc,
.cs-about {
  --bg: #f1f1ef;
  --ink: #16161a;
  --mute: rgba(22, 22, 26, 0.56);
  --faint: rgba(22, 22, 26, 0.42);
  --hair: rgba(22, 22, 26, 0.12);
}

/* Smooth section jumps from the nav; keep targets clear of the fixed brand/nav. */
html { scroll-behavior: smooth; }
.cs-disc, .cs-about, #how-it-works { scroll-margin-top: 96px; }

/* No orphans/widows site-wide: balance headings (even line lengths, no stray
   last word) and let paragraphs avoid a single-word final line. Applies on top
   of any explicit <br> the copy already sets. */
h1, h2, h3, h4, h5, h6,
.cs-disc-title, .cs-app-h, .cs-foot-h, .hero-name { text-wrap: balance; }
p, li, .cs-disc-meta { text-wrap: pretty; }

/* About is its OWN tab/view, not part of the scroll feed: hidden until the nav's
   About link (#about) is targeted, then a full-screen overlay above the feed but
   below the nav/logo (z52) so clicking another tab changes the hash + dismisses it. */
.cs-about { display: none; }
.cs-about:target {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 45; /* above the feed, below the corner logo (z50) + nav (z56) so the lockup stays */
  background: var(--bg);
  color: var(--ink);
  /* top-left, lodged on the same 28px gutter as the logo + discover masthead */
  padding: clamp(104px, 15vh, 200px) 28px clamp(108px, 15vh, 180px);
  overflow-y: auto;
}
.cs-about-text {
  margin: 0;
  max-width: 1180px;
  font-family: 'Times Now', 'Times New Roman', Georgia, serif;
  font-weight: 600;
  font-size: clamp(30px, 4.4vw, 76px);
  line-height: 1.08;
  letter-spacing: -0.02em;
}

/* Page chrome (top-right [about] + Join App, bottom IG/iOS pills). All revealed
   after the intro via .cs-chrome.is-in. */
.cs-chrome { opacity: 0; transition: opacity 0.5s ease, transform 0.5s ease; }
.cs-chrome.is-in { opacity: 1; }

/* Transparent click target over the corner lockup → back to the Discover feed. */
.cs-corner-link {
  position: fixed;
  top: 18px;
  left: 22px;
  width: 200px;
  height: 42px;
  z-index: 57;
  pointer-events: none;
}
.cs-corner-link.is-in { pointer-events: auto; }

/* Top-right: [about] link + Join App pill. */
.cs-topright {
  position: fixed;
  top: 22px;
  right: 24px;
  z-index: 56;
  display: inline-flex;
  align-items: center;
  gap: 18px;
  transform: translateY(-6px);
}
.cs-topright.is-in { transform: none; }
.cs-tr-about {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: #16161a;
  text-decoration: none;
  transition: opacity 0.2s ease;
}
.cs-tr-about { line-height: 1; }
.cs-tr-about:hover { opacity: 0.55; }
.cs-tr-join {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 22px;
  border-radius: 999px;
  background: #16161a;
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.01em;
  text-decoration: none;
  /* Helvetica Neue OTF sits high — bias the text down to optically centre it. */
  padding-top: 14px;
  padding-bottom: 10px;
  transition: background 0.2s ease, transform 0.2s ease;
}
.cs-tr-join:hover { background: #000; transform: translateY(-1px); }

/* Bottom social pills flanking the player. */
.cs-spill {
  position: fixed;
  bottom: clamp(12px, 1.6vw, 22px);
  z-index: 61;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 18px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.55);
  -webkit-backdrop-filter: blur(30px) saturate(1.7);
          backdrop-filter: blur(30px) saturate(1.7);
  border: 1px solid rgba(255, 255, 255, 0.5);
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.12);
  color: #16161a;
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.01em;
  text-decoration: none;
}
.cs-spill:hover { transform: translateY(-1px); }
/* Both the icon and the text get the same downward nudge so they stay aligned
   with each other and sit at the pill's optical centre (Helvetica Neue sits high). */
.cs-spill svg { display: block; position: relative; top: 1px; }
.cs-spill span { line-height: 1; position: relative; top: 1px; }
.cs-spill-ig { left: clamp(12px, 2vw, 24px); }
.cs-spill-ios { right: clamp(12px, 2vw, 24px); }

@media (max-width: 720px) {
  /* Vertically centre the Join App pill on the corner logo's row (logo sits at
     top:26 ~30px tall → centre ~41). Asymmetric padding centres the text. */
  .cs-topright { top: 21px; right: 16px; gap: 12px; }
  .cs-tr-join { padding: 12px 16px 8px; }
  .cs-spill { display: none; }
}

/* ── Editorial index of artists — magazine masthead + numbered plate grid;
   hovering a plate floats a frosted-glass quick-look card over the image. ── */
/* Horizontal gutter = the logo lockup's left edge (CORNER_LEFT in intro.js, 28px),
   so the masthead + grid share the same vertical edge as the corner logo. */
.cs-disc {
  position: relative;
  background: var(--bg);
  color: var(--ink);
  padding: clamp(104px, 15vh, 200px) 28px clamp(44px, 7vh, 88px);
}
/* Masthead */
.cs-disc-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: clamp(12px, 1.3vw, 18px);
  margin-bottom: clamp(14px, 1.6vw, 24px);
  border-bottom: 1px solid var(--hair);
}
.cs-disc-title {
  font-family: 'Times Now', Georgia, 'Times New Roman', serif;
  font-weight: 600;
  font-size: clamp(22px, 2.3vw, 38px);
  line-height: 1;
  letter-spacing: -0.015em;
  margin: 0;
}
.cs-disc-meta {
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: none;
  font-weight: 600;
  color: var(--mute);
  white-space: nowrap;
  padding-bottom: 5px;
}

.cs-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: clamp(26px, 2.6vw, 46px) clamp(14px, 1.4vw, 26px);
}

/* Title toggle: "Discover Artists Tastemakers on the Rise" — both words are
   labels; the inactive view is greyed. Pure-CSS via the hidden radios. */
.cs-view-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.cs-tword { cursor: pointer; color: var(--faint); transition: color 0.2s ease; }
.cs-tword:hover { color: var(--mute); }
/* Selected choice = orange text. */
#cs-view-artists:checked ~ .cs-disc-head .cs-tword[for="cs-view-artists"],
#cs-view-people:checked ~ .cs-disc-head .cs-tword[for="cs-view-people"] { color: #ff3724; }

/* Swap the two views (tastemakers = a two-column editorial list). */
.cs-people {
  display: none;
  grid-template-columns: 1fr 1fr;
  column-gap: clamp(28px, 5vw, 96px);
}
#cs-view-people:checked ~ .cs-people { display: grid; }
#cs-view-people:checked ~ .cs-grid-artists { display: none; }
.cs-person {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 0;
  border-top: 1px solid var(--hair);
  text-decoration: none;
  color: var(--ink);
  transition: opacity 0.2s ease;
}
.cs-person:hover { opacity: 0.55; }
.cs-person-num {
  flex: none;
  width: 1.7em;
  font-size: 12px;
  font-weight: 700;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.cs-person-img {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  background: #e6e6e2;
  filter: grayscale(0.15);
}
.cs-person-img-fb {
  display: grid;
  place-items: center;
  font-family: 'Times Now', Georgia, serif;
  font-size: 19px;
  color: var(--mute);
}
.cs-person-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* Name + put-on stat on one line. */
.cs-person-top { display: flex; align-items: baseline; gap: 10px; min-width: 0; flex-wrap: wrap; }
.cs-person-name {
  font-family: 'Times Now', Georgia, 'Times New Roman', serif;
  font-weight: 600;
  font-size: clamp(17px, 1.3vw, 21px);
  line-height: 1.04;
  letter-spacing: -0.01em;
  color: var(--ink);
  white-space: nowrap;
}
.cs-person-stat { font-size: 12px; color: var(--mute); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cs-person-stat b { font-weight: 600; color: #ff3724; }
/* The track they put people onto — a live 3-bar waveform (currently listening)
   to the LEFT of the song · artist. */
.cs-person-puton { display: flex; align-items: center; gap: 9px; min-width: 0; }
.cs-person-track {
  font-size: 13px;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cs-person-track em { font-style: normal; color: var(--mute); }
.cs-person-eq { display: inline-flex; align-items: center; gap: 2.5px; height: 15px; flex: none; }
.cs-person-eq i {
  width: 3px;
  background: #ff3724;
  border-radius: 999px;
  transform-origin: center;
  animation: cs-eq 0.85s ease-in-out infinite;
}
.cs-person-eq i:nth-child(1) { height: 58%; animation-delay: -0.15s; }
.cs-person-eq i:nth-child(2) { height: 100%; animation-delay: -0.45s; }
.cs-person-eq i:nth-child(3) { height: 72%; animation-delay: -0.05s; }
@keyframes cs-eq { 0%, 100% { transform: scaleY(0.4); } 50% { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) { .cs-person-eq i { animation: none; transform: scaleY(0.8); } }

/* Photo fallback for a person with no avatar. */
.cs-tile-fallback {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: #e6e6e2;
  color: var(--mute);
  font-family: 'Times Now', Georgia, 'Times New Roman', serif;
  font-size: clamp(38px, 4vw, 64px);
}

.cs-tile { display: block; min-width: 0; text-decoration: none; color: inherit; -webkit-tap-highlight-color: transparent; }
.cs-tile-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The square image plate */
.cs-tile-media {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: 5px;
  background: #e6e6e2;
}
.cs-tile-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(0.12) saturate(0.95);
}
/* Always-on frosted "Discovered by {name} + N" badge, inset in the bottom-left
   of the plate (no hover states). */
.cs-tile-disc {
  position: absolute;
  bottom: 10px;
  left: 10px;
  max-width: calc(100% - 20px);
  color: #16161a;
  background: rgba(255, 255, 255, 0.55);
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
          backdrop-filter: blur(16px) saturate(1.5);
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: 9px;
  padding: 6px 10px;
  font-size: 11.5px;
  line-height: 1.2;
  letter-spacing: -0.005em;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cs-tile-disc strong { font-weight: 600; color: #16161a; }

/* Always-visible caption below the plate. */
.cs-tile-caption {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-top: 13px;
}
.cs-tile-name {
  font-family: 'Times Now', Georgia, 'Times New Roman', serif;
  font-weight: 600;
  font-size: clamp(16px, 1.2vw, 22px);
  line-height: 1.04;
  letter-spacing: -0.01em;
}

/* Fade-up reveal as the grid enters (intro.js adds .cs-reveal then .is-in). */
.cs-disc.cs-reveal .cs-tile {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.55s ease, transform 0.65s cubic-bezier(0.2, 0.8, 0.2, 1);
  transition-delay: var(--cd, 0s);
}
.cs-disc.cs-reveal.is-in .cs-tile { opacity: 1; transform: none; }

@media (max-width: 1200px) { .cs-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 900px)  { .cs-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 600px) {
  .cs-grid { grid-template-columns: repeat(2, 1fr); gap: 22px 14px; }
  .cs-disc-head { flex-direction: column; align-items: flex-start; gap: 12px; }
  /* Bigger title, moved up (less top clearance over the corner logo). */
  .cs-disc { padding-top: clamp(74px, 11vh, 108px); }
  .cs-disc-title { font-size: clamp(22px, 5.6vw, 32px); line-height: 1.04; }
  /* Tastemakers: vertical list of 4, swipe horizontally to the next column
     (Apple-Music "Best New Songs" pattern). Inset within the 28px gutter — no
     edge bleed — so the first column isn't pulled off the left. */
  .cs-people {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-template-rows: repeat(4, auto);
    grid-auto-columns: 84%;
    column-gap: 20px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 8px;
  }
  .cs-people::-webkit-scrollbar { display: none; }
  .cs-person { scroll-snap-align: start; min-width: 0; }
  .cs-person-main { min-width: 0; }
  .cs-person-name { white-space: normal; }
  .cs-person-track { min-width: 0; }
}

/* ── Footer contact card — bold accent block, two columns. Left: the thesis +
   Instagram / Email / Terms. Right: Get the app. (--cs-foot-bg swaps the colour.) */
/* Full-bleed light-grey footer (dark text). */
.cs-foot {
  background: #e6e6e3;
  color: #16161a;
  /* bottom space clears the fixed IG/iOS social pills */
  padding: clamp(44px, 6vw, 84px) clamp(24px, 4vw, 56px) clamp(80px, 9vw, 104px);
}
.cs-foot-card {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: clamp(28px, 4vw, 72px);
  color: #16161a;
}
.cs-foot-col { display: flex; flex-direction: column; min-width: 0; }
.cs-foot-left { justify-content: space-between; gap: 40px; }
.cs-foot-h {
  margin: 0;
  font-weight: 700;
  font-size: clamp(30px, 4.8vw, 68px);
  line-height: 1.0;
  letter-spacing: -0.025em;
}
.cs-foot-bottom { display: flex; flex-direction: column; gap: 12px; }
.cs-foot-links { display: flex; flex-wrap: wrap; gap: 22px; }
.cs-foot-links a {
  color: #16161a;
  text-decoration: none;
  font-weight: 600;
  font-size: clamp(14px, 1.1vw, 17px);
  letter-spacing: -0.01em;
}
.cs-foot-links a:hover { text-decoration: underline; }
.cs-foot-copy { font-size: 12.5px; font-weight: 500; color: rgba(22, 22, 26, 0.5); }
.cs-foot-right { justify-content: flex-start; gap: 22px; }
.cs-foot-label {
  margin: 0;
  font-weight: 700;
  font-size: clamp(20px, 2.4vw, 34px);
  line-height: 1.0;
  letter-spacing: -0.02em;
}
.cs-foot-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  background: #16161a;
  color: #fff;
  /* asymmetric padding centres the text (Helvetica Neue sits high) */
  padding: 16px 26px 12px;
  border-radius: 999px;
  font-weight: 600;
  font-size: clamp(14px, 1.1vw, 16px);
  line-height: 1;
  letter-spacing: -0.01em;
  text-decoration: none;
  transition: background 0.2s ease;
}
.cs-foot-cta:hover { background: #000; }
@media (max-width: 720px) {
  .cs-foot-card { grid-template-columns: 1fr; gap: 36px; }
}

/* ── Fixed bottom "now playing" bar — Crowdsurf radio aesthetic. Play/pause is a
   pure-CSS checkbox; the dots become an equaliser while "playing". Decorative. */
.cs-pl-checkbox { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.cs-player {
  position: fixed;
  left: 50%;
  bottom: clamp(12px, 1.6vw, 22px);
  width: min(900px, calc(100% - 320px));
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 40px);
  padding: 10px clamp(18px, 2vw, 26px);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.5);
  -webkit-backdrop-filter: blur(44px) saturate(1.9);
          backdrop-filter: blur(44px) saturate(1.9);
  border: 1px solid rgba(255, 255, 255, 0.55);
  box-shadow: 0 18px 54px rgba(0, 0, 0, 0.18);
  color: #16161a;
}
.cs-pl-now { display: flex; align-items: center; gap: 14px; min-width: 0; flex: 1; margin-left: clamp(6px, 1.2vw, 16px); }
.cs-pl-art { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; flex: none; background: #e6e6e2; }
.cs-pl-art-fb { background: linear-gradient(135deg, #c7f0cb, #7cd98a); }
.cs-pl-meta { display: flex; flex-direction: column; min-width: 0; gap: 2px; }
.cs-pl-title { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-pl-artist { font-size: 13px; color: rgba(22, 22, 26, 0.56); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-pl-controls { display: flex; align-items: center; gap: 8px; flex: none; }
.cs-pl-btn {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border: none; background: none; padding: 0; margin: 0;
  color: #16161a; cursor: pointer; border-radius: 50%;
  transition: background 0.2s ease;
}
.cs-pl-btn:hover { background: rgba(22, 22, 26, 0.07); }
.cs-pl-btn svg { width: 19px; height: 19px; }
.cs-pl-toggle { width: 44px; height: 44px; background: #16161a; color: #fff; }
.cs-pl-toggle:hover { background: #000; }
.cs-pl-toggle .cs-ico-pause { display: none; }
.cs-pl-checkbox:checked ~ .cs-player .cs-pl-toggle .cs-ico-play { display: none; }
.cs-pl-checkbox:checked ~ .cs-player .cs-pl-toggle .cs-ico-pause { display: block; }
.cs-pl-station { display: flex; flex-direction: column; gap: 1px; flex: none; min-width: 0; }
.cs-pl-station-name { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }
.cs-pl-station-show { font-size: 13px; color: rgba(22, 22, 26, 0.56); text-decoration: underline; text-underline-offset: 2px; }
.cs-pl-listening { font-size: 12px; color: rgba(22, 22, 26, 0.42); }
.cs-pl-viz { display: flex; align-items: center; gap: 4px; flex: none; height: 26px; }
.cs-pl-bar { width: 4px; height: 4px; border-radius: 50%; background: #16161a; opacity: 0.8; }
.cs-pl-checkbox:checked ~ .cs-player .cs-pl-bar {
  animation: cs-pl-pulse 1s ease-in-out infinite;
  animation-delay: calc(var(--i) * -0.06s);
}
@keyframes cs-pl-pulse {
  0%, 100% { opacity: 0.22; transform: translateY(0); }
  50%      { opacity: 1; transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
  .cs-pl-checkbox:checked ~ .cs-player .cs-pl-bar { animation: none; }
}
@media (max-width: 1080px) { .cs-pl-station { display: none; } }
@media (max-width: 760px) { .cs-pl-viz { display: none; } }
/* Below the social-pill breakpoint the player reclaims the full nested width. */
@media (max-width: 720px) { .cs-player { width: calc(100% - 24px); gap: clamp(12px, 3vw, 24px); } }

/* ── App section — pinned two-beat: "share" → "curate your music identity".
   Reuses .hiw-pin (sticky) + .hiw-spacer runway; intro.js crossfades the
   data-hiw beats. Soft pastel backdrop + gently floating cards. ── */
.cs-app-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    radial-gradient(58% 54% at 18% 24%, #ffd6e2, transparent 70%),
    radial-gradient(54% 50% at 84% 20%, #d6deff, transparent 70%),
    radial-gradient(60% 60% at 80% 84%, #e7d6ff, transparent 70%),
    radial-gradient(56% 56% at 20% 82%, #d6efff, transparent 70%),
    #f1f1ef;
}
.cs-app-beat {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(30px, 5vh, 64px);
  padding: clamp(86px, 13vh, 150px) clamp(20px, 4vw, 48px) clamp(64px, 10vh, 120px);
  opacity: 0;
  transition: opacity 0.7s ease;
  pointer-events: none;
}
.cs-app-beat.is-active { opacity: 1; }
.cs-app-h {
  margin: 0;
  text-align: center;
  font-family: 'Helvetica Neue', -apple-system, BlinkMacSystemFont, sans-serif;
  font-weight: 700;
  font-size: clamp(28px, 4.2vw, 60px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: #16161a;
}

/* Beat 0 — orbit: listener's pfp in the centre, a ring of alternating artist
   (circle) + song (square) thumbnails that pop in one by one (.is-in, staggered
   by --i) when scrolled into view. */
.cs-orbit { position: relative; width: min(460px, 82vw); aspect-ratio: 1; }
/* The ring slowly rotates; each thumb counter-rotates to stay upright. The centre
   pfp lives outside the ring, so it never spins. */
.cs-orbit-ring { position: absolute; inset: 0; animation: cs-orbit-spin 52s linear infinite; }
.cs-orbit-spin { display: block; animation: cs-orbit-spin-rev 52s linear infinite; }
@keyframes cs-orbit-spin { to { transform: rotate(360deg); } }
@keyframes cs-orbit-spin-rev { to { transform: rotate(-360deg); } }
.cs-orbit-me {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(86px, 12vw, 124px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: #e6e6e2 center / cover no-repeat;
  border: 4px solid #fff;
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.2);
  transform: translate(-50%, -50%);
  z-index: 2;
}
.cs-orbit-me-fb { background: linear-gradient(135deg, #c7d8ff, #9fb4ff); }
.cs-orbit-item {
  position: absolute;
  left: 50%;
  top: 50%;
  --angle: calc(var(--i) * (360deg / var(--n)));
  --radius: clamp(122px, 20vw, 200px);
  /* place on the ring, then counter-rotate so the thumbnail stays upright */
  transform: translate(-50%, -50%) rotate(var(--angle)) translateY(calc(-1 * var(--radius))) rotate(calc(-1 * var(--angle)));
}
.cs-orbit-thumb {
  display: block;
  width: clamp(54px, 8vw, 84px);
  aspect-ratio: 1;
  background: #e6e6e2 center / cover no-repeat;
  border: 3px solid #fff;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.16);
  opacity: 0;
  transform: scale(0.2);
  transition: opacity 0.4s ease, transform 0.55s cubic-bezier(0.2, 1.35, 0.4, 1);
}
.cs-orbit-artist { border-radius: 50%; } /* artists = circles */
.cs-orbit-song { border-radius: 12px; }  /* songs = squares */
.cs-orbit.is-in .cs-orbit-thumb {
  opacity: 1;
  transform: scale(1);
  transition-delay: calc(var(--i) * 0.13s); /* pop in one by one around the ring */
}
@media (prefers-reduced-motion: reduce) {
  .cs-orbit-thumb { transition: none; opacity: 1; transform: scale(1); }
  .cs-orbit-ring, .cs-orbit-spin { animation: none; }
}

/* Beat 1 — floating stat-card collage. Cards are pre-rendered PNGs (rounded +
   transparent), so drop-shadow follows their shape; wrappers hold rotation,
   the <img> floats so position + float never fight. */
.cs-collage { position: relative; width: min(720px, 92vw); height: min(600px, 62vh); }
.cs-card { position: absolute; }
.cs-card img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 26px 54px rgba(0, 0, 0, 0.22));
  animation: cs-float 5s ease-in-out infinite;
}
.cs-card-c  { width: 44%; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 2; }
.cs-card-c img  { animation-duration: 6.2s; }
.cs-card-tr { width: 33%; right: 1%;  top: 2%;    transform: rotate(6deg);  z-index: 3; }
.cs-card-tr img { animation-delay: -0.6s; animation-duration: 5.4s; }
.cs-card-tl { width: 35%; left: -1%;  top: 36%;   transform: rotate(-9deg); z-index: 3; }
.cs-card-tl img { animation-delay: -1.2s; animation-duration: 4.8s; }
.cs-card-br { width: 33%; right: 2%;  bottom: 1%; transform: rotate(5deg);  z-index: 3; }
.cs-card-br img { animation-delay: -1.9s; animation-duration: 5.7s; }

@keyframes cs-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }
@media (prefers-reduced-motion: reduce) {
  .cs-share, .cs-card img { animation: none; }
}

/* Beat 2 — "amplify" cascade: rising-artist photos step diagonally and grow,
   amplifying in one by one when the beat becomes active. Orange→red grain panel. */
.cs-amp {
  position: relative;
  width: min(560px, 86vw);
  aspect-ratio: 1;
}
.cs-amp-card {
  position: absolute;
  z-index: var(--i);
  width: calc(22% + var(--i) * 4.4%);
  left: calc(var(--i) * 6%);
  top: calc(var(--i) * 6%);
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  background: #2a2a2a center / cover no-repeat;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.32);
  opacity: 0;
  transform: scale(0.82) translateY(8px);
  transition: opacity 0.45s ease, transform 0.6s cubic-bezier(0.2, 1.2, 0.4, 1);
}
.cs-app-beat.is-active .cs-amp-card {
  opacity: 1;
  transform: scale(1) translateY(0);
  transition-delay: calc(var(--i) * 0.13s); /* amplify in, one by one */
}
@media (prefers-reduced-motion: reduce) {
  .cs-amp-card { transition: none; opacity: 1; transform: none; }
}

/* ── Mobile App section — the pinned crossfade scroll is finnicky on touch, so
   unpin it: three stacked full-height beats, text top-left, graphics sized to
   the screen, no off-screen clipping. (Placed last so it wins the cascade.) ── */
@media (max-width: 760px) {
  /* Light App section sits flush against the dark discovery section — the
     beat's own top padding clears the headline, so no top margin (which would
     expose the dark body background as a black bar at the boundary). */
  .hiw { background: #f1f1ef; }
  .hiw-pin { position: static; height: auto; display: block; overflow: visible; }
  .hiw-spacer { display: none; }
  .cs-app-bg { position: absolute; }
  .cs-app-beat {
    /* relative (not static) so z-index works — otherwise the absolute bg paints
       over the beats and they vanish. Content-sized = simple stacked scroll. */
    position: relative;
    z-index: 1;
    opacity: 1;
    pointer-events: auto;
    min-height: auto;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: clamp(24px, 6vw, 40px);
    padding: clamp(32px, 8vw, 56px) 24px;
  }
  .cs-app-h { text-align: center; width: 100%; font-size: clamp(28px, 7.6vw, 40px); }

  /* Beat 0 — orbit. Explicit square height (don't rely on aspect-ratio in the
     flex column — it can collapse, which throws the ring off the top). Sized to
     stay well inside the screen; thumbnails forced visible. */
  .cs-orbit { width: min(74vw, 300px); height: min(74vw, 300px); margin: 0 auto; }
  .cs-orbit-item { --radius: min(26vw, 104px); }
  .cs-orbit-thumb { width: min(13vw, 54px); height: min(13vw, 54px); opacity: 1; transform: scale(1); transition: none; }
  .cs-orbit-me { width: min(19vw, 80px); height: min(19vw, 80px); }

  /* Beat 1 — collage centred, bigger, every card on-screen. */
  .cs-collage { width: min(92vw, 400px); height: auto; aspect-ratio: 0.95; margin: 0 auto; }
  .cs-card-c  { width: 60%; }
  .cs-card-tr { width: 46%; right: 1%; top: 1%; }
  .cs-card-tl { width: 48%; left: 1%; top: 40%; }
  .cs-card-br { width: 46%; right: 2%; bottom: 2%; }

  /* Beat 2 — cascade compact so it fits the screen (no off-screen cards). The
     cards run from 0% to 84% of the square container (rightmost edge =
     28% + 7×8%), so the cluster's bounding box is offset 8% to centre it within
     the (already margin-auto-centred) container — otherwise it reads top-left. */
  .cs-amp { width: min(78vw, 320px); margin: 0 auto; }
  .cs-amp-card {
    width: calc(28% + var(--i) * 3.4%);
    left: calc(8% + var(--i) * 4.6%);
    top: calc(8% + var(--i) * 4.6%);
    opacity: 1;
    transform: none;
    transition: none;
  }
}
