/* ──────────────────────────────────────────────────────────────────────────
   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 — flat design system: pure-black
   canvas, sharp full-bleed posters, hairlines (mirrors the app's reskin,
   brain/product/design-system.md) ── */
@font-face {
  font-family: 'Times Now';
  src: url('/fonts/times-now/TimesNowSemiBold.otf') format('opentype');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* Flat 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: #000000;
  --ink: #ffffff;
  --mute: rgba(255, 255, 255, 0.64);
  --faint: rgba(255, 255, 255, 0.45);
  --hair: rgba(255, 255, 255, 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: #fff;
  text-decoration: none;
  transition: opacity 0.2s ease;
}
.cs-tr-about { line-height: 1; }
.cs-tr-about:hover { opacity: 0.55; }
/* Accent pill — the one focused CTA on screen (pills = controls; accent
   marks the single action, everything else stays quiet). */
.cs-tr-join {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 22px;
  border-radius: 999px;
  background: #ff3724;
  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: filter 0.2s ease, transform 0.2s ease;
}
.cs-tr-join:hover { filter: brightness(1.08); transform: translateY(-1px); }

/* Bottom social pills flanking the player — quiet neutral chrome pills
   (glass/frosted fills are a rejected treatment). */
.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: #161618;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: #fff;
  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; }
}

/* ── Index of artists — masthead + sharp poster grid (the app's Breaking-now /
   tastemaker poster language: 0-radius full-bleed photo + bottom scrim + bold
   name inside the frame). ── */
/* 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: kicker title + underline text tabs riding the full-bleed hairline
   (the ONE toggle treatment, same as the app's profile/activity tabs). */
.cs-disc-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(14px, 1.6vw, 20px);
  margin-bottom: clamp(14px, 1.6vw, 24px);
  border-bottom: 1px solid var(--hair);
}
.cs-disc-title {
  font-weight: 700;
  font-size: clamp(22px, 2.3vw, 34px);
  line-height: 1;
  letter-spacing: -0.025em;
  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);
}

/* Artists / Tastemakers toggle — underline text tabs on the masthead hairline.
   Pure-CSS via the hidden radios; the active tab is white with a 2px white
   underline (the app's profile-tab-bar treatment), inactive tabs recede. */
.cs-view-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.cs-tabs { display: flex; gap: 26px; }
/* No-tastemakers fallback (no tab row): keep the title off the hairline. */
.cs-disc-head:not(:has(.cs-tabs)) { padding-bottom: clamp(12px, 1.3vw, 18px); }
.cs-tword {
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--faint);
  padding-bottom: 12px;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px; /* underline rides the masthead hairline */
  transition: color 0.2s ease, border-color 0.2s ease;
}
.cs-tword:hover { color: var(--mute); }
#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: #fff;
  border-color: #fff;
}

/* 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%; /* circles = people */
  object-fit: cover;
  flex: none;
  background: #1a1a1a;
}
.cs-person-img-fb {
  display: grid;
  place-items: center;
  font-size: 17px;
  font-weight: 700;
  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-weight: 700;
  font-size: clamp(16px, 1.2vw, 19px);
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: var(--ink);
  white-space: nowrap;
}
/* Accent stays scarce — a red number repeated down every row reads as a wall,
   so the stat leads in white. */
.cs-person-stat { font-size: 12px; color: var(--mute); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cs-person-stat b { font-weight: 700; color: var(--ink); }
/* 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; }
/* White bars, not accent — the waveform repeats down every row. */
.cs-person-eq i {
  width: 3px;
  background: rgba(255, 255, 255, 0.85);
  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: #1a1a1a;
  color: var(--mute);
  font-weight: 700;
  font-size: clamp(38px, 4vw, 64px);
}

.cs-tile { display: block; min-width: 0; text-decoration: none; color: inherit; -webkit-tap-highlight-color: transparent; }

/* The poster: sharp (0-radius) full-bleed photo + bottom scrim + bold name
   inside the frame — the app's one card language (Breaking-now artist tiles,
   tastemaker posters). Posters are sharp; rounding is for people + controls. */
.cs-tile-media {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: 0;
  background: #1a1a1a;
}
.cs-tile-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Bottom scrim so the name reads on any photo — the scrim-over-photo
   treatment is the one sanctioned translucency. */
.cs-tile-scrim {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 45%;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.8));
  pointer-events: none;
}
.cs-tile-overlay {
  position: absolute;
  left: 12px; right: 12px; bottom: 11px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.cs-tile-name {
  font-weight: 700;
  font-size: clamp(15px, 1.15vw, 19px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The discovery credit under the name, inside the poster. */
.cs-tile-disc {
  font-size: 11.5px;
  line-height: 1.25;
  letter-spacing: -0.005em;
  color: rgba(255, 255, 255, 0.8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cs-tile-disc strong { font-weight: 600; color: #fff; }
.cs-tile-disc em { font-style: normal; color: rgba(255, 255, 255, 0.45); }

/* 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 — two columns. Left: the thesis + Instagram / Email /
   Terms. Right: Get the app. Flat black storey separated by a hairline. */
.cs-foot {
  background: #000;
  color: #fff;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  /* 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: #fff;
}
.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: #fff;
  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(255, 255, 255, 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: #ff3724;
  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: filter 0.2s ease;
}
.cs-foot-cta:hover { filter: brightness(1.08); }
@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. Pure-black canvas — the imagery carries the colour. ── */
.cs-app-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: #000;
}
.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: #fff;
}

/* 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: #1a1a1a 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: #1a1a1a 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: 0; }     /* songs = sharp art tiles */
.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: 0;
  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) {
  /* The App section sits flush against the discovery section — the beat's own
     top padding clears the headline, so no top margin. */
  .hiw { background: #000; }
  .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;
  }
}
