:root { --lastfm-red:#d51007; --lastfm-red-hover:#e6130a; --lastfm-red-text:#ff5a50; --lastfm-red-glow:rgba(213,16,7,0.25); --lastfm-red-subtle:rgba(213,16,7,0.08); --on-accent:#ffffff; --spotify-green:#1DB954; --spotify-green-hover:#1ed760; --spotify-green-subtle:rgba(29,185,84,0.08); --spotify-green-border:rgba(29,185,84,0.25); --on-spotify:#0b0b0f; --spotify-green-text:#1DB954; --scrim:rgba(0,0,0,0.62); --bg-primary:#0b0b0f; --bg-secondary:#111116; --bg-tertiary:#18181f; --bg-elevated:#1e1e27; --border:#222230; --border-subtle:#1a1a25; --text-primary:#e8e6e3; --text-secondary:#b4b4bc; --text-tertiary:#92929c; --text-muted:#80808a; --success:#22c55e; --error:#ef4444; --warning:#eab308; --shadow-float:0 12px 32px rgba(0,0,0,0.35); --dur-fast:0.15s; --dur-base:0.2s; --dur-slow:0.35s; --ease-out-quart:cubic-bezier(0.25,1,0.5,1); --ease-out-expo:cubic-bezier(0.16,1,0.3,1); }
[data-theme="light"] { --lastfm-red-text:#c60f06; --spotify-green-text:#0f6b2f; --scrim:rgba(0,0,0,0.35); --bg-primary:#f5f5f7; --bg-secondary:#ffffff; --bg-tertiary:#eaeaed; --bg-elevated:#ffffff; --border:#d4d4d8; --border-subtle:#e4e4e7; --text-primary:#18181b; --text-secondary:#52525b; --text-tertiary:#5f5f68; --text-muted:#65656e; --lastfm-red-glow:rgba(213,16,7,0.15); --lastfm-red-subtle:rgba(213,16,7,0.06); --shadow-float:0 12px 32px rgba(0,0,0,0.12); }
/* Tokens: colors on the two lines above (tests/contrast.test.js reads them by line number), never hardcoded below.
   --on-accent / --on-spotify are the text colors on a red / green fill; --shadow-float is for floating lists only.
   --spotify-green-text is green as text or an icon (fills and borders keep --spotify-green); --scrim dims the page under a sheet. */
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Barlow','Open Sans','Lucida Grande','Helvetica Neue',Helvetica,Arial,sans-serif; background:var(--bg-primary); color:var(--text-primary); min-height:100vh; display:flex; flex-direction:column; align-items:center; -webkit-font-smoothing:antialiased; }
body::before { content:''; position:fixed; inset:0; pointer-events:none; opacity:0.03; background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); z-index:0; }
[data-theme="light"] body::before { display:none; }
/* One focus ring for every control (text inputs draw their own glow instead) */
button:focus-visible, a:focus-visible, input[type="range"]:focus-visible, [tabindex]:focus-visible { outline:2px solid var(--lastfm-red-text); outline-offset:2px; }
.theme-toggle { width:44px; height:44px; display:flex; align-items:center; justify-content:center; background:none; border:1.5px solid var(--border); border-radius:8px; color:var(--text-primary); opacity:0.7; font-size:16px; line-height:1; cursor:pointer; transition:opacity var(--dur-fast), border-color var(--dur-fast); }
.theme-toggle:hover { opacity:1; border-color:var(--text-primary); }
.container { width:100%; max-width:680px; padding:0 20px; position:relative; z-index:1; }
.setup-banner { background:var(--bg-secondary); border:1px solid var(--border); border-radius:8px; padding:16px 20px; margin-bottom:20px; font-size:13px; line-height:1.7; color:var(--text-secondary); }
.setup-banner strong { color:var(--warning); display:block; margin-bottom:4px; }
.setup-banner code { font-family:'JetBrains Mono',monospace; font-size:12px; color:var(--lastfm-red-text); background:var(--lastfm-red-subtle); padding:1px 6px; border-radius:8px; }
.setup-banner a { color:var(--lastfm-red-text); text-decoration:underline; text-underline-offset:2px; }
.controls { display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-bottom:28px; }
/* Text field: the username (44px tall, red glow on focus) */
.input-username { min-height:44px; padding:10px 14px; background:var(--bg-secondary); border:1px solid var(--border); border-radius:8px; color:var(--text-primary); font-size:14px; font-family:inherit; transition:border-color var(--dur-base); }
.input-username { flex:1 1 200px; }
.input-username:focus { outline:none; border-color:var(--lastfm-red); box-shadow:0 0 0 3px var(--lastfm-red-glow); }
.input-username::placeholder { color:var(--text-muted); }
.input-username:disabled { opacity:0.5; }
.btn { min-height:44px; padding:11px 20px; border:none; border-radius:8px; font-size:14px; font-weight:600; font-family:inherit; cursor:pointer; white-space:nowrap; transition:background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast), transform var(--dur-fast); }
.btn:active:not(:disabled) { transform:scale(0.98); }
.btn:disabled { opacity:0.4; cursor:not-allowed; }
.btn-spotify { background:var(--spotify-green); color:var(--on-spotify); }
.btn-spotify:hover:not(:disabled) { background:var(--spotify-green-hover); transform:translateY(-1px); }
.btn-primary { background:var(--lastfm-red); color:var(--on-accent); }
.btn-primary:hover:not(:disabled) { background:var(--lastfm-red-hover); transform:translateY(-1px); }
.btn-ghost { background:transparent; border:1px solid var(--border); color:var(--text-secondary); }
.btn-ghost:hover:not(:disabled) { border-color:var(--text-tertiary); color:var(--text-primary); }
.spotify-badge { display:inline-flex; align-items:center; gap:8px; padding:6px 10px; background:var(--spotify-green-subtle); border:1px solid var(--spotify-green-border); border-radius:8px; color:var(--spotify-green); font-size:13px; font-weight:600; white-space:nowrap; }
/* small inside the badge, but the ::before extends its hit area to 44px */
.btn-disconnect { position:relative; display:inline-flex; align-items:center; justify-content:center; width:20px; height:20px; background:none; border:none; border-radius:4px; cursor:pointer; color:var(--spotify-green); opacity:0.7; font-size:12px; line-height:1; }
.btn-disconnect::before { content:""; position:absolute; inset:-12px; }
.btn-disconnect:hover { opacity:1; }
.btn-save-playlist { min-height:44px; padding:0 16px; border:1.5px solid var(--spotify-green); border-radius:8px; background:transparent; color:var(--spotify-green); font-size:13px; font-weight:700; font-family:inherit; cursor:pointer; transition:background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast); white-space:nowrap; }
.btn-save-playlist:hover { background:var(--spotify-green-subtle); }
.btn-save-playlist:disabled { opacity:0.4; cursor:not-allowed; }
.btn-save-playlist.saved { border-color:var(--success); color:var(--success); cursor:default; }
.footer { margin-top:auto; padding:32px 20px; font-size:12px; color:var(--text-muted); text-align:center; }
.footer a { color:var(--text-tertiary); text-decoration:none; }
.footer a:hover { color:var(--lastfm-red-text); }
@media (max-width:520px) {
  .controls { flex-direction:column; }
  .input-username { flex:1 1 100%; }
  .btn { width:100%; text-align:center; }
  .spotify-badge { width:100%; text-align:center; }
}


