/* ==========================================================================
   player.css — Sticky sample mini player
   Mirrors the in-app mini player: circular art, title/meta stack,
   pause + close controls, hairline progress bar.
   Linked from index.html only.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Cover orb — doubles as the play/pause control. The gradient artwork sits on
   an inner layer, so the button itself needs no overflow clipping and its
   tooltip is free to escape the circle.
   -------------------------------------------------------------------------- */
.mini-player__orb {
  position: relative;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  border-radius: 50%;
  color: var(--color-text-primary);
  transition: transform var(--transition-fast);
}

.mini-player__orb:active {
  transform: scale(0.94);
}

.mini-player__orb-art {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%, rgba(255, 255, 255, 0.22), transparent 55%),
    radial-gradient(circle at 70% 75%, var(--color-accent-gold), transparent 60%),
    linear-gradient(145deg, rgb(4, 46, 30), var(--color-accent-green));
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.12),
    0 2px 12px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}

/* Slow drifting sheen so the orb reads as "sound", not a flat swatch. */
.mini-player__orb-art::after {
  content: '';
  position: absolute;
  inset: -30%;
  background: conic-gradient(
    from 0deg,
    transparent 0deg,
    rgba(255, 214, 130, 0.28) 70deg,
    transparent 150deg,
    transparent 360deg
  );
  opacity: 0;
  transition: opacity var(--transition-base);
}

/* Scrim over the artwork: dark enough for a white glyph to read, light enough
   that the gradient underneath still shows. */
.mini-player__orb::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.4);
  transition: background-color var(--transition-base);
}

.mini-player__orb:hover::before {
  background-color: rgba(0, 0, 0, 0.52);
}

/* Glyphs ride above both artwork and scrim. */
.mini-player__orb .mini-player__icon {
  position: relative;
  z-index: 1;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.7));
}

/* --------------------------------------------------------------------------
   Mini player — fixed bottom bar
   -------------------------------------------------------------------------- */
.mini-player {
  /* Overall size of the bar. Every dimension below derives from this, so the
     whole component can be retuned from this one number. */
  --mp-scale: 0.85;

  /* Gap from the resting/pinned bottom edge. Read by the module too, so the
     two stay in step. */
  --mp-gap: var(--space-4);
  --mini-player-offset: 0px;

  position: absolute;
  top: var(--mp-top, 0);
  right: var(--space-4);
  left: var(--space-4);
  /* Below the nav (100) and the fullscreen mobile menu (99) so the bar slides
     behind them, and below the consent banner (1000) which it offsets above. */
  z-index: 90;
  max-width: calc(420px * var(--mp-scale));
  margin: 0 auto;
  /* The hero centres its text; state the bar's own alignment explicitly so no
     ancestor can push the title and meta out of line. */
  text-align: left;
  padding:
    calc(var(--space-3) * var(--mp-scale))
    calc(var(--space-4) * var(--mp-scale))
    calc(var(--space-4) * var(--mp-scale));
  background-color: rgba(6, 8, 7, 0.94);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-pill);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
  transition:
    opacity var(--transition-base),
    visibility var(--transition-base),
    bottom var(--transition-base);
}

/* Pinned: the bar has scrolled out of the hero, so it fades in held at the
   bottom of the viewport. No fill mode, so once the fade finishes the element
   falls back to its normal opacity and cannot fight the reveal state. */
.mini-player[data-pinned='true'] {
  position: fixed;
  top: auto;
  bottom: calc(var(--mp-gap) + var(--mini-player-offset));
}

.mini-player[data-visible='true'][data-pinned='true'] {
  /* Explicit duration: --transition-base already carries an easing function, so
     using it in the animation shorthand yields "250ms ease ease" and is dropped. */
  animation: mini-player-fade-in 250ms ease;
}

@keyframes mini-player-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* A fade-only reveal. An entrance that animated transform gave Safari a chance
   to rasterise the bar before its text was ready and never repaint it. */
