
/* =================================================
   Audio block tool — "Now Playing" card

   Full-bleed media player: the card always spans the editor column. A tall
   rounded cover panel anchors the left; the right column stacks title, artist,
   a hero waveform scrubber and a slim transport bar. The caption spans the
   full width beneath, separated by a hairline. Airbnb-neutral surfaces, black
   active states, restrained shadows — palette mirrors the image/video tools.
   ================================================= */

/* ----- palette / token declarations -----
   Every --blok-audio-* var used below must be declared here so the
   declared-custom-props gate (R3) passes. The waveform fill vars are also
   set inline by waveform.ts; the declarations here supply non-zero defaults
   that read correctly before JS runs. */
[data-blok-tool="audio"] {
  --blok-audio-cover-size: 104px;
  --blok-audio-gap: var(--blok-space-3-5);
  --blok-audio-pad: var(--blok-space-3-5);
  --blok-audio-radius: var(--blok-radius-md);
  --blok-audio-wave-height: 56px;
  --blok-audio-bar-height: 4px;
  /* lift the slim slider thumbs (volume + speed) off the track so they read as
     tactile pucks rather than flat dots */
  --blok-audio-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
  --blok-audio-ctrl-size: 30px;
  --blok-audio-play-size: 36px;
  --blok-audio-bar: var(--blok-border-subtle);
  --blok-audio-bar-played: var(--blok-text-primary);
  /* Comet-head tint — played colour nudged toward the editor accent. Subtle by
     design; the waveform canvas blends bars toward it only at the playhead. */
  --blok-audio-bar-head: color-mix(in srgb, var(--blok-audio-bar-played) 68%, var(--blok-color-accent) 32%);
  --blok-audio-seek-pct: 0%;
  --blok-audio-vol-pct: 100%;
  --blok-audio-speed-pct: 50%;

  /* no-cover vinyl placeholder — a glossy black record. The disc body is built
     from --blok-overlay-dark (near-black in both themes) so it always reads as
     vinyl, not a grey CD; grooves + sheen are white at low alpha, the label is
     a cream-white puck, the spindle is a crisp dark dot. A fixed specular sits
     above the disc (placeholder::after) so grooves shimmer *under* it as it spins. */
  --blok-audio-disc-size: 92px;
  --blok-audio-groove-w: 0.75px;
  --blok-audio-groove-gap: 2px;
  --blok-audio-cover-glow: color-mix(in srgb, var(--blok-bg-primary) 55%, transparent);
  /* glossy black record body: a near-black face with a centre→edge vignette so it
     reads as a curved, light-catching surface rather than a flat circle. */
  --blok-audio-disc-base: var(--blok-overlay-dark);
  --blok-audio-disc-deep: color-mix(in srgb, #000 42%, var(--blok-overlay-dark));
  --blok-audio-disc-edge: color-mix(in srgb, var(--blok-text-on-dark) 6%, var(--blok-overlay-dark));
  --blok-audio-disc-groove: color-mix(in srgb, var(--blok-text-on-dark) 8%, transparent);
  --blok-audio-disc-rim: color-mix(in srgb, var(--blok-text-on-dark) 16%, transparent);
  --blok-audio-disc-rim-light: color-mix(in srgb, var(--blok-text-on-dark) 26%, transparent);
  /* fixed specular reflection — two bright bands of "light" the grooves shimmer
     under as the disc spins (this is what sells real glossy vinyl). */
  --blok-audio-disc-sheen: color-mix(in srgb, var(--blok-text-on-dark) 32%, transparent);
  --blok-audio-disc-sheen-soft: color-mix(in srgb, var(--blok-text-on-dark) 12%, transparent);
  /* a soft highlight wedge printed on the disc — sweeps round with the grooves so
     the (otherwise radially-symmetric) spin actually reads as motion. */
  --blok-audio-disc-shine: color-mix(in srgb, var(--blok-text-on-dark) 10%, transparent);
  /* centre label — a matte, faintly warm cream puck (not a flat white disc) */
  --blok-audio-disc-label: color-mix(in srgb, var(--blok-text-on-dark) 93%, var(--blok-overlay-dark));
  --blok-audio-disc-label-hi: var(--blok-text-on-dark);
  --blok-audio-disc-label-edge: color-mix(in srgb, var(--blok-text-on-dark) 72%, var(--blok-overlay-dark));
  --blok-audio-disc-label-ring: color-mix(in srgb, var(--blok-overlay-dark) 24%, transparent);
  --blok-audio-disc-hole: var(--blok-overlay-dark);
  /* opaque fill for the reflection mask (only its alpha matters) */
  --blok-audio-mask-solid: #000;
  /* depth shadows for the disc rim, label lift and spindle catch-light */
  --blok-audio-disc-inner-shadow: rgba(0, 0, 0, 0.5);
  --blok-audio-label-shadow: rgba(0, 0, 0, 0.35);
  --blok-audio-spindle-catch: rgba(255, 255, 255, 0.4);
  /* cover overlay button — a semi-transparent dark scrim (same near-black as
     the disc, blended down to ~45% opacity so the art shows through) */
  --blok-audio-cover-scrim: color-mix(in srgb, var(--blok-overlay-dark) 50%, transparent);

  position: relative;
  margin: var(--blok-space-2-5) 0;
  font-family: var(--blok-font-family, var(--blok-font-sans));
}

/* ----- alignment (caption text only — the card is always full width) ----- */
[data-blok-tool="audio"][data-align="left"]   { text-align: left; }
[data-blok-tool="audio"][data-align="center"] { text-align: center; }
[data-blok-tool="audio"][data-align="right"]  { text-align: right; }

/* ----- card wrapper (figure) -------------------------------
   CSS grid: cover + body share row 1; the caption spans both columns on
   row 2. The <audio> media element is laid out via display:none so it never
   claims a grid cell. */
[data-blok-tool="audio"] .blok-audio-inner {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: stretch;
  column-gap: var(--blok-audio-gap);
  row-gap: var(--blok-space-2-5);
  width: 100%;
  padding: var(--blok-audio-pad);
  background: var(--blok-bg-primary);
  border: 1px solid var(--blok-border-subtle);
  border-radius: var(--blok-radius-lg);
  box-shadow: var(--blok-image-shadow-resting);
  text-align: left;
  transition: box-shadow var(--blok-duration-base) ease, border-color var(--blok-duration-base) ease;
}
[data-blok-tool="audio"] .blok-audio-inner:hover {
  box-shadow: var(--blok-video-shadow-hover);
  border-color: var(--blok-border-secondary);
}
[data-blok-tool="audio"] [data-role="audio-media"] {
  display: none;
}

/* Top-of-card toolbar anchor — a zero-size marker the editor centers the +/tunes
   buttons on. Pinned to the top-left of the grid; line-height stays a hair above 0
   (the positioner floors a 0 line-height back to its 24px default), so the buttons
   land flush with the top of the cover art. */
[data-blok-tool="audio"] .blok-audio-toolbar-anchor {
  grid-column: 1;
  grid-row: 1;
  align-self: start;
  width: 0;
  height: 0;
  line-height: 1px;
  pointer-events: none;
}

/* ----- block selection ------------------------------------ */
[data-blok-element-content].bg-selection:has([data-blok-tool="audio"]) {
  background-color: transparent;
}
[data-blok-element-content].bg-selection:has([data-blok-tool="audio"]) .blok-audio-inner {
  background-color: var(--blok-selection);
}

/* ----- cover art — tall rounded panel on the left --------- */
[data-blok-tool="audio"] .blok-audio-cover {
  position: relative;
  grid-column: 1;
  grid-row: 1;
  align-self: stretch;
  width: var(--blok-audio-cover-size);
  min-height: var(--blok-audio-cover-size);
  border-radius: var(--blok-radius-md);
  overflow: hidden;
  background: var(--blok-bg-secondary);
  box-shadow: inset 0 0 0 1px var(--blok-border-subtle);
  display: flex;
  align-items: center;
  justify-content: center;
}
[data-blok-tool="audio"] .blok-audio-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ----- change-cover overlay button (edit mode only) -------- */
/* Stretches across the full cover panel; stays invisible until the cover
   is hovered or the button receives keyboard focus — preventing it from
   obscuring the art in read-only contexts. */
[data-blok-tool="audio"] .blok-audio-cover__change {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border: 0;
  margin: 0;
  padding: 0;
  cursor: pointer;
  color: var(--blok-text-on-dark);
  background: var(--blok-audio-cover-scrim);
  opacity: 0;
  transition: opacity var(--blok-duration-base) ease;
}
[data-blok-tool="audio"] .blok-audio-cover:hover .blok-audio-cover__change,
[data-blok-tool="audio"] .blok-audio-cover.is-picker-open .blok-audio-cover__change,
[data-blok-tool="audio"] .blok-audio-cover__change:focus-visible {
  opacity: 1;
}
[data-blok-tool="audio"] .blok-audio-cover__change svg {
  width: 20px;
  height: 20px;
  pointer-events: none;
}

/* ----- cover-picker dialog (top-layer promoted) ------------- */
/* The dialog is its own elevated surface so the media-empty card inside layers
   correctly. Two UA/reset hazards to beat:
   1. The `[data-blok-top-layer][popover]` reset in main.css (specificity 0,0,2,0)
      forces width:auto and strips border/padding — without an explicit width the
      flex-column surface collapses to a ~2px sliver. So every box-model property
      is re-asserted with matching specificity (mirrors the image-lightbox /
      file-preview precedent).
   2. The UA `[popover]` rule paints `background: Canvas` (white) and the reset
      does NOT clear it. The media-empty card uses --blok-bg-secondary, which in
      the dark theme is a translucent white overlay meant to sit on a dark parent;
      over the white canvas it reads white. Painting the dialog with the solid
      --blok-bg-primary surface gives that overlay the dark backdrop it expects.
   Width stays a plain length (not a --blok-space token) per the proven pattern;
   the other surface tokens resolve fine on the promoted element (colors +
   spacing are bridged to [data-blok-top-layer]). The base rule covers the
   no-Popover-API fallback (element stays in normal flow, no reset applied). */
.blok-audio-cover-picker,
.blok-audio-cover-picker[data-blok-top-layer][popover] {
  z-index: 1;
  width: min(440px, calc(100vw - 32px));
  padding: var(--blok-space-2);
  background: var(--blok-bg-primary);
  border: 1px solid var(--blok-border-subtle);
  border-radius: var(--blok-radius-lg);
  box-shadow: var(--blok-popover-box-shadow);
}
/* The picker lives at document.body, outside blok's scoped border-box reset, so
   its subtree would default to content-box. The media-empty Upload/Link height-
   swap animation measures the border-box height but animates the `height`
   property — under content-box that adds the panel padding on top, overshooting
   then snapping back (a visible height jump). Match the inline (border-box)
   context the component was built for. */
.blok-audio-cover-picker,
.blok-audio-cover-picker * {
  box-sizing: border-box;
}

/* Entrance — the picker rises + scales up from its top-left anchor corner so it
   reads as growing out of the cover, matching the block's own mount language
   (blok-audio-rise / --blok-ease-popover). The directional content slide between
   the Upload/Link tabs is driven from media-empty-state.ts (WAAPI). */
.blok-audio-cover-picker {
  transform-origin: top left;
  animation: blok-audio-cover-picker-in var(--blok-duration-slow) var(--blok-ease-popover) both;
}

@keyframes blok-audio-cover-picker-in {
  from { opacity: 0; transform: translateY(-6px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .blok-audio-cover-picker { animation: none; }
}

/* ----- no-cover placeholder: a glossy black vinyl record --- */
[data-blok-tool="audio"] .blok-audio-cover__placeholder {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  /* faint top-centre sheen so the panel has depth behind the disc */
  background: radial-gradient(120% 90% at 50% 36%, var(--blok-audio-cover-glow), transparent 70%);
}

/* fixed specular glint pinned over the disc — it does NOT rotate, so the grooves
   shimmer beneath it as the record spins (the bit that sells the motion). */
[data-blok-tool="audio"] .blok-audio-cover__placeholder::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--blok-audio-disc-size);
  height: var(--blok-audio-disc-size);
  transform: translate(-50%, -50%);
  border-radius: var(--blok-radius-pill);
  background:
    /* bright crescent of light along the top rim */
    radial-gradient(72% 50% at 50% 2%, var(--blok-audio-disc-sheen), transparent 60%),
    /* the main gloss: two opposed soft bands (a vinyl "bow-tie" reflection) */
    conic-gradient(
      from 142deg at 50% 50%,
      transparent 0 6%,
      var(--blok-audio-disc-sheen) 15%,
      transparent 30% 64%,
      var(--blok-audio-disc-sheen-soft) 80%,
      transparent 92% 100%
    ),
    /* faint bounce light in the lower-right quadrant */
    radial-gradient(44% 36% at 72% 84%, var(--blok-audio-disc-sheen-soft), transparent 62%);
  /* the gloss only lives on the vinyl — keep it off the matte paper label */
  mask: radial-gradient(circle at center, transparent 30%, var(--blok-audio-mask-solid) 40%);
  -webkit-mask: radial-gradient(circle at center, transparent 30%, var(--blok-audio-mask-solid) 40%);
  pointer-events: none;
}

/* the record body: fine concentric grooves over a near-black radial face,
   lifted off the panel by an inset rim + soft shadow. Its rotation is driven
   imperatively by disc.ts (transform: rotate), which spins the platter up on
   play and lets it coast down on pause — so the disc has real inertia rather
   than snapping on/off with a CSS animation. */
[data-blok-tool="audio"] .blok-audio-cover__disc {
  position: relative;
  will-change: transform;
  width: var(--blok-audio-disc-size);
  height: var(--blok-audio-disc-size);
  border-radius: var(--blok-radius-pill);
  background:
    /* soft shine wedge that rotates with the grooves (rotation feedback) */
    conic-gradient(
      from 210deg,
      transparent 0 64%,
      var(--blok-audio-disc-shine) 78%,
      transparent 92% 100%
    ),
    /* a bright hairline run just inside the edge — the glossy outer bevel */
    radial-gradient(
      circle at center,
      transparent 82%,
      var(--blok-audio-disc-rim-light) 85% 87%,
      transparent 90%
    ),
    /* fine concentric grooves */
    repeating-radial-gradient(
      circle at center,
      var(--blok-audio-disc-groove) 0 var(--blok-audio-groove-w),
      transparent var(--blok-audio-groove-w) var(--blok-audio-groove-gap)
    ),
    /* glossy black face with a centre→edge vignette (curved-surface shading) */
    radial-gradient(
      circle at center,
      var(--blok-audio-disc-edge) 0 14%,
      var(--blok-audio-disc-base) 44%,
      var(--blok-audio-disc-base) 72%,
      var(--blok-audio-disc-deep) 100%
    );
  box-shadow:
    inset 0 0 0 1px var(--blok-audio-disc-rim),
    inset 0 0 7px var(--blok-audio-disc-inner-shadow),
    var(--blok-image-shadow-resting);
}

/* centre label — a small matte cream puck with a printed concentric ring */
[data-blok-tool="audio"] .blok-audio-cover__disc::before {
  content: "";
  position: absolute;
  inset: 36%;
  border-radius: var(--blok-radius-pill);
  background:
    /* a thin printed ring near the label rim */
    radial-gradient(
      circle at center,
      transparent 58%,
      var(--blok-audio-disc-label-ring) 60% 64%,
      transparent 66%
    ),
    /* paper with a soft off-axis sheen */
    radial-gradient(
      circle at 40% 34%,
      var(--blok-audio-disc-label-hi),
      var(--blok-audio-disc-label) 52%,
      var(--blok-audio-disc-label-edge)
    );
  box-shadow:
    inset 0 0 0 1px var(--blok-audio-disc-rim),
    0 1px 1px var(--blok-audio-label-shadow);
}

/* spindle hole — a crisp dark dot with a tiny rim catch */
[data-blok-tool="audio"] .blok-audio-cover__disc::after {
  content: "";
  position: absolute;
  inset: 47%;
  border-radius: var(--blok-radius-pill);
  background: var(--blok-audio-disc-hole);
  box-shadow: inset 0 1px 1px var(--blok-audio-spindle-catch);
}

/* ----- right column (title + artist + waveform + controls) - */
[data-blok-tool="audio"] .blok-audio-body {
  grid-column: 2;
  grid-row: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--blok-space-1-5);
}

