﻿/* Light theme customizations */

/*
 * THEMED TOKENS — the LIGHT half. The dark half is the matching :root in dark.css.
 * =============================================================================
 * These are the counterpart to the --st-player-* family in tokens.css, and the
 * difference matters: the players are dark in BOTH site themes, so their tokens are
 * defined once, globally. Cards and the surfaces around them are page content on
 * pages that honour the light/dark toggle, so theirs are defined TWICE - here and in
 * dark.css - and the two must be kept in step.
 *
 * Do not point a card rule at a --st-player-* token. Measured on white:
 * --st-blue-bright is ~2.1:1, --st-violet ~2.9:1, --st-amber ~2.1:1. All fail AA.
 *
 * Every value below is measured against the surface it actually sits on, not the page.
 */
:root {
    --st-surface: #ffffff;
    --st-surface-hover: #f1f4f8;
    --st-line: #dee2e6;
    /* Control boundaries ONLY. --st-line is 1.30:1 on --st-surface, which is fine
       for a card edge but below the 3:1 WCAG 1.4.11 asks for on the border of an
       INTERACTIVE control - an unchecked checkbox at that ratio reads as absent. */
    --st-control-line: #7f8894; /* 3.59:1 on --st-surface, 3.40:1 on --st-page, 3.25:1 on --st-surface-hover */
    --st-text: #0f1b2d; /* 17.28:1 on --st-surface */
    --st-text-2: #4a5b70; /*  6.95:1 */
    --st-text-3: #5e6f85; /*  5.14:1 - the dimmest that still passes AA */
    --st-accent: #0166d6; /*  5.42:1, and white-on-it is 5.42:1 too */
    --st-accent-hover: #0159b8;
    --st-accent-soft: rgba(1, 102, 214, .10);
    --st-genre: #7d3c98; /*  7.07:1 - NOT #8e44ad, which is for dark surfaces */
    --st-warn: #9a5c00; /*  5.38:1 - NOT #ffa500, which is 2.1:1 on white */
    /* Solid, not an alpha: --st-warn-soft composited differently over --st-page than
       over --st-surface, and on the page it left --st-warn at 4.34:1, under AA. */
    --st-warn-tint: #f7f1e8; /* --st-warn #9a5c00 on it = 4.79:1 */
    --st-track: rgba(15, 27, 45, .14);
    /* The page behind the cards, so a sticky header can hide what scrolls under it. */
    --st-page: #f8f9fa;
    /* Only ever carries white text or white icons, so both stops clear 4.5:1 on white. */
    --st-brand-gradient: linear-gradient(135deg, #0166d6 0%, #0186fd 100%);
    /* Scrollbar: a quiet gutter, not branding. Muted grey on the light page. */
    --st-scrollbar-thumb: #c2c9d2;
    --st-scrollbar-thumb-hover: #a7b0bc;
    /*
     * FILL family. Distinct from --st-accent on purpose: that one is measured as TEXT on
     * --st-surface, which says nothing about what is legible ON TOP of it. These are
     * measured the other way round, and --st-on-* is the only foreground allowed on them.
     */
    --st-accent-fill: #0166d6;
    --st-accent-fill-hover: #0159b8;
    --st-on-accent: #ffffff; /* 5.42:1 on the fill, 6.73:1 on the hover */
    --st-on-accent-soft: rgba(255, 255, 255, .28);
    --st-genre-fill: #7d3c98;
    /*
     * DESTRUCTIVE. Syncfusion ships e-danger as #dc3545 and it was the last colour in
     * the app with no theme variant at all: as TEXT or a 1px BORDER it measures
     * 4.53:1 on --st-surface but 4.30:1 on --st-page, so every Delete link, outlined
     * Cancel and danger-zone edge failed. Filled with a white label it squeaked
     * through at 4.53:1, which is why it went unnoticed.
     *
     * Contrast is symmetric, so ONE value does both jobs here - unlike --st-accent,
     * which needed a separate fill family only because its FOREGROUND was wrong.
     * --st-on-danger is the only foreground permitted on --st-danger.
     */
    --st-danger: #c8102e; /* 5.88:1 on --st-surface, 5.58:1 on --st-page, 5.33:1 on --st-surface-hover */
    --st-on-danger: #ffffff; /* 5.88:1 on the fill */
    /* The background a danger ALERT sits on. Solid for the same reason --st-warn-tint
       is: an alpha composites differently over --st-page than over --st-surface, so the
       pair cannot be measured once. */
    --st-danger-tint: #fdf0f1; /* --st-danger on it = 5.30:1, --st-text = 15.56:1 */
    --st-on-genre: #ffffff; /* 7.07:1 */
    /* A shadow is always dark, in both themes. dark.css used to use a WHITE one. */
    --st-elev: 0 2px 6px rgba(15, 27, 45, .06), 0 8px 24px rgba(15, 27, 45, .07);
    --st-elev-hover: 0 4px 10px rgba(15, 27, 45, .09), 0 14px 34px rgba(15, 27, 45, .11);
}

body {
    background-color: #f8f9fa;
    color: #212529;
}

.e-btn {
    background: white;
    color: black;
}

    .e-btn:hover {
        background: #e9ecef;
        color: black;
    }

.e-switch-wrapper .e-switch-handle, .e-css.e-switch-wrapper .e-switch-handle {
    background-color: rgb(13 110 253 / 80%);
    box-shadow: 0 2px 4px rgba(var(--color-sf-black), 0.075);
}

.mobile-app-install-banner {
    background-color: #ffffff;
    border-color: #d9dee3;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.mobile-app-install-title {
    color: #111111;
}

.mobile-app-install-subtitle {
    color: #495057;
}

.mobile-app-install-store-text {
    background-color: #111111;
    color: #ffffff;
}

.mobile-app-install-store-text:hover {
    background-color: #242424;
    color: #ffffff;
}

.admin-messages-panel {
    border: 1px solid #d9dde3;
    background-color: #ffffff;
    box-shadow: 0 12px 28px rgba(15, 23, 42, 0.08);
}

.admin-messages-panel-header {
    background-color: #f6f8fb;
    border-bottom: 1px solid #d9dde3;
}

.admin-messages-panel-body {
    background-color: #ffffff;
}

.admin-messages-channel-section {
    background-color: #f6f8fb;
    border: 1px solid #d9dde3;
}

.admin-messages-channel-options .e-checkbox-wrapper .e-label,
.admin-messages-channel-options .e-css.e-checkbox-wrapper .e-label {
    color: #212529;
}

.song-title {
    color: #282828;
}
/* Playlists Page Colors */
.playlists-page-date {
    opacity: 0.7;
}

.playlists-page-songs-section {
    border: 1px solid #ddd;
}

.playlists-page-song-item {
    border: 1px solid #eee;
}

.playlists-page-song-genre {
    opacity: 0.7;
}

.playlists-page-add-song-item {
    border: 1px solid #eee;
}

/* Like/Dislike Component - Light Theme Colors */
.like-button,
.dislike-button,
.like-display,
.dislike-display {
    color: black;
    background-color: white;
}

.like-button:hover,
.dislike-button:hover {
    background-color: rgba(179, 179, 179, 0.2);
    /*color: #fff;*/
}

.like-button.active,
.dislike-button.active {
    background-color: rgba(179, 179, 179, 0.2);
    /*color: #fff;*/
}

.count-text {
    color: inherit;
}

.stream-count-info, .playlist-track-info {
    color: #282828;
}

/* Subscribe CTA Dialog */
.subscribe-cta-dialog .e-dlg-header-content {
    background: transparent !important;
}

.subscribe-cta-dialog-content {
    background: #2d3748;
}

.subscribe-cta-dialog-content .cta-title {
    color: #fff;
}

.subscribe-cta-dialog-content .cta-price-highlight {
    color: #fff;
}

.subscribe-cta-dialog-content .cta-auth-text {
    color: #fff;
}

.subscribe-cta-dialog .e-dlg-closeicon-btn {
    color: #fff !important;
}

.test-server-banner {
    background-color: #fff3cd;
    border-bottom-color: #ffc107;
}

.test-server-banner-label {
    color: #856404;
}

.test-server-banner-link {
    color: #664d03;
}

.test-server-banner-link:hover,
.test-server-banner-link:focus {
    color: #523b00;
}

/* Planned Maintenance Notice - Light Theme */
.maintenance-banner {
    background-color: #fff3cd;
    border-bottom-color: #ffc107;
}

.maintenance-warning-label {
    color: #856404;
}

.maintenance-notice-dialog .e-dlg-header-content {
    background-color: #fff3cd !important;
    border-bottom: 1px solid #ffc107 !important;
}

.maintenance-dialog-header {
    color: #856404;
}

.maintenance-dialog-content {
    color: #1a1a2e;
}

.maintenance-dialog-times {
    color: #1a1a2e;
    background-color: #fff3cd;
    border-color: #ffc107;
}

.maintenance-ack-button {
    background-color: #1db954 !important;
    color: #fff !important;
    border: none !important;
}

.maintenance-ack-button:hover {
    background-color: #1ed760 !important;
}

/* Tip Jar - Light Theme */
.tip-button.control-button {
    color: #e91e63;
}

.tip-heart-button .tip-heart-icon {
    color: #e91e63;
    fill: #e91e63;
}

.tip-bucket {
    background-color: #f8f9fa;
    border: 1px solid #dee2e6;
}

.tip-bucket-amount {
    color: #28a745;
}

/* Admin Log Viewer */
.log-viewer {
    border: 1px solid #dee2e6;
    background-color: #f8f9fa;
}

.log-content {
    color: #212529;
}

.google-auth-button {
    background-color: #ffffff !important;
    border-color: #dadce0 !important;
    color: #1f1f1f !important;
}

.google-auth-button:hover {
    background-color: #f8fafd !important;
    border-color: #c6c6c6 !important;
    color: #1f1f1f !important;
}

/* Lyric timing dialog. The counter is quiet until it is not: over the limit it
   turns into the reason the Submit button is disabled, so it has to be findable. */
.lyrics-dialog-counter {
    color: #6c757d;
}

.lyrics-dialog-counter.is-over {
    color: #b02a37;
}

.lyrics-dialog-hint {
    color: #6c757d;
}

.lyrics-dialog-progress-label {
    color: #495057;
}

/* ============================================================
   Scrolling lyrics - light
   ============================================================ */

.lyrics-scroller {
    background-color: #f4f4f4;
    color: #6b6b6b;
}

.lyrics-scroller-empty {
    color: #7a7a7a;
}

.lyrics-line--active {
    color: #1a1a1a;
}

.lyrics-line--untimed {
    color: #8d8d8d;
}

.lyrics-toggle-button {
    background-color: rgba(255, 255, 255, 0.85);
    color: #333;
}

.lyrics-editor-help {
    background-color: #f6f6f6;
    border: 1px solid #e0e0e0;
}

.lyrics-editor-selection {
    background-color: #f6f6f6;
    border: 1px solid #e0e0e0;
}

.lyrics-editor-record {
    background-color: #f6f6f6;
    border: 1px solid #e0e0e0;
}

/* =========================================================================
   SONG PLAYER - "Marquee" colour
   =========================================================================
   THIS BLOCK IS IDENTICAL IN light.css AND dark.css. THAT IS DELIBERATE.

   The song player is an immersive listening surface and stays dark whichever
   theme the listener has chosen; only the app bar above it changes. It is
   duplicated rather than moved to app.css because ThemeProvider injects the
   theme sheet into HeadContent, i.e. AFTER app.css and after the breakpoint
   sheets, so a colour set in app.css would lose to any theme rule that
   happens to match - light.css already sets .song-title and
   .stream-count-info, which would have painted dark text on a dark hero.

   Change one copy, change the other.

   The palette is measured, not chosen: every value resolves to a token in
   tokens.css that was sampled from wwwroot/images/logo-dark-small.png.
   Contrast ratios are against --st-player-bg. Two pairings are load-bearing:
     - play button = --st-blue-bright with a BLACK glyph  (9.28:1)
     - never white text on --st-blue (3.6:1, fails AA); use --st-blue-deep.
   ========================================================================= */

.song-player-container {
    background-color: var(--st-player-bg);
    color: var(--st-player-text);
}

.song-player-container .loading-state,
.song-player-container .error-state {
    color: var(--st-player-text-3);
}

.song-player-container .loading-pulse {
    background-color: var(--st-blue-bright);
}

/* ---- Hero band -------------------------------------------------------- */

.song-player-container .song-hero-scrim {
    background: linear-gradient(180deg, rgba(7, 13, 22, .42) 0%, rgba(7, 13, 22, .72) 55%, var(--st-player-bg) 100%);
}

.song-player-container .player-art-shell {
    box-shadow: var(--st-shadow-art), 0 0 0 1px rgba(255, 255, 255, .12);
}

.song-player-container .song-chip-genre {
    background-color: rgba(155, 135, 245, .24);
    color: #c8b9ff;
    border: 1px solid rgba(155, 135, 245, .45);
}

.song-player-container .song-chip-genre:hover {
    background-color: rgba(155, 135, 245, .34);
    border-color: rgba(155, 135, 245, .6);
    color: #ffffff;
}

.song-player-container .song-title {
    color: var(--st-player-text);
    text-shadow: 0 4px 30px rgba(0, 0, 0, .5);
}

.song-player-container .stream-count-info,
.song-player-container .album-track-info {
    color: var(--st-player-text-3);
}

.song-player-container .artist-link {
    color: var(--st-blue-bright);
}

.song-player-container .artist-link:hover {
    color: var(--st-blue-pale);
}

.song-player-container .subscription-badge {
    color: var(--st-blue-bright);
}

.song-player-container .preview-label {
    color: var(--st-amber);
}

.song-player-container .play-button-large {
    background-color: var(--st-blue-bright);
    box-shadow: var(--st-shadow-play);
}

.song-player-container .play-button-large .play-icon {
    color: #000000;
}

/* ---- Stage panels ----------------------------------------------------- */

.song-player-container .song-panel {
    background-color: var(--st-player-surface);
    border-color: var(--st-player-line);
}

.song-player-container .song-panel-caption {
    color: var(--st-player-text-3);
}

.song-player-container .song-panel-switch {
    background-color: var(--st-player-surface-2);
    border-color: var(--st-player-line);
}

.song-player-container .lyrics-toggle-button,
.song-player-container .art-toggle-button {
    color: var(--st-player-text-3);
}

.song-player-container .lyrics-toggle-button:hover,
.song-player-container .art-toggle-button:hover {
    color: var(--st-player-text);
}

.song-player-container .lyrics-toggle-button.is-active,
.song-player-container .art-toggle-button.is-active {
    background-color: var(--st-blue-bright);
    color: #04121f;
}

.song-player-container .song-stage-art {
    box-shadow: 0 18px 44px rgba(0, 0, 0, .55), 0 0 0 1px rgba(255, 255, 255, .09);
}

.song-player-container .persona-bio {
    color: var(--st-player-text-2);
}

.song-player-container .persona-website {
    color: var(--st-violet);
}

.song-player-container .song-tip-cta {
    background-color: var(--st-blue-deep);
    color: #ffffff;
}

.song-player-container .song-tip-cta:hover {
    background-color: var(--st-blue);
}

/* ---- Transport pill --------------------------------------------------- */

.song-player-container .player-bar {
    background-color: rgba(13, 23, 39, .92);
    border-color: var(--st-player-line-strong);
    box-shadow: var(--st-shadow-float);
}

.song-player-container .control-button {
    color: var(--st-player-text-3);
}

.song-player-container .control-button:hover {
    color: var(--st-player-text);
    background-color: rgba(255, 255, 255, .07);
}

.song-player-container .control-button.active {
    color: var(--st-blue-bright);
}

.song-player-container .control-button[disabled],
.song-player-container .control-button[disabled]:hover {
    color: var(--st-player-text-3);
    background-color: transparent;
}

.song-player-container .play-button-small {
    background-color: #ffffff;
}

.song-player-container .play-button-small .play-icon-small {
    color: #000000;
}

.song-player-container .time-display {
    color: var(--st-player-text-3);
}

.song-player-container .progress-bar-container,
.song-player-container .volume-bar-container {
    background-color: rgba(255, 255, 255, .16);
}

.song-player-container .progress-bar {
    background-color: var(--st-blue-bright);
}

.song-player-container .volume-bar {
    background-color: var(--st-blue-pale);
}

.song-player-container .progress-thumb,
.song-player-container .volume-thumb {
    background-color: #ffffff;
    box-shadow: 0 2px 6px rgba(0, 0, 0, .7);
}

.song-player-container .progress-limit-marker {
    background-color: var(--st-amber);
}

/* ---- Lyrics scroller inside the stage panel ---------------------------
   The shared .lyrics-scroller rules above paint it as a standalone card:
   #f4f4f4 in light.css, #121212 in dark.css. Inside the stage panel that
   reads as a box within a box - and in light mode it painted a WHITE panel
   into the middle of a dark player. It has to inherit the panel instead.

   .lyrics-word--active is the important one. It ships as #0f7a37 / #3ddc84,
   which is the old Spotify green, and it lands on the single most-looked-at
   element of this design - the word being sung. It is the brand accent here. */

.song-player-container .lyrics-scroller {
    background-color: transparent;
    color: var(--st-player-text-3);
}

.song-player-container .lyrics-scroller-empty {
    color: var(--st-player-text-3);
}

.song-player-container .lyrics-line--active {
    color: var(--st-player-text);
}

.song-player-container .lyrics-word--active {
    color: var(--st-blue-bright);
}

.song-player-container .lyrics-word--selected {
    background-color: rgba(2, 184, 253, .16);
    outline: 1px solid var(--st-blue-bright);
}

.song-player-container .lyrics-line--untimed {
    color: rgba(200, 234, 253, .45);
}

/* ---- Hero backdrop when the song has no cover art ---------------------
   Most of the catalogue has artwork, but without it the backdrop element is
   empty and the hero is a flat black slab. A brand wash keeps the band
   looking deliberate; real artwork covers it completely. */

.song-player-container .song-hero-backdrop {
    background:
        radial-gradient(680px 420px at 22% 30%, rgba(1, 134, 253, .34), transparent 70%),
        radial-gradient(560px 380px at 78% 12%, rgba(2, 184, 253, .18), transparent 72%),
        radial-gradient(620px 420px at 60% 90%, rgba(155, 135, 245, .16), transparent 74%);
}

.song-player-container .persona-more {
    color: var(--st-blue-bright);
}

.song-player-container .persona-more:hover {
    color: var(--st-blue-pale);
}

/* =========================================================================
   PLAYLIST PLAYER - "Marquee" colour
   =========================================================================
   IDENTICAL IN light.css AND dark.css, DELIBERATELY - same reasoning as the
   song player block above: this page is an immersive listening surface and
   stays dark whichever theme the listener picked, and the theme sheet is
   injected after app.css and the breakpoint sheets, so a colour set anywhere
   else would lose to whatever theme rule happens to match.

   light.css still carries unscoped .song-title { color:#282828 } and
   .stream-count-info/.playlist-track-info { color:#282828 } with no dark.css
   counterpart. Without the overrides below those paint near-black text on the
   dark hero in light theme.

   Change one copy, change the other.
   ========================================================================= */

.playlist-player-container {
    background-color: var(--st-player-bg);
    color: var(--st-player-text);
}

.playlist-player-container .loading-state,
.playlist-player-container .error-state { color: var(--st-player-text-3); }

.playlist-player-container .loading-pulse { background-color: var(--st-blue-bright); }

/* ---- Hero -------------------------------------------------------------- */

.playlist-player-container .playlist-hero-backdrop {
    background:
        radial-gradient(680px 420px at 22% 30%, rgba(1, 134, 253, .34), transparent 70%),
        radial-gradient(560px 380px at 78% 12%, rgba(2, 184, 253, .18), transparent 72%),
        radial-gradient(620px 420px at 60% 90%, rgba(155, 135, 245, .16), transparent 74%);
}

.playlist-player-container .playlist-hero-scrim {
    background: linear-gradient(180deg, rgba(7, 13, 22, .42) 0%, rgba(7, 13, 22, .72) 55%, var(--st-player-bg) 100%);
}

.playlist-player-container .player-art-shell {
    box-shadow: var(--st-shadow-art), 0 0 0 1px rgba(255, 255, 255, .12);
}

.playlist-player-container .player-art-shell.is-round {
    box-shadow: var(--st-shadow-art), 0 0 0 3px rgba(2, 184, 253, .35);
}

.playlist-player-container .playlist-chip {
    background-color: rgba(155, 135, 245, .24);
    color: #c8b9ff;
    border: 1px solid rgba(155, 135, 245, .45);
}

.playlist-player-container .song-title {
    color: var(--st-player-text);
    text-shadow: 0 4px 30px rgba(0, 0, 0, .5);
}

.playlist-player-container .playlist-track-info,
.playlist-player-container .stream-count-info,
.playlist-player-container .now-playing-info { color: var(--st-player-text-3); }

.playlist-player-container .now-playing-track { color: var(--st-blue-bright); }

.playlist-player-container .subscription-badge { color: var(--st-blue-bright); }
.playlist-player-container .preview-label { color: var(--st-amber); }

.playlist-player-container .artist-link { color: var(--st-blue-bright); }
.playlist-player-container .artist-link:hover { color: var(--st-blue-pale); }

.playlist-player-container .play-button-large {
    background-color: var(--st-blue-bright);
    box-shadow: var(--st-shadow-play);
}

.playlist-player-container .play-button-large .play-icon { color: #000000; }

/* ---- Panels ------------------------------------------------------------ */

.playlist-player-container .playlist-panel {
    background-color: var(--st-player-surface);
    border-color: var(--st-player-line);
}

.playlist-player-container .playlist-panel-caption,
.playlist-player-container .playlist-panel-count { color: var(--st-player-text-3); }

.playlist-player-container .playlist-panel-switch {
    background-color: var(--st-player-surface-2);
    border-color: var(--st-player-line);
}

.playlist-player-container .lyrics-toggle-button,
.playlist-player-container .art-toggle-button { color: var(--st-player-text-3); }

.playlist-player-container .lyrics-toggle-button:hover,
.playlist-player-container .art-toggle-button:hover { color: var(--st-player-text); }

.playlist-player-container .lyrics-toggle-button.is-active,
.playlist-player-container .art-toggle-button.is-active {
    background-color: var(--st-blue-bright);
    color: #04121f;
}

.playlist-player-container .playlist-stage-art {
    box-shadow: 0 18px 44px rgba(0, 0, 0, .55), 0 0 0 1px rgba(255, 255, 255, .09);
}

.playlist-player-container .lyrics-scroller {
    background-color: transparent;
    color: var(--st-player-text-3);
}

.playlist-player-container .lyrics-scroller-empty { color: var(--st-player-text-3); }
.playlist-player-container .lyrics-line--active { color: var(--st-player-text); }
.playlist-player-container .lyrics-word--active { color: var(--st-blue-bright); }
.playlist-player-container .lyrics-line--untimed { color: rgba(200, 234, 253, .45); }

/* ---- Track list -------------------------------------------------------- */

.playlist-player-container .track-list th {
    color: var(--st-player-text-3);
    background-color: var(--st-player-surface);
    border-bottom: 1px solid var(--st-player-line);
}

.playlist-player-container .track-row td { color: var(--st-player-text-2); }
.playlist-player-container .track-row:hover td { background-color: rgba(255, 255, 255, .06); }

/*
 * The current track was signalled three ways in #1db954 - Spotify's brand
 * green. All three are the brand accent now.
 */
.playlist-player-container .track-row.current-track td { background-color: rgba(2, 184, 253, .10); }
.playlist-player-container .track-row.current-track td:first-child { box-shadow: inset 2px 0 0 var(--st-blue-bright); }
.playlist-player-container .track-name { color: var(--st-player-text); }
.playlist-player-container .track-name.playing { color: var(--st-blue-bright); }
.playlist-player-container .playing-indicator span { background-color: var(--st-blue-bright); }

.playlist-player-container .track-index,
.playlist-player-container .track-sub,
.playlist-player-container .track-artist,
.playlist-player-container .track-streams,
.playlist-player-container .track-duration { color: var(--st-player-text-3); }

.playlist-player-container .track-play-btn { color: var(--st-player-text); }

.playlist-player-container .track-genre-link { color: var(--st-violet); }
.playlist-player-container .track-genre-link:hover { color: #b8a8f8; }

.playlist-player-container .track-preview-badge {
    color: var(--st-amber);
    background-color: rgba(255, 165, 0, .15);
}

.playlist-player-container .tip-heart-inline { color: var(--st-pink); }

/* ---- Artist / About ---------------------------------------------------- */

.playlist-player-container .persona-bio { color: var(--st-player-text-2); }
.playlist-player-container .persona-website { color: var(--st-violet); }
.playlist-player-container .persona-more { color: var(--st-blue-bright); }
.playlist-player-container .persona-more:hover { color: var(--st-blue-pale); }

.playlist-player-container .playlist-tip-cta {
    background-color: var(--st-blue-deep);
    color: #ffffff;
}

.playlist-player-container .playlist-tip-cta:hover { background-color: var(--st-blue); }

/* ---- Transport pill ---------------------------------------------------- */

.playlist-player-container .player-bar {
    background: rgba(13, 23, 39, .92);
    border-color: var(--st-player-line-strong);
    box-shadow: var(--st-shadow-float);
}

.playlist-player-container .control-button { color: var(--st-player-text-3); }

.playlist-player-container .control-button:hover {
    color: var(--st-player-text);
    background-color: rgba(255, 255, 255, .07);
}

.playlist-player-container .control-button.active { color: var(--st-blue-bright); }

.playlist-player-container .play-button-small { background-color: #ffffff; }
.playlist-player-container .play-button-small .play-icon-small { color: #000000; }

.playlist-player-container .time-display { color: var(--st-player-text-3); }

.playlist-player-container .progress-bar-container,
.playlist-player-container .volume-bar-container { background-color: rgba(255, 255, 255, .16); }

.playlist-player-container .progress-bar { background-color: var(--st-blue-bright); }
.playlist-player-container .volume-bar { background-color: var(--st-blue-pale); }

.playlist-player-container .progress-thumb,
.playlist-player-container .volume-thumb {
    background-color: #ffffff;
    box-shadow: 0 2px 6px rgba(0, 0, 0, .7);
}

.playlist-player-container .progress-limit-marker { background-color: var(--st-amber); }

/* =========================================================================
   CARDS, FILTER PILLS AND CTAs — colour
   =========================================================================
   THIS BLOCK IS IDENTICAL IN light.css AND dark.css, and that is the point:
   every value is a --st-* token, and the tokens are what differ between the
   two sheets. Change one copy, change the other.

   That is the opposite arrangement to the players, whose colour block is
   also duplicated but with LITERAL values, because those pages are dark in
   both themes. Here the page follows the toggle, so the tokens carry it.

   Replaces ~73 scattered colour rules, including several that were plainly
   wrong on a light page: .loading-state was #fff on #f8f9fa (invisible),
   .music-card was rgba(0,0,0,.125) on #f8f9fa (a grey hole), and the dark
   card's "shadow" was rgba(255,255,255,.3) — white, so a halo.
   ========================================================================= */

.loading-state,
.error-state { color: var(--st-text-2); }

/* ---- The card surface -------------------------------------------------- */

.music-card,
.e-card.music-card {
    background: var(--st-surface);
    border-color: var(--st-line);
    box-shadow: var(--st-elev);
    color: var(--st-text);
}

.music-card:hover,
.e-card.music-card:hover {
    background: var(--st-surface-hover);
    box-shadow: var(--st-elev-hover);
}

.card-album-art { background: var(--st-surface-hover); }

/* Was a raw #06acfc — the only place the logo blue appeared unmediated. */
.card-album-art-animation { border: 3px solid var(--st-accent); }

.card-song-title { color: var(--st-text); }
.card-artist-name { color: var(--st-text-3); }
.card-artist-name a { color: var(--st-accent); }
.card-artist-name a:hover { color: var(--st-accent-hover); }
.card-genre a { color: var(--st-genre); }
.card-genre a:hover { color: var(--st-text); }
.card-stream-count,
.card-stream-info { color: var(--st-text-3); }

.action-button {
    background: transparent;
    border: 1px solid var(--st-control-line);
    color: var(--st-text-2);
}

.action-button:hover {
    background: var(--st-surface-hover);
    border-color: var(--st-accent);
    color: var(--st-accent);
}

/* ---- The in-card mini player -------------------------------------------
   Unscoped on purpose: Creator/LyricsTimingEditor.razor renders these same
   classes and is asserted on them. A card ancestor here would leave that
   page's controls unstyled. */

.card-volume-button,
.card-time-display { color: var(--st-text-3); }

.card-volume-button:hover { color: var(--st-text); }

.card-volume-bar-container,
.card-progress-bar-container { background-color: var(--st-track); }

.card-volume-bar,
.card-progress-bar { background-color: var(--st-accent); }

.card-volume-thumb,
.card-progress-thumb {
    background-color: var(--st-surface);
    box-shadow: 0 1px 4px rgba(0, 0, 0, .45);
}

.card-progress-limit-marker { background-color: var(--st-warn); }

/* ---- Filter pills -------------------------------------------------------
   These were solid #1db954 and BYTE-IDENTICAL in both theme sheets, so they
   get a real light/dark split here for the first time. Resting state is now
   quiet and only the active state carries the accent — a header of six
   saturated pills was reading as six primary actions. */

.music-library-sticky-header { background-color: var(--st-page, transparent); }

.filter-pill {
    background-color: var(--st-surface);
    border-color: var(--st-control-line);
    color: var(--st-text-2);
}

.filter-pill:hover {
    background-color: var(--st-surface-hover);
    border-color: var(--st-accent);
    color: var(--st-text);
}

.filter-pill.active,
.filter-pill.active:hover,
.music-type-filter.active {
    background-color: var(--st-accent-fill);
    border-color: var(--st-accent-fill);
    color: var(--st-on-accent);
}

/* These sit INSIDE the active pill, so they take its foreground, not a fixed white. */
.filter-pill-clear { color: inherit; opacity: .78; }
.filter-pill-clear:hover { opacity: 1; }
.filter-pill-count { background-color: var(--st-on-accent-soft); color: inherit; }

.filter-pill-dropdown {
    background-color: var(--st-surface);
    border-color: var(--st-line);
    box-shadow: var(--st-elev-hover);
}

.filter-pill-search-input {
    background-color: var(--st-surface);
    border-color: var(--st-control-line);
    color: var(--st-text);
}

.filter-pill-search-input:focus { border-color: var(--st-accent); }

.filter-pill-dropdown-item:hover,
.filter-pill-dropdown-option:hover,
.filter-pill-dropdown-option.selected { background-color: var(--st-surface-hover); }

.filter-pill-dropdown-item span,
.filter-pill-dropdown-option { color: var(--st-text); }

.filter-pill-dropdown-item input[type="checkbox"] { accent-color: var(--st-accent); }

.filter-pill-option-indicator { color: var(--st-accent); }

/* ---- Playlist cards ----------------------------------------------------
   Same surface as the song card; only the left accent stripe differs. */

.recommended-playlist-card { border-left: 4px solid var(--st-accent); }
.liked-songs-playlist-card { border-left: 4px solid #d81b60; }

/* ---- CTAs ---------------------------------------------------------------
   The last large block of #1db954 on a public page. From AGENTS.md:
   destructive actions stay on e-danger, and cta-secondary/hero-secondary-cta
   stay the documented VIOLET for creator and account actions - which on a
   light page must be --st-genre (#7d3c98, 7.07:1), not #8e44ad. */

.cta-primary,
.cta-button {
    background-color: var(--st-accent-fill) !important;
    color: var(--st-on-accent) !important;
    border: none !important;
}

.cta-primary:hover,
.cta-button:hover {
    background-color: var(--st-accent-fill-hover) !important;
    box-shadow: var(--st-elev-hover);
}

.cta-secondary,
.hero-secondary-cta {
    background-color: var(--st-genre-fill) !important;
    color: var(--st-on-genre) !important;
    border: none !important;
}

.cta-secondary:hover,
.hero-secondary-cta:hover {
    background-color: var(--st-genre-fill) !important;
    box-shadow: var(--st-elev-hover);
}

.hero-highlight { color: var(--st-accent); }

.cta-benefits li svg { color: var(--st-accent); }

.cta-price-highlight,
.cta-price-highlight .price { color: var(--st-accent); }

.feature-icon {
    background: var(--st-brand-gradient);
    color: #fff;
}

.music-library-link:hover { color: var(--st-accent-hover); }

.contact-icon { color: var(--st-accent); }

/* =========================================================================
   PUBLIC LINK AND CTA COLOUR — the tail of the green
   =========================================================================
   ALSO IDENTICAL IN light.css AND dark.css; the tokens carry the difference.

   Everything here previously lived as a hex literal in app.css, which is a
   structure sheet - so it could not follow the theme at all, and the artist
   and genre links rendered the same colour on both. The declarations were
   removed from app.css; the structural half (text-decoration, weight, size,
   transition) stayed behind.
   ========================================================================= */

.music-library-link { color: var(--st-accent); }
.artist-link { color: var(--st-accent); }
.artist-link:hover { color: var(--st-accent-hover); }
.genre-link { color: var(--st-genre); }
.genre-link:hover { color: var(--st-text); }

/* The card's own karaoke highlight, and the lyrics editor's selection. These are the
   UNSCOPED copies - both players override them at higher specificity, so this pair only
   ever paints inside a card or the timing editor. Still Spotify green until now: dark
   #1db954, light #0f7a37. */
.lyrics-word--active { color: var(--st-accent); }

.lyrics-word--selected {
    background-color: var(--st-accent-soft);
    outline: 1px solid var(--st-accent);
}

/* The subscribe dialog is a LISTENER action, so it takes the accent rather than the
   creator violet. Scoped, so it outranks the .cta-button rule above. */
.subscriber-cta .cta-icon { background: var(--st-brand-gradient); }

.subscribe-cta-dialog-content .cta-price-highlight .price { color: var(--st-accent); }

.subscribe-cta-dialog-content .cta-button {
    background-color: var(--st-accent-fill) !important;
    color: var(--st-on-accent) !important;
}

.subscribe-cta-dialog-content .cta-button:hover {
    background-color: var(--st-accent-fill-hover) !important;
}

/* =========================================================================
   CARD ACTION HIERARCHY — colour
   =========================================================================
   IDENTICAL IN light.css AND dark.css; the tokens carry the difference.

   Play is the card's primary action and takes the accent fill. View stays the
   quiet outline defined further up. Before this both were the same outline, so
   the card had no primary at all and the Facebook share bar - full width and
   solid - read as the most important control on it.
   ========================================================================= */

.action-button-play {
    background: var(--st-accent-fill);
    border-color: var(--st-accent-fill);
    color: var(--st-on-accent);
}

.action-button-play:hover,
.action-button-play:focus {
    background: var(--st-accent-fill-hover);
    border-color: var(--st-accent-fill-hover);
    color: var(--st-on-accent);
}

/* Syncfusion paints .e-btn on hover/focus/active; these have to win or the fill flashes
   back to the default grey mid-interaction. */
.e-btn.action-button-play,
.e-btn.action-button-play:hover,
.e-btn.action-button-play:focus,
.e-btn.action-button-play:active {
    background: var(--st-accent-fill);
    border-color: var(--st-accent-fill);
    color: var(--st-on-accent);
}

.e-btn.action-button-play:hover,
.e-btn.action-button-play:focus {
    background: var(--st-accent-fill-hover);
    border-color: var(--st-accent-fill-hover);
}

/* The approved layout has these as bare icon + count, with no button chrome - the card
   already carries enough boxes. Scoped to the row, which only the song card renders. */
.card-ai-actions-row .like-button,
.card-ai-actions-row .dislike-button {
    background: transparent;
    border: none;
    box-shadow: none;
    color: var(--st-text-3);
}

.card-ai-actions-row .like-button:hover,
.card-ai-actions-row .dislike-button:hover {
    background: transparent;
    color: var(--st-accent);
}

.card-ai-actions-row .like-button.active,
.card-ai-actions-row .dislike-button.active {
    background: transparent;
    color: var(--st-accent);
}

/* =========================================================================
   MINI-PLAYER TRANSPORT — colour
   =========================================================================
   IDENTICAL IN light.css AND dark.css; the tokens carry the difference.

   These were bare Syncfusion .e-btn — a light grey box with a dark glyph,
   which on a dark card read as two white blocks. Now they mirror the resting
   card exactly: primary filled, secondary outlined, same shapes and colours,
   so the eye does not have to re-find the control when playback starts.

   Also styles Creator/LyricsTimingEditor.razor, which renders the same row.
   ========================================================================= */

.card-mini-controls .e-btn,
.card-mini-controls .e-btn:hover,
.card-mini-controls .e-btn:focus,
.card-mini-controls .e-btn:active {
    background: transparent;
    border-color: var(--st-control-line);
    color: var(--st-text-2);
}

.card-mini-controls .e-btn:hover,
.card-mini-controls .e-btn:focus {
    background: var(--st-surface-hover);
    border-color: var(--st-accent);
    color: var(--st-accent);
}

/* Play/pause — the row's primary, matching .action-button-play on the resting card. */
.card-mini-controls .e-btn:first-child,
.card-mini-controls .e-btn:first-child:active {
    background: var(--st-accent-fill);
    border-color: var(--st-accent-fill);
    color: var(--st-on-accent);
}

.card-mini-controls .e-btn:first-child:hover,
.card-mini-controls .e-btn:first-child:focus {
    background: var(--st-accent-fill-hover);
    border-color: var(--st-accent-fill-hover);
    color: var(--st-on-accent);
}

/* =========================================================================
   SECTION HEADERS AND PAGE STATES — colour
   =========================================================================
   IDENTICAL IN light.css AND dark.css; the tokens carry the difference.
   ========================================================================= */

.section-eyebrow { color: var(--st-accent); }
.section-link { color: var(--st-accent); }
.section-link:hover { color: var(--st-accent-hover); }

.empty-state-icon {
    background: var(--st-surface-hover);
    color: var(--st-text-3);
}

.empty-state-title { color: var(--st-text); }
.empty-state-body { color: var(--st-text-2); }

.state-action {
    background: var(--st-accent-fill);
    border-color: var(--st-accent-fill);
    color: var(--st-on-accent);
}

.state-action:hover {
    background: var(--st-accent-fill-hover);
    border-color: var(--st-accent-fill-hover);
}

.cta-group-note { color: var(--st-text-2); }

/* =========================================================================
   HOME SURFACES AND HEADINGS — colour
   =========================================================================
   IDENTICAL IN light.css AND dark.css; the tokens carry the difference.

   Replaces the last un-migrated block on the site. Home was half done: buttons and accents
   were already on --st-*, while every surface, heading and body colour was a raw hex - which
   is why the page could not follow the card surfaces it sits above.

   Two of those literals were plainly wrong rather than merely untokenised:
     .cta-card    box-shadow: 0 4px 20px #b3b3b3   - an OPAQUE grey, not an alpha shadow
     .feature-card  had no border at all, so it had no edge on a light page
   ========================================================================= */

.hero-title { color: var(--st-text); }
.hero-subtitle { color: var(--st-text-2); }

.section-title { color: var(--st-text); }
.section-subtitle { color: var(--st-text-2); }
.loading-text { color: var(--st-text-2); }

.feature-card,
.cta-card {
    background: var(--st-surface);
    border: 1px solid var(--st-line);
    box-shadow: var(--st-elev);
}

.feature-card:hover,
.cta-card:hover { box-shadow: var(--st-elev-hover); }

.feature-card h3 { color: var(--st-text); }
.feature-card p { color: var(--st-text-2); }

.cta-title { color: var(--st-text); }
.cta-description { color: var(--st-text-2); }
.cta-benefits li { color: var(--st-text); }
.cta-auth-text { color: var(--st-text); }

/* =========================================================================
   SCROLLBAR — colour
   =========================================================================
   IDENTICAL IN light.css AND dark.css; the tokens carry the difference.

   Two separate mechanisms, one per engine: scrollbar-color is Firefox, the ::-webkit-*
   pseudo-elements are Chromium and Safari. Both are needed; neither is a fallback for the other.
   ========================================================================= */

html { scrollbar-color: var(--st-scrollbar-thumb) var(--st-page); }

::-webkit-scrollbar-track { background: var(--st-page); }
::-webkit-scrollbar-thumb { background-color: var(--st-scrollbar-thumb); }
::-webkit-scrollbar-thumb:hover { background-color: var(--st-scrollbar-thumb-hover); }

/* ---- Listener-side button tiers ----------------------------------------
   IDENTICAL IN light.css AND dark.css; the tokens carry the difference. */

.cta-outline {
    background-color: transparent !important;
    border: 1px solid var(--st-control-line) !important;
    color: var(--st-text) !important;
}

.cta-outline:hover {
    background-color: var(--st-surface-hover) !important;
    border-color: var(--st-accent) !important;
    color: var(--st-accent) !important;
}

.cta-quiet {
    background-color: transparent !important;
    border: 1px solid transparent !important;
    color: var(--st-text-2) !important;
}

.cta-quiet:hover {
    background-color: var(--st-surface-hover) !important;
    color: var(--st-text) !important;
}

/* ---- Destructive buttons ------------------------------------------------
   AGENTS.md keeps destructive actions on e-danger rather than restyling them as
   CTAs. These give that class a themed value; see --st-danger above. */

.e-btn.e-danger,
.e-css.e-btn.e-danger {
    background-color: var(--st-danger);
    border-color: var(--st-danger);
    color: var(--st-on-danger);
}

.e-btn.e-danger:hover,
.e-css.e-btn.e-danger:hover {
    background-color: var(--st-danger);
    border-color: var(--st-danger);
    color: var(--st-on-danger);
    box-shadow: var(--st-elev-hover);
}

/* Moved out of app.css, where a coloured box-shadow had no theme variant and
   broke the property-routing rule. Unmistakably armed: a creator who does not
   realise recording is live will press space expecting play/pause. */
.lyrics-editor-record.is-recording {
    box-shadow: 0 0 0 2px var(--st-danger);
}

/* ---- Auth pages ---------------------------------------------------------
   The BRAND PANEL is deliberately one palette in both themes, so its colours sit in app.css,
   not here - only the themed half of the page is below. Measured on the panel base #102e55:
   #ffffff is 13.60:1, #c8eafd is 10.78:1, #02b8fd is 6.01:1.

   IDENTICAL IN light.css AND dark.css; the tokens carry the difference. */

.auth-page { background-color: var(--st-page); }

.auth-panel-eyebrow { color: #02b8fd; }
.auth-panel-title { color: #ffffff; }
.auth-panel-body { color: #c8eafd; }

.auth-title { color: var(--st-text); }
.auth-subtitle { color: var(--st-text-2); }
.auth-label { color: var(--st-text-2); }
.auth-link { color: var(--st-accent); }
.auth-link:hover { color: var(--st-accent-hover); }
.auth-footer { color: var(--st-text-2); }
.auth-dev-hint { color: var(--st-text-3); }

.auth-alert {
    background-color: var(--st-warn-tint);
    border: 1px solid var(--st-warn);
    color: var(--st-warn);
}

.auth-divider::before,
.auth-divider::after { background-color: var(--st-line); }
.auth-divider span { color: var(--st-text-3); }

/* Not --st-line: this is the boundary of an interactive control, so it takes the 3:1 value.
   See the --st-control-line note in the :root block above. */
.auth-page .e-input-group.e-outline:not(.e-disabled),
.auth-page .e-input-group.e-control-wrapper.e-outline:not(.e-disabled) {
    border-color: var(--st-control-line);
    background-color: var(--st-surface);
}

.auth-page .e-input-group.e-outline:not(.e-disabled):hover,
.auth-page .e-input-group.e-control-wrapper.e-outline:not(.e-disabled):hover {
    border-color: var(--st-text-3);
}

.auth-page .e-input-group.e-outline.e-input-focus,
.auth-page .e-input-group.e-control-wrapper.e-outline.e-input-focus {
    border-color: var(--st-accent);
    box-shadow: 0 0 0 3px var(--st-accent-soft);
}

.auth-page .e-input-group input.e-input { color: var(--st-text); }

.auth-page .e-checkbox-wrapper .e-frame,
.auth-page .e-css.e-checkbox-wrapper .e-frame { border-color: var(--st-control-line); }

.auth-page .e-checkbox-wrapper .e-frame.e-check,
.auth-page .e-css.e-checkbox-wrapper .e-frame.e-check {
    background-color: var(--st-accent-fill);
    border-color: var(--st-accent-fill);
    color: var(--st-on-accent);
}

.auth-page .e-checkbox-wrapper .e-label,
.auth-page .e-css.e-checkbox-wrapper .e-label { color: var(--st-text-2); }

.auth-reactivate {
    background-color: var(--st-accent-soft);
    border: 1px solid var(--st-accent);
    border-radius: var(--st-radius-sm);
}

/* Not the Google button - that one is white with #1f1f1f in BOTH themes, a brand rule
   .google-auth-button already handles. */
.auth-page .e-btn.auth-provider:not(.google-auth-button) {
    background-color: var(--st-surface);
    border-color: var(--st-control-line);
    color: var(--st-text);
}

.auth-page .e-btn.auth-provider:not(.google-auth-button):hover {
    background-color: var(--st-surface-hover);
    border-color: var(--st-accent);
    color: var(--st-accent);
}

/* ---- Register ------------------------------------------------------------
   IDENTICAL IN light.css AND dark.css; the tokens carry the difference. */

.auth-legal { background-color: var(--st-surface); border-color: var(--st-control-line); }
.auth-legal-split { background-color: var(--st-line); }
.auth-legal-optional { color: var(--st-text-3); }

.auth-page .legal-text { color: var(--st-text-2); }
.auth-page .legal-link { color: var(--st-accent); }
.auth-page .legal-link:hover { color: var(--st-accent-hover); }

.auth-hint { color: var(--st-text-3); }
.auth-verify-lead { color: var(--st-text-2); }
.auth-countdown { color: var(--st-text-3); }
.auth-countdown strong { color: var(--st-text-2); }
.auth-rule { background-color: var(--st-line); }
.auth-subhead { color: var(--st-text); }
.auth-subhead-note { color: var(--st-text-2); }

/* An interactive boundary, so --st-control-line rather than --st-line. */
.auth-page .auth-input.form-control {
    background-color: var(--st-surface);
    border-color: var(--st-control-line);
    color: var(--st-text);
}

.auth-page .auth-input.form-control:hover { border-color: var(--st-text-3); }

.auth-page .auth-input.form-control:focus {
    background-color: var(--st-surface);
    border-color: var(--st-accent);
    box-shadow: 0 0 0 3px var(--st-accent-soft);
    color: var(--st-text);
}

.auth-page .auth-input.form-control::placeholder { color: var(--st-text-3); }

/* EditForm renders these; unstyled they arrive as browser-default red on the page tint. */
.auth-page .validation-message,
.auth-page .validation-errors li { color: var(--st-danger); }

.auth-alert-info {
    background-color: var(--st-accent-soft);
    border-color: var(--st-accent);
    color: var(--st-accent-hover);
}

/* ---- Settings surfaces ---------------------------------------------------
   Shared by Manage Account and Creator Settings.
   IDENTICAL IN light.css AND dark.css; the tokens carry the difference. */

.settings-page { background-color: var(--st-page); }

.settings-nav-heading { color: var(--st-text-3); }
.settings-nav-link { color: var(--st-text-2); }
.settings-nav-link:hover { background-color: var(--st-surface-hover); color: var(--st-text); }
.settings-nav-link-danger { color: var(--st-danger); }

.settings-head-eyebrow { color: var(--st-accent); }
.settings-head-title { color: var(--st-text); }
.settings-head-note { color: var(--st-text-2); }
.settings-head-email { color: var(--st-text); }

.settings-card {
    background-color: var(--st-surface);
    border-color: var(--st-line);
    box-shadow: var(--st-elev);
}

.settings-card-danger { border-color: var(--st-danger); }

.settings-eyebrow { color: var(--st-accent); }
.settings-title { color: var(--st-text); }
.settings-note { color: var(--st-text-2); }
.settings-prose { color: var(--st-text-2); }
.settings-tz { color: var(--st-text-3); }
.settings-subhead { color: var(--st-text); }
.settings-hint { color: var(--st-text-3); }
.settings-working { color: var(--st-text-2); }

.status-pill {
    background-color: var(--st-accent-soft);
    border-color: var(--st-accent);
    color: var(--st-accent-hover);
}

.status-pill-dot { background-color: var(--st-accent); }

.status-pill-warn {
    background-color: var(--st-warn-tint);
    border-color: var(--st-warn);
    color: var(--st-warn);
}

.status-pill-warn .status-pill-dot { background-color: var(--st-warn); }

.fact-row { border-bottom: 1px solid var(--st-line); }
.fact-row:last-child { border-bottom: none; }
.fact-label { color: var(--st-text-2); }
.fact-value { color: var(--st-text); }

.terms-list li { color: var(--st-text-2); }
.terms-list li strong { color: var(--st-text); }
.terms-list li::before { color: var(--st-accent); }

.passkey-icon { background-color: var(--st-accent-soft); color: var(--st-accent); }
.passkey-row { border-bottom: 1px solid var(--st-line); }
.passkey-row:last-child { border-bottom: none; }
.passkey-name { color: var(--st-text); }
.passkey-meta { color: var(--st-text-3); }

.settings-empty-icon { background-color: var(--st-accent-soft); color: var(--st-accent); }
.settings-empty-title { color: var(--st-text); }
.settings-empty-body { color: var(--st-text-2); }

.settings-guard {
    background-color: var(--st-surface-hover);
    border: 1px solid var(--st-line);
    color: var(--st-text-2);
}

.settings-guard-icon { color: var(--st-text-3); }

.settings-alert-info {
    background-color: var(--st-accent-soft);
    border: 1px solid var(--st-accent);
    color: var(--st-accent-hover);
}

.settings-alert-warn {
    background-color: var(--st-warn-tint);
    border: 1px solid var(--st-warn);
    color: var(--st-warn);
}

.settings-label { color: var(--st-text-2); }
.settings-loading { color: var(--st-text-2); }
.settings-spinner { border-color: var(--st-track); border-top-color: var(--st-accent); }

/* Account actions take the violet; destructive stays on the danger token. */
:is(.settings-page, .settings-dialog) .e-btn.settings-btn {
    background-color: transparent;
    border-color: var(--st-control-line);
    color: var(--st-text);
}

:is(.settings-page, .settings-dialog) .e-btn.settings-btn:hover {
    background-color: var(--st-surface-hover);
    border-color: var(--st-accent);
    color: var(--st-accent);
}

:is(.settings-page, .settings-dialog) .e-btn.settings-btn.settings-btn-violet:not(:disabled):not(.e-disabled),
:is(.settings-page, .settings-dialog) .e-btn.settings-btn.settings-btn-violet:not(:disabled):not(.e-disabled):hover {
    background-color: var(--st-genre-fill);
    border-color: var(--st-genre-fill);
    color: var(--st-on-genre);
}

:is(.settings-page, .settings-dialog) .e-btn.settings-btn.settings-btn-danger:not(:disabled):not(.e-disabled),
:is(.settings-page, .settings-dialog) .e-btn.settings-btn.settings-btn-danger:not(:disabled):not(.e-disabled):hover {
    background-color: var(--st-danger);
    border-color: var(--st-danger);
    color: var(--st-on-danger);
}

:is(.settings-page, .settings-dialog) .e-btn.settings-btn.settings-btn-danger-outline {
    background-color: transparent;
    border-color: var(--st-danger);
    color: var(--st-danger);
}

:is(.settings-page, .settings-dialog) .e-btn.settings-btn.settings-btn-danger-outline:hover {
    background-color: var(--st-danger);
    color: var(--st-on-danger);
}

:is(.settings-page, .settings-dialog) .e-input-group.e-outline:not(.e-disabled),
:is(.settings-page, .settings-dialog) .e-input-group.e-control-wrapper.e-outline:not(.e-disabled) {
    border-color: var(--st-control-line);
    background-color: var(--st-surface);
}

:is(.settings-page, .settings-dialog) .e-input-group.e-outline.e-input-focus,
:is(.settings-page, .settings-dialog) .e-input-group.e-control-wrapper.e-outline.e-input-focus {
    border-color: var(--st-accent);
    box-shadow: 0 0 0 3px var(--st-accent-soft);
}

:is(.settings-page, .settings-dialog) .e-input-group input.e-input { color: var(--st-text); }

:is(.settings-page, .settings-dialog) .e-checkbox-wrapper .e-frame,
:is(.settings-page, .settings-dialog) .e-css.e-checkbox-wrapper .e-frame { border-color: var(--st-control-line); }

:is(.settings-page, .settings-dialog) .e-checkbox-wrapper .e-frame.e-check,
:is(.settings-page, .settings-dialog) .e-css.e-checkbox-wrapper .e-frame.e-check {
    background-color: var(--st-accent-fill);
    border-color: var(--st-accent-fill);
    color: var(--st-on-accent);
}

:is(.settings-page, .settings-dialog) .e-checkbox-wrapper .e-label,
:is(.settings-page, .settings-dialog) .e-css.e-checkbox-wrapper .e-label { color: var(--st-text-2); }

/* A disabled control has to read as disabled. The fill rules above are deliberately
   scoped :not(:disabled) so they cannot paint one as live - Subscribe is gated on the
   terms checkbox, and a violet button that does nothing is worse than a grey one. */
:is(.settings-page, .settings-dialog) .e-btn.settings-btn:disabled,
:is(.settings-page, .settings-dialog) .e-btn.settings-btn.e-disabled {
    background-color: var(--st-surface-hover);
    border-color: var(--st-control-line);
    color: var(--st-text-3);
    cursor: not-allowed;
    opacity: 1;
}

.settings-inline-status { color: var(--st-accent-hover); }
.settings-inline-status-bad { color: var(--st-danger); }

/* ---- Creator settings ---------------------------------------------------
   Contrast, measured on the surface each pairing actually sits on:
     status-tile label   --st-text-2 on --st-surface-hover   6.30 light / 5.41 dark
     step body, bio      --st-text-2 on --st-surface         6.95 / 6.28
     persona meta        --st-text-3 on --st-surface         5.14 / 5.03
     pill in a tile      --st-accent-hover on accent-soft over --st-surface-hover
                                                             5.30 / 7.06
     done tick, hero     --st-on-accent on --st-accent-fill  5.42 / 8.35
     consent + payout edge --st-control-line on --st-surface 3.59 / 3.74
   --st-text-3 is deliberately NOT used on --st-surface-hover: it measures 4.33:1
   in dark, under AA. That is the same trap the disabled labels fell into.
   ------------------------------------------------------------------------- */

.settings-consent { background-color: var(--st-surface); border-color: var(--st-control-line); color: var(--st-text-2); }
.settings-consent a { color: var(--st-accent); }

.settings-hero-icon { background-color: var(--st-accent-fill); color: var(--st-on-accent); }

.settings-count, .settings-optional { color: var(--st-text-3); }
.settings-link { color: var(--st-accent); }

.status-tile { background-color: var(--st-surface-hover); border-color: var(--st-line); }
.status-tile-label { color: var(--st-text-2); }

.step { border-bottom-color: var(--st-line); }
.step-badge { background-color: var(--st-accent-soft); border-color: var(--st-accent); color: var(--st-accent-hover); }
.step-badge-done { background-color: var(--st-accent-fill); border-color: var(--st-accent-fill); color: var(--st-on-accent); }
.step-title { color: var(--st-text); }
.step-body { color: var(--st-text-2); }

.payout-section { background-color: var(--st-surface); border-color: var(--st-control-line); }
.payout-num { background-color: var(--st-accent-soft); border-color: var(--st-accent); color: var(--st-accent-hover); }
.payout-heading-title { color: var(--st-text); }

.retry-window { background-color: var(--st-surface-hover); border-color: var(--st-control-line); color: var(--st-text-2); }

.info-strip { background-color: var(--st-accent-soft); border-color: var(--st-accent); color: var(--st-accent-hover); }
.info-strip-warn { background-color: var(--st-warn-tint); border-color: var(--st-warn); color: var(--st-warn); }

.persona-row { border-bottom-color: var(--st-line); }
.persona-avatar { background-color: var(--st-surface-hover); border-color: var(--st-line); color: var(--st-text-2); }
.persona-name { color: var(--st-text); }
.persona-bio { color: var(--st-text-2); }
.persona-meta { color: var(--st-text-3); }

.persona-summary { color: var(--st-text-3); }
.persona-card { background-color: var(--st-surface); border-color: var(--st-line); box-shadow: var(--st-elev); }
.persona-card-bio { color: var(--st-text-2); }
.persona-card-site { color: var(--st-accent); }
.persona-card-site-none { color: var(--st-text-3); }

/* Dashed, and on --st-control-line rather than --st-line: it is the boundary of a file
   picker, which WCAG 1.4.11 puts at 3:1 like any other control. */
.persona-image-picker { border-color: var(--st-control-line); }
.persona-image-title { color: var(--st-text); }
.persona-image-input { color: var(--st-text-2); }

.crop-tool { background-color: var(--st-surface-hover); border-color: var(--st-line); }
.crop-canvas { background-color: var(--st-page); }
.crop-zoom input[type="range"] { accent-color: var(--st-accent-fill); }

/* ---- Upload ------------------------------------------------------------
   Twelve hard-coded colours came out of the inline block this replaces, none
   of which had a dark variant. Contrast, measured:
     dropzone label   --st-accent on --st-surface   5.42 light / 5.72 dark
     dashed edges     --st-control-line             3.59 / 3.74 (WCAG 1.4.11)
     held/target edge --st-accent                   5.42 / 5.72, well over 3
   ------------------------------------------------------------------------ */

.upload-box { border-color: var(--st-control-line); background-color: var(--st-surface); }
.upload-box:hover { background-color: var(--st-surface-hover); border-color: var(--st-accent); }
.upload-content { color: var(--st-text-2); }
.upload-content .upload-icon { color: var(--st-text-3); }

.cover-art-pool { border-color: var(--st-control-line); }

/* Only while something is held, so the drop targets are obvious mid-gesture and
   invisible otherwise - a page permanently outlined in dashed boxes reads as broken. */
.cover-art-pool-active { border-color: var(--st-accent); background-color: var(--st-accent-soft); }

.cover-art-chip { border-color: var(--st-line); background-color: var(--st-surface); }
.cover-art-chip:hover { border-color: var(--st-accent); }
.cover-art-chip-held { border-color: var(--st-accent); box-shadow: 0 0 0 3px var(--st-accent-soft); }
.cover-art-chip-name { color: var(--st-text); }
.cover-art-thumb { background-color: var(--st-surface-hover); }

.cover-art-dropzone { border-color: var(--st-accent); color: var(--st-accent); }
.cover-art-target { outline-color: var(--st-accent); background-color: var(--st-accent-soft); }
.cover-art-target .cover-art-dropzone { background-color: var(--st-accent-soft); }
.cover-art-hint-swatch { border-color: var(--st-accent); color: var(--st-accent); }

.apply-all { background-color: var(--st-accent-soft); border-color: var(--st-accent); }
.apply-all-label { color: var(--st-accent-hover); }
.title-source-warn { color: var(--st-warn); }
.inline-create-link { color: var(--st-accent); }
.inline-create-link:hover { color: var(--st-accent-hover); }
.review-outstanding { color: var(--st-warn); }

/* Below 992px each review row is a card, and every cell is titled by its
   data-label. Declared here because it is colour; the layout is in md_app.css. */
.review-table > tbody > tr > td::before { color: var(--st-text-3); }
.review-table > tbody > tr { border-color: var(--st-line); background-color: var(--st-surface); }

/* A row with something to fix. Bootstrap paints .table-warning a fixed #fff3cd through
   its cells, which is not a themed colour - on the dark surface it is a slab of yellow.
   The card takes the warn tint instead, and the cells are stripped of their own paint
   in md_app.css so this is the only thing showing. */
.review-table > tbody > tr.table-warning {
    background-color: var(--st-warn-tint);
    border-color: var(--st-warn);
}

.ai-declare { border-color: var(--st-line); }
.ai-declare-invalid { border-color: var(--st-danger); }
.ai-declare-or { color: var(--st-text-3); }
