@import url("tokens.css");

/* Inside the phone screen, in pt (1 pt = 1 CSS px), from the Figma player
   (DESIGN.md). Values are tokens from tokens.css. Colours come only from the
   --player-* variables on .screen and the mixes of them in tokens.css, plus
   the Plus badge's fixed blue and white (--plus-badge-*, tokens.css). The
   gradient (Step 6) and the mesh (8) are on .screen, under all of it (app.css).

   The rows stack from the top and add up to exactly 874:
   62 + 44 + 31 + 338 + 26 + 20 + 24 + 81 + 7 + 62 + 82 + 9 + 48 + 40

   In the square layout (7), the cover, the titles, then the bar and the times:
   62 + 44 + 27 + 322 + 41 + 81 + 31 + 8 + 6 + 20 − 9 + 62 + 82 + 9 + 48 + 40 */

.player {
  display: flex;
  flex-direction: column;
  padding: var(--top-inset) 0 var(--bottom-inset);
  color: var(--player-fg);
  font-family: var(--font-family);
}

.player > * { flex: none; }

/* Nav: chevron-down · podcast name · share */
.player-nav {
  display: flex;
  align-items: center;
  gap: var(--nav-gap);
  height: var(--nav-height);
  padding: 0 var(--nav-inset);
}

.player-nav-button {
  flex: none;
  width: var(--nav-icon);
  height: var(--nav-icon);
}

.player-nav-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  overflow: hidden;
  font: var(--type-nav-title);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Layouts (7): circle shows the ring and its time; square (.is-square, player.js)
   shows the cover, and the bar and the times under the titles */
.player-cover,
.player-bar,
.player-times,
.player.is-square .player-ring,
.player.is-square .player-time { display: none; }

.player.is-square .player-cover,
.player.is-square .player-bar { display: block; }
.player.is-square .player-times { display: flex; }

/* Ring: the scrubber around the circular artwork, centred. --progress (0–1) is
   set by player.js and drives both the arc and the thumb. The ring is the slider (5f) */
.player-ring {
  --progress: 0;
  position: relative;
  align-self: center;
  width: var(--ring-size);
  height: var(--ring-size);
  margin-top: var(--space-above-ring);
  border-radius: 50%;
  touch-action: none; /* a drag scrubs rather than scrolls */
  -webkit-user-select: none;
  user-select: none;
}

/* The touch area: a --scrub-band wide band centred on the track, reaching 18 pt past
   the ring. player.js tells the band from the artwork inside it */
.player-ring::before {
  content: "";
  position: absolute;
  inset: calc(var(--track-width) / 2 - var(--scrub-band) / 2);
  border-radius: 50%;
}

.player-ring.is-over-track,
.player-ring.is-scrubbing { cursor: pointer; }

/* No focus ring on the ring (after the 5f checkpoint): it didn't look good */
.player-ring:focus-visible { outline: none; }

.player-artwork {
  position: absolute;
  inset: var(--artwork-inset);
  display: block;
  width: calc(100% - 2 * var(--artwork-inset));
  height: calc(100% - 2 * var(--artwork-inset));
  object-fit: cover;
  border-radius: 50%;
  background: var(--player-track); /* until it loads */
}

/* Track and arc: circles on the track's centre line, the arc starting at 12 o'clock and
   running clockwise. Flat ends, as Figma's arcs; the thumb covers the leading one */
.player-scrubber {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  transform: rotate(-90deg);
}

.player-scrubber circle {
  cx: 50%;
  cy: 50%;
  r: calc(50% - var(--track-width) / 2);
  fill: none;
  stroke-width: var(--track-width);
}

.player-track { stroke: var(--player-track); }

.player-progress {
  stroke: var(--player-fg);
  stroke-dasharray: var(--progress) 1;
}

/* Thumb: on the track's centre line at the arc's end. Turned out and back, so its
   shadow keeps falling straight down */
.player-thumb {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--thumb-size);
  height: var(--thumb-size);
  margin: calc(var(--thumb-size) / -2);
  border-radius: 50%;
  background: var(--player-fg);
  box-shadow: var(--thumb-shadow) var(--player-shadow);
  transform:
    rotate(calc(var(--progress) * 1turn))
    translateY(calc(var(--track-width) / 2 - var(--ring-size) / 2))
    rotate(calc(var(--progress) * -1turn));
}

.player-time {
  height: var(--time-height);
  margin: var(--space-above-time) 0 0;
  font: var(--type-time);
  font-variant-numeric: tabular-nums;
  text-align: center;
  white-space: nowrap;
}

/* Cover (7): the square layout's artwork, centred, with 4 pt corners and no shadow.
   The same <img> as in the ring, moved here by player.js */