/* ----- title ----------------------------------------------- */
[data-blok-tool="audio"] .blok-audio-title {
  font-size: var(--blok-font-size-body);
  font-weight: var(--blok-font-weight-semibold);
  color: var(--blok-text-primary);
  /* `text-overflow: ellipsis` forces `overflow: hidden`, which clips at the
   * padding box — a 1.0 line-height would shear descenders and the caret. */
  line-height: var(--blok-line-height-option);
  letter-spacing: -0.01em;
  outline: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-blok-tool="audio"] [data-role="audio-title"][contenteditable="true"]:empty::before {
  content: attr(data-placeholder);
  color: var(--blok-text-tertiary);
  pointer-events: none;
}

/* ----- artist ---------------------------------------------- */
[data-blok-tool="audio"] .blok-audio-artist {
  font-size: var(--blok-font-size-ui-label);
  font-weight: var(--blok-font-weight-regular);
  color: var(--blok-text-secondary);
  line-height: var(--blok-line-height-option);
  outline: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-blok-tool="audio"] [data-role="audio-artist"][contenteditable="true"]:empty::before {
  content: attr(data-placeholder);
  color: var(--blok-text-tertiary);
  pointer-events: none;
}

/* ----- waveform canvas (hero scrubber) -------------------- */
[data-blok-tool="audio"] .blok-audio-waveform {
  position: relative;
  width: 100%;
  height: var(--blok-audio-wave-height);
  margin-top: var(--blok-space-1);
  cursor: pointer;
}
[data-blok-tool="audio"] .blok-audio-waveform__canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* ----- controls bar --------------------------------------- */
[data-blok-tool="audio"] .blok-audio-controls {
  --blok-audio-seek-pct: 0%;
  --blok-audio-vol-pct: 100%;
  --blok-audio-speed-pct: 50%;
  display: flex;
  align-items: center;
  gap: var(--blok-space-2-5);
  margin-top: var(--blok-space-1);
}

