/* ==========================================================================
   TuneDance frontend — the track wall.

   Copied from the funnel's audio-maker page (cenematic/audio-maker,
   styles/samples.css plus scripts/samples.js and sample-tints.js) rather than
   rebuilt. It is in production there, the ten cards are the same ten, and a
   second implementation of a seekable player grid would only drift.

   Renamed samples -> tracks throughout. This page already has a .samples
   section, the player rows further up, and reusing the block name would have
   had two unrelated components fighting over the same selectors. Its generic
   `.container` also became `.tracks__container`, since this page has no such
   global.

   Hover states removed: the thumbnail zoom and the play-button hover are gone
   outright, and the progress bar and time chip now key off the playing state
   alone instead of the pointer.
   ========================================================================== */

.tracks {
  position: relative;
  background: #161830;
  padding-block: 6vi;
  overflow: hidden;
}

.tracks__visualizer {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.tracks__container {
  position: relative;
  z-index: 1;
  width: min(100% - 2rem, 1216px);
  margin-inline: auto;
}

.tracks__header {
  display: grid;
  place-items: center;
  gap: 14px;
  text-align: center;
  padding-inline: 16px;
  padding-block-end: 4vi;
}

.tracks__title {
  font-weight: 800;
  font-size: clamp(1.625rem, 0.9rem + 2.7vw, 3.25rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: #fff;
  max-inline-size: 900px;
}

/* "Mindblowing" in the electric gradient — the bright pops finally get a
   dark ground to shine on */
.tracks__title-accent {
  background: linear-gradient(92deg, var(--pop-green) 0%, var(--pop-blue) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

.tracks__subtitle {
  font-size: clamp(0.95rem, 0.6rem + 0.7vw, 1.25rem);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.6);
  max-inline-size: 760px;
}

.tracks__grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  row-gap: clamp(24px, 2.4vw, 40px);
  column-gap: clamp(14px, 1.4vw, 22px);
}

.tracks__card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: opacity 0.3s ease;
}

/* While one card plays, the rest step back — gently, so the section
   still reads as fully alive */
.tracks__grid:has(.tracks__card.is-playing) .tracks__card:not(.is-playing) {
  opacity: 0.82;
}

/* The playing card's art gets the emerald ring */
.tracks__card.is-playing .tracks__thumb {
  box-shadow: 0 0 0 3px var(--band-green), 0 8px 24px rgba(0, 0, 0, 0.08);
}

.tracks__thumb {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: 18px;
  overflow: hidden;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  cursor: pointer;
}

.tracks__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.3s ease;
}

/* Frosted white disc — readable on any artwork; solid emerald while playing */
.tracks__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: none;
  border-radius: 50%;
  color: #12141f;
  cursor: pointer;
  transition: transform 0.15s, background 0.15s, color 0.15s;
}

.tracks__card.is-playing .tracks__play {
  background: var(--band-green);
  color: #fff;
}

.tracks__play svg {
  width: 28px;
  height: 28px;
  fill: currentColor;
}

.tracks__play .tracks__icon-pause {
  display: none;
}

.tracks__card.is-playing .tracks__icon-play {
  display: none;
}

.tracks__card.is-playing .tracks__icon-pause {
  display: block;
}

/* Floating scrub pill, inset from the card edges so the knob never clips */
.tracks__progress {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 12px;
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s, height 0.15s ease;
}

.tracks__card.is-playing .tracks__progress {
  opacity: 1;
}

/* Chip rises out of the way when the scrub pill appears, settles back after */
.tracks__card.is-playing .tracks__time {
  bottom: 30px;
}

.tracks__progress-fill {
  position: relative;
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--pop-green);
  pointer-events: none;
}

/* Scrubber handle at the playhead — makes the bar read as seekable */
.tracks__progress-fill::after {
  content: "";
  position: absolute;
  right: -7px;
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--pop-green);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.4);
}