.player-cover {
  position: relative;
  align-self: center;
  width: var(--cover-size);
  height: var(--cover-size);
  margin-top: var(--space-above-cover);
  border-radius: var(--cover-radius);
}

.player-cover .player-artwork {
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: inherit;
}

/* Titles: episode title, podcast name, badges */
.player-titles {
  display: flex;
  flex-direction: column;
  gap: var(--title-gap);
  margin-top: var(--space-above-titles);
  padding: 0 var(--text-inset);
}

.player-titles > * { flex: none; margin: 0; }

/* One line. Titles that don't fit fade out at the edges; the mask works on any colour.
   The marquee (5g, player.js) moves the text by --marquee-x, from 0 to -(its overflow).
   Each fade is as wide as the text hidden beyond its edge, up to --title-fade: at rest
   only the right edge fades, at the end only the left. With Reduce motion, the text
   stays at 0, so it rests with the right fade, as in 5a */
@property --marquee-x { syntax: "<length>"; inherits: true; initial-value: 0px; }

.player-episode {
  --marquee-x: 0px;
  --marquee-distance: 0px; /* set by player.js: how far the text overflows */
  height: var(--title-height);
  overflow: hidden;
  font: var(--type-episode-title);
  white-space: nowrap;
}

.player-episode-text {
  display: inline-block;
  transform: translateX(var(--marquee-x));
}

.player-episode.is-overflowing {
  mask-image: linear-gradient(to right,
    transparent,
    oklch(0 0 0) min(var(--title-fade), -1 * var(--marquee-x)),
    oklch(0 0 0) calc(100% - min(var(--title-fade), var(--marquee-distance) + var(--marquee-x))),
    transparent);
}

.player-podcast {
  height: var(--podcast-name-height);
  overflow: hidden;
  font: var(--type-podcast-name);
  color: var(--player-fg-2);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Badges: Plus, in the design's fixed blue with a white logo. Figma's Live badge is empty and not built */
.player-badges {
  display: flex;
  height: var(--badges-height);
}

.player-badge-plus {
  display: flex;
  padding: var(--badge-padding);
  border-radius: var(--badge-radius);
  background: var(--plus-badge-bg);
}

.player-badge-plus .icon { background-color: var(--plus-badge-logo); }

/* Bar (7): the square layout's scrubber, across the text column under the titles, in
   the ring's colours: the 8 pt track, the fill from the left end to the thumb's centre,
   and the thumb, 16 pt here (--thumb-size on .is-square, tokens.css). Rounded ends, as
   in the wireframe. --progress (0–1) is set by player.js and drives the fill and the
   thumb, as on the ring */
.player-bar {
  --progress: 0;
  position: relative;
  height: var(--track-width);
  margin: var(--space-above-bar) var(--text-inset) 0;
  border-radius: calc(var(--track-width) / 2);
  background: var(--player-track);
  cursor: pointer;
  touch-action: none; /* a drag scrubs rather than scrolls */
  -webkit-user-select: none;
  user-select: none;
}

/* The touch area (7b): a --scrub-band tall band centred on the track, reaching half a
   thumb past each end, so the thumb can be grabbed at 0 and at the end */
.player-bar::before {
  content: "";
  position: absolute;
  inset: calc(var(--track-width) / 2 - var(--scrub-band) / 2) calc(var(--thumb-size) / -2);
}

/* No focus ring, as on the ring */
.player-bar:focus-visible { outline: none; }

.player-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--progress) * 100%);
  border-radius: inherit;
  background: var(--player-fg);
}

/* The ring's thumb, on the track's centre line at the fill's end */
.player-bar .player-thumb {
  left: calc(var(--progress) * 100%);
  transform: none;
}

/* Times (7): elapsed at the left, total at the right, under the bar. They sit in the
   Switch row's empty top 15 pt, 6 above the pill (--space-above-switch, tokens.css).
   In the podcast name's type and colour (7b checkpoint), with tabular figures, as the
   ring's time, so the digits don't shift as they count */
.player-times {
  justify-content: space-between;
  height: var(--time-height);
  margin: var(--space-above-times) var(--text-inset) 0;
  font: var(--type-podcast-name);
  color: var(--player-fg-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* --- Controls: real buttons. Play, the skips and "1x" act (5e, player.js); the rest only press */
.player button {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--focus-radius);
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent; /* the pressed state below instead */
}

.player button:focus-visible {
  outline: var(--focus-ring) solid var(--player-fg);
  outline-offset: var(--focus-offset);
}

/* Pressed (5e): every button dims to 50% while held, except Play/Pause (below) */
.player button:active { opacity: var(--pressed-opacity); }

/* Switch to video: a centred pill */
.player-switch {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--switch-row-height);
  margin-top: var(--space-above-switch);
}

