/* ── Music player: light spilling out of the bottom-right corner ──
   No card. A WebGL shader (player.js) paints a drifting, warm field whose alpha fades
   out from the corner along a noise-shaped edge, so it bleeds into the page. The
   controls float on the densest part, right in the corner. Sizes come from --light,
   --controls-* and --player-inset (header.css). On phones the light is a full-width
   horizon band (--horizon) with the controls centered in it (see the end). */

/* Layers: .player itself creates no stacking context (no z-index, no transform), so its
   children layer against the header's text: the light (z 0) under the greetings and
   description (z 1, header.css), the controls (z 2) above everything, clickable. */
.player {
  position: absolute;
  right: 0;
  bottom: 0;
  width: var(--light);
  height: var(--light);
  pointer-events: none;
}

.player__canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  transform-origin: 100% 100%;
  animation: light-in 2.2s cubic-bezier(0.2, 0.7, 0.2, 1) 0.3s both;
}

@keyframes light-in {
  from {
    opacity: 0;
    transform: scale(0.85);
  }
}

/* Without WebGL, a soft radial wash stands in for the shader. */
.player.is-fallback {
  background: radial-gradient(
    circle at 100% 100%,
    var(--accent) 0%,
    var(--player-art-2) 30%,
    color-mix(in srgb, var(--player-art-2) 30%, transparent) 55%,
    transparent 72%
  );
}

/* ── Controls ── */

.player__controls {
  position: absolute;
  right: var(--player-inset);
  bottom: max(var(--player-inset), calc(env(safe-area-inset-bottom) + 12px));
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--player-fg);
  pointer-events: auto;
}

.player__title {
  margin: 0;
  white-space: nowrap;
  font-family: var(--font-serif);
  font-variation-settings: 'STYL' 0;
  font-weight: 300;
  font-size: clamp(22px, 1.9vw, 32px);
  line-height: 1;
  letter-spacing: -0.015em;
  text-shadow: var(--player-title-shadow);
}

/* Play / pause in liquid glass: the lens blurs and saturates the light behind it, a
   sheen lies across its upper half, and light catches the rim. While playing, the rim
   glow swells with the music (--level is its loudness, 0..1, set by player.js). */
.player__toggle {
  position: relative;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: var(--controls-h);
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--player-glass);
  color: var(--player-fg);
  cursor: pointer;
  -webkit-backdrop-filter: blur(14px) saturate(1.8);
  backdrop-filter: blur(14px) saturate(1.8);
  box-shadow:
    var(--player-glass-edge),
    0 0 calc(var(--level, 0) * 28px) color-mix(in srgb, var(--player-fg) 35%, transparent);
  transition: background 0.25s ease, transform 0.25s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.player__toggle::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--player-glass-sheen);
  pointer-events: none;
}

.player__toggle:hover {
  background: var(--player-glass-hover);
  transform: scale(1.06);
}

.player__toggle:active {
  transform: scale(0.96);
}

.player__toggle:focus-visible {
  outline: 2px solid var(--player-fg);
  outline-offset: 3px;
}

.player__icon {
  position: relative; /* above the glass sheen */
  width: 38%;
  height: 38%;
  fill: currentColor;
}

.player__icon--pause,
.player.is-playing .player__icon--play {
  display: none;
}

.player.is-playing .player__icon--pause {
  display: block;
}

/* ── Phones: a horizon instead of a corner ──
   The light spans the full width as a band below the description (header.css reserves
   it), rising from the bottom edge, with the controls centered in its densest part.
   The band takes touches (touch-action: none) so a tap or drag can stir the light.

   It is fixed to the viewport so it can run under the browser's bottom toolbar (iOS
   Safari): the page itself is locked to the visible height (100dvh), so without this the
   strip behind the toolbar shows only the plain page background, a dark bar in dark
   mode. The band starts where the visible area ends minus --horizon, and reaches down to
   the large viewport (100lvh), which includes the area under the toolbar; the controls
   are lifted by the same amount so they stay above it. Where the browser has no toolbar
   overlap, 100lvh equals 100dvh and nothing changes. */
@media (max-width: 600px) {
  .player {
    position: fixed;
    left: 0;
    width: auto;
    height: var(--horizon);
    pointer-events: auto;
    touch-action: none;
  }

  .player__canvas {
    transform-origin: 50% 100%;
  }

  .player__controls {
    right: auto;
    left: 50%;
    translate: -50% 0;
    bottom: max(24px, calc(env(safe-area-inset-bottom) + 14px));
  }

  @supports (height: 100lvh) {
    .player {
      top: calc(100dvh - var(--horizon));
      bottom: auto;
      height: calc(var(--horizon) + 100lvh - 100dvh);
    }

    .player__controls {
      bottom: calc(100lvh - 100dvh + max(24px, calc(env(safe-area-inset-bottom) + 14px)));
    }
  }

  .player.is-fallback {
    background: radial-gradient(
      ellipse 90% 100% at 50% 100%,
      var(--accent) 0%,
      var(--player-art-2) 35%,
      color-mix(in srgb, var(--player-art-2) 30%, transparent) 60%,
      transparent 80%
    );
  }
}

/* iPhone Safari: see the iOS 26 note at the end of base.css. Instead of a fixed band
   (Safari shows its fallback color behind the toolbar for those), the band is part of
   the page and bleeds --ios-bleed below the visible area, so there are real pixels under
   the toolbar; the controls are lifted back above it. */
@supports (-webkit-touch-callout: none) {
  @media (max-width: 600px) {
    .player {
      position: absolute;
      top: auto;
      bottom: calc(-1 * var(--ios-bleed));
      height: calc(var(--horizon) + var(--ios-bleed));
    }

    .player__controls {
      bottom: calc(var(--ios-bleed) + max(24px, calc(env(safe-area-inset-bottom) + 14px)));
    }
  }
}
