/* ================================================================
   FOR YOU — the card around the glow slider.

   One language with the slider: the same spring, the same colour
   (--fy-tint is albumColor, exactly what paints the pill), and light
   rather than motion doing most of the work. Transform, scale,
   translate and opacity only; nothing here delays a tap or the audio.
   ================================================================ */

/* ---- depth between songs ----------------------------------------------
   A scroll-driven timeline on each card, run by the compositor: the sleeve
   comes up out of the dark as its card arrives and sinks as it leaves, the
   words travel a little further than the art, and the bed fades so two
   records' colours never meet at a hard line mid-swipe. No JS, no scroll
   listener. Browsers without view timelines get the old hard snap. */
@supports (animation-timeline: view()) {
  .fy-card { view-timeline: --fy block; }
  .fy-art-wrap { animation: fyDepthArt linear both; animation-timeline: --fy; }
  .fy-meta     { animation: fyDepthMeta linear both; animation-timeline: --fy; }
  .fy-bed-wrap { animation: fyDepthBed linear both; animation-timeline: --fy; }
}
/* `scale`/`translate`, never `transform`: these hold for ever, and the press
   and the drag below own `transform` on the sleeve itself. */
@keyframes fyDepthArt  { 0% { scale: .84; opacity: .3; } 50% { scale: 1; opacity: 1; } 100% { scale: .84; opacity: .3; } }
@keyframes fyDepthMeta { 0% { translate: 0 56px; opacity: 0; } 50% { translate: 0 0; opacity: 1; } 100% { translate: 0 -56px; opacity: 0; } }
@keyframes fyDepthBed  { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }

/* No blank square while a sleeve decodes. */
.fy-art { background: var(--surface-2, #1a1816); }

/* ---- the halo: the slider's light, cast on the record -------------------
   Behind the sleeve, in the score's colour, brighter the higher the score.
   Dragging lifts it and leans the sleeve forward a touch, so the record
   reacts to the verdict being formed under it. */
.fy-art-wrap::before {
  content: ''; position: absolute; inset: -16%; z-index: -1; pointer-events: none; border-radius: 50%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--fy-tint) 60%, transparent), transparent);
  opacity: calc(.12 + var(--fy-v, .7) * .22);
  transition: opacity 320ms ease;
}
.fy-card:has(.gs-drag) .fy-art-wrap::before { opacity: calc(.25 + var(--fy-v, .7) * .6); }
.fy-art { transition: transform 520ms var(--gs-spring, var(--ease)), box-shadow 320ms ease; }
.fy-card:has(.gs-drag) .fy-art {
  transform: scale(calc(.985 + var(--fy-v, .7) * .045));
  box-shadow: 0 26px 70px rgba(0,0,0,.6), 0 0 0 1px color-mix(in srgb, var(--fy-tint) 45%, transparent);
  transition: transform 160ms ease-out, box-shadow 200ms ease;
}

/* ---- the clip, as a line ------------------------------------------------
   Thirty seconds drawn along the foot of the sleeve. Started by the same
   class that starts the equaliser, so it can only run while audio does. */
.fy-art::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; z-index: 4; pointer-events: none;
  background: linear-gradient(90deg, rgba(255,245,235,.55), #fff);
  box-shadow: 0 0 10px rgba(255,255,255,.5);
  transform: scaleX(0); transform-origin: left center; opacity: 0;
}
.fy-card.is-playing .fy-art::before { opacity: 1; animation: fyClip 30s linear forwards; }
@keyframes fyClip { to { transform: scaleX(1); } }

/* ---- the verdict ---------------------------------------------------------- */
/* The sleeve takes the press, then springs past rest and settles. */
.fy-card.fy-commit .fy-art { animation: fyPress 560ms var(--gs-spring, ease); }
@keyframes fyPress { 0% { transform: scale(1); } 28% { transform: scale(.955); } 70% { transform: scale(1.03); } 100% { transform: scale(1); } }
/* The halo flares once and returns to the score's resting glow. */
.fy-card.fy-commit .fy-art-wrap::before { animation: fyFlare 760ms ease-out; }
@keyframes fyFlare { from { opacity: 1; transform: scale(1.18); } }
/* And the tray answers the slider it holds. */
.fy-card.fy-commit .fy-rate { animation: fyTray 700ms ease-out; }
@keyframes fyTray { from { border-color: var(--fy-tint); box-shadow: 0 0 0 1px var(--fy-tint), 0 0 30px color-mix(in srgb, var(--fy-tint) 55%, transparent); } }

/* Rate lights in the score's colour while pressing it would change something. */
.fy-save { transition: box-shadow 260ms ease, transform 160ms var(--ease), filter 200ms ease; }
.fy-save.ready { box-shadow: 0 0 0 1px color-mix(in srgb, var(--fy-tint) 80%, transparent), 0 0 22px color-mix(in srgb, var(--fy-tint) 55%, transparent); }
.fy-save:active { transform: scale(.95); }

/* ---- desktop: the sleeve answers a pointer ------------------------------ */
@media (hover: hover) and (pointer: fine) {
  .fy-art:hover { transform: translateY(-4px) scale(1.012); box-shadow: 0 34px 80px rgba(0,0,0,.65), 0 0 0 1px rgba(255,245,235,.12); }
  .fy-card:not(.is-playing) .fy-art:hover .fy-cue { opacity: .9; transform: none; }
  .fy-title:hover, .fy-alb:hover { text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--fy-tint) 70%, transparent); text-underline-offset: 4px; }
}

