/* ==========================================================================
   MP-Beats — persistent player bar + Now Playing sheet
   ========================================================================== */

.player-root {
  position: fixed;
  inset: auto 0 0 0;
  z-index: var(--z-player);
  pointer-events: none;
}

.player-root > * {
  pointer-events: auto;
}

.player-bar {
  position: relative;
  height: var(--player-h);
  background: var(--glass-thick);
  backdrop-filter: blur(var(--glass-blur-heavy)) saturate(1.4);
  -webkit-backdrop-filter: blur(var(--glass-blur-heavy)) saturate(1.4);
  border-top: 1px solid var(--border-default);
  box-shadow: 0 -8px 40px rgb(0 0 0 / 0.45);
  animation: player-in var(--dur-slow) var(--ease-out) both;
}

@keyframes player-in {
  from { transform: translateY(100%); }
}

.player-bar[hidden] {
  display: none;
}

/* Hairline progress across the very top of the bar — always readable at a glance */
.player-bar__progress-mini {
  position: absolute;
  top: -1px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--surface-active);
  overflow: hidden;
}

.player-bar__progress-fill {
  display: block;
  height: 100%;
  background: var(--gradient-ember);
  transform-origin: left;
  transform: scaleX(0);
  transition: transform 120ms linear;
}

.player-bar__inner {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) minmax(0, 2.2fr) minmax(180px, 1fr);
  align-items: center;
  gap: var(--space-5);
  height: 100%;
  max-width: var(--content-wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ---- Track identity ---------------------------------------------------- */

.player-bar__track {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.player-bar__art {
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-base) var(--ease-out);
}

.player-bar__art:hover {
  transform: scale(1.05);
}

.player-bar__art .art {
  border-radius: 0;
}

.player-bar__text {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.player-bar__title-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.player-bar__title {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
  transition: color var(--dur-fast) var(--ease-soft);
}

.player-bar__title:hover {
  color: var(--accent-text);
}

.player-bar__meta {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}

/* ---- Centre transport --------------------------------------------------- */

.player-bar__center {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
  width: 100%;
}

.player-bar__controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.player-bar__play {
  --play-size: 38px;
}

.player-bar__scrub {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
}

.player-bar__wave {
  flex: 1 1 auto;
  min-width: 0;
}

.player-bar__time {
  flex: 0 0 auto;
  font-size: var(--text-2xs);
  color: var(--text-tertiary);
  min-width: 34px;
  text-align: center;
}

/* ---- Right cluster ------------------------------------------------------ */

.player-bar__right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
}

.player-bar__volume {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

/* Animating `width` 0 → 80px relaid out the player bar's entire right cluster
   on every frame of a 240ms transition — 60 forced layouts, while audio
   decoding is already competing for the main thread. The reveal is now
   compositor-only: the track keeps a constant 80px box and scales in from its
   right edge, so nothing around it ever reflows.

   The space is reserved rather than animated, which means it has to be space
   the bar actually has. Below 1100px the right cluster (Buy · volume · queue ·
   expand) has no room to spare, so the track collapses to zero and the mute
   button stands alone — the control is never lost, only its fine adjustment. */
.player-bar__volume-slider {
  appearance: none;
  width: 0;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--surface-active);
  opacity: 0;
  pointer-events: none;
  cursor: pointer;
}

@media (min-width: 1100px) {
  .player-bar__volume-slider {
    width: 80px;
    transform: scaleX(0);
    transform-origin: right center;
    transition:
      transform var(--dur-base) var(--ease-out),
      opacity var(--dur-base) var(--ease-soft);
  }

  .player-bar__volume:hover .player-bar__volume-slider,
  .player-bar__volume:focus-within .player-bar__volume-slider {
    transform: scaleX(1);
    opacity: 1;
    pointer-events: auto;
  }
}

.player-bar__volume-slider::-webkit-slider-thumb {
  appearance: none;
  width: 12px;
  height: 12px;
  border-radius: var(--radius-circle);
  background: var(--text-primary);
  box-shadow: var(--shadow-xs);
}

.player-bar__volume-slider::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: none;
  border-radius: var(--radius-circle);
  background: var(--text-primary);
}

.player-bar__mobile-actions {
  display: none;
}

.player-bar__error {
  position: absolute;
  inset: auto 0 100% 0;
  padding: var(--space-2) var(--gutter);
  background: var(--danger-soft);
  border-top: 1px solid color-mix(in oklab, var(--danger) 30%, transparent);
  color: var(--danger);
  font-size: var(--text-xs);
  text-align: center;
}