.player .player-switch-button {
  gap: var(--switch-gap);
  height: var(--switch-height);
  padding: 0 var(--switch-padding);
  border-radius: calc(var(--switch-height) / 2);
  background: var(--player-fill);
  font: var(--type-switch);
  white-space: nowrap;
}

/* Playback: Back 10 · play · Forward 30, centred */
.player-playback {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--playback-gap);
  height: var(--playback-row-height);
}

/* The glyph sits where Figma has it in the 32 frame, top-aligned */
.player .player-skip {
  position: relative;
  width: var(--skip-size);
  height: var(--skip-size);
}

.player-skip .icon {
  position: absolute;
  top: 0;
  left: var(--skip-glyph-x);
}

/* The play button: an fg circle with the glyph in the colour around it (--player-cutout: bg,
   or bg under the gradient); Figma's 2 pt stroke in its own fill is dropped.
   Play, Pause and the spinner are stacked in one cell; Play and Pause crossfade (5g) */
.player .player-play {
  display: grid;
  place-items: center;
  width: var(--play-size);
  height: var(--play-size);
  border-radius: 50%;
  background: var(--player-fg);
  transition: transform var(--press-out), opacity var(--press-out-fade);
}

/* Pressed (5g): as iOS buttons do, it shrinks and dims at once while held, and springs
   back when let go (the transition above). Wins over the 50% dim on the other buttons */
.player .player-play:active {
  transform: scale(var(--play-pressed-scale));
  opacity: var(--play-pressed-opacity);
  transition: transform var(--press-in), opacity var(--press-in);
}

.player-play > * { grid-area: 1 / 1; }

.player-play .icon {
  background-color: var(--player-cutout);
  transition: opacity var(--crossfade);
}

.player-play .icon-pause,
.player-play.is-playing .icon-play { opacity: 0; }
.player-play.is-playing .icon-pause { opacity: 1; }

/* Buffering (5e): not in the design. A spinner in the glyph's colour replaces the glyph
   while the audio loads or seeks: a 3/4 ring, turning once a second. It comes and goes
   at once, without the crossfade */
.player-spinner {
  display: none;
  width: var(--spinner-size);
  height: var(--spinner-size);
  box-sizing: border-box;
  border: var(--spinner-stroke) solid var(--player-cutout);
  border-top-color: transparent;
  border-radius: 50%;
  animation: player-spin 1s linear infinite;
}

.player-play.is-buffering .icon { display: none; }
.player-play.is-buffering .player-spinner { display: block; }

@keyframes player-spin { to { transform: rotate(1turn); } }

/* Bottom row: sleep timer and speed on the left, cast on the right, in 48 pt hit areas */
.player-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--controls-height);
  margin-top: var(--space-above-controls);
  padding: 0 var(--controls-inset);
}

.player-controls-group { display: flex; align-items: center; }

.player .player-control {
  width: var(--control-size);
  height: var(--control-size);
}

.player .player-speed {
  height: var(--speed-height);
  padding: 0 var(--speed-padding);
  font: var(--type-speed);
  white-space: nowrap;
}

/* --- Icons: each SVG from assets/icons/ (Figma, unchanged) as a mask, painted
   with a player colour, at the SVG's own width and height ------------------ */
.icon {
  display: block;
  flex: none;
  background-color: var(--player-fg);
  mask: var(--icon) no-repeat 0 0 / 100% 100%;
}

.icon-chevron-down { --icon: url("../assets/icons/chevron-down.svg"); width: 24px; height: 24px; }
.icon-share { --icon: url("../assets/icons/share.svg"); width: 24px; height: 24px; }
.icon-plus-logo { --icon: url("../assets/icons/plus-logo.svg"); width: 29px; height: 13px; }
.icon-video { --icon: url("../assets/icons/video.svg"); width: 14px; height: 10px; }
.icon-back-10 { --icon: url("../assets/icons/back-10.svg"); width: 28px; height: 30px; }
.icon-forward-30 { --icon: url("../assets/icons/forward-30.svg"); width: 28px; height: 30px; }
.icon-pause { --icon: url("../assets/icons/pause.svg"); width: 32px; height: 32px; }
.icon-play { --icon: url("../assets/icons/play.svg"); width: 32px; height: 32px; } /* the paused state (5e) */
.icon-sleep-off { --icon: url("../assets/icons/sleep-off.svg"); width: 24px; height: 24px; }
.icon-cast { --icon: url("../assets/icons/cast.svg"); width: 24px; height: 24px; }