.mini-player[data-visible='false'] {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.mini-player[data-visible='true'] {
  opacity: 1;
  visibility: visible;
}

.mini-player__inner {
  display: flex;
  align-items: center;
  gap: calc(var(--space-3) * var(--mp-scale));
}

.mini-player__orb {
  width: calc(48px * var(--mp-scale));
  height: calc(48px * var(--mp-scale));
}

.mini-player[data-playing='true'] .mini-player__orb-art::after {
  opacity: 1;
  animation: orb-spin 9s linear infinite;
}

@keyframes orb-spin {
  to {
    transform: rotate(360deg);
  }
}

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

.mini-player__title {
  font-family: var(--font-display);
  font-size: calc(1.0625rem * var(--mp-scale));
  font-weight: 600;
  line-height: 1.25;
  color: var(--color-text-primary);
  white-space: nowrap;
}

.mini-player__meta {
  font-size: calc(0.875rem * var(--mp-scale));
  line-height: 1.3;
  color: var(--color-text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mini-player__actions {
  display: flex;
  align-items: center;
  gap: calc(var(--space-2) * var(--mp-scale));
  flex-shrink: 0;
}

.mini-player__btn {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(40px * var(--mp-scale));
  height: calc(40px * var(--mp-scale));
  color: var(--color-text-primary);
  border-radius: 50%;
  transition:
    background-color var(--transition-base),
    border-color var(--transition-base),
    transform var(--transition-fast);
}

.mini-player__btn:active {
  transform: scale(0.94);
}

.mini-player__btn--volume {
  background-color: rgba(255, 255, 255, 0.12);
}

.mini-player__btn--volume:hover {
  background-color: rgba(255, 255, 255, 0.2);
}

.mini-player__btn--download {
  color: rgb(247, 198, 122);
  background-color: rgba(247, 198, 122, 0.14);
  border: 1px solid rgba(247, 198, 122, 0.32);
}

.mini-player__btn--download:hover {
  background-color: rgba(247, 198, 122, 0.24);
  border-color: rgba(247, 198, 122, 0.5);
}

/* --------------------------------------------------------------------------
   Tooltips — hover/keyboard only; the aria-label carries the same meaning for
   screen readers, so these are purely visual.
   -------------------------------------------------------------------------- */
.mini-player [data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + var(--space-2));
  left: 50%;
  transform: translate(-50%, 4px);
  padding: calc(5px * var(--mp-scale)) calc(10px * var(--mp-scale));
  font-family: var(--font-body);
  font-size: calc(0.75rem * var(--mp-scale));
  font-weight: 500;
  line-height: 1.35;
  white-space: nowrap;
  color: var(--color-text-primary);
  background-color: rgba(18, 18, 18, 0.97);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-sm);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
  opacity: 0;
  pointer-events: none;
  transition:
    opacity var(--transition-fast),
    transform var(--transition-fast);
}

.mini-player [data-tooltip]:hover::after,
.mini-player [data-tooltip]:focus-visible::after {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* The download tooltip is the widest and sits on the rightmost control, so
   anchor it to that edge instead of centring it off the side of the bar. */
.mini-player__btn--download[data-tooltip]::after {
  left: auto;
  right: 0;
  transform: translate(0, 4px);
}

.mini-player__btn--download[data-tooltip]:hover::after,
.mini-player__btn--download[data-tooltip]:focus-visible::after {
  transform: translate(0, 0);
}

/* Touch devices have no hover, and a tapped tooltip would just stick. */
@media (hover: none) {
  .mini-player [data-tooltip]::after {
    content: none;
  }
}

/* Only one glyph of each pair shows, driven by player state. */
.mini-player__icon--pause,
.mini-player__icon--muted {
  display: none;
}

.mini-player[data-playing='true'] .mini-player__icon--pause {
  display: block;
}

.mini-player[data-playing='true'] .mini-player__icon--play {
  display: none;
}

.mini-player[data-muted='true'] .mini-player__icon--muted {
  display: block;
}

.mini-player[data-muted='true'] .mini-player__icon--unmuted {
  display: none;
}

/* --------------------------------------------------------------------------
   Volume — the vertical slider is the button's hover affordance, which is why
   this control carries no tooltip of its own; they would fight for the space.
   -------------------------------------------------------------------------- */
.mini-player__volume {
  position: relative;
  display: flex;
}

.mini-player__volume-panel {
  position: absolute;
  /* Flush against the button's top edge, so travelling up into the panel never
     crosses a dead zone that would close it. */
  bottom: 100%;
  left: 50%;
  transform: translate(-50%, 4px);
  width: calc(32px * var(--mp-scale));
  height: calc(104px * var(--mp-scale));
  background-color: rgba(18, 18, 18, 0.97);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-pill);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--transition-fast),
    transform var(--transition-fast),
    visibility var(--transition-fast);
}

