/**
 * BOOM Audio Player — base styles only.
 * Layout and visual design are the user's job via Cornerstone elements + state classes
 * (.is-playing / .is-paused / .is-loading / .is-muted on .boom-audio-player).
 */

.boom-waveform {
    width: 100%;
    cursor: pointer;
    /* Anchor for the loading indicator, which is positioned rather than laid out in flow. */
    position: relative;
}

/* While decoding, hint the loading state without forcing any visual design. */
.boom-audio-player.is-loading .boom-waveform {
    opacity: 0.6;
}

/* Reactive variation switching: the form hides the non-active variation's player (or its
   outer .boom-audio-frame wrapper). Uses a class (not inline display) so the user's own
   display type is preserved when shown. The editor never adds it, so all stay visible. */
.bap-variation-hidden {
    display: none !important;
}

/* Native <audio> fallback should never be cropped. */
.boom-audio-fallback {
    display: block;
    width: 100%;
}

/* Editor placeholder waveform (removed on the frontend once the real player mounts). */
.boom-waveform-ph {
    width: 100%;
    display: block;
    opacity: 0.5;
    pointer-events: none;
}
.boom-waveform-ph svg {
    width: 100%;
    height: 100%;
    display: block;
}

/* Shown in place of the player when the audio source cannot be loaded. Inherits the surrounding
   type so it sits in the design instead of announcing itself. */
.boom-audio-unavailable {
    margin: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    opacity: 0.6;
}

/* Shown while the source is being probed. Deciding whether a file is playable can take seconds,
   and on a request that never answers it runs into the 8s timeout — without a sign of activity the
   empty slot reads as broken. Sized off the current font so it fits wherever the player sits, and
   drawn in the inherited colour so it needs no palette of its own. */
.boom-audio-loading {
    /* Positioned, not laid out in flow. In flow it sits after wavesurfer's own wrapper, which the
       library mounts into this container before its height is settled — so the indicator started
       at the bottom edge and jumped to the middle once that height resolved. Taking it out of flow
       makes its position independent of whatever else is in the container at the time.
       Centred via inset + auto margins rather than a translate, which would collide with the
       rotation on `transform`. */
    position: absolute;
    inset: 0;
    margin: auto;
    width: 1.2em;
    height: 1.2em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    opacity: 0.4;
    animation: boom-audio-spin 0.7s linear infinite;
}

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

/* Respect a reduced-motion preference: keep the indicator, drop the rotation. */
@media (prefers-reduced-motion: reduce) {
    .boom-audio-loading {
        animation: none;
        border-right-color: currentColor;
        opacity: 0.25;
    }
}

/* ---------------------------------------------------------------------------
 * Scrolling track title ("Lauftext")
 *
 * Opt in per element with data-bap-marquee, e.g. on the track-name text inside the player.
 * Giving the surrounding info column a fixed width is what makes every waveform on a page the
 * same width; the titles that no longer fit that column are the ones this handles.
 *
 * The JS wraps the element's contents in .bap-marquee-track, measures the overflow and only then
 * adds .is-marquee — a title that fits stays completely static.
 * --------------------------------------------------------------------------- */

[data-bap-marquee] {
    overflow: hidden;
    /* Two clamps, because the element sits in a flex column: min-width kills the automatic
       minimum size (content width) that would push the fixed-width column wider, max-width holds
       it to the column once align-items is not stretch. */
    min-width: 0;
    max-width: 100%;
}

.bap-marquee-track {
    display: inline-block;
    white-space: nowrap;
}

/* Scroll to the end, hold, scroll back, hold. There-and-back rather than a wrapping loop: the
   title reads from its start on every pass and the markup stays a single copy of the text. */
[data-bap-marquee].is-marquee .bap-marquee-track {
    animation: bap-marquee var(--bap-marquee-duration, 8s) ease-in-out infinite;
}

@keyframes bap-marquee {
    0%,  8%   { transform: translateX(0); }
    42%, 58%  { transform: translateX(var(--bap-marquee-shift, 0px)); }
    92%, 100% { transform: translateX(0); }
}

/* Reduced motion: no scrolling. The tail is then unreachable, so mark it as cut rather than
   ending the visible text flush against the edge. The full title is on the title attribute. */
@media (prefers-reduced-motion: reduce) {
    [data-bap-marquee].is-marquee .bap-marquee-track {
        animation: none;
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
    }
}
