/* ttsCast — custom web audio player.
 *
 * Pairs with static/js/tts-player.js. The markup on every public page ships a
 * plain <audio controls preload="metadata"> inside a [data-tts-player] wrapper;
 * the script builds the chrome below and only then hides the native controls.
 * If the script never runs (blocked, errored, old browser) nothing here shows
 * and the native player stays fully usable — see the "fallback" block.
 *
 * Colours come from static/css/tokens.css where a token exists; the rest are
 * the mobile app's values (accent #5FD48B, navy #0d0f25). Every non-text part
 * (track, buffered band, played bar, knob, button borders) clears 3:1 against
 * the dark card it sits on; the [data-theme="light"] / .ttsp--light overrides
 * do the same against a light surface.
 */

/* ---------------------------------------------------------------- fallback */

/* Kept from PR #184: force the NATIVE chrome to its light skin, because in a
 * dark OS Chrome/Safari otherwise paint a near-invisible dark control skin.
 * Once the script upgrades a player the native element is hidden, so this only
 * ever affects the fallback state. */
audio {
    color-scheme: light;
}

[data-tts-player] > audio {
    width: 100%;
    background: #f7fafc;
    border-radius: 8px;
    padding: 2px 4px;
}

/* Upgraded: keep the element in the accessibility/media pipeline but out of
 * sight. Deliberately NOT display:none — a hidden-by-display media element has
 * a history of playback quirks; clipping it to 1px has none. */
[data-tts-player].ttsp-ready > audio {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    opacity: 0;
    pointer-events: none;
}

/* ------------------------------------------------------------------ tokens */

[data-tts-player] {
    /* Accent A (#5FD48B) — the shipped mobile-app green. tokens.css still
       carries the original mint as --tts-color-play-icon; don't use it here. */
    --ttsp-accent: #5FD48B;
    --ttsp-accent-hover: #7ee0a4;
    --ttsp-ink: #0d0f25;
    --ttsp-track: #6b7a99;
    --ttsp-buffered: #aab6cc;
    --ttsp-text: #e8eefc;
    --ttsp-text-dim: #cbd5e0;
    --ttsp-btn-bg: rgba(255, 255, 255, 0.08);
    --ttsp-btn-bg-hover: rgba(255, 255, 255, 0.16);
    --ttsp-focus: #94f6a5;
    --ttsp-error: #ff8a8a;

    position: relative;
    font-family: var(--tts-font-sans, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);
}

/* Future light surfaces (no public page uses one today). Accent darkens so the
 * played bar and knob still clear 3:1 against white — #5FD48B does not. */
[data-theme="light"] [data-tts-player],
[data-tts-player].ttsp--light {
    --ttsp-accent: #1f9d57;
    --ttsp-accent-hover: #177f45;
    --ttsp-ink: #ffffff;
    --ttsp-track: #8a93a5;
    --ttsp-buffered: #c8cedb;
    --ttsp-text: #111827;
    --ttsp-text-dim: #4b5563;
    --ttsp-btn-bg: rgba(17, 24, 39, 0.06);
    --ttsp-btn-bg-hover: rgba(17, 24, 39, 0.12);
    --ttsp-focus: #1f9d57;
    --ttsp-error: #b91c1c;
}

/* -------------------------------------------------------------------- grid */

.ttsp-ui {
    display: grid;
    grid-template-columns: auto auto 1fr auto auto auto;
    grid-template-areas: "play cur bar dur rate vol";
    align-items: center;
    column-gap: 10px;
    width: 100%;
}

/* ------------------------------------------------------------- play/pause */

.ttsp-play {
    grid-area: play;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    min-width: 44px;
    padding: 0;
    border: none;
    border-radius: 9999px;
    background: var(--ttsp-accent);
    color: var(--ttsp-ink);
    cursor: pointer;
    align-self: center;
    transition: background var(--tts-dur-fast, 200ms) ease, transform var(--tts-dur-fast, 200ms) ease;
}

.ttsp-play:hover { background: var(--ttsp-accent-hover); }
.ttsp-play:active { transform: scale(0.94); }
.ttsp-play svg { width: 20px; height: 20px; display: block; fill: currentColor; }

/* Icon swap is driven by the wrapper's state class — no innerHTML churn. */
.ttsp-play .ttsp-i-pause,
.ttsp-play .ttsp-i-spin { display: none; }
[data-tts-player].ttsp-playing .ttsp-play .ttsp-i-play { display: none; }
[data-tts-player].ttsp-playing .ttsp-play .ttsp-i-pause { display: block; }
[data-tts-player].ttsp-loading .ttsp-play .ttsp-i-play,
[data-tts-player].ttsp-loading .ttsp-play .ttsp-i-pause { display: none; }
[data-tts-player].ttsp-loading .ttsp-play .ttsp-i-spin { display: block; }

.ttsp-i-spin {
    animation: ttsp-spin var(--tts-dur-spin, 900ms) linear infinite;
    transform-origin: 50% 50%;
}

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

/* ------------------------------------------------------------------ times */

.ttsp-time {
    font-size: 12px;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    color: var(--ttsp-text-dim);
    white-space: nowrap;
}

.ttsp-cur { grid-area: cur; }

.ttsp-dur {
    grid-area: dur;
    background: none;
    border: none;
    padding: 4px 2px;
    margin: 0;
    cursor: pointer;
    font-family: inherit;
}

.ttsp-dur:hover { color: var(--ttsp-text); }

/* ---------------------------------------------------------- progress bar */

.ttsp-bar {
    grid-area: bar;
    position: relative;
    min-width: 0;            /* the 1fr column must be allowed to shrink */
    height: 28px;
    padding: 0 8px;          /* knob travel stays inside the box */
    box-sizing: border-box;
    cursor: pointer;
    touch-action: none;      /* drag-to-seek must win over page scroll */
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    border-radius: 6px;
}