/* generic control button — scoped to <button> so the volume <input> and the
   time <span> (both carry data-role) keep their own slim/text styling instead
   of being clobbered into a 30px pill. Every button-specific rule below is also
   anchored on `button[data-role…]` so they share this rule's specificity and
   win on source order. */
[data-blok-tool="audio"] .blok-audio-controls button[data-role] {
  flex-shrink: 0;
  display: inline-grid;
  place-items: center;
  width: var(--blok-audio-ctrl-size);
  height: var(--blok-audio-ctrl-size);
  padding: 0;
  border: 0;
  border-radius: var(--blok-radius-pill);
  background: transparent;
  color: var(--blok-text-secondary);
  cursor: pointer;
  transition: background var(--blok-duration-base) ease, color var(--blok-duration-base) ease, transform var(--blok-duration-base) ease;
}
[data-blok-tool="audio"] .blok-audio-controls button[data-role]:hover {
  background: var(--blok-bg-hover);
  color: var(--blok-text-primary);
}
[data-blok-tool="audio"] .blok-audio-controls button[data-role]:active {
  transform: scale(0.92);
}
[data-blok-tool="audio"] .blok-audio-controls button[data-role] svg {
  width: 17px;
  height: 17px;
}

/* play / pause — filled black puck */
[data-blok-tool="audio"] .blok-audio-controls button[data-role="audio-play"] {
  width: var(--blok-audio-play-size);
  height: var(--blok-audio-play-size);
  margin-right: var(--blok-space-0-5);
  background: var(--blok-text-primary);
  color: var(--blok-bg-primary);
  box-shadow: var(--blok-image-shadow-resting);
}
[data-blok-tool="audio"] .blok-audio-controls button[data-role="audio-play"]:hover {
  background: var(--blok-text-primary);
  color: var(--blok-bg-primary);
  transform: scale(1.05);
}
[data-blok-tool="audio"] .blok-audio-controls button[data-role="audio-play"]:active {
  transform: scale(0.96);
}
[data-blok-tool="audio"] .blok-audio-controls button[data-role="audio-play"] svg {
  width: 19px;
  height: 19px;
}