/* Changelog overlay */
.overlay { position:fixed; top:0; left:0; right:0; bottom:0; background:var(--bg-primary); z-index:1000; display:flex; flex-direction:column; animation:overlayIn var(--dur-slow) var(--ease-out-expo); }
.overlay.leaving { animation:overlayOut var(--dur-base) var(--ease-out-quart) forwards; }
@keyframes overlayOut { to { opacity:0; transform:translateY(12px); } }
@keyframes overlayIn { from { opacity:0; transform:translateY(20px); } to { opacity:1; transform:translateY(0); } }
.overlay-header { display:flex; justify-content:space-between; align-items:center; padding:12px 20px; border-bottom:1px solid var(--border); flex-shrink:0; }
.overlay-title { font-size:16px; font-weight:700; color:var(--text-primary); }
.overlay-close { width:44px; height:44px; display:inline-flex; align-items:center; justify-content:center; background:none; border:none; font-size:20px; color:var(--text-tertiary); cursor:pointer; border-radius:8px; transition:background var(--dur-fast), color var(--dur-fast); }
.overlay-close:hover { background:var(--bg-secondary); color:var(--text-primary); }
.overlay-frame { flex:1; border:none; width:100%; }

.radio-btn.liked i { animation:heart-pop var(--dur-slow) var(--ease-out-expo); }
@keyframes heart-pop { from { transform:scale(0.6); } to { transform:scale(1); } }