.ttsp-bar[aria-disabled="true"] {
    cursor: default;
    opacity: 0.55;
}

.ttsp-rail {
    position: absolute;
    left: 8px;
    right: 8px;
    top: 50%;
    height: 6px;
    margin-top: -3px;
    border-radius: 3px;
    background: var(--ttsp-track);
    overflow: hidden;
}

.ttsp-buffered,
.ttsp-played {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    transform: scaleX(0);
    transform-origin: 0 50%;
    will-change: transform;
}

.ttsp-buffered { background: var(--ttsp-buffered); }
.ttsp-played { background: var(--ttsp-accent); }

.ttsp-knob {
    position: absolute;
    left: 8px;
    top: 50%;
    width: 14px;
    height: 14px;
    margin-left: -7px;
    border-radius: 50%;
    background: var(--ttsp-accent);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
    transform: translate3d(0, -50%, 0);
    will-change: transform;
    pointer-events: none;
}

.ttsp-bar.ttsp-dragging .ttsp-knob,
.ttsp-bar:hover .ttsp-knob { width: 16px; height: 16px; margin-left: -8px; }

/* ----------------------------------------------------- rate / volume pills */

.ttsp-rate,
.ttsp-vol {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 28px;
    padding: 0 8px;
    border: 1px solid var(--ttsp-track);
    border-radius: 9999px;
    background: var(--ttsp-btn-bg);
    color: var(--ttsp-text);
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--tts-dur-fast, 200ms) ease;
}

.ttsp-rate { grid-area: rate; min-width: 40px; }
.ttsp-volbox { grid-area: vol; display: inline-flex; align-items: center; gap: 8px; }
.ttsp-vol { width: 32px; padding: 0; }
.ttsp-rate:hover,
.ttsp-vol:hover { background: var(--ttsp-btn-bg-hover); }
.ttsp-vol svg { width: 16px; height: 16px; display: block; fill: currentColor; }
.ttsp-vol .ttsp-i-muted { display: none; }
[data-tts-player].ttsp-muted .ttsp-vol .ttsp-i-loud { display: none; }
[data-tts-player].ttsp-muted .ttsp-vol .ttsp-i-muted { display: block; }

/* -------------------------------------------------------- volume slider */

/* Native range so keyboard/AT behave for free. The filled part is a gradient
 * driven by --v (set from JS); rail and knob reuse the progress-bar colours. */
.ttsp-vslider {
    -webkit-appearance: none;
    appearance: none;
    width: 84px;
    height: 28px;
    margin: 0;
    padding: 0;
    background: transparent;
    cursor: pointer;
    --v: 100%;
}
.ttsp-vslider::-webkit-slider-runnable-track {
    height: 6px;
    border-radius: 3px;
    background: linear-gradient(to right, var(--ttsp-accent) var(--v), var(--ttsp-track) var(--v));
}
.ttsp-vslider::-moz-range-track {
    height: 6px;
    border-radius: 3px;
    background: linear-gradient(to right, var(--ttsp-accent) var(--v), var(--ttsp-track) var(--v));
}
.ttsp-vslider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 14px;
    height: 14px;
    margin-top: -4px;
    border: none;
    border-radius: 50%;
    background: var(--ttsp-accent);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}
.ttsp-vslider::-moz-range-thumb {
    width: 14px;
    height: 14px;
    border: none;
    border-radius: 50%;
    background: var(--ttsp-accent);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}
.ttsp-vslider:hover::-webkit-slider-thumb { background: var(--ttsp-accent-hover); }
.ttsp-vslider:hover::-moz-range-thumb { background: var(--ttsp-accent-hover); }
.ttsp-vslider:focus-visible {
    outline: 2px solid var(--ttsp-focus);
    outline-offset: 2px;
    border-radius: 6px;
}

/* -------------------------------------------------------------- focus/error */

.ttsp-ui button:focus-visible,
.ttsp-bar:focus-visible {
    outline: 2px solid var(--ttsp-focus);
    outline-offset: 2px;
}

@supports not selector(:focus-visible) {
    .ttsp-ui button:focus,
    .ttsp-bar:focus {
        outline: 2px solid var(--ttsp-focus);
        outline-offset: 2px;
    }
}

.ttsp-error {
    margin: 6px 0 0;
    font-size: 12px;
    line-height: 1.4;
    color: var(--ttsp-error);
}

/* Upgrade failed at runtime: custom chrome out, native control back in. */
[data-tts-player].ttsp-failed .ttsp-ui { display: none; }

[data-tts-player].ttsp-failed > audio {
    position: static;
    width: 100%;
    height: auto;
    opacity: 1;
    pointer-events: auto;
    padding: 2px 4px;
}

/* ------------------------------------------------------------- narrow */

/* Phones: the bar gets its own full-width row above the readouts. Declared
   after the component rules above so these overrides win at equal specificity. */
@media (max-width: 520px) {
    .ttsp-ui {
        grid-template-columns: auto auto 1fr auto;
        grid-template-areas:
            "play bar bar  bar"
            "play cur dur  rate";
        column-gap: 8px;
        row-gap: 2px;
    }

    .ttsp-play { grid-row: 1 / span 2; }

    /* Push the duration up against the speed pill: 0:00 ...... -3:21  1x */
    .ttsp-dur { justify-self: end; }

    /* Hardware keys own volume on the phones that reach this breakpoint. */
    .ttsp-volbox { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .ttsp-play,
    .ttsp-rate,
    .ttsp-vol { transition: none; }
    .ttsp-i-spin { animation: none; }
    .ttsp-play:active { transform: none; }
}