/* time readout */
[data-blok-tool="audio"] .blok-audio-controls__time {
  flex-shrink: 0;
  margin-right: auto;
  font-size: var(--blok-font-size-ui-compact);
  font-weight: var(--blok-font-weight-medium);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--blok-text-secondary);
  user-select: none;
}

/* volume cluster */
[data-blok-tool="audio"] .blok-audio-controls__volume-wrap {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: var(--blok-space-1);
}

/* volume range */
[data-blok-tool="audio"] .blok-audio-controls__volume {
  width: 0;
  height: var(--blok-audio-bar-height);
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
  background: linear-gradient(
    to right,
    var(--blok-audio-bar-played) var(--blok-audio-vol-pct),
    var(--blok-audio-bar) var(--blok-audio-vol-pct)
  );
  border-radius: var(--blok-radius-pill);
  opacity: 0;
  cursor: pointer;
  transition: width var(--blok-duration-slow) ease, opacity var(--blok-duration-slow) ease;
}
[data-blok-tool="audio"] .blok-audio-controls__volume-wrap:hover .blok-audio-controls__volume,
[data-blok-tool="audio"] .blok-audio-controls__volume:focus-visible {
  width: 64px;
  opacity: 1;
}
[data-blok-tool="audio"] .blok-audio-controls__volume::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  border-radius: var(--blok-radius-pill);
  background: var(--blok-text-primary);
  box-shadow: var(--blok-audio-thumb-shadow);
}
[data-blok-tool="audio"] .blok-audio-controls__volume::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: var(--blok-radius-pill);
  background: var(--blok-text-primary);
  box-shadow: var(--blok-audio-thumb-shadow);
}