/* Home view */
.app-header { display:flex; justify-content:space-between; align-items:center; gap:12px; padding:24px 0 20px; }
.app-brand { display:flex; align-items:center; gap:10px; min-width:0; }
.app-brand-icon { font-size:26px; color:var(--lastfm-red-text); flex-shrink:0; }
.app-brand h1 { font-size:18px; font-weight:800; letter-spacing:-0.3px; }
.app-header-right { display:flex; align-items:center; gap:10px; }
.status-dot { width:8px; height:8px; border-radius:50%; background:var(--spotify-green); display:inline-block; }
.radio-card { padding:28px; margin-bottom:32px; border-radius:16px; background:var(--bg-secondary); border:1px solid var(--border); }
.radio-card .controls { margin-bottom:0; align-items:stretch; }
.eyebrow { display:block; margin-bottom:12px; font-size:12px; font-weight:700; letter-spacing:1.5px; text-transform:uppercase; color:var(--lastfm-red-text); }
.home-headline { font-size:clamp(28px,6vw,44px); font-weight:800; letter-spacing:-1px; line-height:1.05; margin-bottom:12px; }
.home-meta { color:var(--text-secondary); font-size:14px; margin-bottom:20px; }
.btn-radio { flex:1 1 100%; min-height:56px; padding:14px 28px; border-radius:12px; font-size:18px; font-weight:700; display:inline-flex; align-items:center; justify-content:center; gap:8px; }
/* Station tabs: Library | Discover | Mix, with a sliding indicator, and one panel under them that holds the picked station's options and eases to its height */
.station-tabs { position:relative; display:flex; padding:4px; margin:0 0 10px; border-radius:12px; background:var(--bg-tertiary); border:1px solid var(--border); }
.tab-ind { position:absolute; top:4px; bottom:4px; left:4px; width:calc((100% - 8px) / 3); border-radius:8px; background:var(--lastfm-red-subtle); border:1.5px solid var(--lastfm-red); box-sizing:border-box; transform:translateX(calc(var(--i, 0) * 100%)); transition:transform var(--dur-slow) var(--ease-out-quart); }
.tab { position:relative; flex:1; min-width:0; min-height:44px; display:flex; align-items:center; justify-content:center; gap:8px; padding:0 8px; font-family:inherit; font-size:14px; font-weight:600; color:var(--text-secondary); background:none; border:none; border-radius:8px; cursor:pointer; transition:color var(--dur-fast); }
.tab:hover { color:var(--text-primary); }
.tab.active { color:var(--text-primary); font-weight:700; }
.tab > i { font-size:18px; color:var(--text-tertiary); flex-shrink:0; transition:color var(--dur-fast); }
.tab.active > i { color:var(--lastfm-red-text); }
.tab:focus-visible { outline:2px solid var(--lastfm-red-text); outline-offset:2px; }
.station-panel { margin:0 0 16px; overflow:hidden; border-radius:12px; background:var(--bg-tertiary); border:1px solid var(--border); transition:height var(--dur-slow) var(--ease-out-quart); }
.station-panel-in { display:flex; flex-direction:column; gap:16px; padding:16px; transition:opacity var(--dur-fast) var(--ease-out-quart); }
.station-panel-in.out { opacity:0; }
.station-blurb { margin:0; font-size:14px; line-height:1.45; color:var(--text-secondary); }
.radio-eyebrow-row { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:6px 12px; }
.radio-chip { display:inline-flex; align-items:center; gap:6px; padding:4px 10px; border-radius:999px; font-size:12px; font-weight:600; white-space:nowrap; min-width:0; max-width:170px; flex-shrink:0; color:var(--lastfm-red-text); background:var(--lastfm-red-subtle); }
.radio-chip i { font-size:12px; flex-shrink:0; }
.radio-chip span { overflow:hidden; text-overflow:ellipsis; }
.radio-chip.past { color:var(--text-secondary); background:var(--bg-tertiary); }
.radio-row .radio-chip { max-width:160px; }
.mix-balance { display:flex; flex-direction:column; gap:6px; }
.seg { display:flex; gap:4px; padding:4px; border-radius:12px; background:var(--bg-tertiary); border:1px solid var(--border); }
.seg-opt { flex:1; min-height:40px; padding:0 8px; font-family:inherit; font-size:13px; font-weight:600; color:var(--text-secondary); background:none; border:1.5px solid transparent; border-radius:8px; cursor:pointer; }
.seg-opt:hover { color:var(--text-primary); }
.seg-opt.active { color:var(--text-primary); background:var(--lastfm-red-subtle); border-color:var(--lastfm-red); }
/* Library options (only while Library is picked): How it plays and When, each a segmented control with a line of help */
.library-options { display:flex; flex-direction:column; gap:16px; }
.station-panel .seg { background:var(--bg-secondary); }
.lib-opt { display:flex; flex-direction:column; gap:6px; }
.lib-opt-label { font-size:12px; font-weight:700; letter-spacing:1.5px; text-transform:uppercase; color:var(--text-tertiary); }
.lib-opt-help { font-size:13px; line-height:1.4; color:var(--text-tertiary); }
.lib-when { display:flex; gap:8px; flex-wrap:wrap; }
.lib-when .seg { flex:1 1 220px; }
.lib-year { flex:1 0 120px; min-height:50px; padding:0 34px 0 14px; border-radius:12px; border:1.5px solid var(--lastfm-red); background-color:var(--bg-secondary); color:var(--text-primary); font-family:'JetBrains Mono',monospace; font-size:15px; font-weight:600; cursor:pointer; -webkit-appearance:none; appearance:none; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23606068' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right 12px center; }
.lib-year:focus-visible { outline:2px solid var(--lastfm-red-text); outline-offset:2px; }
.lib-year option { background:var(--bg-secondary); color:var(--text-primary); }
.radio-playing { display:flex; align-items:center; gap:10px; margin-bottom:14px; padding:12px 14px; border-radius:12px; background:var(--bg-tertiary); font-size:14px; color:var(--text-secondary); min-width:0; }
.radio-playing i { color:var(--lastfm-red-text); font-size:18px; flex-shrink:0; }
/* Equalizer: four bars that dance while it plays and freeze (mid-beat) when paused */
.eq { display:inline-flex; align-items:flex-end; gap:2px; width:18px; height:18px; flex-shrink:0; }
.eq i { display:block; width:3px; height:100%; border-radius:1px; background:var(--lastfm-red-text); transform-origin:bottom; transform:scaleY(0.5); animation:eq-bar 0.9s ease-in-out infinite alternate; }
.eq i:nth-child(2) { animation-duration:0.7s; animation-delay:-0.3s; }
.eq i:nth-child(3) { animation-duration:1.1s; animation-delay:-0.6s; }
.eq i:nth-child(4) { animation-duration:0.8s; animation-delay:-0.15s; }
.radio-playing.paused .eq i { animation-play-state:paused; }
.radio-playing strong { color:var(--text-primary); }
.radio-playing-text { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
@media (max-width:520px) { .radio-card { padding:20px; } }
/* First run: username, then Connect Spotify. The Home card with every option comes after connecting. */
#homeView .radio-card.landing { max-width:560px; margin-left:auto; margin-right:auto; }
.landing-steps { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:20px; }
.landing-step { display:flex; align-items:flex-start; gap:14px; position:relative; }
.landing-step:not(:last-child)::after { content:""; position:absolute; left:13.25px; top:34px; bottom:-14px; width:1.5px; background:var(--border); }
.step-badge { flex:0 0 28px; width:28px; height:28px; box-sizing:border-box; display:flex; align-items:center; justify-content:center; border-radius:50%; border:1.5px solid var(--border); color:var(--text-tertiary); font-size:13px; font-weight:700; }
.step-check { display:none; font-size:14px; }
.landing-step.active .step-badge { background:var(--lastfm-red); border-color:var(--lastfm-red); color:var(--on-accent); }
.landing-step.done .step-badge { background:var(--bg-elevated); border-color:var(--spotify-green); color:var(--spotify-green); }
.landing-step.done .step-num { display:none; }
.landing-step.done .step-check { display:inline; }
.step-body { flex:1; min-width:0; display:flex; flex-direction:column; gap:8px; }
.step-title { font-size:16px; font-weight:700; line-height:28px; color:var(--text-primary); }
.landing-step.locked .step-title { color:var(--text-secondary); }
.step-help { font-size:13px; line-height:1.4; color:var(--text-tertiary); }
.landing-input { flex:none; width:100%; min-height:48px; font-size:16px; }
.landing .btn-radio { flex:none; width:100%; }

@media (max-width:520px) { .app-brand h1 { font-size:16px; } }

/* Library radio view */
.radio-view { width:100%; padding-bottom:48px; animation:view-in var(--dur-slow) var(--ease-out-expo); }
.view-in { animation:view-in var(--dur-slow) var(--ease-out-expo); }
.radio-top { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:20px; }
.radio-title { text-align:right; font-size:13px; font-weight:700; letter-spacing:1.5px; text-transform:uppercase; color:var(--lastfm-red-text); }
.btn-text { background:none; border:none; color:var(--text-secondary); font-family:inherit; font-size:14px; cursor:pointer; display:inline-flex; align-items:center; gap:6px; padding:0; min-height:44px; }
.btn-text:hover { color:var(--text-primary); }
/* Now playing: a 224px card, cover on the left, text / progress / controls stacked on the right (phones: see the 520px query) */
.radio-now { display:grid; grid-template-columns:192px minmax(0,1fr); grid-template-rows:auto 1fr auto; column-gap:24px; height:224px; box-sizing:border-box; padding:16px; margin-bottom:28px; border-radius:16px; background:var(--bg-secondary); border:1px solid var(--border); }
.radio-hero { display:contents; }
.radio-art { grid-column:1; grid-row:1 / span 3; width:192px; height:192px; border-radius:12px; object-fit:cover; background:var(--bg-tertiary); }
.radio-hero-text { grid-column:2; grid-row:1; min-width:0; position:relative; }
.radio-hero-text .radio-heart-title { display:none; }  /* phones only: the heart sits next to the title (see the 520px query) */
.radio-hero-text .eyebrow { margin-bottom:0; }
.radio-track { font-size:28px; font-weight:800; line-height:1.1; letter-spacing:-0.6px; margin-top:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.radio-artist { font-size:15px; color:var(--text-secondary); margin-top:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hero-swap .radio-art { animation:art-in var(--dur-slow) var(--ease-out-expo); }
.hero-swap .radio-track { animation:hero-in var(--dur-slow) var(--ease-out-expo) 0.05s backwards; }
.hero-swap .radio-artist { animation:hero-in var(--dur-slow) var(--ease-out-expo) 0.1s backwards; }
/* Cover still loading (or no cover yet): the placeholder pulses; when the image arrives the loading class goes and art-in plays */
.radio-now .radio-art.loading, .radio-now .radio-art:not([src]) { animation:skeleton-pulse 1.2s ease-in-out infinite; }
/* No cover (yet) or it failed to load: Safari paints a broken-image icon for an <img> without a usable source, so swap the element's content for a transparent pixel and let the placeholder show */
.radio-now .radio-art:not([src]), .radio-now .radio-art.failed { content:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); }
.radio-progress { grid-column:2; grid-row:2; align-self:center; display:flex; align-items:center; gap:12px; }
.radio-progress span { font-family:'JetBrains Mono',monospace; font-size:12px; color:var(--text-tertiary); flex-shrink:0; }
.progress-track { flex:1; height:6px; background:var(--bg-tertiary); border-radius:999px; cursor:pointer; }
.progress-fill { height:100%; width:0; background:var(--lastfm-red); border-radius:999px; transition:width 0.25s linear; }
.radio-controls { grid-column:2; grid-row:3; display:flex; align-items:center; justify-content:flex-start; gap:8px; }
.radio-btn { background:none; border:none; color:var(--text-primary); font-size:22px; cursor:pointer; width:44px; height:44px; border-radius:8px; display:inline-flex; align-items:center; justify-content:center; transition:background var(--dur-fast), transform 0.1s; }
.radio-btn:hover { background:var(--bg-tertiary); }
.radio-btn:active { transform:scale(0.96); }
.radio-play { width:56px; height:56px; font-size:24px; background:var(--text-primary); color:var(--bg-primary); border-radius:999px; }
.radio-volume { display:none; align-items:center; gap:8px; margin-left:auto; color:var(--text-secondary); }
.radio-volume.sdk { display:flex; }
.radio-volume i { font-size:20px; }
.radio-volume.locked { color:var(--text-tertiary); cursor:not-allowed; }  /* a speaker Spotify does not let us set (Sonos): the reason is the title */
.radio-volume.locked .volume-range { opacity:0.4; pointer-events:none; }  /* the hover reaches the wrap, so its title shows */
.volume-range { -webkit-appearance:none; appearance:none; width:140px; height:44px; background:transparent; cursor:pointer; --vol:80%; }
.volume-range::-webkit-slider-runnable-track { height:4px; border-radius:2px; background:linear-gradient(to right, var(--text-secondary) var(--vol), var(--border) var(--vol)); }
.volume-range::-webkit-slider-thumb { -webkit-appearance:none; width:14px; height:14px; margin-top:-5px; border:none; border-radius:50%; background:var(--text-primary); }
.volume-range::-moz-range-track { height:4px; border-radius:2px; background:var(--border); }
.volume-range::-moz-range-progress { height:4px; border-radius:2px; background:var(--text-secondary); }
.volume-range::-moz-range-thumb { width:14px; height:14px; border:none; border-radius:50%; background:var(--text-primary); }
.radio-play:hover { background:var(--text-secondary); }
.radio-btn.liked { color:var(--lastfm-red-text); }
.radio-upnext-title { font-size:22px; font-weight:700; color:var(--text-primary); margin-bottom:10px; }
.radio-upnext { background:var(--bg-secondary); border:1px solid var(--border-subtle); border-radius:12px; overflow:hidden; }
.radio-row { display:flex; justify-content:space-between; align-items:center; gap:12px; padding:10px 16px; min-height:44px; box-sizing:border-box; }
.radio-row:not(:last-child) { border-bottom:1px solid var(--border-subtle); }
.radio-row-text { min-width:0; flex:1; }
.radio-row-art { width:40px; height:40px; border-radius:6px; object-fit:cover; background:var(--bg-tertiary); flex-shrink:0; }
.radio-row-title { font-size:14px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.radio-row-artist { font-size:12px; color:var(--text-tertiary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.radio-row-tuning .radio-row-title { color:var(--text-secondary); font-weight:500; }
.radio-row-in { animation:row-in var(--dur-slow) var(--ease-out-expo) backwards; }
.radio-row-tuning { animation:skeleton-pulse 1.2s ease-in-out infinite; }
.skeleton { background:var(--bg-tertiary); }
@media (max-width:520px) {
  .radio-now { display:flex; flex-direction:column; gap:16px; height:auto; padding:20px; }
  .radio-hero { display:flex; flex-direction:column; align-items:stretch; gap:16px; }
  .radio-art { width:100%; height:auto; aspect-ratio:1/1; }
  .radio-track { font-size:26px; white-space:normal; overflow-wrap:anywhere; }
  .radio-artist { white-space:normal; }
  .radio-progress { align-self:stretch; }  /* in the stacked card the row must span the width, or the bar collapses to 0 */
  .radio-controls { justify-content:center; gap:20px; }
  .radio-hero-text { padding-right:52px; }
  .radio-eyebrow-row { margin-right:-52px; }  /* the text column keeps 52px for the heart below; this row ignores it so the chip lines up with the right edge of the cover */
  .radio-eyebrow-row { min-height:24px; }  /* the chip is 24px tall: the row keeps that height without one, so the title (and the heart beside it) sits at the same place */
  .radio-hero-text .radio-heart-title { display:inline-flex; position:absolute; right:0; top:20px; }  /* centered on the first line of the title (24px row + 4px + half a 28px line - half the 44px button) */
  #radioHeart { display:none; }  /* the controls row keeps prev / play / next, centered */
}

@media (max-width:720px) { .radio-volume.sdk { display:none; } }


/* Reduced motion: everything collapses to static */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation:none !important; transition:none !important; scroll-behavior:auto !important; }
}

/* Radio: your play counts and artist bio */
.radio-info { margin-bottom:28px; animation:view-in var(--dur-slow) var(--ease-out-expo); }
.radio-stats { background:var(--bg-secondary); border:1px solid var(--border-subtle); border-radius:12px; padding:14px 16px; font-size:14px; line-height:1.5; color:var(--text-secondary); margin-bottom:16px; }
.radio-stats strong { color:var(--text-primary); font-weight:700; }
.radio-bio-name { font-size:18px; font-weight:800; letter-spacing:-0.3px; margin-bottom:8px; }
.radio-bio-text { font-size:14px; line-height:1.6; color:var(--text-secondary); display:-webkit-box; -webkit-line-clamp:4; line-clamp:4; -webkit-box-orient:vertical; overflow:hidden; margin-bottom:8px; }
.radio-bio-link { font-size:13px; color:var(--lastfm-red-text); text-decoration:none; }
.radio-bio-link:hover { text-decoration:underline; }
.radio-artist-photo { display:none; }  /* wide desktop only: see the min-width:1100px block */
.radio-info-body { min-width:0; flex:1; }

.radio-top-left { display:flex; align-items:center; gap:16px; }
.btn-text:disabled { opacity:0.4; cursor:not-allowed; }
.radio-row-play { cursor:pointer; transition:background var(--dur-fast); }
.radio-row-play:hover { background:var(--bg-tertiary); }
/* Library in Moments: the first song of the next moment gets a stronger line above it; the chips carry the dates */
.radio-row.moment-start { box-shadow:inset 0 1px 0 var(--text-muted); }
/* This moment: when it was, how many songs, Save this moment and Next moment */
.radio-moment { display:flex; flex-direction:column; gap:8px; margin-bottom:28px; padding:20px; border-radius:16px; background:var(--bg-secondary); border:1px solid var(--border); animation:view-in var(--dur-slow) var(--ease-out-expo); }
.radio-moment-label { font-size:20px; font-weight:700; letter-spacing:-0.3px; line-height:1.25; }
.radio-moment-meta { font-size:14px; line-height:1.5; color:var(--text-secondary); }
.radio-moment-actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:6px; }
.radio-moment-actions .btn-save-playlist, .radio-moment-actions .btn { display:inline-flex; align-items:center; gap:6px; }
@media (max-width:520px) { .radio-moment-actions > * { flex:1 1 100%; justify-content:center; } }

/* Wide desktop (1100px and up): a 1120px container. Home: the radio card, centered at 680px.
   Radio: player, moment and artist panels on the left (640px), Up next on the right as a panel of the same height
   (as many rows as fit). Narrower screens keep one column. */
@media (min-width:1100px) {
  .container { max-width:1120px; }
  #homeView .radio-card { max-width:680px; margin-left:auto; margin-right:auto; }
  .radio-cols { display:grid; grid-template-columns:640px minmax(0,1fr); grid-template-rows:minmax(476px,auto); gap:28px; align-items:stretch; }
  .radio-col-main { display:flex; flex-direction:column; gap:28px; min-width:0; }
  .radio-col-main .radio-now, .radio-col-main .radio-moment { margin-bottom:0; }
  .radio-col-main .radio-info { margin-bottom:0; padding:20px; border-radius:16px; background:var(--bg-secondary); border:1px solid var(--border); }
  .radio-info .radio-stats { padding:0; border:none; background:none; }
  .radio-col-main .radio-info { display:flex; gap:20px; align-items:flex-start; }
  .radio-artist-photo { position:relative; display:flex; align-items:center; justify-content:center; flex:0 0 148px; width:148px; height:148px; border-radius:12px; overflow:hidden; background:var(--bg-tertiary); color:var(--text-tertiary); font-size:48px; }
  .radio-artist-photo img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
  .radio-col-list { position:relative; min-height:0; }
  .radio-col-list > #radioUpNextBlock { position:absolute; inset:0; display:flex; flex-direction:column; margin:0; border-radius:16px; background:var(--bg-secondary); border:1px solid var(--border); overflow:hidden; }
  .radio-col-list .radio-upnext-title { flex:0 0 auto; display:flex; justify-content:space-between; align-items:center; gap:12px; min-height:64px; box-sizing:border-box; margin:0; padding:10px 16px 10px 20px; border-bottom:1px solid var(--border); }
  .radio-col-list .radio-upnext { flex:1; min-height:0; margin:0; border:none; border-radius:0; background:none; }
  .radio-col-list .radio-upnext { display:flex; flex-direction:column; }
  .radio-col-list .radio-row { padding-top:5px; padding-bottom:5px; }  /* tighter rows: 8 fit where 6 did (the 40px cover still gets 44px+ per row) */
  .radio-col-list .radio-upnext .radio-row { flex:0 0 auto; }  /* every row has its natural height (51px with the divider), as in the phone list; radioUpNextRows() shows as many as fit */
}

/* Toasts: errors and warnings, bottom center, one at a time (showStatus() in ui.js). Inverted like the play button; errors take the accent fill. */
.toast-host { position:fixed; left:0; right:0; bottom:calc(16px + env(safe-area-inset-bottom, 0px)); z-index:1100; display:flex; justify-content:center; padding:0 16px; pointer-events:none; }
.toast { pointer-events:auto; display:flex; align-items:center; gap:10px; box-sizing:border-box; max-width:min(520px, 100%); padding:10px 6px 10px 16px; border-radius:12px; background:var(--text-primary); color:var(--bg-primary); box-shadow:var(--shadow-float); font-size:14px; line-height:1.4; animation:toast-in 0.28s var(--ease-out-quart); }
.toast.error { background:var(--lastfm-red); color:var(--on-accent); }
.toast.leaving { animation:toast-out var(--dur-fast) var(--ease-out-quart) forwards; }
.toast > i { font-size:20px; flex-shrink:0; }
.toast-text { min-width:0; overflow-wrap:anywhere; }
.toast-close { flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; width:44px; height:44px; margin:-10px 0; background:none; border:none; border-radius:8px; color:inherit; font-size:18px; cursor:pointer; opacity:0.75; }
.toast-close:hover { opacity:1; }
.toast-close:focus-visible { outline-color:currentColor; }  /* the global ring is red: not visible on the red error fill */
@keyframes toast-in { from { opacity:0; transform:translateY(24px); } to { opacity:1; transform:translateY(0); } }
@keyframes toast-out { to { opacity:0; transform:translateY(12px); } }

/* Play on: the Playing on bar (radio view, under the player), the Plays on row (Home, above Start), the device list
   (a dropdown under the Change that opened it; a bottom sheet over a scrim on phones) and the phone strip (Home, phones only) */
.connect-anchor { position:relative; }
.connect-bar { display:flex; align-items:center; gap:12px; min-height:60px; box-sizing:border-box; margin:-12px 0 28px; padding:8px 8px 8px 18px; border-radius:12px; background:var(--bg-secondary); border:1px solid var(--border); }
.connect-bar-icon, .connect-home-icon, .connect-now-icon { font-size:20px; flex-shrink:0; }
.connect-bar-icon, .connect-now-icon { color:var(--spotify-green-text); }
.connect-bar-text { flex:1; min-width:0; font-size:14px; line-height:1.35; color:var(--text-secondary); overflow-wrap:anywhere; }
.connect-bar-name { color:var(--text-primary); font-weight:700; }
.connect-bar.checking .connect-bar-icon { color:var(--text-tertiary); }
.connect-bar.checking .connect-bar-label { display:none; }
.connect-bar.checking .connect-bar-name { color:var(--text-secondary); font-weight:500; }
.connect-change { flex-shrink:0; display:inline-flex; align-items:center; gap:6px; min-height:44px; padding:0 12px 0 16px; border-radius:8px; border:1.5px solid var(--spotify-green); background:none; color:var(--spotify-green-text); font-family:inherit; font-size:13px; font-weight:700; cursor:pointer; white-space:nowrap; transition:background var(--dur-fast); }
.connect-change:hover { background:var(--spotify-green-subtle); }
.connect-change i { font-size:14px; transition:transform var(--dur-base) var(--ease-out-quart); }
.connect-change[aria-expanded="true"] i { transform:rotate(180deg); }
.connect-home { flex:1 1 100%; display:flex; align-items:center; gap:10px; min-height:52px; min-width:0; box-sizing:border-box; padding:4px 4px 4px 14px; border-radius:12px; border:1px solid var(--border); }
.connect-home-icon { color:var(--text-secondary); }
.connect-home-text { flex:1; min-width:0; font-size:14px; line-height:1.35; color:var(--text-secondary); overflow-wrap:anywhere; }
.connect-home-text strong { color:var(--text-primary); }
.connect-list { position:absolute; top:calc(100% + 6px); right:0; z-index:20; width:360px; max-width:calc(100vw - 32px); max-height:70vh; overflow-y:auto; box-sizing:border-box; padding:8px; border-radius:12px; background:var(--bg-elevated); border:1px solid var(--border); box-shadow:var(--shadow-float); display:flex; flex-direction:column; gap:2px; text-align:left; transform-origin:top right; animation:pop-in var(--dur-base) var(--ease-out-quart); }
.connect-list > * { flex-shrink:0; }
.connect-list[hidden], .connect-scrim[hidden], .connect-now[hidden], .connect-now-open[hidden] { display:none; }
.connect-grab { display:none; }
.connect-head { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:0 0 6px 12px; }
.connect-title { font-size:12px; font-weight:700; letter-spacing:1.5px; text-transform:uppercase; color:var(--text-tertiary); }
.connect-refresh { display:inline-flex; align-items:center; gap:6px; min-height:44px; padding:0 12px; border-radius:8px; border:1px solid var(--border); background:none; color:var(--text-secondary); font-family:inherit; font-size:13px; font-weight:600; cursor:pointer; transition:color var(--dur-fast), border-color var(--dur-fast); }
.connect-refresh:hover { color:var(--text-primary); border-color:var(--text-tertiary); }
.connect-refresh i { font-size:14px; }
.connect-refresh.busy i { animation:connect-spin 0.8s linear infinite; }
.connect-rows { display:flex; flex-direction:column; gap:2px; }
.connect-row { display:flex; align-items:center; gap:12px; width:100%; min-height:56px; box-sizing:border-box; padding:8px 12px; border-radius:8px; border:none; background:none; color:var(--text-secondary); font-family:inherit; text-align:left; cursor:pointer; transition:background var(--dur-fast), opacity var(--dur-fast); }
.connect-row:hover:not(:disabled), .connect-row.current { background:var(--bg-tertiary); }
.connect-row.busy { opacity:0.6; }
.connect-row-icon { font-size:20px; flex-shrink:0; }
.connect-row-text { display:flex; flex-direction:column; gap:2px; flex:1; min-width:0; }
.connect-row-name { font-size:14px; font-weight:600; color:var(--text-primary); overflow-wrap:anywhere; }
.connect-row-line { font-size:12px; line-height:1.35; color:var(--text-tertiary); }
.connect-row.current .connect-row-icon, .connect-row.current .connect-row-name, .connect-row-check { color:var(--spotify-green-text); }
.connect-row.current .connect-row-name { font-weight:700; }
.connect-row-check { font-size:18px; flex-shrink:0; }
.connect-row:disabled { cursor:default; }
.connect-row:disabled .connect-row-icon { color:var(--text-tertiary); }
.connect-row:disabled .connect-row-name { color:var(--text-secondary); }
.connect-sep { height:1px; margin:6px 8px; background:var(--border); }
.connect-group { padding:4px 12px 2px; font-size:12px; font-weight:700; letter-spacing:1.5px; text-transform:uppercase; color:var(--text-tertiary); }
.connect-empty { padding:8px 12px; font-size:14px; line-height:1.45; color:var(--text-secondary); }
.connect-hint { padding:8px 12px 4px; font-size:12px; line-height:1.45; color:var(--text-tertiary); }
.connect-scrim { position:fixed; inset:0; z-index:1050; background:var(--scrim); animation:fade-in var(--dur-base) var(--ease-out-quart); }
body.connect-locked { overflow:hidden; }
.connect-now { display:flex; align-items:center; gap:10px; min-width:0; margin-bottom:14px; padding:6px 4px 6px 14px; border-radius:12px; background:var(--bg-tertiary); }
.connect-now-text { display:flex; flex-direction:column; gap:2px; flex:1; min-width:0; }
.connect-now-line, .connect-now-track { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.connect-now-line { font-size:14px; color:var(--text-secondary); }
.connect-now-line strong { color:var(--text-primary); }
.connect-now-track { font-size:13px; color:var(--text-tertiary); }
.connect-now-btn { flex-shrink:0; font-size:20px; }
.connect-now-btn:hover { background:var(--bg-elevated); }
.connect-now-open { padding:0 14px; }  /* the hand-off: this phone opens the radio that plays (no caret: it is not a menu) */
@media (max-width:720px) {
  .connect-list.sheet { position:fixed; top:auto; left:0; right:0; bottom:0; z-index:1060; width:auto; max-width:none; max-height:85vh; padding:8px 12px calc(24px + env(safe-area-inset-bottom, 0px)); border:none; border-top:1px solid var(--border); border-radius:20px 20px 0 0; transform-origin:bottom center; animation:sheet-in var(--dur-slow) var(--ease-out-expo); }
  .connect-list.sheet .connect-grab { display:block; align-self:center; width:36px; height:4px; margin:2px 0 10px; border-radius:2px; background:var(--text-muted); }
  .connect-list.sheet .connect-head { padding:0 4px 10px 12px; }
  .connect-list.sheet .connect-title { font-size:18px; font-weight:800; letter-spacing:-0.3px; text-transform:none; color:var(--text-primary); }
  .connect-list.sheet .connect-row { min-height:60px; gap:14px; border-radius:10px; }
  .connect-list.sheet .connect-row-name { font-size:15px; }
  .connect-list.sheet .connect-hint { padding-top:10px; }
}
@media (max-width:520px) {
  .connect-bar { min-height:64px; padding-left:16px; }
  .connect-bar-text { display:flex; flex-direction:column; gap:2px; }
  .connect-bar-label { font-size:12px; color:var(--text-tertiary); }
  .connect-bar-name { font-size:15px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .connect-bar-kind { display:none; }
}
@media (min-width:1100px) { .radio-col-main .connect-bar { margin:0; } }  /* the column gap (28px) spaces it */

/* Motion keyframes: opacity and transform only; the reduced-motion block above switches them all off */
@keyframes fade-in { from { opacity:0; } to { opacity:1; } }
@keyframes pop-in { from { opacity:0; transform:translateY(-8px) scale(0.96); } to { opacity:1; transform:none; } }
@keyframes view-in { from { opacity:0; transform:translateY(16px); } to { opacity:1; transform:none; } }
@keyframes hero-in { from { opacity:0; transform:translateY(12px); } to { opacity:1; transform:none; } }
@keyframes art-in { from { opacity:0; transform:scale(0.94); } to { opacity:1; transform:none; } }
@keyframes row-in { from { opacity:0; transform:translateY(14px); } to { opacity:1; transform:none; } }
@keyframes eq-bar { from { transform:scaleY(0.25); } to { transform:scaleY(1); } }
@keyframes skeleton-pulse { 0%, 100% { opacity:1; } 50% { opacity:0.5; } }
@keyframes sheet-in { from { transform:translateY(100%); } to { transform:none; } }
@keyframes connect-spin { to { transform:rotate(360deg); } }
