/* Radio Station Player Public Styles
 * --------------------------------------------------------------------
 * Every player color lives in the :root custom-property block below.
 * The Colors tab in wp-admin overrides these via an inline <style>
 * block emitted by RSP_Public::output_custom_colors() (which writes
 * the same variable names). Keep the var() fallbacks in sync with
 * RSP_Admin::get_default_color_settings() so the player still looks
 * sensible if the inline block is ever missing.
 * ------------------------------------------------------------------ */

:root {
    /* Compact Play Button (shared by compact + mini) */
    --rsp-btn-bg: #ffffff;
    --rsp-btn-border: #ffffff;
    --rsp-btn-shadow: rgba(0, 0, 0, 0.15);
    --rsp-btn-hover-shadow: rgba(0, 0, 0, 0.2);
    --rsp-btn-play-icon: #333333;
    --rsp-btn-pause-icon: #333333;
    --rsp-btn-pulse-1: #ff8c42;
    --rsp-btn-pulse-2: #ff1493;

    /* Listen Live overlay */
    --rsp-listen-live-color: #ffffff;
    --rsp-listen-live-shadow: rgba(0, 0, 0, 0.4);
    --rsp-listen-live-stroke: rgba(255, 255, 255, 0.8);

    /* Now-Playing Pill */
    --rsp-pill-bg: rgba(0, 0, 0, 0.85);
    --rsp-pill-text: #ffffff;
    --rsp-pill-label: rgba(255, 255, 255, 0.65);
    --rsp-pill-artist: #ffffff;
    --rsp-pill-title: rgba(255, 255, 255, 0.92);
    --rsp-pill-placeholder: rgba(255, 255, 255, 0.75);
    --rsp-pill-separator: rgba(255, 255, 255, 0.6);
    --rsp-pill-cover-bg: rgba(255, 255, 255, 0.08);
    --rsp-pill-cover-shadow: rgba(0, 0, 0, 0.4);
    --rsp-pill-shadow: rgba(0, 0, 0, 0.22);

    /* Vote buttons (inside the pill) */
    --rsp-vote-idle: rgba(255, 255, 255, 0.7);
    --rsp-vote-hover: #ffffff;
    --rsp-vote-up-active: #4caf50;
    --rsp-vote-down-active: #e53935;
    /* Heart fill when the listener has favourited the song. Pink keeps
       the affordance idiomatic ("liked = heart") and stays clearly
       distinct from the red dislike thumb. */
    --rsp-vote-favorite-active: #e91e63;
    --rsp-vote-disabled-opacity: 0.4;

    /* Toast (favourite-added confirmation) */
    --rsp-toast-bg: rgba(20, 20, 20, 0.92);
    --rsp-toast-color: #ffffff;
    --rsp-toast-shadow: rgba(0, 0, 0, 0.25);

    /* Volume popup card (shared) */
    --rsp-vol-popup-bg: rgba(20, 20, 22, 0.95);
    --rsp-vol-popup-shadow: rgba(0, 0, 0, 0.35);
    --rsp-vol-icon: #333333;
    --rsp-vol-icon-muted: #999999;
    --rsp-vol-track-bg: rgba(255, 255, 255, 0.22);
    --rsp-vol-track-fill: rgba(255, 255, 255, 0.95);
    --rsp-vol-thumb-bg: #ffffff;
    --rsp-vol-thumb-shadow: rgba(0, 0, 0, 0.45);
    --rsp-vol-thumb-hover-shadow: rgba(0, 0, 0, 0.55);

    /* Recently Played history list */
    --rsp-history-separator: rgba(0, 0, 0, 0.08);
    --rsp-history-artist: #000000;
    --rsp-history-title: rgba(0, 0, 0, 0.9);
    --rsp-history-time: rgba(0, 0, 0, 0.7);
    --rsp-history-status: rgba(0, 0, 0, 0.75);
    --rsp-history-error: #b94a48;
    --rsp-history-cover-bg: rgba(0, 0, 0, 0.06);

    /* Standalone Now Playing ([now_playing]) */
    --rsp-now-playing-bg: #f8f9fa;
    --rsp-now-playing-border: #dee2e6;
    --rsp-now-playing-artist: #000000;
    --rsp-now-playing-song: #666666;

    /* Error messages */
    --rsp-error-text: #dc3545;
    --rsp-error-bg: rgba(248, 215, 218, 0.9);
    --rsp-error-border: rgba(245, 198, 203, 0.9);
}

.rsp-player {
    margin: 0;
    padding: 0;
    background: transparent;
    border: none;
}

.rsp-audio-player {
    display: none; /* Hide the native audio element */
}

.rsp-play-pause-btn,
.rsp-volume-btn {
    border: none;
    background: none;
    cursor: pointer;
    padding: 0;
    opacity: 0.8;
    transition: opacity 0.2s;
}

.rsp-play-pause-btn:hover,
.rsp-volume-btn:hover {
    opacity: 1;
}

.rsp-play-pause-icon,
.rsp-volume-icon {
    width: 60px;
    height: 60px;
    display: block;
}

.rsp-volume-control {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.rsp-volume-btn {
    border: none;
    background: none;
    cursor: pointer;
    padding: 0;
    opacity: 0.8;
    transition: opacity 0.2s;
}

.rsp-volume-btn:hover {
    opacity: 1;
}

.rsp-volume-icon {
    width: 32px;
    height: 32px;
    display: block;
    color: var(--rsp-vol-icon);
}

.rsp-volume-slider-container {
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    background: transparent;
    padding: 10px;
    border-radius: 10px;
    display: none;
    height: 120px;
    margin-bottom: 5px;
}

.rsp-volume-control:hover .rsp-volume-slider-container {
    display: block;
}

.rsp-volume-slider {
    -webkit-appearance: none;
    width: 100px;
    height: 4px;
    background: var(--rsp-vol-track-bg);
    border-radius: 2px;
    transform: rotate(-90deg) translateX(-50px) translateY(-50px);
    transform-origin: left;
    margin: 0;
}

.rsp-volume-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 20px;
    height: 20px;
    background: var(--rsp-vol-thumb-bg);
    border-radius: 50%;
    cursor: pointer;
    transition: all 0.2s;
    box-shadow: 0 2px 4px var(--rsp-vol-thumb-shadow);
}

.rsp-volume-slider::-webkit-slider-thumb:hover {
    transform: scale(1.2);
    box-shadow: 0 3px 6px var(--rsp-vol-thumb-hover-shadow);
}

.rsp-volume-slider::-moz-range-thumb {
    width: 20px;
    height: 20px;
    background: var(--rsp-vol-thumb-bg);
    border-radius: 50%;
    cursor: pointer;
    border: none;
    transition: all 0.2s;
    box-shadow: 0 2px 4px var(--rsp-vol-thumb-shadow);
}

.rsp-volume-slider::-moz-range-thumb:hover {
    transform: scale(1.2);
    box-shadow: 0 3px 6px var(--rsp-vol-thumb-hover-shadow);
}

/* Make the clickable area larger */
.rsp-volume-slider::-webkit-slider-runnable-track {
    height: 8px;
    cursor: pointer;
}

.rsp-volume-slider::-moz-range-track {
    height: 8px;
    cursor: pointer;
}

/* Error message styling */
.rsp-player-error {
    color: var(--rsp-error-text);
    font-size: 14px;
    margin-top: 10px;
    padding: 10px;
    background: var(--rsp-error-bg);
    border: 1px solid var(--rsp-error-border);
    border-radius: 4px;
}

/* Now Playing styles ([now_playing] shortcode container) */
.rsp-now-playing {
    margin: 20px 0;
    padding: 15px;
    background: var(--rsp-now-playing-bg);
    border: 1px solid var(--rsp-now-playing-border);
    border-radius: 4px;
    display: flex;
    align-items: center;
}

.rsp-now-playing-artwork {
    flex: 0 0 80px;
    margin-right: 15px;
}

.rsp-now-playing-artwork img {
    width: 80px;
    height: 80px;
    border-radius: 4px;
    display: block;
}

.rsp-now-playing-info {
    flex: 1;
}

.rsp-now-playing-artist {
    font-size: 18px;
    font-weight: bold;
    margin-bottom: 5px;
    color: var(--rsp-now-playing-artist);
}

.rsp-now-playing-song {
    font-size: 16px;
    color: var(--rsp-now-playing-song);
}

/* Firefox specific styles */
@-moz-document url-prefix() {
    .rsp-audio-player {
        width: 150px;
    }
}

/* Edge/IE specific styles */
@supports (-ms-ime-align:auto) {
    .rsp-audio-player {
        width: 150px;
    }
}

/* Who's On Air Now Widget - Photo Layering */
.elementor-element-94861b6 {
    position: relative;
}

.elementor-element-39e3e5b {
    position: relative;
    display: block;
    /* Border is applied by Elementor Loop Grid styles */
    /* Background image is set via inline style from PHP - sits behind border */
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}

/* Hide the img tag visually - kept in HTML for accessibility/SEO, but using background-image for layering */
.rsp-on-air-photo {
    display: none;
}

/* Compact Player Styles */
.rsp-compact-player {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0;
    flex-direction: row;
}

/* Circular Play Button
 *
 * !important on geometry/chrome: Theme Builder syncs Brand Kit
 * button_radius into Elementor Theme Style → Buttons, which targets
 * native <button> site-wide. When radius is 0 (common for country /
 * brutalist archetypes) that flattens this control into a square
 * unless we lock the circle and player chrome. Same for font-family
 * — Elementor widget/global typography rules load later. */
.rsp-compact-play-btn {
    width: 203px !important;
    height: 203px !important;
    border-radius: 50% !important;
    border: 10px solid var(--rsp-btn-border) !important;
    background: var(--rsp-btn-bg) !important;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 !important;
    margin: 0;
    flex-shrink: 0;
    position: absolute;
    right: 0;
    z-index: 10;
    transition: all 0.3s ease;
    box-shadow: 0 2px 8px var(--rsp-btn-shadow);
    font-family: inherit !important;
    font-style: inherit !important;
}

.rsp-compact-play-btn:hover {
    transform: scale(1.05);
    box-shadow: 0 3px 12px var(--rsp-btn-hover-shadow);
}

.rsp-compact-play-btn:active {
    transform: scale(0.98);
}

/* Pulsing background animation when playing.
 *
 * NOTE: The keyframe `rsp-pulse-orange-pink` is emitted DYNAMICALLY by
 * RSP_Public::output_custom_colors() so the pulse uses whichever two
 * colors the admin saved. We keep a baseline keyframe here as a
 * fallback for environments where the inline <style> block isn't
 * present yet (e.g. plugin just activated, no save yet). The dynamic
 * version overrides it. CSS variables aren't reliably interpolated
 * inside @keyframes in Safari/Firefox, which is why the values are
 * inlined per-emit rather than referenced via var(). */
@keyframes rsp-pulse-orange-pink {
    0% {
        background-color: #ff8c42;
    }
    50% {
        background-color: #ff1493;
    }
    100% {
        background-color: #ff8c42;
    }
}

.rsp-compact-play-btn.rsp-compact-playing {
    animation: rsp-pulse-orange-pink 3s ease-in-out infinite;
}

.rsp-compact-play-icon {
    width: 120px;
    height: 120px;
    color: var(--rsp-btn-play-icon);
    display: block;
}

.rsp-compact-pause-icon {
    width: 120px;
    height: 120px;
    color: var(--rsp-btn-pause-icon);
    display: block;
}