/* loop active state — neutral black, no accent color */
[data-blok-tool="audio"] .blok-audio-controls button[data-role="audio-loop"][aria-pressed="true"] {
  color: var(--blok-bg-primary);
  background: var(--blok-text-primary);
}
[data-blok-tool="audio"] .blok-audio-controls button[data-role="audio-loop"][aria-pressed="true"]:hover {
  color: var(--blok-bg-primary);
  background: var(--blok-text-primary);
}

/* speed gear + its anchored menu */
[data-blok-tool="audio"] .blok-audio-controls__speed-wrap {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
}
[data-blok-tool="audio"] .blok-audio-controls button[data-role="audio-speed"][aria-expanded="true"] {
  background: var(--blok-bg-hover);
  color: var(--blok-text-primary);
}

/* ----- speed menu ----------------------------------------- */
[data-blok-tool="audio"] .blok-audio-controls__speed-menu {
  position: absolute;
  bottom: calc(100% + var(--blok-space-2));
  left: 0;
  min-width: 132px;
  padding: var(--blok-space-2);
  background: var(--blok-bg-primary);
  border: 1px solid var(--blok-border-subtle);
  border-radius: var(--blok-radius-md);
  box-shadow: var(--blok-image-shadow-popover);
  z-index: var(--blok-z-popover);
}
[data-blok-tool="audio"] .blok-audio-controls__speed-menu[hidden] { display: none; }