/* Time chip — duration at rest, remaining countdown while playing */
.tracks__time {
  position: absolute;
  right: 12px;
  bottom: 12px;
  transition: bottom 0.2s ease;
  padding: 3px 8px;
  border-radius: 8px;
  background: rgba(10, 10, 10, 0.72);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

.tracks__name {
  font-weight: 600;
  font-size: clamp(1rem, 0.65rem + 0.55vw, 1.125rem);
  letter-spacing: -0.005em;
  color: #fff;
  padding-inline: 4px;
  margin-block-start: 4px;
}

.tracks__tags {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-inline: 4px;
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

.tracks__tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.tracks__tag--type-music::before,
.tracks__tag--type-soundtrack::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
}

.tracks__tag--type-music::before {
  background: #8b5cf6;
  box-shadow: 0 0 10px rgba(139, 92, 246, 0.6);
}

.tracks__tag--type-soundtrack::before {
  background: #34d4b7;
  box-shadow: 0 0 10px rgba(52, 212, 183, 0.6);
}

.tracks__tag--genre::before {
  content: "·";
  margin-inline-end: 2px;
  color: rgba(255, 255, 255, 0.35);
}

@media (max-width: 1100px) {
  .tracks__grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 860px) {
  .tracks__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .tracks__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .tracks__play {
    width: 52px;
    height: 52px;
  }
}

/* --- "Made with TuneDance" band ------------------------------------------ */

/* Full-bleed yellow band flush to the section's bottom edge. The section has
   padding-block: 6vi, so the negative bottom margin cancels the lower half
   and the band sits hard against the edge. */
.tracks__made {
  /* Deep violet, a darker relative of this section's own accent (#8b5cf6, the
     music tag dots). The yellow belonged to neither the navy above nor the
     ash below. */
  --band: #472c9f;

  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(8px, 1vw, 14px);
  margin: 6vi 0 -6vi;
  padding: clamp(8px, 1.1vw, 14px) 24px;
  background: var(--band);
  color: #fff;
  font-size: clamp(15px, 1.8vw, 22px);
  font-weight: 700;
  letter-spacing: -0.01em;
  text-align: center;
}

.tracks__made strong {
  position: relative;
  display: inline-block;
  padding: 0 0.08em 0.12em;
  background: linear-gradient(92deg, #7cf0ac 0%, #54e6cf 48%, #7ed8ff 100%);
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  font-weight: 900;
  filter: drop-shadow(0 0 9px rgba(84, 230, 207, 0.28));
}

.tracks__made strong::before {
  content: attr(data-text);
  position: absolute;
  z-index: 1;
  inset: 0;
  background:
    linear-gradient(
      110deg,
      transparent 27%,
      rgba(255, 255, 255, 0.28) 39%,
      #fff 49%,
      #fff 53%,
      rgba(255, 255, 255, 0.3) 63%,
      transparent 75%
    )
    180% 0 / 250% 100% no-repeat;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.65));
  opacity: 0;
  pointer-events: none;
}

.tracks__made.is-shining strong::before {
  animation: samples-made-shine 3s cubic-bezier(0.22, 0.7, 0.28, 1) infinite;
}

@keyframes samples-made-shine {
  0% {
    background-position: 180% 0;
    opacity: 0;
  }
  12% { opacity: 1; }
  88% { opacity: 1; }
  100% {
    background-position: -180% 0;
    opacity: 0;
  }
}

.tracks__made strong::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: -0.05em;
  left: 0;
  height: 0.12em;
  border-radius: 999px;
  background: linear-gradient(90deg, #7cf0ac, #54e6cf 50%, #7ed8ff);
  box-shadow: 0 0 10px rgba(84, 230, 207, 0.5);
  transform: rotate(-1deg);
  z-index: 2;
}

@media (prefers-reduced-motion: reduce) {
  .tracks__made.is-shining strong::before {
    animation: none;
  }
}

/* The background-less mark is portrait (1689x2294). Height drives it and the
   width follows, otherwise a square box squashes it. No radius — there is no
   longer a tile behind the note to round off. */
.tracks__made img {
  width: auto;
  height: clamp(22px, 2.6vw, 32px);
}

/* Concave top corners. The fill is the region OUTSIDE an arc centred on the
   fillet's inner-TOP corner, not the quarter-disc beside the edge — filling the
   disc gives a convex bulge and leaves the outer corner empty. This way the
   yellow reaches the section's edge at full height and coves inward. */