/* Listen Live Text Overlay */
.rsp-listen-live-text {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    /* Inherit font-family from the page (Elementor/theme) rather than
     * falling back to the UA <button> default. !important needed to
     * defeat Elementor's later-loaded widget/global typography rules. */
    font-family: inherit !important;
    font-style: inherit !important;
    font-size: 20px;
    font-weight: 900;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--rsp-listen-live-color);
    z-index: 11;
    pointer-events: none;
    text-shadow: 0 2px 8px var(--rsp-listen-live-shadow), 0 0 2px var(--rsp-listen-live-shadow);
    -webkit-text-stroke: 0.5px var(--rsp-listen-live-stroke);
    text-stroke: 0.5px var(--rsp-listen-live-stroke);
    white-space: nowrap;
    transition: all 0.3s ease;
    opacity: 1;
}

.rsp-compact-play-btn:hover .rsp-listen-live-text {
    text-shadow: 0 2px 10px var(--rsp-listen-live-shadow), 0 0 3px var(--rsp-listen-live-shadow);
}

/* Hide "Listen Live" text when playing */
.rsp-compact-play-btn.rsp-compact-playing .rsp-listen-live-text,
.rsp-mini-compact-play-btn.rsp-mini-compact-playing .rsp-listen-live-text {
    opacity: 0;
    visibility: hidden;
}

.rsp-compact-volume-control {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0;
}

/* Icon-only — lock chrome so Elementor Theme Style → Buttons
 * (synced from Theme Builder Brand Kit) cannot paint this as a CTA. */
.rsp-compact-volume-btn {
    border: none !important;
    background: none !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    cursor: pointer;
    padding: 4px !important;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0.85;
    transition: opacity 0.2s;
    flex-shrink: 0;
}

.rsp-compact-volume-btn:hover {
    opacity: 1;
}

.rsp-compact-volume-icon {
    width: 32px;
    height: 32px;
    display: block;
    color: var(--rsp-vol-icon);
}

/* === Vertical volume popup (Spotify/YouTube style) ===
 * Anchored BELOW the icon (popping up was getting clipped by parent
 * containers / page chrome). Hidden by default; revealed when the
 * volume control is hovered or focused. Because the popup is a child
 * of .rsp-compact-volume-control, the parent's :hover state stays
 * active while the cursor is on the popup. */
.rsp-compact-volume-slider-container {
    position: absolute;
    top: 100%;
    left: 50%;
    width: 36px;
    height: 118px;
    background: var(--rsp-vol-popup-bg);
    border-radius: 18px;
    box-shadow: 0 6px 18px var(--rsp-vol-popup-shadow);
    transform: translate(-50%, -6px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform-origin: top center;
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0s linear 0.18s;
    z-index: 10001; /* above the now-playing pill (9999) */
}

.rsp-compact-volume-control:hover .rsp-compact-volume-slider-container,
.rsp-compact-volume-control:focus-within .rsp-compact-volume-slider-container {
    opacity: 1;
    visibility: visible;
    transform: translate(-50%, 0);
    pointer-events: auto;
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0s linear 0s;
}

/* The rotated vertical slider sits absolute-centered inside the card.
 * Pre-rotation it's laid out as 86px × 4px; rotate(-90deg) makes it
 * visually 4px × 86px. The fill gradient is applied via JS so the
 * filled portion grows from the bottom up as volume increases. */
.rsp-compact-volume-slider {
    -webkit-appearance: none;
    appearance: none;
    width: 86px;
    height: 4px;
    background: var(--rsp-vol-track-bg);
    border-radius: 2px;
    margin: 0;
    padding: 0;
    cursor: pointer;
    outline: none;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) rotate(-90deg);
    transform-origin: center;
}

.rsp-compact-volume-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 14px;
    height: 14px;
    background: var(--rsp-vol-thumb-bg);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 1px 4px var(--rsp-vol-thumb-shadow);
    transition: transform 0.15s ease;
    margin-top: -5px;
}

.rsp-compact-volume-slider::-webkit-slider-thumb:hover,
.rsp-compact-volume-slider::-webkit-slider-thumb:active {
    transform: scale(1.18);
    box-shadow: 0 1px 4px var(--rsp-vol-thumb-hover-shadow);
}

.rsp-compact-volume-slider::-moz-range-thumb {
    width: 14px;
    height: 14px;
    background: var(--rsp-vol-thumb-bg);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 1px 4px var(--rsp-vol-thumb-shadow);
    transition: transform 0.15s ease;
}

.rsp-compact-volume-slider::-moz-range-thumb:hover,
.rsp-compact-volume-slider::-moz-range-thumb:active {
    transform: scale(1.18);
    box-shadow: 0 1px 4px var(--rsp-vol-thumb-hover-shadow);
}

.rsp-compact-volume-slider::-webkit-slider-runnable-track {
    height: 4px;
    background: transparent;
    border-radius: 2px;
    cursor: pointer;
}

.rsp-compact-volume-slider::-moz-range-track {
    height: 4px;
    background: transparent;
    border-radius: 2px;
    cursor: pointer;
}

/* Responsive Design for Compact Player */
@media (max-width: 768px) {
    .rsp-compact-play-btn {
        width: 110px !important;
        height: 110px !important;
    }

    .rsp-compact-play-icon,
    .rsp-compact-pause-icon {
        width: 40px;
        height: 40px;
    }

    .rsp-compact-volume-slider-container {
        width: 80px;
    }

    /* Mobile Listen Live Text */
    .rsp-listen-live-text {
        font-size: 12px;
        letter-spacing: 1px;
        -webkit-text-stroke: 0.3px var(--rsp-listen-live-stroke);
        text-stroke: 0.3px var(--rsp-listen-live-stroke);
    }
}

/* Mini Compact Player Styles (Half Size) */
.rsp-mini-compact-player {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0;
    flex-direction: row;
    /* Half the desktop offset since everything is half-size. */
    --rsp-content-shift-y: 20px;
}

/* Circular Play Button - Mini (see .rsp-compact-play-btn note). */
.rsp-mini-compact-play-btn {
    width: 101px !important;
    height: 101px !important;
    border-radius: 50% !important;
    border: 2.5px solid var(--rsp-btn-border) !important;
    background: var(--rsp-btn-bg) !important;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 !important;
    margin: 0;
    flex-shrink: 0;
    position: absolute;
    right: 0;
    z-index: 10;
    transition: all 0.3s ease;
    box-shadow: 0 1px 4px var(--rsp-btn-shadow);
    font-family: inherit !important;
    font-style: inherit !important;
}

.rsp-mini-compact-play-btn:hover {
    transform: scale(1.05);
    box-shadow: 0 1.5px 6px var(--rsp-btn-hover-shadow);
}

.rsp-mini-compact-play-btn:active {
    transform: scale(0.98);
}

.rsp-mini-compact-play-btn.rsp-mini-compact-playing {
    animation: rsp-pulse-orange-pink 3s ease-in-out infinite;
}

.rsp-mini-compact-play-icon {
    width: 60px;
    height: 60px;
    color: var(--rsp-btn-play-icon);
    display: block;
}

.rsp-mini-compact-pause-icon {
    width: 60px;
    height: 60px;
    color: var(--rsp-btn-pause-icon);
    display: block;
}

/* Mini Listen Live Text Overlay */
.rsp-listen-live-text-mini {
    font-size: 12px;
    font-weight: 900;
    letter-spacing: 1.5px;
    top: 50%;
    transform: translate(-50%, -50%);
    -webkit-text-stroke: 0.3px var(--rsp-listen-live-stroke);
    text-stroke: 0.3px var(--rsp-listen-live-stroke);
}

/* Expandable Panel - Mini */
.rsp-mini-compact-expandable {
    display: flex;
    align-items: center;
    gap: 10px;
    overflow: hidden;
    max-width: 0;
    opacity: 0;
    transition: max-width 0.3s ease-in-out, opacity 0.3s ease-in-out 0.1s;
    padding-left: 0;
    padding-right: 12.5px;
    flex-shrink: 0;
    position: absolute;
    right: 101px;
    /* Floats the EQ + volume row above the (centered) now-playing pill. */
    top: calc(50% - var(--rsp-content-shift-y, 25px));
    transform: translateY(-50%);
    height: 101px;
    justify-content: flex-end;
    white-space: nowrap;
    z-index: 10000;
}

.rsp-mini-compact-player.rsp-compact-expanded .rsp-mini-compact-expandable {
    max-width: 175px !important;
    opacity: 1;
    padding-left: 12.5px;
    /* Allow the vertical volume popup to rise above the panel. */
    overflow: visible;
}

.rsp-mini-compact-player.rsp-compact-collapsed .rsp-mini-compact-expandable {
    max-width: 0 !important;
    opacity: 0;
    padding-left: 0;
}

/* Volume Section - Mini */
.rsp-mini-compact-volume-section {
    display: flex;
    align-items: center;
    gap: 5px;
    flex-shrink: 0;
}

.rsp-mini-compact-volume-control {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0;
}

/* See .rsp-compact-volume-btn — keep icon-only under Elementor kit. */
.rsp-mini-compact-volume-btn {
    border: none !important;
    background: none !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    cursor: pointer;
    padding: 3px !important;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0.85;
    transition: opacity 0.2s;
    flex-shrink: 0;
}

.rsp-mini-compact-volume-btn:hover {
    opacity: 1;
}

.rsp-mini-compact-volume-icon {
    width: 20px;
    height: 20px;
    display: block;
    color: var(--rsp-vol-icon);
}

/* Vertical volume popup — mini variant (half-size card + slider). */
.rsp-mini-compact-volume-slider-container {
    position: absolute;
    top: 100%;
    left: 50%;
    width: 26px;
    height: 84px;
    background: var(--rsp-vol-popup-bg);
    border-radius: 13px;
    box-shadow: 0 4px 12px var(--rsp-vol-popup-shadow);
    transform: translate(-50%, -4px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform-origin: top center;
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0s linear 0.18s;
    z-index: 10001;
}

.rsp-mini-compact-volume-control:hover .rsp-mini-compact-volume-slider-container,
.rsp-mini-compact-volume-control:focus-within .rsp-mini-compact-volume-slider-container {
    opacity: 1;
    visibility: visible;
    transform: translate(-50%, 0);
    pointer-events: auto;
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0s linear 0s;
}

.rsp-mini-compact-volume-slider {
    -webkit-appearance: none;
    appearance: none;
    width: 60px;
    height: 3px;
    background: var(--rsp-vol-track-bg);
    border-radius: 2px;
    margin: 0;
    padding: 0;
    cursor: pointer;
    outline: none;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) rotate(-90deg);
    transform-origin: center;
}

.rsp-mini-compact-volume-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 10px;
    height: 10px;
    background: var(--rsp-vol-thumb-bg);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 1px 3px var(--rsp-vol-thumb-shadow);
    transition: transform 0.15s ease;
    margin-top: -3.5px;
}

.rsp-mini-compact-volume-slider::-webkit-slider-thumb:hover,
.rsp-mini-compact-volume-slider::-webkit-slider-thumb:active {
    transform: scale(1.2);
    box-shadow: 0 1px 3px var(--rsp-vol-thumb-hover-shadow);
}

.rsp-mini-compact-volume-slider::-moz-range-thumb {
    width: 10px;
    height: 10px;
    background: var(--rsp-vol-thumb-bg);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 1px 3px var(--rsp-vol-thumb-shadow);
    transition: transform 0.15s ease;
}

.rsp-mini-compact-volume-slider::-moz-range-thumb:hover,
.rsp-mini-compact-volume-slider::-moz-range-thumb:active {
    transform: scale(1.2);
    box-shadow: 0 1px 3px var(--rsp-vol-thumb-hover-shadow);
}

.rsp-mini-compact-volume-slider::-webkit-slider-runnable-track {
    height: 3px;
    background: transparent;
    border-radius: 2px;
    cursor: pointer;
}

.rsp-mini-compact-volume-slider::-moz-range-track {
    height: 3px;
    background: transparent;
    border-radius: 2px;
    cursor: pointer;
}