[data-blok-tool="audio"] .blok-audio-controls__speed-readout {
  font-size: var(--blok-font-size-ui-label);
  font-weight: var(--blok-font-weight-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--blok-text-primary);
  text-align: center;
  margin-bottom: var(--blok-space-2);
}

/* − [slider] ＋ — flat icon steppers flank a flexible track (mirrors the video
   player's speed control). */
[data-blok-tool="audio"] .blok-audio-controls__speed-slider-row {
  display: flex;
  align-items: center;
  gap: var(--blok-space-1-5);
  margin-bottom: var(--blok-space-2);
}
[data-blok-tool="audio"] .blok-audio-controls__speed-step {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--blok-radius-sm);
  background: transparent;
  color: var(--blok-text-tertiary);
  cursor: pointer;
  transition: background var(--blok-duration-base) ease, color var(--blok-duration-base) ease, transform var(--blok-duration-base) ease, opacity var(--blok-duration-base) ease;
}
[data-blok-tool="audio"] .blok-audio-controls__speed-step:hover {
  background: var(--blok-bg-hover);
  color: var(--blok-text-primary);
}
[data-blok-tool="audio"] .blok-audio-controls__speed-step:active {
  transform: scale(0.92);
}
[data-blok-tool="audio"] .blok-audio-controls__speed-step:disabled {
  opacity: 0.35;
  cursor: default;
  transform: none;
}
[data-blok-tool="audio"] .blok-audio-controls__speed-step svg {
  width: 15px;
  height: 15px;
}