/* ---- Mobile mini bar ---------------------------------------------------- */

@media (max-width: 860px) {
  .player-bar {
    height: var(--player-h-mobile);
    /* Sits directly above the tab bar */
    margin-bottom: calc(var(--tabbar-h) + var(--safe-b));
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    cursor: pointer;
  }

  .player-bar__inner {
    grid-template-columns: 1fr auto;
    gap: var(--space-3);
    padding-inline: var(--space-3);
  }

  .player-bar__center,
  .player-bar__right {
    display: none;
  }

  .player-bar__art {
    width: 44px;
    height: 44px;
  }

  .player-bar__mobile-actions {
    display: flex;
    align-items: center;
    gap: var(--space-1);
  }

  /* Only play/pause and next survive at this width */
  .player-bar.is-mobile .player-bar__mobile-actions {
    display: flex;
  }
}

/* ==========================================================================
   Now Playing sheet (mobile full screen)
   ========================================================================== */

.now-playing {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  display: flex;
  flex-direction: column;
  background: var(--surface-void);
  transform: translateY(100%);
  transition: transform var(--dur-slow) var(--ease-out);
  overflow: hidden;
}

.now-playing.is-open {
  transform: translateY(0);
}

.now-playing[hidden] {
  display: none;
}

/* Blurred, scaled artwork behind everything — the classic music-app treatment */
.now-playing__backdrop {
  position: absolute;
  inset: -15%;
  z-index: 0;
  filter: blur(64px) saturate(1.7);
  opacity: 0.55;
  transform: scale(1.2);
  pointer-events: none;
}

.now-playing__backdrop .art {
  width: 100%;
  height: 100%;
  border-radius: 0;
}

.now-playing__backdrop::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgb(8 9 13 / 0.55), rgb(8 9 13 / 0.92));
}

.now-playing__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  height: 100%;
  padding: calc(var(--safe-t) + var(--space-4)) var(--space-6) calc(var(--safe-b) + var(--space-6));
  overflow-y: auto;
}

.now-playing__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex: 0 0 auto;
}

.now-playing__art {
  flex: 0 1 auto;
  width: min(78vw, 340px);
  margin-inline: auto;
  aspect-ratio: 1;
  border-radius: var(--radius-xl);
  overflow: hidden;
  box-shadow: var(--shadow-xl);
  animation: art-in var(--dur-slower) var(--ease-spring) both;
}

@keyframes art-in {
  from { opacity: 0; transform: scale(0.9) translateY(20px); }
}

.now-playing__art .art {
  border-radius: 0;
}

.now-playing__info {
  text-align: center;
  flex: 0 0 auto;
}

.now-playing__title {
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-display);
}

.now-playing__meta {
  margin-top: var(--space-1);
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.now-playing__wave {
  flex: 0 0 auto;
}

.now-playing__times {
  display: flex;
  justify-content: space-between;
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  margin-top: calc(var(--space-3) * -1);
}

.now-playing__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
  flex: 0 0 auto;
}

.now-playing__controls .icon-btn {
  width: 46px;
  height: 46px;
}

.now-playing__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: auto;
  flex: 0 0 auto;
}

@media (min-width: 861px) {
  .now-playing {
    display: none;
  }
}

/* ==========================================================================
   Waveform
   ========================================================================== */

.waveform {
  position: relative;
  width: 100%;
  height: var(--wave-h, 64px);
  cursor: pointer;
  touch-action: none;
  border-radius: var(--radius-xs);
}

.waveform[role='img'] {
  cursor: default;
}

.waveform__canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.waveform:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.waveform__tip {
  position: absolute;
  bottom: calc(100% + 6px);
  left: var(--tip-x, 0);
  transform: translateX(-50%);
  padding: 2px var(--space-2);
  border-radius: var(--radius-xs);
  background: var(--surface-overlay);
  border: 1px solid var(--border-default);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  color: var(--text-primary);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-soft);
  z-index: var(--z-raised);
}

.waveform.is-hovering .waveform__tip {
  opacity: 1;
}

/* An ember glow under the waveform while it is the playing track.
   It is driven by --wave-level, which the analyser writes once per frame
   (0–1) on the current track's element, so the glow breathes with the audio
   instead of sitting at a fixed opacity that responds to nothing. The
   fallback of 0 in the var() means an element nobody is writing to simply
   renders the quiet resting state — no JS, no glow, no broken look. */