@media (max-width: 480px) {
    .rsp-compact-play-btn {
        width: 100px !important;
        height: 100px !important;
    }

    .rsp-compact-play-icon,
    .rsp-compact-pause-icon {
        width: 36px;
        height: 36px;
    }

    .rsp-compact-volume-slider-container {
        width: 70px;
    }

    /* Smaller Mobile Listen Live Text */
    .rsp-listen-live-text {
        font-size: 10px;
        letter-spacing: 0.8px;
        -webkit-text-stroke: 0.2px var(--rsp-listen-live-stroke);
        text-stroke: 0.2px var(--rsp-listen-live-stroke);
    }
}

/* =============================================================
 * Recently Played (StreamB) history list
 *
 * Baseline so the list is visible even with no theme styling.
 * Themes / Elementor can override these freely.
 * ============================================================= */
.rsp-history-list,
ul.rsp-history-list.custom-player-history-list {
    list-style: none;
    margin: 1em 0;
    padding: 0;
    min-height: 1.5em;
    display: block;
}

.rsp-history-list .custom-history-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--rsp-history-separator);
    line-height: 1.4;
}

.rsp-history-list .custom-history-item:last-child {
    border-bottom: none;
}

/* Album cover thumbnail. Hidden until JS sets a real src, so empty
 * items never render a broken-image icon. */
.rsp-history-list .track-cover {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border-radius: 4px;
    object-fit: cover;
    background: var(--rsp-history-cover-bg);
}

.rsp-history-list .track-cover[hidden] {
    display: none;
}