[data-blok-tool="audio"] .blok-audio-controls__speed-slider {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--blok-audio-bar-height);
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
  background: linear-gradient(
    to right,
    var(--blok-audio-bar-played) var(--blok-audio-speed-pct),
    var(--blok-audio-bar) var(--blok-audio-speed-pct)
  );
  border-radius: var(--blok-radius-pill);
  cursor: pointer;
}
[data-blok-tool="audio"] .blok-audio-controls__speed-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  border-radius: var(--blok-radius-pill);
  background: var(--blok-text-primary);
  box-shadow: var(--blok-audio-thumb-shadow);
}
[data-blok-tool="audio"] .blok-audio-controls__speed-slider::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: var(--blok-radius-pill);
  background: var(--blok-text-primary);
  box-shadow: var(--blok-audio-thumb-shadow);
}

[data-blok-tool="audio"] .blok-audio-controls__speed-chips {
  display: flex;
  gap: var(--blok-space-1);
}
[data-blok-tool="audio"] .blok-audio-controls__speed-chip {
  flex: 1 1 0;
  padding: var(--blok-space-1) 0;
  border: 0;
  border-radius: var(--blok-radius-sm);
  background: transparent;
  color: var(--blok-text-secondary);
  font-size: var(--blok-font-size-ui-compact);
  font-weight: var(--blok-font-weight-medium);
  font-variant-numeric: tabular-nums;
  text-align: center;
  cursor: pointer;
  transition: background var(--blok-duration-base) ease, color var(--blok-duration-base) ease;
}
[data-blok-tool="audio"] .blok-audio-controls__speed-chip:hover {
  background: var(--blok-bg-hover);
  color: var(--blok-text-primary);
}

/* ----- caption row (full-width footer) --------------------
   The row claims its full height in a single layout step; the visible reveal
   rides transform + opacity on the inner, keeping the whole animation on the
   compositor. This is deliberate: animating the row's *height* would resize the
   card every frame, forcing a re-raster of its 24px-blur box-shadow and the
   high-DPI waveform canvas each frame — which is what made the toggle lag.
   overflow:hidden clips the inner as it slides; padding/border live on the
   caption child below so they're clipped too. */
[data-blok-tool="audio"] .blok-audio-caption-row {
  grid-column: 1 / -1;
  grid-row: 2;
  overflow: hidden;
}
[data-blok-tool="audio"] .blok-audio-caption-row__inner {
  display: flex;
  align-items: flex-start;
  gap: var(--blok-space-2);
  transition:
    transform var(--blok-duration-slow) var(--blok-ease-popover),
    opacity var(--blok-duration-slow) var(--blok-ease-popover);
}
[data-blok-tool="audio"] .blok-audio-caption-row.is-collapsed .blok-audio-caption-row__inner {
  transform: translateY(6px);
  opacity: 0;
}
[data-blok-tool="audio"] .blok-audio-caption {
  flex: 1 1 auto;
  min-width: 0;
  display: block;
  padding-top: var(--blok-space-2-5);
  border-top: 1px solid var(--blok-border-subtle);
  font-size: var(--blok-audio-caption-font-size, var(--blok-font-size-ui-label));
  color: var(--blok-text-secondary);
  line-height: var(--blok-line-height-body);
  outline: none;
  min-height: 1em;
}
[data-blok-tool="audio"] [data-role="audio-caption"][contenteditable="true"]:empty::before {
  content: attr(data-placeholder);
  color: var(--blok-text-tertiary);
  pointer-events: none;
}

/* ----- empty / loading / error states --------------------- */
[data-blok-tool="audio"][data-state="empty"] .blok-audio-inner,
[data-blok-tool="audio"][data-state="loading"] .blok-audio-inner {
  opacity: 0.7;
}
[data-blok-tool="audio"][data-state="error"] .blok-audio-inner {
  border-color: color-mix(in srgb, var(--blok-color-danger) 30%, var(--blok-border-subtle));
  background: color-mix(in srgb, var(--blok-color-danger) 4%, var(--blok-bg-primary));
}