/* Hover drives it on a pointer device; focus-within keeps it keyboard reachable.
   data-open is the explicit state the module manages, because touch cannot rely
   on either: WebKit does not focus a range input on tap, so :focus-within would
   drop the panel the moment you touched the slider. */
.mini-player__volume:hover .mini-player__volume-panel,
.mini-player__volume:focus-within .mini-player__volume-panel,
.mini-player__volume[data-open='true'] .mini-player__volume-panel {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

/* A horizontal range rotated upright. Native vertical ranges disagree across
   engines and refuse custom track/thumb styling; rotation renders identically
   everywhere and keeps the input's real keyboard and ARIA semantics.
   --vol is set by the module and drives the gold fill. */
.mini-player__volume-slider {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(84px * var(--mp-scale));
  height: calc(12px * var(--mp-scale));
  margin: 0;
  transform: translate(-50%, -50%) rotate(-90deg);
  background: transparent;
  cursor: pointer;
}

/* Muted keeps the level visible but greys the control, rather than emptying the
   track while the thumb stays put — which read as a bug. */
.mini-player[data-muted='true'] .mini-player__volume-slider {
  opacity: 0.45;
}

.mini-player__volume-slider::-webkit-slider-runnable-track {
  height: calc(4px * var(--mp-scale));
  border-radius: 2px;
  background:
    linear-gradient(
      to right,
      rgb(247, 198, 122) var(--vol, 50%),
      rgba(255, 255, 255, 0.22) var(--vol, 50%)
    );
}

.mini-player__volume-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: calc(12px * var(--mp-scale));
  height: calc(12px * var(--mp-scale));
  margin-top: calc(-4px * var(--mp-scale));
  background-color: rgb(247, 198, 122);
  border: none;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
}

.mini-player__volume-slider::-moz-range-track {
  height: calc(4px * var(--mp-scale));
  border-radius: 2px;
  background-color: rgba(255, 255, 255, 0.22);
}

.mini-player__volume-slider::-moz-range-progress {
  height: calc(4px * var(--mp-scale));
  border-radius: 2px;
  background-color: rgb(247, 198, 122);
}

.mini-player__volume-slider::-moz-range-thumb {
  width: calc(12px * var(--mp-scale));
  height: calc(12px * var(--mp-scale));
  background-color: rgb(247, 198, 122);
  border: none;
  border-radius: 50%;
}

.mini-player__volume-slider:focus-visible {
  outline: 2px solid var(--color-text-secondary);
  outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   Progress bar
   -------------------------------------------------------------------------- */
.mini-player__progress {
  position: relative;
  height: calc(4px * var(--mp-scale));
  margin: calc(var(--space-3) * var(--mp-scale)) calc(var(--space-4) * var(--mp-scale)) 0;
  background-color: rgba(255, 255, 255, 0.18);
  border-radius: 2px;
  cursor: pointer;
}

/* Widen the pointer target without thickening the visible line. */
.mini-player__progress::before {
  content: '';
  position: absolute;
  inset: -10px 0;
}

.mini-player__progress-fill {
  width: 0%;
  height: 100%;
  background: linear-gradient(90deg, rgb(214, 138, 74), rgb(247, 198, 122));
  border-radius: inherit;
  transition: width 120ms linear;
}

.mini-player__progress:focus-visible {
  outline: 2px solid var(--color-text-secondary);
  outline-offset: 4px;
}

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 520px) {
  .mini-player {
    right: var(--space-2);
    left: var(--space-2);
  }

  .mini-player {
    padding:
      calc(var(--space-3) * var(--mp-scale))
      calc(var(--space-3) * var(--mp-scale))
      calc(var(--space-4) * var(--mp-scale));
  }

  .mini-player__progress {
    margin: calc(var(--space-3) * var(--mp-scale)) calc(var(--space-3) * var(--mp-scale)) 0;
  }

  .mini-player__orb {
    width: calc(42px * var(--mp-scale));
    height: calc(42px * var(--mp-scale));
  }

  .mini-player__title {
    font-size: calc(1rem * var(--mp-scale));
  }

  .mini-player__meta {
    font-size: calc(0.8125rem * var(--mp-scale));
  }

  .mini-player__btn {
    width: calc(36px * var(--mp-scale));
    height: calc(36px * var(--mp-scale));
  }
}

/* --------------------------------------------------------------------------
   Reduced motion — keep the state changes, drop the movement
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .mini-player[data-playing='true'] .mini-player__orb::after {
    animation: none;
  }
}