.rsp-history-list .track-info {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    line-height: 1.25;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

/* Stacked layout to match the now-playing pill: bold first line (song)
 * on top, lighter artist line below. The data flow upstream puts the
 * song name in item.artist and the artist name in item.title, so the
 * .track-artist / .track-title classes keep their roles. */
.rsp-history-list .track-artist {
    display: block;
    font-weight: 700;
    color: var(--rsp-history-artist);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rsp-history-list .track-title {
    display: block;
    color: var(--rsp-history-title);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rsp-history-list .track-time {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    font-size: 0.85em;
    color: var(--rsp-history-time);
    white-space: nowrap;
}

/* Status states (loading / empty / error) */
.rsp-history-list .rsp-history-status {
    padding: 8px 12px;
    font-style: italic;
    color: var(--rsp-history-status);
    list-style: none;
}

.rsp-history-list .rsp-history-error {
    color: var(--rsp-history-error);
    font-style: normal;
    opacity: 1;
}

.rsp-history-list .rsp-history-loading::after {
    content: '';
    display: inline-block;
    width: 0.8em;
    height: 0.8em;
    margin-left: 6px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    vertical-align: -2px;
    animation: rsp-history-spin 0.8s linear infinite;
}

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

/* Headless history list — exists only to drive the fetch loop so it
 * can populate the now-playing pill. Not meant to be seen. */
.rsp-history-list-headless {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    margin: 0 !important;
    padding: 0 !important;
    overflow: hidden !important;
    clip: rect(0 0 0 0) !important;
    clip-path: inset(50%) !important;
    white-space: nowrap !important;
    border: 0 !important;
    pointer-events: none !important;
}

/* Suppress the cover <img> inside the headless list so the browser
 * doesn't fetch a thumbnail no user will ever see. The pill's own
 * <img> already loads the same URL (and the browser will cache it). */
.rsp-history-list-headless .track-cover {
    display: none !important;
}

/* =============================================================
 * Now-playing card (sits to the LEFT of the play button, vertically
 * centered on it). Houses the big album cover, track info, and the
 * volume control on its right edge.
 * ============================================================= */
.rsp-now-playing-pill {
    position: absolute;
    /* Sits vertically centered on the play button, then shifted up by
       --rsp-pill-lift so it floats above the page-nav band below.
       Tune the value (or override per-page) to taste. */
    --rsp-pill-lift: 40px;
    top: calc(50% - var(--rsp-pill-lift, 0px));
    transform: translateY(-50%);
    /* 203px play button + 12px gap. */
    right: 215px;
    display: inline-flex;
    align-items: center;
    gap: 14px;
    max-width: 520px;
    padding: 10px 14px;
    background: var(--rsp-pill-bg);
    color: var(--rsp-pill-text);
    font-size: 14px;
    line-height: 1.3;
    border-radius: 16px;
    box-shadow: 0 4px 14px var(--rsp-pill-shadow);
    /* overflow: visible lets the volume popup escape the card; the
     * inner .rsp-now-playing-pill-track does its own ellipsis. */
    overflow: visible;
    pointer-events: auto;
    z-index: 9999;
}

/* Mini compact player variant — sits left of the 101px mini button. */
.rsp-mini-compact-player .rsp-now-playing-pill {
    right: 113px;
}

/* Big album cover — the visual anchor of the card. */
.rsp-now-playing-pill-cover {
    flex: 0 0 auto;
    width: 90px;
    height: 90px;
    border-radius: 8px;
    object-fit: cover;
    background: var(--rsp-pill-cover-bg);
    box-shadow: 0 2px 6px var(--rsp-pill-cover-shadow);
}

/* Text column between the cover and the volume control. */
.rsp-now-playing-pill-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    overflow: hidden;
}

.rsp-now-playing-pill-label {
    flex: 0 0 auto;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--rsp-pill-label);
}

/* Two-line track block: artist on the first line, song title on the
 * second. Each child handles its own ellipsis so a long artist won't
 * push the title off the card. */
.rsp-now-playing-pill-track {
    min-width: 0;
    line-height: 1.25;
}

.rsp-now-playing-pill-placeholder {
    display: block;
    font-style: italic;
    color: var(--rsp-pill-placeholder);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rsp-now-playing-pill-artist {
    display: block;
    font-weight: 700;
    color: var(--rsp-pill-artist);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Separator is redundant once artist and title are on separate lines. */
.rsp-now-playing-pill-sep {
    display: none;
}

.rsp-now-playing-pill-title {
    display: block;
    color: var(--rsp-pill-title);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Volume control inside the card uses the same shared volume colors,
 * but renders smaller than the default 32px icon so the card stays
 * compact. Only the pill instance shrinks; the standalone control
 * keeps the original size. */
.rsp-now-playing-pill .rsp-compact-volume-control {
    flex: 0 0 auto;
    margin-left: 4px;
}

.rsp-now-playing-pill .rsp-compact-volume-btn {
    padding: 2px !important;
}

.rsp-now-playing-pill .rsp-compact-volume-icon {
    width: 18px;
    height: 18px;
    color: var(--rsp-vol-icon);
}

/* =============================================================
 * Thumbs up / thumbs down vote buttons (inside the pill).
 * Sit on a row BELOW the artist/title, icon-only, no chrome.
 * Color shifts to indicate the active vote.
 * ============================================================= */
.rsp-vote-buttons {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-top: 6px;
}

.rsp-vote-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 6px 10px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--rsp-vote-idle);
    line-height: 1;
    cursor: pointer;
    transition: color 0.15s ease, background-color 0.15s ease, transform 0.1s ease;
    -webkit-appearance: none;
    appearance: none;
}

.rsp-vote-btn:hover:not(:disabled) {
    color: var(--rsp-vote-hover);
    background-color: rgba(255, 255, 255, 0.08);
}

.rsp-vote-btn:active:not(:disabled) {
    transform: scale(0.9);
}

.rsp-vote-btn:disabled {
    opacity: var(--rsp-vote-disabled-opacity);
    cursor: default;
}

.rsp-vote-btn .rsp-vote-icon {
    flex: 0 0 auto;
    display: block;
}

/* Active states — solid green like / solid red dislike / gold star. */
.rsp-vote-btn.rsp-vote-up.is-active {
    color: var(--rsp-vote-up-active);
}

.rsp-vote-btn.rsp-vote-down.is-active {
    color: var(--rsp-vote-down-active);
}

.rsp-vote-btn.rsp-favorite-btn.is-active {
    color: var(--rsp-vote-favorite-active);
}

.rsp-vote-buttons[data-busy="1"] .rsp-vote-btn {
    pointer-events: none;
    opacity: 0.7;
}

/* Hide on very small screens to keep the pill compact. */
@media (max-width: 480px) {
    .rsp-vote-buttons {
        display: none;
    }
}

/* Standalone volume control (no StreamB pill configured) — sits to
 * the left of the play button as a small floating button so the user
 * can still adjust audio. */
.rsp-compact-volume-control-standalone {
    position: absolute;
    top: 50%;
    right: 215px;
    transform: translateY(-50%);
    z-index: 9999;
}

/* On tablets, scale the cover down so the card stays balanced
 * against the 110px play button. */
@media (max-width: 768px) {
    .rsp-now-playing-pill {
        max-width: 360px;
        gap: 10px;
        padding: 8px 10px;
        font-size: 13px;
    }
    .rsp-now-playing-pill-cover {
        width: 58px;
        height: 58px;
    }
    .rsp-compact-player .rsp-now-playing-pill,
    .rsp-compact-player .rsp-compact-volume-control-standalone {
        right: 122px;
    }
}

/* On phones, hide the "Now Playing" label and shrink further. */
@media (max-width: 600px) {
    .rsp-now-playing-pill {
        max-width: 280px;
        font-size: 12px;
    }
    .rsp-now-playing-pill-cover {
        width: 42px;
        height: 42px;
    }
    .rsp-now-playing-pill-label {
        display: none;
    }
}

@media (max-width: 480px) {
    .rsp-compact-player .rsp-now-playing-pill,
    .rsp-compact-player .rsp-compact-volume-control-standalone {
        right: 112px;
    }
}

/* =============================================================
 * Header layout (Theme Builder Listen Live slot)
 *
 * layout="header" puts the pill in normal flow beside a 64px play
 * button so Theme Builder no longer has to scale the 203px hero
 * player. Pill before button via flex order; absolute positioning
 * and the Listen Live overlay are turned off.
 * ============================================================= */
.rsp-compact-player--header {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    position: relative;
    flex-direction: row;
    justify-content: flex-end;
}

.rsp-compact-player--header .rsp-compact-play-btn {
    order: 2;
    width: 64px !important;
    height: 64px !important;
    border-width: 3px !important;
    position: relative;
    right: auto;
    flex-shrink: 0;
}

.rsp-compact-player--header .rsp-compact-play-icon,
.rsp-compact-player--header .rsp-compact-pause-icon {
    width: 36px;
    height: 36px;
}

.rsp-compact-player--header .rsp-listen-live-text {
    display: none;
}

.rsp-compact-player--header .rsp-now-playing-pill {
    order: 1;
    position: static;
    top: auto;
    right: auto;
    transform: none;
    /* Fluid width capped at 260px so the header nav keeps room. */
    width: clamp(200px, 18vw, 260px);
    max-width: 260px;
    box-sizing: border-box;
    flex: 0 0 auto;
    min-height: 72px;
    padding: 10px 12px;
    gap: 10px;
    font-size: 13px;
    border-radius: 12px;
    --rsp-pill-lift: 0px;
}

.rsp-compact-player--header .rsp-now-playing-pill-cover {
    width: 48px;
    height: 48px;
    border-radius: 6px;
}

.rsp-compact-player--header .rsp-now-playing-pill-label {
    display: none;
}

.rsp-compact-player--header .rsp-now-playing-pill-text {
    gap: 2px;
}

/* ~20 character visual cap per line; full text stays in the DOM. */
.rsp-compact-player--header .rsp-now-playing-pill-artist,
.rsp-compact-player--header .rsp-now-playing-pill-title,
.rsp-compact-player--header .rsp-now-playing-pill-placeholder {
    max-width: 20ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rsp-compact-player--header .rsp-vote-buttons {
    margin-top: 4px;
    gap: 6px;
}

.rsp-compact-player--header .rsp-vote-btn {
    padding: 2px 4px;
}

.rsp-compact-player--header .rsp-vote-btn .rsp-vote-icon {
    width: 14px;
    height: 14px;
}

.rsp-compact-player--header .rsp-compact-volume-control-standalone {
    order: 1;
    position: static;
    top: auto;
    right: auto;
    transform: none;
}

/* Header volume: larger + white (beats admin/JS dark fill on dark pills). */
.rsp-compact-player--header .rsp-compact-volume-btn {
    padding: 4px !important;
}

.rsp-compact-player--header .rsp-compact-volume-icon {
    width: 24px !important;
    height: 24px !important;
    color: #ffffff !important;
}

.rsp-compact-player--header .rsp-compact-volume-icon path {
    fill: #ffffff !important;
}

/* Hide the pill below desktop; keep the round button (Theme Builder
 * also sizes the slot for tablet/phone). */
@media (max-width: 1024px) {
    .rsp-compact-player--header .rsp-now-playing-pill {
        display: none;
    }

    .rsp-compact-player--header .rsp-compact-play-btn {
        width: 52px !important;
        height: 52px !important;
    }

    .rsp-compact-player--header .rsp-compact-play-icon,
    .rsp-compact-player--header .rsp-compact-pause-icon {
        width: 28px;
        height: 28px;
    }
}

/* =============================================================
 * Bottom player banner (layout="banner")
 *
 * Fixed overlay at the bottom of the viewport. Works alongside the
 * Theme Builder sticky header player. Collapsible via the handle;
 * state is remembered in localStorage by the public JS.
 * ============================================================= */
.rsp-bottom-banner {
    --rsp-bottom-banner-bg: var(--rsp-pill-bg, rgba(17, 24, 39, 0.96));
    --rsp-bottom-banner-fg: var(--rsp-pill-text, #ffffff);
    --rsp-bottom-banner-height: 88px;
    --rsp-bottom-banner-collapsed-height: 44px;

    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 99990;
    display: flex;
    flex-direction: column;
    color: var(--rsp-bottom-banner-fg);
    background: var(--rsp-bottom-banner-bg);
    box-shadow: 0 -8px 28px rgba(0, 0, 0, 0.28);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    box-sizing: border-box;
}

/* Mobile-only mode: hide on desktop / tablet landscape. */
@media (min-width: 768px) {
    .rsp-bottom-banner[data-mode="mobile"] {
        display: none !important;
    }
}

.rsp-bottom-banner__toggle {
    position: absolute;
    top: -14px;
    left: 50%;
    transform: translateX(-50%);
    width: 44px;
    height: 28px;
    border: 0;
    border-radius: 14px 14px 0 0;
    background: var(--rsp-bottom-banner-bg);
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.18);
    padding: 0;
    z-index: 1;
}

.rsp-bottom-banner__toggle:hover,
.rsp-bottom-banner__toggle:focus-visible {
    filter: brightness(1.08);
    outline: none;
}

.rsp-bottom-banner__toggle-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    line-height: 0;
}

.rsp-bottom-banner__toggle-icon svg {
    margin: 0;
    flex: none;
}

.rsp-bottom-banner__toggle-icon .rsp-bottom-banner__chevron-down {
    display: block;
}

.rsp-bottom-banner__toggle-icon .rsp-bottom-banner__chevron-up {
    display: none;
}

.rsp-bottom-banner.is-collapsed .rsp-bottom-banner__toggle-icon .rsp-bottom-banner__chevron-down {
    display: none;
}

.rsp-bottom-banner.is-collapsed .rsp-bottom-banner__toggle-icon .rsp-bottom-banner__chevron-up {
    display: block;
}

.rsp-bottom-banner__panel {
    min-height: var(--rsp-bottom-banner-height);
    display: flex;
    align-items: center;
    width: 100%;
    padding: 10px 16px;
    box-sizing: border-box;
}

.rsp-bottom-banner.is-collapsed .rsp-bottom-banner__panel {
    min-height: var(--rsp-bottom-banner-collapsed-height);
    padding-top: 6px;
    padding-bottom: 6px;
}

/* Keep a slim play control when collapsed; hide now-playing details. */
.rsp-bottom-banner.is-collapsed .rsp-compact-player--banner .rsp-now-playing-pill {
    display: none;
}

.rsp-bottom-banner.is-collapsed .rsp-compact-player--banner .rsp-compact-play-btn {
    width: 32px !important;
    height: 32px !important;
    border-width: 2px !important;
}

.rsp-bottom-banner.is-collapsed .rsp-compact-player--banner .rsp-compact-play-icon,
.rsp-bottom-banner.is-collapsed .rsp-compact-player--banner .rsp-compact-pause-icon {
    width: 16px;
    height: 16px;
}

/* Hidden while the header now-playing pill is visible (unscrolled desktop).
 * JS toggles .is-suppressed; the media query below is a no-JS / first-paint
 * fallback for Theme Builder radio sticky headers. */
.rsp-bottom-banner.is-suppressed {
    display: none !important;
}

@media (min-width: 1025px) {
    /* First-paint / no-JS fallback matching Theme Builder scrolled pill hide. */
    body.tb-header-compact:not(.tb-header-is-scrolled) .rsp-bottom-banner {
        display: none !important;
    }
}

/* Reserve space so page content / footer are not covered.
 * Skip padding while suppressed, or while the unscrolled desktop
 * header pill is still showing (CSS fallback above). */
body:has(.rsp-bottom-banner[data-mode="all"]:not(.is-collapsed):not(.is-suppressed)) {
    padding-bottom: calc(var(--rsp-bottom-banner-height, 88px) + env(safe-area-inset-bottom, 0px)) !important;
}

body:has(.rsp-bottom-banner[data-mode="all"].is-collapsed:not(.is-suppressed)) {
    padding-bottom: calc(var(--rsp-bottom-banner-collapsed-height, 44px) + env(safe-area-inset-bottom, 0px)) !important;
}

@media (min-width: 1025px) {
    body.tb-header-compact:not(.tb-header-is-scrolled):has(.rsp-bottom-banner[data-mode="all"]) {
        padding-bottom: 0 !important;
    }
}

@media (max-width: 767px) {
    body:has(.rsp-bottom-banner[data-mode="mobile"]:not(.is-collapsed):not(.is-suppressed)) {
        padding-bottom: calc(var(--rsp-bottom-banner-height, 88px) + env(safe-area-inset-bottom, 0px)) !important;
    }

    body:has(.rsp-bottom-banner[data-mode="mobile"].is-collapsed:not(.is-suppressed)) {
        padding-bottom: calc(var(--rsp-bottom-banner-collapsed-height, 44px) + env(safe-area-inset-bottom, 0px)) !important;
    }
}

.rsp-compact-player--banner {
    display: flex;
    align-items: center;
    gap: 12px;
    position: relative;
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    flex-direction: row;
    justify-content: flex-start;
}

.rsp-compact-player--banner .rsp-compact-play-btn {
    order: 1;
    width: 56px !important;
    height: 56px !important;
    border-width: 3px !important;
    position: relative;
    right: auto;
    flex-shrink: 0;
}

.rsp-compact-player--banner .rsp-compact-play-icon,
.rsp-compact-player--banner .rsp-compact-pause-icon {
    width: 28px;
    height: 28px;
}

.rsp-compact-player--banner .rsp-listen-live-text {
    display: none;
}

.rsp-compact-player--banner .rsp-now-playing-pill {
    order: 2;
    position: static;
    top: auto;
    right: auto;
    transform: none;
    flex: 1 1 auto;
    width: auto;
    max-width: none;
    min-width: 0;
    min-height: 64px;
    padding: 8px 12px;
    gap: 12px;
    font-size: 14px;
    border-radius: 12px;
    --rsp-pill-lift: 0px;
    background: transparent;
    box-shadow: none;
}

.rsp-compact-player--banner .rsp-now-playing-pill-cover {
    width: 52px;
    height: 52px;
    border-radius: 8px;
    flex-shrink: 0;
}

.rsp-compact-player--banner .rsp-now-playing-pill-label {
    display: block;
    grid-area: label;
    font-size: 12px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    opacity: 0.75;
}

/* Label on top; track text left + votes right on the second row. */
.rsp-compact-player--banner .rsp-now-playing-pill-text {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
        "label label"
        "track votes";
    align-items: center;
    column-gap: 14px;
    row-gap: 2px;
    min-width: 0;
    flex: 1 1 auto;
}

.rsp-compact-player--banner .rsp-now-playing-pill-track {
    grid-area: track;
    min-width: 0;
}

.rsp-compact-player--banner .rsp-now-playing-pill-artist,
.rsp-compact-player--banner .rsp-now-playing-pill-title,
.rsp-compact-player--banner .rsp-now-playing-pill-placeholder {
    max-width: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rsp-compact-player--banner .rsp-now-playing-pill-artist {
    font-size: 18px;
    line-height: 1.2;
}

.rsp-compact-player--banner .rsp-now-playing-pill-title {
    font-size: 16px;
    line-height: 1.25;
    opacity: 0.9;
}

.rsp-compact-player--banner .rsp-now-playing-pill-placeholder {
    font-size: 16px;
}

/* Larger rating targets to the right of the track text. */
.rsp-compact-player--banner .rsp-vote-buttons {
    grid-area: votes;
    margin-top: 0;
    gap: 10px;
    align-self: center;
}

.rsp-compact-player--banner .rsp-vote-btn {
    width: 48px;
    height: 48px;
    min-width: 48px;
    min-height: 48px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.1);
}

.rsp-compact-player--banner .rsp-vote-btn .rsp-vote-icon {
    width: 26px;
    height: 26px;
}

.rsp-compact-player--banner .rsp-compact-volume-control {
    order: 3;
    position: static;
    top: auto;
    right: auto;
    transform: none;
    flex-shrink: 0;
    margin-left: auto;
}

.rsp-compact-player--banner .rsp-compact-volume-control-standalone {
    order: 3;
    position: static;
    top: auto;
    right: auto;
    transform: none;
    margin-left: auto;
}

.rsp-compact-player--banner .rsp-now-playing-pill .rsp-compact-volume-control {
    order: 0;
    margin-left: 8px;
}

/* Banner volume: larger + white (same visibility fix as header). */
.rsp-compact-player--banner .rsp-compact-volume-btn {
    padding: 4px !important;
}

.rsp-compact-player--banner .rsp-compact-volume-icon {
    width: 28px !important;
    height: 28px !important;
    color: #ffffff !important;
}

.rsp-compact-player--banner .rsp-compact-volume-icon path {
    fill: #ffffff !important;
}

@media (max-width: 767px) {
    .rsp-bottom-banner {
        --rsp-bottom-banner-height: 96px;
    }

    .rsp-bottom-banner__panel {
        padding: 10px 12px;
    }

    .rsp-compact-player--banner {
        gap: 8px;
    }

    .rsp-compact-player--banner .rsp-compact-play-btn {
        width: 48px !important;
        height: 48px !important;
    }

    .rsp-compact-player--banner .rsp-compact-play-icon,
    .rsp-compact-player--banner .rsp-compact-pause-icon {
        width: 24px;
        height: 24px;
    }

    .rsp-compact-player--banner .rsp-now-playing-pill {
        padding: 6px 8px;
        gap: 8px;
        min-height: 56px;
    }

    .rsp-compact-player--banner .rsp-now-playing-pill-cover {
        width: 44px;
        height: 44px;
    }

    .rsp-compact-player--banner .rsp-now-playing-pill-text {
        column-gap: 10px;
    }

    .rsp-compact-player--banner .rsp-now-playing-pill-artist {
        font-size: 16px;
    }

    .rsp-compact-player--banner .rsp-now-playing-pill-title,
    .rsp-compact-player--banner .rsp-now-playing-pill-placeholder {
        font-size: 14px;
    }

    .rsp-compact-player--banner .rsp-vote-btn {
        width: 44px;
        height: 44px;
        min-width: 44px;
        min-height: 44px;
    }

    .rsp-compact-player--banner .rsp-vote-btn .rsp-vote-icon {
        width: 24px;
        height: 24px;
    }

    /* Volume popup can clash with the banner edge on narrow phones. */
    .rsp-compact-player--banner .rsp-compact-volume-slider-container {
        bottom: calc(100% + 8px);
        top: auto;
    }
}

/* Screen-reader helper when themes do not define .screen-reader-text. */
.rsp-bottom-banner .screen-reader-text {
    border: 0;
    clip: rect(1px, 1px, 1px, 1px);
    clip-path: inset(50%);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
    word-wrap: normal !important;
}

/* ---------------------------------------------------------------
   Email Gate Modal
   Shown when "Require email to stream" is enabled in admin and the
   visitor has not yet provided an email (stored in localStorage).
   --------------------------------------------------------------- */
.rsp-email-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 999999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    animation: rsp-email-modal-fade 0.18s ease-out;
}

@keyframes rsp-email-modal-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.rsp-email-modal {
    position: relative;
    overflow: visible;
    background: #ffffff;
    color: #222222;
    border-radius: 10px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
    width: 100%;
    max-width: 420px;
    padding: 28px 24px 24px;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
    animation: rsp-email-modal-pop 0.2s ease-out;
    --rsp-modal-primary: var(--rsp-btn-pulse-1, #ff8c42);
}

@keyframes rsp-email-modal-pop {
    from { transform: scale(0.96); opacity: 0; }
    to   { transform: scale(1);    opacity: 1; }
}

.rsp-email-modal h3 {
    margin: 0 0 14px;
    font-size: 20px;
    font-weight: 600;
    line-height: 1.3;
    /* Force dark text: theme/Elementor heading colors often inherit as
     * bright accents that fail contrast on the white modal card. */
    color: #111827 !important;
}

/* Legacy block kept for back-compat with any saved
   rsp_access_settings.modal_message text in older installs. The new
   layout uses .rsp-email-modal-notice instead and never injects this
   element. */
.rsp-email-modal-message {
    margin: 0 0 18px;
    font-size: 14px;
    line-height: 1.45;
    color: #555555;
}

.rsp-email-modal-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.rsp-email-modal-label {
    font-size: 13px;
    font-weight: 600;
    color: #333333;
    margin-bottom: -6px;
}

.rsp-email-modal-input {
    width: 100%;
    padding: 11px 12px;
    font-size: 15px;
    line-height: 1.3;
    border: 1px solid #cccccc;
    border-radius: 6px;
    background: #ffffff;
    color: #222222;
    box-sizing: border-box;
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.rsp-email-modal-input:focus {
    border-color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42)) 15%, transparent);
}