/* ----- error state — flat soft-danger callout (mirrors video error) ----- */
[data-blok-tool="audio"] .blok-audio-error-state {
  padding: var(--blok-space-3);
  background: color-mix(in srgb, var(--blok-color-danger) 6%, var(--blok-bg-secondary));
  border: 1px solid color-mix(in srgb, var(--blok-color-danger) 18%, var(--blok-border-subtle));
  border-radius: var(--blok-radius-lg);
  display: flex; gap: var(--blok-space-3); align-items: center;
  color: var(--blok-text-primary);
  font-family: var(--blok-font-family, var(--blok-font-sans));
  text-align: left;
}
[data-blok-tool="audio"] .blok-audio-retry {
  margin-left: auto;
  flex-shrink: 0;
  appearance: none;
  padding: var(--blok-space-1-5) var(--blok-space-3);
  border-radius: var(--blok-radius-md);
  border: 1px solid var(--blok-border-subtle);
  background: var(--blok-bg-primary);
  color: var(--blok-text-primary);
  font-size: 12.5px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background var(--blok-duration-base) ease, border-color var(--blok-duration-base) ease;
}
[data-blok-tool="audio"] .blok-audio-retry:hover {
  background: var(--blok-bg-hover);
  border-color: var(--blok-border-primary);
}
[data-blok-tool="audio"] .blok-audio-retry:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--blok-color-accent) 40%, transparent);
}

/* ----- hide caption in non-rendered states --------------- */
[data-blok-tool="audio"]:not([data-state="rendered"]) .blok-audio-caption-row {
  display: none;
}

/* =================================================
   Motion — bring the player to life

   A staggered entrance as the rendered card mounts — CSS-only and
   reduced-motion gated.
   ================================================= */

/* ----- mount entrance — rows lift into place, staggered -------- */
[data-blok-tool="audio"][data-state="rendered"] .blok-audio-cover,
[data-blok-tool="audio"][data-state="rendered"] .blok-audio-title,
[data-blok-tool="audio"][data-state="rendered"] .blok-audio-artist,
[data-blok-tool="audio"][data-state="rendered"] .blok-audio-waveform,
[data-blok-tool="audio"][data-state="rendered"] .blok-audio-controls {
  animation: blok-audio-rise var(--blok-duration-fade) var(--blok-ease-popover) both;
}
[data-blok-tool="audio"] .blok-audio-title    { animation-delay: 40ms; }
[data-blok-tool="audio"] .blok-audio-artist   { animation-delay: 80ms; }
[data-blok-tool="audio"] .blok-audio-waveform { animation-delay: 120ms; }
[data-blok-tool="audio"] .blok-audio-controls { animation-delay: 160ms; }

@keyframes blok-audio-rise {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* The vinyl placeholder's spin is driven by disc.ts (inertial rotation via
   transform), not a CSS animation — see the .blok-audio-cover__disc rule. */

/* ----- reduced motion ------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  [data-blok-tool="audio"] .blok-audio-inner,
  [data-blok-tool="audio"] .blok-audio-controls [data-role],
  [data-blok-tool="audio"] .blok-audio-controls__volume { transition: none; }

  [data-blok-tool="audio"][data-state="rendered"] .blok-audio-cover,
  [data-blok-tool="audio"][data-state="rendered"] .blok-audio-title,
  [data-blok-tool="audio"][data-state="rendered"] .blok-audio-artist,
  [data-blok-tool="audio"][data-state="rendered"] .blok-audio-waveform,
  [data-blok-tool="audio"][data-state="rendered"] .blok-audio-controls {
    animation: none;
  }
  /* The record holds still under reduced motion (disc.ts skips the spin loop). */
  /* Caption appears/disappears instantly (JS also takes the instant path). */
  [data-blok-tool="audio"] .blok-audio-caption-row__inner { transition: none; }
  /* Cover overlay button appears instantly — no fade. */
  [data-blok-tool="audio"] .blok-audio-cover__change { transition: none; }
}