.waveform.is-playing::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(
    calc(50% + var(--wave-level, 0) * 30%) 100% at 50% 100%,
    var(--accent-soft),
    transparent 70%
  );
  opacity: calc(0.35 + var(--wave-level, 0) * 0.65);
}

/* The scrub affordance. There is otherwise nothing on this element to say it
   can be grabbed — it looks like a picture of a waveform, not a control. */
.waveform:not([role='img']):hover {
  --wave-idle: rgb(255 255 255 / 0.3);
}

.waveform.is-scrubbing {
  cursor: grabbing;
}

.waveform.is-scrubbing .waveform__tip {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .waveform.is-playing::after {
    opacity: 0.35;
  }
}

/* ==========================================================================
   Queue drawer
   ========================================================================== */

.queue-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.queue-item__btn {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  text-align: left;
  transition:
    background-color var(--dur-fast) var(--ease-soft),
    transform var(--dur-instant) var(--ease-out);
}

.queue-item__btn:hover {
  background: var(--surface-hover);
}

.queue-item.is-current .queue-item__btn {
  background: var(--accent-softer);
}

.queue-item__index {
  flex: 0 0 24px;
  display: grid;
  place-items: center;
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-quiet);
}

.queue-item__art {
  flex: 0 0 40px;
  width: 40px;
  border-radius: var(--radius-xs);
  overflow: hidden;
}

.queue-item__info {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.queue-item__title {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-primary);
}

.queue-item__meta {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}

/* ==========================================================================
   Drawer shell (used by queue + cart)
   ========================================================================== */

.overlay--drawer {
  place-items: stretch;
  justify-items: end;
  padding: 0;
}

.drawer {
  display: flex;
  flex-direction: column;
  width: min(420px, 100vw);
  height: 100%;
  background: var(--surface-base);
  border-left: 1px solid var(--border-default);
  box-shadow: var(--shadow-xl);
  animation: drawer-in var(--dur-slow) var(--ease-out) both;
}

@keyframes drawer-in {
  from { transform: translateX(100%); }
}

.drawer.is-leaving {
  animation: drawer-out var(--dur-base) var(--ease-soft) both;
}

@keyframes drawer-out {
  to { transform: translateX(100%); }
}

.drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
  flex: 0 0 auto;
}

.drawer__body {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-5);
  padding-bottom: calc(var(--space-5) + var(--safe-b));
}

@media (max-width: 640px) {
  .overlay--drawer {
    justify-items: stretch;
    align-items: end;
  }
  .drawer {
    width: 100%;
    height: min(88svh, 100%);
    border-left: none;
    border-top: 1px solid var(--border-default);
    border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
    animation: sheet-in var(--dur-slow) var(--ease-out) both;
  }
  .drawer.is-leaving {
    animation: sheet-out var(--dur-base) var(--ease-soft) both;
  }
  @keyframes sheet-out {
    to { transform: translateY(100%); }
  }
}

/* ==========================================================================
   Shared small controls
   ========================================================================== */

.icon-btn {
  display: grid;
  place-items: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-circle);
  color: var(--text-secondary);
  transition: var(--transition-colors), transform var(--dur-instant) var(--ease-out);
}

.icon-btn:hover:not(:disabled) {
  background: var(--glass-medium);
  color: var(--text-primary);
}

.icon-btn:active:not(:disabled) {
  transform: scale(0.92);
}

/* The mini-bar's expand chevron is the ONLY visible control on a phone, so it
   gets the platform minimum regardless of the icon inside it. */
@media (pointer: coarse) {
  .player-bar__mobile-actions .icon-btn {
    width: var(--tap-min);
    height: var(--tap-min);
  }
}

.icon-btn:disabled {
  opacity: 0.35;
  pointer-events: none;
}

.icon-btn.is-active {
  color: var(--accent-text);
}

.fav-btn.is-active {
  color: var(--danger);
}

.fav-btn.is-bumping {
  animation: fav-bump var(--dur-slow) var(--ease-spring);
}

@keyframes fav-bump {
  40% { transform: scale(1.32); }
  70% { transform: scale(0.94); }
  100% { transform: scale(1); }
}

.play-btn__spinner {
  width: 16px;
  height: 16px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: var(--radius-circle);
  animation: spin 0.6s linear infinite;
}

.spinner {
  display: inline-block;
  width: var(--spinner-size, 18px);
  height: var(--spinner-size, 18px);
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  border-radius: var(--radius-circle);
  animation: spin 0.7s linear infinite;
}