/* Static privacy / data-use notice. Sits between the email field and
   the Club Mix opt-in so the visitor reads it before they choose to
   subscribe. */
.rsp-email-modal-notice {
    margin: 2px 0 4px;
    font-size: 12px;
    line-height: 1.5;
    color: #5a5a5a;
}

/* Optional Club Mix opt-in. Mirrors the "Remember me" checkbox on
   the Radio Contests entry form so a visitor who's seen one form
   recognises the other. */
.rsp-email-modal-consent {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 13px;
    line-height: 1.45;
    color: #333333;
    cursor: pointer;
    user-select: none;
}

.rsp-email-modal-consent-input {
    margin-top: 2px;
    flex: 0 0 auto;
    accent-color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
}

.rsp-email-modal-consent-text {
    flex: 1 1 auto;
}

/* Honeypot: visually hidden but still focusable/fillable by bots. */
.rsp-email-modal-hp {
    position: absolute !important;
    left: -9999px !important;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.rsp-email-modal-error {
    min-height: 18px;
    font-size: 13px;
    color: #c0392b;
}

.rsp-email-modal-submit {
    width: 100%;
    padding: 11px 14px;
    font-size: 15px;
    font-weight: 600;
    color: #ffffff;
    background: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s ease, opacity 0.15s ease, filter 0.15s ease;
}

.rsp-email-modal-submit:hover,
.rsp-email-modal-submit:focus {
    filter: brightness(0.9);
    outline: none;
}

.rsp-email-modal-submit:disabled,
.rsp-email-modal-submit--loading {
    opacity: 0.7;
    cursor: progress;
}

/* Theme isolation: reset properties WordPress themes commonly override
   on generic button selectors before modal-specific rules apply. */
.rsp-email-modal button {
    box-sizing: border-box;
    min-height: 0;
    text-transform: none;
    letter-spacing: normal;
    font-family: inherit;
    appearance: none;
    -webkit-appearance: none;
}

.rsp-email-modal .rsp-email-modal-close {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    margin: 0;
    border: none;
    background: transparent;
    box-shadow: none;
    color: #888888;
    font-size: 22px;
    font-weight: 400;
    line-height: 1;
    cursor: pointer;
    border-radius: 50%;
    text-transform: none;
    min-height: 0;
}

.rsp-email-modal .rsp-email-modal-close:hover,
.rsp-email-modal .rsp-email-modal-close:focus {
    background: rgba(0, 0, 0, 0.06);
    color: #333333;
    outline: none;
    filter: none;
}

/* ---------------------------------------------------------------
   Listen-Live Access Modal (Login / Register / Personalization)
   Layered on top of the email-modal shell. The chooser, login
   form, and register form are sibling .rsp-access-step panels;
   the JS toggles `[hidden]` to swap between them. The same
   submit / input / error styling carries over from the legacy
   email gate so the two flows look like one design system.
   --------------------------------------------------------------- */
.rsp-access-modal {
    /* Tightened from the legacy single-email modal width so the
       chooser doesn't look top-heavy with two giant buttons. */
    max-width: 400px;
    padding: 22px 22px 20px;
}

.rsp-access-modal h3 {
    font-size: 17px;
    margin-bottom: 8px;
    color: #111827 !important;
}

.rsp-access-testing-hint {
    margin: 0;
    padding: 8px 10px;
    border-radius: 6px;
    background: #fff7ed;
    border: 1px solid #fdba74;
    color: #9a3412;
    font-size: 12px;
    line-height: 1.4;
}

.rsp-perso-prompt h3 {
    color: #111827 !important;
}

.rsp-access-step {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.rsp-access-step[hidden] {
    display: none;
}

/* Scoped overrides for the submit button when it lives inside the
   access modal — the legacy email-gate keeps its larger sizing. */
.rsp-access-modal .rsp-email-modal-submit {
    padding: 8px 14px;
    font-size: 14px;
    font-weight: 600;
    border-radius: 6px;
}

/* Log In + Register side-by-side on the login step. */
.rsp-access-button-row {
    display: flex;
    align-items: stretch;
    gap: 10px;
}

.rsp-access-button-row .rsp-email-modal-submit,
.rsp-access-button-row .rsp-access-choice-btn {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
    padding: 8px 14px;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.25;
    border-radius: 6px;
    text-transform: none;
    letter-spacing: normal;
}

/* Tighten the form-field gap so the modal isn't dominated by white
   space between rows. */
.rsp-access-modal .rsp-email-modal-form {
    gap: 8px;
}

.rsp-access-modal .rsp-email-modal-input {
    padding: 8px 10px;
    font-size: 14px;
    border-radius: 5px;
}

.rsp-access-modal .rsp-email-modal-label {
    font-size: 12px;
    margin-bottom: -3px;
}

.rsp-access-modal .rsp-email-modal-notice {
    font-size: 12px;
    margin: 2px 0 0;
}

.rsp-access-modal .rsp-email-modal-consent {
    font-size: 12px;
    gap: 6px;
}

.rsp-access-modal .rsp-email-modal-error {
    font-size: 12px;
    min-height: 16px;
}

.rsp-access-fineprint {
    margin-top: 2px;
    font-size: 11px;
    color: #6b7280;
}

/* Stacked chooser buttons. Sized so they read as compact CTAs
   rather than dominating the modal. Vertical stack still — putting
   them side-by-side cramps the labels at narrow viewport widths. */
.rsp-access-choice-buttons {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 2px;
}

.rsp-access-choice-btn {
    display: block;
    width: 100%;
    padding: 9px 14px;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.25;
    text-align: center;
    border-radius: 6px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.rsp-access-choice-btn--login {
    color: #ffffff;
    background: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
}

.rsp-access-choice-btn--login:hover,
.rsp-access-choice-btn--login:focus {
    filter: brightness(0.9);
    outline: none;
}

.rsp-access-choice-btn--register {
    color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
    background: #ffffff;
    border-color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
}

.rsp-access-choice-btn--register:hover,
.rsp-access-choice-btn--register:focus {
    background: color-mix(in srgb, var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42)) 8%, #ffffff);
    outline: none;
}

/* Footer row: text-button "Back" and (on login) the Forgot-password
   link. Sits below each form. */
.rsp-access-step-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 4px;
}

/* Centered variant used on the register step where the only footer
   element is a single "Already have an account? Log in" text link. */
.rsp-access-step-actions--center {
    justify-content: center;
}

.rsp-access-link {
    display: inline-flex;
    align-items: center;
    padding: 6px 4px;
    font-size: 13px;
    font-weight: 500;
    color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
    background: transparent;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    text-decoration: none;
    transition: color 0.15s ease, filter 0.15s ease;
}

.rsp-access-link:hover,
.rsp-access-link:focus {
    filter: brightness(0.85);
    text-decoration: underline;
    outline: none;
}

/* Personalization radio cards. Two stacked tappable rows — title
   + subtitle on the right, an inline radio dot on the left. The
   selected card gets a tinted background + accent border so the
   visitor can see which option is active at a glance. The cards
   are <button>s (not <input type="radio">) so the whole row is the
   click target — the [role="radio"] + [aria-checked] pair carry
   the assistive-tech semantics. */
.rsp-access-personalize-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 2px 0;
}

/* Side-by-side variant: the two personalize cards sit on a single
   row, each taking equal width. Falls back to the stacked layout
   below ~360px so the cards never crowd into illegible columns. */
.rsp-access-personalize-group--inline {
    flex-direction: row;
    align-items: stretch;
}

.rsp-access-personalize-group--inline .rsp-access-personalize-card {
    flex: 1 1 0;
    min-width: 0;
}

@media (max-width: 360px) {
    .rsp-access-personalize-group--inline {
        flex-direction: column;
    }
}

.rsp-access-personalize-card {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    font-family: inherit;
    font-size: inherit;
    font-weight: inherit;
    text-align: left;
    text-transform: none;
    letter-spacing: normal;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    color: #1f2937;
    cursor: pointer;
    box-shadow: none;
    transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.rsp-email-modal .rsp-access-personalize-card {
    min-height: 0;
    color: #1f2937;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
}

.rsp-email-modal .rsp-access-personalize-card:hover,
.rsp-email-modal .rsp-access-personalize-card:focus {
    color: #1f2937;
    background: #f1f5f9;
    border-color: #94a3b8;
}

.rsp-email-modal .rsp-access-personalize-card.is-selected {
    color: #1f2937;
    background: color-mix(in srgb, var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42)) 8%, #ffffff);
    border-color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
    box-shadow: 0 0 0 1px var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42)) inset;
}

.rsp-access-personalize-group--error .rsp-access-personalize-card {
    border-color: #c0392b;
}

.rsp-access-personalize-group--error .rsp-access-personalize-card.is-selected {
    border-color: #c0392b;
    box-shadow: 0 0 0 1px #c0392b inset;
}

.rsp-access-personalize-card-radio {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    margin-top: 3px;
    border-radius: 50%;
    border: 2px solid #94a3b8;
    background: #ffffff;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    position: relative;
}

.rsp-access-personalize-card.is-selected .rsp-access-personalize-card-radio {
    border-color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
    box-shadow: inset 0 0 0 3px var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
}