/* ---- reduced motion: light stays, movement goes ------------------------ */
@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="full"]) .fy-art-wrap,
  html:not([data-motion="full"]) .fy-meta,
  html:not([data-motion="full"]) .fy-bed-wrap,
    html:not([data-motion="full"]) .fy-card.fy-commit .fy-art,
  html:not([data-motion="full"]) .fy-card.fy-commit .fy-art-wrap::before,
  html:not([data-motion="full"]) .fy-card.fy-commit .fy-rate { animation: none; }
  html:not([data-motion="full"]) .fy-card .fy-art { transform: none; }
  html:not([data-motion="full"]) .fy-card.is-playing .fy-art::before { animation: none; opacity: 0; }
}
html[data-motion="none"] .fy-art-wrap, html[data-motion="none"] .fy-meta, html[data-motion="none"] .fy-bed-wrap,
html[data-motion="none"] .fy-card.fy-commit .fy-art,
html[data-motion="none"] .fy-card.fy-commit .fy-art-wrap::before, html[data-motion="none"] .fy-card.fy-commit .fy-rate { animation: none; }
html[data-motion="none"] .fy-card .fy-art { transform: none; }
html[data-motion="none"] .fy-card.is-playing .fy-art::before { animation: none; opacity: 0; }

/* A rated sleeve keeps a thin ring in its score's colour — the old lime
   outline said "done" without saying what; the number lives on the Rate
   button ("Rated 8"), not stamped over the artwork. */
.fy-card.is-rated .fy-art { outline: 2px solid color-mix(in srgb, var(--fy-tint) 65%, transparent); outline-offset: 3px; }

/* ---- the fire: the record lights the room --------------------------------
   A second copy of the sleeve sits BEHIND the art, blurred hard and saturated,
   so the glow is made of the album's own colours rather than a colour guessed
   for it. While the clip plays it turns slowly and breathes; a blurred image
   rotating reads as moving heat, not a spinning picture. Transform/opacity
   only, so the compositor carries it. The score halo (::before, the slider's
   colour) sits over it: the record's light, tinted by your verdict. */
.fy-glow {
  position: absolute; left: -22%; top: -22%; z-index: -2; pointer-events: none;
  width: 144%; height: 144%;
  object-fit: cover; border-radius: 50%;
  filter: blur(38px) saturate(1.9) brightness(1.15);
  opacity: .7;
  transition: opacity 600ms ease, transform 900ms var(--gs-spring, ease);
  will-change: transform, opacity;
}
.fy-card.is-playing .fy-glow { opacity: .9; animation: fyEmber 14s linear infinite, fyBreathe 3.6s ease-in-out infinite; }
.fy-card:has(.gs-drag) .fy-glow { opacity: calc(.7 + var(--fy-v, .7) * .3); transform: scale(calc(1 + var(--fy-v, .7) * .12)); }
/* rotate and scale as independent properties, so the two animations and the
   drag's transform never replace one another (trap 2). */
@keyframes fyEmber { to { rotate: 360deg; } }
@keyframes fyBreathe { 0%, 100% { scale: 1; } 50% { scale: 1.09; } }

/* The bed: more of the album's colour, heat rising from the foot in the
   score's colour, and a vignette so the words still read. */
.fy-bed { filter: blur(52px) saturate(1.65) brightness(.5); }
.fy-bed-wrap::before {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(120% 60% at 50% 108%, color-mix(in srgb, var(--fy-tint) 38%, transparent), transparent 60%),
    radial-gradient(80% 50% at 50% 42%, rgba(255,140,60,.10), transparent 70%);
  mix-blend-mode: screen; opacity: .55; transition: opacity 400ms ease;
}
.fy-card.is-playing .fy-bed-wrap::before { opacity: .85; }
.fy-card:has(.gs-drag) .fy-bed-wrap::before { opacity: calc(.6 + var(--fy-v, .7) * .4); }
.fy-bed-wrap::after { z-index: 2; background:
  radial-gradient(140% 90% at 50% 45%, transparent 40%, rgba(4,3,3,.55)),
  linear-gradient(to bottom, rgba(6,5,5,.5), rgba(6,5,5,.08) 38%, rgba(6,5,5,.8)); }

/* The words and the tray pick up the same light. */
.fy-why { color: color-mix(in srgb, var(--fy-tint) 70%, #fff); }
.fy-eq i { background: color-mix(in srgb, var(--fy-tint) 75%, #fff); box-shadow: 0 0 8px color-mix(in srgb, var(--fy-tint) 60%, transparent); }
.fy-rate { transition: border-color 300ms ease, box-shadow 300ms ease; }
.fy-card:has(.gs-drag) .fy-rate { border-color: color-mix(in srgb, var(--fy-tint) 55%, transparent); box-shadow: 0 0 26px color-mix(in srgb, var(--fy-tint) 28%, transparent); }

@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="full"]) .fy-card.is-playing .fy-glow { animation: none; }
}
html[data-motion="none"] .fy-card.is-playing .fy-glow { animation: none; }