.tracks__made::before,
.tracks__made::after {
  --r: clamp(12px, 1.8vw, 24px);
  content: "";
  position: absolute;
  bottom: 100%;
  width: var(--r);
  height: var(--r);
  pointer-events: none;
}

.tracks__made::before {
  left: 0;
  background: radial-gradient(circle var(--r) at 100% 0, transparent 0 var(--r), var(--band) var(--r));
}

.tracks__made::after {
  right: 0;
  background: radial-gradient(circle var(--r) at 0 0, transparent 0 var(--r), var(--band) var(--r));
}

/* --- now-playing wash ----------------------------------------------------

   While a track is playing the section takes on that artwork's colour and a
   heavily blurred copy of the art itself, the way Apple Music and Spotify do.

   The colour is a background-COLOR shaped by a mask, not a gradient. That
   matters: background-image never interpolates, so building the falloff as a
   gradient made every track change snap. As a masked colour it cross-fades.

   The artwork needs two layers for the same reason — background-image cannot
   transition, so the incoming art is loaded onto the idle layer and the two
   are cross-faded.

   Legibility is handled by the scrim, not by dulling the colour. Without one,
   the lightest artwork drove the subtitle to 2.97:1, under the 4.5:1 AA floor;
   dimming the wash enough to fix that drained it. The scrim sits over the art
   and under the copy, exactly where the heading and subtitle are, so the wash
   can stay saturated.

   The wash is present only while a track is actually playing: it fades out on
   pause as well as at the end, over 0.8s so it reads as a settle, not a flash.

   Colours come from scripts/sample-tints.js, resolved offline by
   scripts/generate_sample_tints.py. Nothing is sampled in the browser. */

.tracks__wash {
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0;
  pointer-events: none;
  background-color: rgba(var(--tint, 60, 155, 59), 0.5);
  /* Shape of the falloff, held still while the colour underneath changes.
     It bottoms out at 0.52 rather than transparent so the wash reaches the
     foot of the section — stopping short left the lower half on bare navy. */
  -webkit-mask-image: radial-gradient(135% 105% at 50% 0%, #000 0%, rgba(0,0,0,0.72) 48%, rgba(0,0,0,0.52) 100%);
  mask-image: radial-gradient(135% 105% at 50% 0%, #000 0%, rgba(0,0,0,0.72) 48%, rgba(0,0,0,0.52) 100%);
  transition: opacity 0.8s ease, background-color 0.8s ease;
}

.tracks.is-washed .tracks__wash { opacity: 1; }

/* the artwork, blurred past recognition and overscaled so no edge shows */
/* Anchored to the top and faded out downward, the way a now-playing view
   carries the cover behind its header. Full-bleed at an even opacity read as
   noise; concentrated up top it reads as the artwork. Blurred less hard than
   before so the shapes and colour of the cover survive, and masked so it never
   competes with the grid below. */
.tracks__art {
  position: absolute;
  top: -14%;
  right: -12%;
  left: -12%;
  height: 66%;
  opacity: 0;
  background-size: cover;
  background-position: center 32%;
  filter: blur(34px) saturate(1.45);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,0.72) 42%, rgba(0,0,0,0.28) 72%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,0.72) 42%, rgba(0,0,0,0.28) 72%, transparent 100%);
  transition: opacity 0.8s ease;
}

.tracks__art.is-on { opacity: 0.58; }

/* Scrim over the art, under the copy. Kept light on purpose: it paints above
   the artwork layers, so a heavy one erases the cover it is meant to sit over.
   Just enough to hold the heading and subtitle legible. */
.tracks__wash::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(10, 12, 26, 0.34) 0%, rgba(10, 12, 26, 0.1) 38%, transparent 62%);
}

@media (prefers-reduced-motion: reduce) {
  .tracks__wash,
  .tracks__art { transition: none; }
}

/* Muted copy is tuned for the flat #161830 base. Over a bright wash — the
   worst case is Clear Horizon's orange — the subtitle fell to 3.64:1 and the
   tag row to 3.32:1, both under the 4.5:1 AA floor for body-size text. The
   text is lifted rather than the wash dulled, so the colour keeps its punch. */
.tracks.is-washed .tracks__subtitle { color: rgba(255, 255, 255, 0.88); }
.tracks.is-washed .tracks__tags { color: rgba(255, 255, 255, 0.82); }