.rsp-access-personalize-card-text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    flex: 1 1 auto;
    min-width: 0;
}

.rsp-access-personalize-card-title {
    font-size: 13px;
    font-weight: 600;
    color: #1f2937;
    line-height: 1.25;
}

.rsp-email-modal .rsp-access-personalize-card .rsp-access-personalize-card-title,
.rsp-email-modal .rsp-access-personalize-card.is-selected .rsp-access-personalize-card-title {
    color: #1f2937;
}

.rsp-access-personalize-card-subtitle {
    font-size: 11px;
    line-height: 1.35;
    color: #64748b;
}

.rsp-email-modal .rsp-access-personalize-card .rsp-access-personalize-card-subtitle,
.rsp-email-modal .rsp-access-personalize-card.is-selected .rsp-access-personalize-card-subtitle {
    color: #64748b;
}

.rsp-access-personalize-note {
    margin: 0;
}

/* "Already have an account? Log in" pivot link rendered after a
   409 from the register endpoint. Visually a text link, sits
   directly under the error message. */
.rsp-access-login-pivot {
    margin-top: 4px;
    align-self: flex-start;
}

/* First name / Last name side-by-side row on the register form.
   Labels stay stacked above their input as usual; the row just
   places the two name fields next to each other. Collapses to a
   single column on very narrow viewports. */
.rsp-access-name-row {
    display: flex;
    gap: 10px;
}

.rsp-access-name-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1 1 0;
    min-width: 0;
}

.rsp-access-name-field .rsp-email-modal-label {
    margin-bottom: 0;
}

@media (max-width: 360px) {
    .rsp-access-name-row {
        flex-direction: column;
        gap: 0;
    }
}

/* Quiet text-link pivot at the bottom of the register form — same
   visual weight as a body link, no button chrome. */
.rsp-access-link--pivot {
    font-size: 12px;
    color: #475569;
}

.rsp-access-link--pivot:hover,
.rsp-access-link--pivot:focus {
    color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
    text-decoration: underline;
}

/* ---------------------------------------------------------------
   Personalization prompt (rating-button gate)
   Opened when a logged-in listener with personalization off clicks
   thumbs-up / thumbs-down. Inherits .rsp-access-modal sizing for
   consistency; adds a side-by-side action row.
   --------------------------------------------------------------- */
.rsp-perso-prompt {
    max-width: 380px;
}

.rsp-perso-prompt-message {
    margin: 0 0 6px;
    font-size: 13px;
    line-height: 1.5;
    color: #475569;
}

.rsp-perso-prompt-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 6px;
}

.rsp-perso-prompt-btn {
    padding: 7px 12px;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
    border-radius: 5px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}

.rsp-perso-prompt-btn--cancel {
    color: #475569;
    background: transparent;
    border-color: transparent;
}

.rsp-perso-prompt-btn--cancel:hover,
.rsp-perso-prompt-btn--cancel:focus {
    background: #f1f5f9;
    color: #1e293b;
    outline: none;
}

.rsp-perso-prompt-btn--activate {
    color: #ffffff;
    background: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
}

.rsp-perso-prompt-btn--activate:hover,
.rsp-perso-prompt-btn--activate:focus {
    filter: brightness(0.9);
    outline: none;
}

.rsp-perso-prompt-btn:disabled,
.rsp-perso-prompt-btn--loading {
    opacity: 0.6;
    cursor: progress;
}

/* ---------------------------------------------------------------
   Profile Completion Modal
   Triggered every 10th stream until the listener submits. Reuses
   the email-modal shell + base classes; these rules layer on the
   profile-specific bits (intro line, station checklist, dual
   action buttons).
   --------------------------------------------------------------- */
.rsp-profile-modal {
    max-width: 460px;
}

.rsp-profile-modal-intro {
    margin: -4px 0 14px;
    font-size: 13px;
    line-height: 1.5;
    color: #555555;
}

.rsp-profile-modal-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.rsp-profile-modal-stations {
    margin-top: 4px;
}

.rsp-profile-modal-checklist {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 6px 12px;
    max-height: 180px;
    overflow-y: auto;
    padding: 4px 2px;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    background: #f8fafc;
}

.rsp-profile-modal-check {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px;
    font-size: 13px;
    line-height: 1.3;
    color: #1f2937;
    cursor: pointer;
    user-select: none;
}

.rsp-profile-modal-check input[type="checkbox"] {
    accent-color: var(--rsp-modal-primary, var(--rsp-btn-pulse-1, #ff8c42));
    flex: 0 0 auto;
}

.rsp-profile-modal-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 6px;
}

.rsp-profile-modal-skip {
    flex: 0 0 auto;
    padding: 10px 14px;
    font-size: 14px;
    font-weight: 500;
    color: #475569;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.rsp-profile-modal-skip:hover,
.rsp-profile-modal-skip:focus {
    background: #f1f5f9;
    color: #1e293b;
    outline: none;
}

.rsp-profile-modal-submit {
    flex: 1 1 auto;
    width: auto;
}

/* =============================================================
 * [full_playlist] — compact card-grid variant of the Recently Played feed.
 *
 * Reuses the same <ul.rsp-history-list> + <template id="song-item-template">
 * pipeline as the standard list shortcode; the `.rsp-card-playlist`
 * modifier class flips the layout from horizontal-row to a small-card
 * grid that auto-packs as many cards per row as fit. Default card
 * footprint is ~100px wide, controlled per-instance via the inline
 * `--rsp-card-min-width` CSS custom property set by the shortcode.
 *
 * The play-log inverts artist/song: `item.artist` (rendered into
 * `.track-artist`) holds the SONG NAME, and `item.title` (rendered into
 * `.track-title`) holds the ARTIST NAME. The card UI shows ARTIST as
 * the dominant headline and SONG as the supporting line, so styling
 * weights `.track-title` heavier than `.track-artist` here even though
 * the list view does the opposite.
 * ============================================================= */
.rsp-card-playlist-wrapper {
    /* Per-instance minimum card width lands on the wrapper as
       `--rsp-card-min-width`; defaults to 100px when the shortcode
       did not set it (e.g. the CSS is included without the PHP). */
    --rsp-card-min-width: 100px;
    margin: 1.5em 0;
}

/* `auto-fill` + `minmax(--rsp-card-min-width, 1fr)` is what makes the
   grid self-row. The browser packs cards left-to-right at the minimum
   width and wraps to a new row as the container fills, so there are
   no manual breakpoints to maintain.
   
   Note: every selector here is prefixed with `ul.` so its specificity
   (0,2,1) matches the base list rule (`ul.rsp-history-list.custom-player-
   history-list`). Without that prefix the base rule's `display: block`
   wins on specificity and collapses the grid into a single column. */
ul.rsp-history-list.rsp-card-playlist {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(var(--rsp-card-min-width, 100px), 1fr));
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Fixed-column override: only takes effect when the [full_playlist]
   shortcode was called with `columns="N"`, which adds the marker
   class on the wrapper and emits `--rsp-card-columns` inline. Cards
   beyond N per row wrap naturally to additional rows, so `count`
   still controls total cards on screen.

   The wrapper carries both the marker class and the custom property;
   we descend into the inner <ul> here to keep the specificity tier
   identical to the base rule above.

   `--rsp-card-columns` is treated as a *maximum*. Breakpoints below
   cap the column count with `min()` so editors who request fewer
   columns still get fewer, while large values (e.g. columns="10")
   step down on tablet/phone instead of crushing cards to ~35px. */
.rsp-card-playlist-wrapper.rsp-card-playlist-has-columns ul.rsp-history-list.rsp-card-playlist {
    grid-template-columns: repeat(var(--rsp-card-columns, 4), minmax(0, 1fr));
}

@media (max-width: 1024px) {
    .rsp-card-playlist-wrapper.rsp-card-playlist-has-columns ul.rsp-history-list.rsp-card-playlist {
        grid-template-columns: repeat(min(var(--rsp-card-columns, 4), 6), minmax(0, 1fr));
    }
}

@media (max-width: 768px) {
    .rsp-card-playlist-wrapper.rsp-card-playlist-has-columns ul.rsp-history-list.rsp-card-playlist {
        grid-template-columns: repeat(min(var(--rsp-card-columns, 4), 4), minmax(0, 1fr));
    }
}

@media (max-width: 480px) {
    .rsp-card-playlist-wrapper.rsp-card-playlist-has-columns ul.rsp-history-list.rsp-card-playlist {
        grid-template-columns: repeat(min(var(--rsp-card-columns, 4), 3), minmax(0, 1fr));
    }
}

/* Each <li> becomes a small vertical card. Border / divider rules
   from the list view do not apply. */
ul.rsp-history-list.rsp-card-playlist .custom-history-item {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    min-width: 0;
    overflow: hidden;
    padding: 6px;
    border: 1px solid var(--rsp-history-separator, rgba(0, 0, 0, 0.08));
    border-radius: 8px;
    background: var(--rsp-card-bg, #ffffff);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
    line-height: 1.2;
}

ul.rsp-history-list.rsp-card-playlist .custom-history-item:last-child {
    border-bottom: 1px solid var(--rsp-history-separator, rgba(0, 0, 0, 0.08));
}

ul.rsp-history-list.rsp-card-playlist .custom-history-item:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
}

/* Square album art fills the card width. Aspect ratio + object-fit
   keeps every card the same height regardless of cover dimensions. */
ul.rsp-history-list.rsp-card-playlist .track-cover {
    flex: 0 0 auto;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    border-radius: 6px;
    object-fit: cover;
    background: var(--rsp-history-cover-bg, #f1f5f9);
}

/* Hide the cover element only when JS hasn't supplied a src and there
   is no fallback to render. Mirrors the list view behavior. */
ul.rsp-history-list.rsp-card-playlist .track-cover[hidden] {
    display: none;
}

ul.rsp-history-list.rsp-card-playlist .track-info {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

/* Artist (upstream `item.title`) — the dominant headline. Allow up to
   two lines before truncating so longer band names stay readable on
   such a small card. */
ul.rsp-history-list.rsp-card-playlist .track-title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    line-clamp: 2;
    overflow: hidden;
    white-space: normal;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--rsp-history-artist, #0f172a);
    order: 1;
}

/* Song (upstream `item.artist`) — secondary line below the artist. */
ul.rsp-history-list.rsp-card-playlist .track-artist {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    line-clamp: 2;
    overflow: hidden;
    white-space: normal;
    font-size: 0.7rem;
    font-weight: 400;
    line-height: 1.2;
    color: var(--rsp-history-title, #475569);
    order: 2;
}

ul.rsp-history-list.rsp-card-playlist .track-time {
    order: 3;
    font-size: 0.65rem;
    color: var(--rsp-history-time, #64748b);
    margin-top: 1px;
}

/* Loading / empty / error states need to span every column instead of
   sitting in a single 1-of-N grid cell, otherwise they read as a tiny
   half-finished card while the first fetch is in flight. */
ul.rsp-history-list.rsp-card-playlist .rsp-history-status {
    grid-column: 1 / -1;
    padding: 12px;
    text-align: center;
    border: 1px dashed var(--rsp-history-separator, rgba(0, 0, 0, 0.12));
    border-radius: 8px;
    background: transparent;
}

/* =============================================================
 * [full_playlist] — per-card thumbs up / thumbs down.
 *
 * Reuses the existing `.rsp-vote-buttons` / `.rsp-vote-btn` selectors
 * but overrides the pill's white-on-dark color palette so the icons
 * stay visible on a light card. Also opts the card-grid back into
 * showing votes on small screens, since the base rule hides the
 * pill's button row at ≤480px.
 * ============================================================= */
ul.rsp-history-list.rsp-card-playlist .rsp-vote-buttons {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-width: 0;
    order: 4;
    margin-top: 2px;
    padding-top: 4px;
    border-top: 1px solid var(--rsp-history-separator, rgba(0, 0, 0, 0.06));
}

ul.rsp-history-list.rsp-card-playlist .rsp-vote-btn {
    min-width: 0;
    padding: 2px 4px;
    border-radius: 4px;
    color: var(--rsp-history-time, #64748b);
    background: transparent;
}

ul.rsp-history-list.rsp-card-playlist .rsp-vote-btn:hover:not(:disabled) {
    color: #0f172a;
    background-color: rgba(0, 0, 0, 0.06);
}

/* Active states keep the same green/red/gold palette as the pill so the
   "voted" / "favourited" affordance is visually consistent across surfaces. */
ul.rsp-history-list.rsp-card-playlist .rsp-vote-btn.rsp-vote-up.is-active {
    color: var(--rsp-vote-up-active, #4caf50);
}

ul.rsp-history-list.rsp-card-playlist .rsp-vote-btn.rsp-vote-down.is-active {
    color: var(--rsp-vote-down-active, #e53935);
}

ul.rsp-history-list.rsp-card-playlist .rsp-vote-btn.rsp-favorite-btn.is-active {
    color: var(--rsp-vote-favorite-active, #f5b301);
}

/* Defeat the global ≤480px hide rule for vote buttons inside cards.
   The card grid stays useful on phones (it collapses to ~3 columns),
   so per-card voting should keep working there. */
@media (max-width: 480px) {
    ul.rsp-history-list.rsp-card-playlist .rsp-vote-buttons {
        display: flex;
    }
}

/* =============================================================
 * [full_playlist] — card cover affordance.
 *
 * Each card cover doubles as the trigger for the song-details
 * modal, so we give it pointer affordance + a subtle scale
 * animation that tells the visitor the artwork is "more than just
 * an image". The legacy hover info-tip has been replaced by the
 * full RspSongDetailsModal — see the JS bindings.
 * ============================================================= */
ul.rsp-history-list.rsp-card-playlist .track-cover {
    cursor: pointer;
    transition: transform 0.18s ease, filter 0.18s ease, box-shadow 0.18s ease;
    border-radius: inherit;
}

ul.rsp-history-list.rsp-card-playlist .custom-history-item:hover .track-cover {
    transform: scale(1.02);
    filter: brightness(1.04);
}

ul.rsp-history-list.rsp-card-playlist .track-cover:focus {
    outline: 2px solid rgba(255, 255, 255, 0.85);
    outline-offset: 2px;
}

ul.rsp-history-list.rsp-card-playlist .track-cover:focus:not(:focus-visible) {
    outline: none;
}

/* The popup itself is fixed-positioned and offset via inline styles
   from the JS positioning routine. Hidden by default so it never
   flashes during page paint; the `.is-visible` modifier reveals it
   with a small opacity/translate transition for polish. */
.rsp-song-info-popup {
    position: absolute;
    width: 280px;
    max-width: calc(100vw - 16px);
    max-height: 70vh;
    overflow: auto;
    z-index: 2147483600;
    padding: 12px 14px;
    background: #ffffff;
    color: #0f172a;
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 10px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.14);
    font-size: 13px;
    line-height: 1.45;
    opacity: 0;
    transform: translateY(4px);
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.rsp-song-info-popup.is-visible {
    opacity: 1;
    transform: translateY(0);
}

.rsp-song-info-popup .rsp-song-info-heading {
    font-size: 13.5px;
    font-weight: 700;
    margin-bottom: 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    color: #0f172a;
}

.rsp-song-info-popup .rsp-song-info-rows {
    display: grid;
    grid-template-columns: 1fr;
    gap: 4px;
}

.rsp-song-info-popup .rsp-song-info-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
}

.rsp-song-info-popup .rsp-song-info-label {
    flex: 0 0 auto;
    font-weight: 600;
    color: #475569;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}

.rsp-song-info-popup .rsp-song-info-value {
    flex: 1 1 auto;
    text-align: right;
    color: #0f172a;
    overflow-wrap: anywhere;
}

.rsp-song-info-popup .rsp-song-info-trivia {
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid rgba(0, 0, 0, 0.06);
    color: #334155;
    font-size: 12.5px;
    line-height: 1.5;
}

.rsp-song-info-popup .rsp-song-info-loading,
.rsp-song-info-popup .rsp-song-info-empty {
    color: #64748b;
    font-style: italic;
    text-align: center;
    padding: 4px 0;
}

/* =============================================================
 * Compact player — album-cover affordance.
 *
 * The cover doubles as the trigger for the song-details modal,
 * so we give it pointer affordance + a subtle scale animation
 * (mirrors the [full_playlist] card cover) and a visible focus
 * ring for keyboard users.
 * ============================================================= */
.rsp-now-playing-pill-cover.rsp-song-modal-trigger {
    cursor: pointer;
    transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease;
    border-radius: inherit;
}

.rsp-now-playing-pill-cover.rsp-song-modal-trigger:hover {
    transform: scale(1.06);
    filter: brightness(1.08);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
}

.rsp-now-playing-pill-cover.rsp-song-modal-trigger:focus {
    outline: 2px solid rgba(255, 255, 255, 0.85);
    outline-offset: 2px;
}

.rsp-now-playing-pill-cover.rsp-song-modal-trigger:focus:not(:focus-visible) {
    outline: none;
}

/* =============================================================
 * Song-details modal (triggered by clicking the compact player's
 * album artwork). Glassmorphic dark vibe with a blurred-artwork
 * hero header that picks up the song's actual cover. Designed to
 * feel native to a music app rather than to the admin email
 * gate that uses .rsp-email-modal-*.
 * ============================================================= */
html.rsp-song-modal-open,
body.rsp-song-modal-open {
    overflow: hidden;
}

.rsp-song-modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 2147483640;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(8, 10, 18, 0.72);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
}

.rsp-song-modal-backdrop.is-visible {
    opacity: 1;
    pointer-events: auto;
}

.rsp-song-modal {
    position: relative;
    width: 100%;
    max-width: 576px;
    max-height: calc(100vh - 40px);
    background: #0f111a;
    color: #f8fafc;
    border-radius: 18px;
    box-shadow:
        0 30px 80px rgba(0, 0, 0, 0.55),
        0 0 0 1px rgba(255, 255, 255, 0.06) inset;
    overflow: hidden;
    transform: scale(0.96) translateY(8px);
    opacity: 0;
    transition: transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.18s ease;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
    display: flex;
    flex-direction: column;
}

.rsp-song-modal-backdrop.is-visible .rsp-song-modal {
    transform: scale(1) translateY(0);
    opacity: 1;
}

.rsp-song-modal-body {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-height: 0;
}

/* Scoped + !important so host-theme `button` / `a` / `h2` rules
   (common on station sites) cannot blank the X icon or tint the
   title navy-on-dark. Nav chevrons live as backdrop siblings, so
   they are scoped to the backdrop rather than the panel. */
.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-close {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 4;
    width: 34px !important;
    height: 34px !important;
    min-width: 34px !important;
    min-height: 34px !important;
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
    border-radius: 50% !important;
    background: rgba(0, 0, 0, 0.45) !important;
    color: #ffffff !important;
    box-shadow: none !important;
    line-height: 1 !important;
    font-size: 16px !important;
    text-decoration: none !important;
    text-transform: none !important;
    letter-spacing: normal !important;
    cursor: pointer;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease, transform 0.15s ease;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-close:hover,
.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-close:focus {
    background: rgba(255, 255, 255, 0.18) !important;
    color: #ffffff !important;
    transform: scale(1.05);
    outline: none;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-close svg {
    display: block !important;
    width: 16px !important;
    height: 16px !important;
    fill: currentColor !important;
    flex-shrink: 0;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-close svg path {
    fill: currentColor !important;
}

/* Prev/next chevrons for walking between playlist cards. Rendered
   as siblings of the modal panel (children of the backdrop) so they
   sit OUTSIDE the panel's overflow-clipped rounded corners. Hidden
   entirely when the modal was opened from the now-playing pill
   (no playlist to walk) and visually dimmed when at a list edge.

   Direction mapping:
     - left chevron (`.rsp-song-modal-nav-prev`)  → newer song (up the list)
     - right chevron (`.rsp-song-modal-nav-next`) → older song (down the list) */
.rsp-song-modal-backdrop .rsp-song-modal-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 5;
    width: 44px !important;
    height: 44px !important;
    min-width: 44px !important;
    min-height: 44px !important;
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
    border-radius: 50% !important;
    background: rgba(0, 0, 0, 0.55) !important;
    color: #ffffff !important;
    cursor: pointer;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease, transform 0.15s ease, opacity 0.15s ease;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45) !important;
    line-height: 1 !important;
    text-decoration: none !important;
}

/* Default desktop: anchor the buttons relative to the backdrop's
   horizontal centre with a calc() that adds half the modal's max-width
   (576px / 2 = 288px) plus a gap so the buttons clear the panel edge
   instead of overlapping it. */
.rsp-song-modal-backdrop .rsp-song-modal-nav-prev { right: calc(50% + 308px); }
.rsp-song-modal-backdrop .rsp-song-modal-nav-next { left:  calc(50% + 308px); }

.rsp-song-modal-backdrop .rsp-song-modal-nav:hover:not(:disabled),
.rsp-song-modal-backdrop .rsp-song-modal-nav:focus:not(:disabled) {
    background: rgba(255, 255, 255, 0.22) !important;
    color: #ffffff !important;
    transform: translateY(-50%) scale(1.06);
    outline: none;
}

.rsp-song-modal-backdrop .rsp-song-modal-nav:disabled {
    opacity: 0.3;
    cursor: default;
}

.rsp-song-modal-backdrop .rsp-song-modal-nav[hidden] {
    display: none;
}

.rsp-song-modal-backdrop .rsp-song-modal-nav svg {
    display: block !important;
    fill: currentColor !important;
}

.rsp-song-modal-backdrop .rsp-song-modal-nav svg path {
    fill: currentColor !important;
}

/* Mid-width viewports — there isn't room for the chevrons outside
   the modal panel anymore, so hug the backdrop's padding gutter
   (the 20px the backdrop reserves before the modal starts). The
   buttons still sit outside the modal, just much closer to it. */
@media (max-width: 740px) {
    .rsp-song-modal-backdrop .rsp-song-modal-nav { width: 38px !important; height: 38px !important; min-width: 38px !important; min-height: 38px !important; }
    .rsp-song-modal-backdrop .rsp-song-modal-nav-prev { right: auto; left: 6px; }
    .rsp-song-modal-backdrop .rsp-song-modal-nav-next { left: auto; right: 6px; }
}

/* Mobile — the backdrop drops its padding entirely (modal is
   edge-to-edge), so falling back to inside-the-modal corners is the
   only option that keeps them visible. */
@media (max-width: 520px) {
    .rsp-song-modal-backdrop .rsp-song-modal-nav { width: 36px !important; height: 36px !important; min-width: 36px !important; min-height: 36px !important; }
    .rsp-song-modal-backdrop .rsp-song-modal-nav-prev { left: 8px; }
    .rsp-song-modal-backdrop .rsp-song-modal-nav-next { right: 8px; }
}

/* ---- Hero ---- */
.rsp-song-modal-hero {
    position: relative;
    padding: 28px 24px 22px;
    background-size: cover;
    background-position: center;
    background-color: #1a1d2b;
    isolation: isolate;
}

.rsp-song-modal-hero-overlay {
    position: absolute;
    inset: 0;
    background:
        linear-gradient(180deg, rgba(15, 17, 26, 0.55) 0%, rgba(15, 17, 26, 0.88) 100%),
        rgba(15, 17, 26, 0.35);
    backdrop-filter: blur(28px) saturate(140%);
    -webkit-backdrop-filter: blur(28px) saturate(140%);
    z-index: 1;
}

.rsp-song-modal-hero-inner {
    position: relative;
    z-index: 2;
    display: grid;
    grid-template-columns: 120px 1fr;
    gap: 18px;
    align-items: center;
}

/* Hero portrait column — stacks the artist's photo on top of an
   icon-only row of social links (Website / Facebook / Instagram).
   The whole column stays the same width as the portrait so the
   right-hand heading column lines up cleanly. */
.rsp-song-modal-portrait-column {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    width: 120px;
}

/* Hero portrait — the song's album artwork. Rendered as a rounded
   square (album-cover proportions) with a soft inset ring and a
   strong drop shadow so it lifts off the blurred backdrop. Falls
   back to a gradient placeholder when no image is available. */
.rsp-song-modal-portrait-wrap {
    width: 120px;
    height: 120px;
    border-radius: 12px;
    overflow: hidden;
    box-shadow:
        0 12px 30px rgba(0, 0, 0, 0.55),
        0 0 0 1px rgba(255, 255, 255, 0.18) inset;
    background: #0b0d15;
    flex: 0 0 auto;
}

/* Hero social icons — circular icon-only buttons beneath the
   artist portrait. Each opens the corresponding profile in a new
   tab. Hover lifts and applies a brand-tinted background so the
   site/Facebook/Instagram identity reads clearly. */
.rsp-song-modal-portrait-socials {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
}

.rsp-song-modal-portrait-socials[hidden] { display: none; }

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 30px !important;
    height: 30px !important;
    min-width: 30px !important;
    min-height: 30px !important;
    padding: 0 !important;
    border-radius: 50% !important;
    background: rgba(255, 255, 255, 0.1) !important;
    border: 1px solid rgba(255, 255, 255, 0.16) !important;
    color: #ffffff !important;
    box-shadow: none !important;
    text-decoration: none !important;
    line-height: 1 !important;
    transition: background 0.15s ease, border-color 0.15s ease,
                color 0.15s ease, transform 0.12s ease;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social:hover,
.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social:focus {
    transform: translateY(-1px);
    outline: none;
    color: #ffffff !important;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social svg {
    display: block !important;
    fill: currentColor !important;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social svg path {
    fill: currentColor !important;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social-web:hover,
.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social-web:focus {
    background: rgba(99, 102, 241, 0.45) !important;
    border-color: rgba(99, 102, 241, 0.75) !important;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social-fb:hover,
.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social-fb:focus {
    background: rgba(24, 119, 242, 0.55) !important;
    border-color: rgba(24, 119, 242, 0.85) !important;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social-ig:hover,
.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social-ig:focus {
    background: linear-gradient(135deg, rgba(225, 48, 108, 0.55) 0%, rgba(245, 133, 41, 0.55) 100%) !important;
    border-color: rgba(225, 48, 108, 0.8) !important;
}

.rsp-song-modal-portrait {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
}

.rsp-song-modal-portrait-empty {
    width: 100%;
    height: 100%;
    background:
        linear-gradient(135deg, #1e2233 0%, #2a2f44 100%);
}

.rsp-song-modal-heading {
    min-width: 0;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-eyebrow {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 1.2px;
    text-transform: uppercase !important;
    color: rgba(255, 255, 255, 0.65) !important;
    text-shadow: none !important;
    font-family: inherit;
    margin-bottom: 6px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-eyebrow::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #f43f5e;
    box-shadow: 0 0 0 4px rgba(244, 63, 94, 0.25);
    animation: rsp-song-modal-pulse 1.6s ease-in-out infinite;
}

/* Historical (previously played) tracks — drop the pulsing red
   live dot and shift the eyebrow text to a calmer slate tone so
   the visitor immediately reads "this isn't playing right now". */
.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-eyebrow-history::before {
    display: none;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-eyebrow-history {
    color: rgba(255, 255, 255, 0.55) !important;
}

@keyframes rsp-song-modal-pulse {
    0%, 100% { box-shadow: 0 0 0 4px rgba(244, 63, 94, 0.25); }
    50%      { box-shadow: 0 0 0 7px rgba(244, 63, 94, 0.05); }
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-title,
.rsp-song-modal-backdrop .rsp-song-modal h2.rsp-song-modal-title {
    margin: 0 0 4px !important;
    padding: 0 !important;
    font-size: 22px !important;
    line-height: 1.15 !important;
    font-weight: 700 !important;
    color: #ffffff !important;
    text-shadow: none !important;
    text-transform: none !important;
    letter-spacing: normal !important;
    font-family: inherit;
    background: transparent !important;
    border: none !important;
    word-break: break-word;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-dim {
    color: rgba(255, 255, 255, 0.55) !important;
    font-weight: 500;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-artist {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.78) !important;
    text-shadow: none !important;
    font-family: inherit;
    word-break: break-word;
}

/* Album line beneath the artist name — small, italic, low-emphasis
   so it reads as supporting metadata without competing with the
   song title. Hidden via the [hidden] attribute when there's no
   resolved album for the current track. */
.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-album-line {
    margin-top: 2px;
    font-size: 13px;
    font-style: italic;
    color: rgba(255, 255, 255, 0.6) !important;
    text-shadow: none !important;
    font-family: inherit;
    word-break: break-word;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-album-line[hidden] { display: none; }

.rsp-song-modal-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 14px;
}

.rsp-song-modal-actions[hidden] { display: none; }

/* ---- Body content (scrollable) ---- */
.rsp-song-modal-content {
    padding: 18px 22px 22px;
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 0;
}

.rsp-song-modal-loading,
.rsp-song-modal-empty {
    padding: 18px 4px;
    text-align: center;
    color: rgba(255, 255, 255, 0.55);
    font-size: 13.5px;
    line-height: 1.6;
}

/* Generic panel chrome shared by the "About [Artist]" and
   "About this song" cards inside the modal body. */
.rsp-song-modal-card {
    margin-bottom: 16px;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.06);
    overflow: hidden;
}

/* Hero thumbs-up / thumbs-down — styled like the compact player's
   now-playing pill: icon-only, transparent background, color shifts
   on hover / active (green for like, red for dislike). The shared
   `.rsp-vote-btn` rules elsewhere in this file already supply the
   compact-player palette via CSS variables; scoping these overrides
   under `.rsp-song-modal-actions` keeps that styling out of the
   global pill while still picking it up here. */
.rsp-song-modal-actions .rsp-song-modal-vote {
    display: inline-flex;
    align-items: center;
}

.rsp-song-modal-actions .rsp-vote-buttons {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 0;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-actions .rsp-vote-btn {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    padding: 6px 8px !important;
    border: 0 !important;
    border-radius: 8px !important;
    background: transparent !important;
    color: rgba(255, 255, 255, 0.7) !important;
    box-shadow: none !important;
    line-height: 1 !important;
    cursor: pointer;
    transition: color 0.15s ease, background-color 0.15s ease, transform 0.1s ease;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-actions .rsp-vote-btn:hover:not(:disabled) {
    color: #ffffff !important;
    background-color: rgba(255, 255, 255, 0.12) !important;
}

.rsp-song-modal-actions .rsp-vote-btn:active:not(:disabled) {
    transform: scale(0.92);
}

.rsp-song-modal-actions .rsp-vote-btn:disabled {
    opacity: 0.45;
    cursor: default;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-actions .rsp-vote-btn.rsp-vote-up.is-active {
    color: #22c55e !important;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-actions .rsp-vote-btn.rsp-vote-down.is-active {
    color: #f43f5e !important;
}

.rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-actions .rsp-vote-btn.rsp-favorite-btn.is-active {
    color: var(--rsp-vote-favorite-active, #e91e63) !important;
}

.rsp-song-modal-actions .rsp-vote-buttons[data-busy="1"] .rsp-vote-btn {
    pointer-events: none;
    opacity: 0.7;
}

/* The mobile global rule hides `.rsp-vote-buttons` at ≤480px to keep
   the now-playing pill compact. Inside the modal we always want the
   thumbs available, so undo that hide. */
@media (max-width: 480px) {
    .rsp-song-modal-actions .rsp-vote-buttons {
        display: inline-flex;
    }
}

/* Artist card — bio paragraph for "About [Artist]". Socials live
   in the hero column now; this card holds only the bio prose. */
.rsp-song-modal-artist-row {
    padding: 14px;
}

.rsp-song-modal-artist-bio {
    margin: 0;
    color: rgba(255, 255, 255, 0.85);
    font-size: 13.5px;
    line-height: 1.55;
    word-break: break-word;
}

/* Song card — pure trivia block. The album row + name moved into
   the hero, so this card now just renders the AI-generated story
   for the current track. */
.rsp-song-modal-song-row {
    padding: 14px;
}

.rsp-song-modal-trivia-body {
    color: rgba(255, 255, 255, 0.88);
}

.rsp-song-modal-trivia-body p {
    margin: 0;
    color: inherit;
    font-size: 13.5px;
    line-height: 1.6;
    word-break: break-word;
}

.rsp-song-modal-section-title {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.9px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
    margin-bottom: 10px;
}

/* ---- Mobile tweaks ---- */
@media (max-width: 520px) {
    .rsp-song-modal-backdrop { padding: 0; align-items: stretch; }
    .rsp-song-modal {
        max-width: 100%;
        max-height: 100vh;
        border-radius: 0;
    }
    .rsp-song-modal-hero {
        padding: 22px 18px 18px;
    }
    .rsp-song-modal-hero-inner {
        grid-template-columns: 88px 1fr;
        gap: 14px;
    }
    .rsp-song-modal-portrait-column { width: 88px; gap: 8px; }
    .rsp-song-modal-portrait-wrap { width: 88px; height: 88px; }
    .rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-social { width: 26px !important; height: 26px !important; min-width: 26px !important; min-height: 26px !important; }
    .rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-title,
    .rsp-song-modal-backdrop .rsp-song-modal h2.rsp-song-modal-title { font-size: 18px !important; }
    .rsp-song-modal-backdrop .rsp-song-modal .rsp-song-modal-artist { font-size: 14px; }
    .rsp-song-modal-content { padding: 16px 18px 22px; }
}

/* =====================================================================
 * Toast — small confirmation pill anchored to the bottom-center of the
 * viewport. Used by the favourite-toggle flow today ("Favourite added"
 * / "Favourite removed"); kept generic so any future ephemeral
 * confirmation can reuse the same DOM node + class.
 *
 * Position: fixed, bottom of viewport, z-indexed above the player but
 * below modal dialogs so an open access / personalization modal still
 * fully covers it. Transitions: 180ms ease for both opacity and the
 * 8px upward translate so the entry / exit feels native (matches the
 * RspVoting.showToast hide timer of ~220ms).
 *
 * Accessibility: role=status + aria-live=polite are set on the JS side
 * so screen readers announce the message without stealing focus.
 * Pointer events are disabled so the toast can't intercept clicks on
 * the buttons that triggered it.
 * ===================================================================== */
.rsp-toast {
    position: fixed;
    left: 50%;
    bottom: 28px;
    transform: translate(-50%, 8px);
    z-index: 9990;
    max-width: min(360px, calc(100vw - 24px));
    padding: 10px 16px;
    border-radius: 999px;
    background: var(--rsp-toast-bg, rgba(20, 20, 20, 0.92));
    color: var(--rsp-toast-color, #ffffff);
    font-size: 14px;
    line-height: 1.3;
    font-weight: 500;
    text-align: center;
    box-shadow: 0 6px 20px var(--rsp-toast-shadow, rgba(0, 0, 0, 0.25));
    opacity: 0;
    pointer-events: none;
    transition: opacity 180ms ease, transform 180ms ease;
}

.rsp-toast.is-visible {
    opacity: 1;
    transform: translate(-50%, 0);
}

@media (max-width: 480px) {
    .rsp-toast {
        bottom: 96px; /* clear of the compact player on mobile */
        font-size: 13px;
        padding: 9px 14px;
    }
}
