mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
feat(themes): community Theme Store + semantic-token refactor (#1009)
* feat(themes): add semantic tokens for the theme-store contract (B0 P1) Additive: define --highlight, --accent-2, --bg-deep, --bg-elevated and --text-on-accent on the :root base as --ctp-* mappings. They resolve per-theme automatically and nothing consumes them yet (zero behaviour change) — groundwork for replacing direct --ctp-* use in components. * refactor(themes): components consume semantic tokens, not --ctp-* (B0 P2) Replace every direct --ctp-* reference in component/layout/track CSS and TSX inline styles with the readable semantic token (--bg-app, --accent, --highlight, --text-on-accent, …). --ctp-* now survives only as the Catppuccin palette layer the base maps from, and as the deliberate categorical rainbow in Composers/Genres/artistsHelpers (left untouched). This is the readable contract surface for the community theme store. Divergences (theme set a semantic var != its --ctp- source) are corrections — the element now uses the theme's real semantic colour. * feat(themes): add player-bar title/artist color tokens New optional --player-title / --player-artist, defaulting to --text-primary / --text-secondary so nothing changes unless a theme overrides them. Lets a theme give the now-playing readout its own colour as a plain token. * refactor(themes): token-only theme library (flatten, whitelist, one file per theme) Turn every built-in theme into a single self-contained [data-theme] var block of semantic whitelist tokens (plus the internal --ctp-* palette layer): - Flatten all themes: drop structural override rules, @keyframes, and global-token overrides (radius / shadow-elevation / transition / spacing / font / focus-ring). Signature player-bar readout colours are preserved via the new --player-title / --player-artist tokens. - Normalize the var blocks to the semantic whitelist: drop the alternate token vocabulary (nav-active / scrollbar / bg-input / success / border-default / ...); rename --success -> --positive and --border-default -> --border where no whitelist equivalent was set. Migrate the few components that read those tokens to the whitelist equivalents. - Split multi-theme files so each theme ships as its own file, making the built-in set 1:1 with the per-theme store packaging. Kept as-is (built-in, not flattened): the two colour-blind-safe accessibility themes, plus the two curated core skins. * chore(themes): remove seven themes retired after the token refactor These themes leaned on heavy structural overrides and were dropped rather than flattened. Full removal each: the CSS file(s), the index.css import, the Theme type union, and the ThemePicker entry. * feat(themes): granular tokens — track lists Wire track rows to per-region tokens: row hover (--row-hover), the now-playing row + indicator (--row-playing-bg / --row-playing-text), track title/artist/ number/duration text, column-header text, row dividers, and the resize-handle active colour. Covers the desktop tracklist, the shared song-row (Tracks hub / search), and the mobile tracklist. Drop a baked border fallback. Visual no-op. * feat(themes): granular tokens — cards Wire album and artist cards to per-region tokens (--card-hover-border, --card-title, --card-subtitle, --card-placeholder-bg). Visual no-op. * fix(themes): drop undefined/baked colour aliases Replace the undefined --bg-surface (resolved to nothing — broken placeholder backgrounds and filter input) with --card-placeholder-bg / --input-bg, and the baked-hex aliases --color-error / --color-warning with --danger / --warning so themes can actually recolour them. * feat(themes): Spectrum demo theme + trim unused cascade tokens Add a loud built-in demo theme that gives each region its own hue (sidebar green, player pink, lists cyan, cards gold, menus red, controls blue) so the per-region granularity is obvious when you switch to it. Drop two unused cascade tokens (--sidebar-text-active, --row-active-bg) and the unused on-media block (those media surfaces stay static by design). * style(themes): make Spectrum demo brutally loud Full-saturation neon per region (toxic green sidebar, magenta player, cyan lists, acid-yellow cards, blood-red menus, electric-blue controls, purple scrollbar) so the per-region separation is unmistakable. The earlier soft tints were too subtle to read. * feat(themes): name the granular demo theme Braindead * feat(themes): granular per-region tokens — cascade layer + sidebar Add an optional per-region token layer (semantic-cascade.css) so a theme can recolour individual regions — sidebar hover, player controls, list rows, menus, inputs, on-media surfaces — independently of the global tokens. Every token defaults to its base token (or a media-safe literal), so this is a visual no-op until a theme overrides one; it only adds control points. Wire the sidebar region as the first consumer and drop the baked grey fallbacks (--bg-tertiary, etc.) that no theme could reach. * feat(themes): granular tokens — controls, menus, scrollbar Wire inputs, buttons, sliders, the custom-select, context menus, submenus and modals to per-region tokens, and tokenise the scrollbar. Complete B0 by dropping the last direct --ctp-* references in the input/button/progress/ scrollbar utility CSS. Fix three undefined-token bugs that fell back to nothing (so no theme could reach them): --surface-2 (context-menu hover had no highlight), --bg-surface (submenu create-input had no background), and the baked grey fallbacks in the custom-select. Every other new token defaults to today's value — a visual no-op that only adds override points. * feat(themes): granular tokens — player bar Wire the desktop player bar's transport controls, time toggle, and overflow menu to per-region tokens (--player-control, --player-time-toggle-*, etc.). Fix the undefined --surface-hover/--surface-active grey fallbacks on the time toggle. Visual no-op; defaults match today's values. * chore(themes): remove empty theme stub files Six theme CSS files were reduced to comment-only stubs by the flatten sweep but their files and @import lines remained. Five are empty structural companions of now-flattened themes (morpheus, p-dvd, aero-glass, luna-teal) and two are orphans of cut themes (order-of-the-phoenix, pandora). Removed the files and their imports. * feat(themes): runtime injection foundation for the theme store Plumbing for installed community themes ahead of the in-app store UI, nothing user-visible yet: - installedThemesStore: persisted (localStorage) record of installed community themes incl. their CSS text, so an active community theme is available synchronously at startup (no flash, fully offline). - themeInjection: reconcile <head> <style data-installed-theme> elements with the store; lightweight defense-in-depth sanitize on top of CI. - themeRegistry: jsDelivr registry client with a 12h localStorage cache and stale-on-error fallback. - App: inject installed themes before applying data-theme, in both webviews. - themeStore: widen the Theme type to accept dynamic installed ids. * feat(themes): dedicated Themes settings tab Move theme selection and the day/night scheduler out of Appearance into a new dedicated Themes tab — the future home of the community Theme Store. Appearance keeps grid columns, visual options, UI scale, font and seekbar. - ThemesTab: theme picker + scheduler (relocated verbatim). - AppearanceTab: drop the two relocated sections + now-unused imports. - Register the tab in settingsTabs (Tab union, resolveTab, search index) and Settings (tab bar, render, label map). - i18n: settings.tabThemes in all 9 locales. * feat(themes): community Theme Store browse + install Add the Theme Store section to the Themes tab: - Fetch the jsDelivr registry (12h cache, stale-on-error fallback). - Search by name/author/description + filter by light/dark + refresh. - Per-row CDN thumbnail, name, author, description and actions: Install / Apply / Update / Uninstall. Installing fetches the CSS, persists it (localStorage) and the runtime injection applies it; uninstalling the active theme falls back to the matching core. - Rating slot left reserved (deferred). - i18n: themeStore* keys in all 9 locales. * feat(themes): slim bundle to fixed cores + flat Themes tab Remove the 86 store palettes (incl. braindead) from the app bundle — the CSS files, their index.css imports, the Theme union and the picker data — leaving only the six fixed cores (Catppuccin Mocha/Latte, Kanagawa Wave, Stark HUD, Vision Dark/Navy). Everything else installs from the store. Themes tab is rebuilt flat (no collapsible accordions): - "Your Themes": one card grid of the fixed cores + installed community themes; click to apply, uninstall on community ones (active theme falls back to the matching core). Catppuccin prefix on Mocha/Latte; a CVD-safe pill on the colour-blind-safe Vision themes. - Scheduler day/night options include installed themes. - Theme Store: alphabetical order, thumbnail lightbox, and a submit hint above the search linking to the themes repository. - Nav order: Servers, Library, Audio, Themes, Appearance, Lyrics, … - ThemePicker accordion removed; fixed-theme data moved to fixedThemes.ts. - i18n for all new strings across 9 locales. * feat(themes): reset removed-from-bundle themes to a bundled fallback After slimming the bundle to the six fixed core themes, a profile upgraded from an older build may have an active or scheduler theme that is now store-only and not installed — it has no [data-theme] block and would render as unstyled :root. Reset any theme/themeDay/themeNight that is neither bundled nor installed to a bundled fallback: Mocha for the main + night slots, Latte for the day slot. Runs synchronously in runPreReactBootstrap, rewriting the persisted selection in localStorage before React mounts (no flash; Zustand rehydrates after first paint). No auto-install and no network — the fallback is always a bundled theme, so it works offline. * feat(themes): floating back-to-top button on the Themes tab The Themes tab can get long (theme grid + scheduler + full store list), so add a floating back-to-top affordance that appears once the page is scrolled and smooth-scrolls to the top. It is portalled into the route host and positioned absolute against it — the main scroll viewport sets contain: paint, which would otherwise make position: fixed resolve against the scrolling box and drift with the content. Reusable component (scroll viewport id + threshold props); i18n common.backToTop added in all nine locales. * feat(themes): accessibility + state polish for the Theme Store - Reuse the shared CoverLightbox for the thumbnail preview instead of a second inline dialog — gains a visible close button and a focus-managed, portalled dialog, and drops duplicated markup. - Theme cards expose aria-pressed so assistive tech announces the selected theme, not just the visual check. - Transient store messages get live-region roles (loading/empty/install failure = status, fetch error = alert). - Thumbnails degrade gracefully when offline/missing (hide the broken-image glyph; the thumbnail button no longer stretches with the row, so its background can't show as letterbox bars). * feat(themes): larger store-row thumbnails (120x75 -> 200x125) The list previews were too small to make a theme out; bump the display size (same 1.6 aspect). Thumbnails are now served at 720x450, so the larger display stays crisp. * fix(themes): bust thumbnail cache on registry change jsDelivr serves theme thumbnails with a 7-day max-age, so when a thumbnail is updated the webview keeps showing its cached old image (the path is unchanged). Append the registry's generatedAt as a cache-busting query to the thumbnail URLs (list + lightbox); it changes on every themes push, so a registry refresh makes the webview re-fetch and reflect the current CDN image instead of a stale one. * docs(themes): changelog + credits for the Theme Store Add the 1.48.0 "Themes — community Theme Store" changelog entry (PR #1009) and the matching line in the Psychotoxical credits. * fix(themes): address PR review (uninstall hygiene, validation, polish) Uninstall/scheduler & validation: - uninstallTheme() repairs every selection slot (active + day + night), not just the manual one, and is shared by both uninstall buttons (dedup). - Validate theme CSS at install time and skip persisting CSS that won't inject (no more "installed/active but renders nothing" with no feedback). - Harden the runtime validator: exactly one rule, scoped exactly to the theme's [data-theme='<id>'] selector (no unscoped/foreign selectors), no at-rules, url() only data:, no expression()/javascript:, size-capped. Tokens & polish: - Fix three dangling undefined tokens (--surface-2 x2, --bg-surface). - Finish the warning/success token sweep (--warning / --positive, themeable). - Apply the active theme synchronously before React mounts (no first-frame flash) and inject installed themes up front. - One-time, dismissible notice when the slim-bundle migration reset a theme. - Update badge uses semver, not string inequality. - Offline/stale indicator in the store; cross-window theme sync; drop the now dead REMOVED_THEME_REMAP and Card.mode field. Tests: themeInjection (validator + sync), themeRegistry (cache/force/stale/ malformed), uninstallTheme (slot repair), migration notice. i18n in all nine locales. Full suite green (1755 tests). * test(bootstrap): cover startup theme apply + cross-window sync The review fixes added applyThemeAtStartup / installCrossWindowThemeSync to bootstrap.ts (a hot-path file) without tests, dropping its coverage to 68.3% and failing the frontend hot-path coverage gate (>=70%). Add unit tests for both (and the no-op / malformed-storage paths); bootstrap.ts is back to ~98%.
This commit is contained in:
@@ -11,14 +11,14 @@
|
||||
}
|
||||
|
||||
.album-card:hover {
|
||||
box-shadow: inset 0 0 0 1px var(--border), var(--shadow-md);
|
||||
box-shadow: inset 0 0 0 1px var(--card-hover-border), var(--shadow-md);
|
||||
}
|
||||
|
||||
.album-card-cover {
|
||||
position: relative;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
background: var(--bg-hover);
|
||||
background: var(--card-placeholder-bg);
|
||||
contain: paint;
|
||||
isolation: isolate;
|
||||
transform: translateZ(0);
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
}
|
||||
|
||||
.album-card-more:hover {
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--shadow-sm);
|
||||
@@ -199,7 +199,7 @@
|
||||
.album-card-offline-badge {
|
||||
flex-shrink: 0;
|
||||
background: color-mix(in srgb, var(--accent) 85%, transparent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 3px 4px;
|
||||
display: flex;
|
||||
@@ -210,7 +210,7 @@
|
||||
.album-card-new-badge {
|
||||
flex-shrink: 0;
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 42%, transparent);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 3px 6px;
|
||||
@@ -243,7 +243,7 @@
|
||||
|
||||
.album-card-details-btn {
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
border: none;
|
||||
padding: 8px 20px;
|
||||
border-radius: var(--radius-full);
|
||||
@@ -386,6 +386,6 @@
|
||||
.album-card-select-check--on {
|
||||
background: var(--accent);
|
||||
border-color: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.06));
|
||||
border-bottom: 1px solid var(--row-divider);
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast);
|
||||
border-radius: 6px;
|
||||
@@ -20,11 +20,11 @@
|
||||
}
|
||||
|
||||
.tracklist-mobile-row.active .tracklist-mobile-title {
|
||||
color: var(--accent);
|
||||
color: var(--row-playing-text);
|
||||
}
|
||||
|
||||
.tracklist-mobile-row.context-active {
|
||||
background: var(--bg-hover);
|
||||
background: var(--row-hover);
|
||||
}
|
||||
|
||||
.tracklist-mobile-main {
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
.tracklist-mobile-num {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
color: var(--row-text-muted);
|
||||
min-width: 18px;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
@@ -54,7 +54,7 @@
|
||||
.tracklist-mobile-title {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
color: var(--row-text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
.tracklist-mobile-duration {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
color: var(--row-text-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
transition: color 0.12s, background 0.12s;
|
||||
}
|
||||
.alphabet-filter-btn:hover { background: var(--bg-hover); }
|
||||
.alphabet-filter-btn.active { background: var(--accent); color: var(--ctp-crust); }
|
||||
.alphabet-filter-btn.active { background: var(--accent); color: var(--text-on-accent); }
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
|
||||
.artist-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
border-color: var(--border);
|
||||
border-color: var(--card-hover-border);
|
||||
}
|
||||
|
||||
.artist-card-avatar {
|
||||
position: relative;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
background: var(--bg-hover);
|
||||
background: var(--card-placeholder-bg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -78,7 +78,7 @@
|
||||
.artist-card-name {
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
color: var(--text-primary);
|
||||
color: var(--card-title);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -86,6 +86,6 @@
|
||||
|
||||
.artist-card-meta {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
color: var(--card-subtitle);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
.artist-card-select-check--on {
|
||||
background: var(--accent);
|
||||
border-color: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
.artist-card--selectable {
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
}
|
||||
.artists-alpha-btn:not(.artists-alpha-btn--active):hover {
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 25%, transparent);
|
||||
}
|
||||
.artists-alpha-btn--active {
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.alphabet-filter-btn.empty { opacity: 0.28; pointer-events: none; }
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/* ─── Back to top button ─── */
|
||||
@keyframes back-to-top-in {
|
||||
from { opacity: 0; transform: translateY(8px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* Pinned to the bottom-right of the content area (its portal host
|
||||
`.app-shell-route-host` spans the region between sidebar/queue and above the
|
||||
player bar). Absolute against that host so it never drifts with the scrolling
|
||||
content — the scroll viewport's `contain: paint` rules out `position: fixed`
|
||||
here. */
|
||||
.back-to-top-btn {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
right: 20px;
|
||||
z-index: 50;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
|
||||
background: var(--bg-elevated);
|
||||
color: var(--accent);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35);
|
||||
animation: back-to-top-in 0.25s ease both;
|
||||
transition: background 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.back-to-top-btn:hover {
|
||||
background: var(--bg-hover);
|
||||
border-color: var(--accent);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.back-to-top-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.back-to-top-btn:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
.context-menu-item--submenu.active,
|
||||
.context-menu-item--submenu:hover {
|
||||
background: var(--surface-2);
|
||||
color: var(--accent);
|
||||
background: var(--menu-item-hover);
|
||||
color: var(--menu-item-active-text);
|
||||
}
|
||||
|
||||
.context-submenu {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
background: var(--bg-card);
|
||||
background: var(--menu-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-1) 0;
|
||||
@@ -45,7 +45,7 @@
|
||||
.context-submenu-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: var(--bg-surface);
|
||||
background: var(--input-bg);
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--text-primary);
|
||||
@@ -63,7 +63,7 @@
|
||||
background: var(--accent);
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
padding: 4px 6px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
background: var(--bg-card);
|
||||
background: var(--menu-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-1) 0;
|
||||
@@ -24,14 +24,14 @@
|
||||
}
|
||||
|
||||
.context-menu-item:hover {
|
||||
background: var(--surface-2);
|
||||
color: var(--accent);
|
||||
background: var(--menu-item-hover);
|
||||
color: var(--menu-item-active-text);
|
||||
}
|
||||
|
||||
.context-menu-item.context-menu-keyboard-active,
|
||||
.context-menu-rating-row.context-menu-keyboard-active {
|
||||
background: var(--surface-2);
|
||||
color: var(--accent);
|
||||
background: var(--menu-item-hover);
|
||||
color: var(--menu-item-active-text);
|
||||
}
|
||||
|
||||
.context-menu-item.context-menu-keyboard-active {
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
|
||||
.context-menu-rating-row.context-menu-keyboard-active {
|
||||
background: color-mix(in srgb, var(--accent) 18%, var(--surface-2));
|
||||
background: color-mix(in srgb, var(--accent) 18%, var(--menu-item-hover));
|
||||
box-shadow: inset 3px 0 0 var(--accent), inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
.context-menu-divider {
|
||||
height: 1px;
|
||||
background: var(--border-subtle);
|
||||
background: var(--menu-divider);
|
||||
margin: var(--space-1) 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
.album-detail-badge {
|
||||
margin-bottom: 0.5rem;
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
/* Konsistenz mit `.album-card-new-badge`: eckig, nicht pill. */
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
@@ -281,14 +281,14 @@
|
||||
.download-progress-bar {
|
||||
flex: 1;
|
||||
height: 4px;
|
||||
background: var(--surface-2);
|
||||
background: var(--bg-elevated, var(--bg-card));
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.download-progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--ctp-mauve), var(--ctp-blue));
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
border-radius: 2px;
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: var(--bg-input);
|
||||
border: 1px solid var(--border-dropdown, var(--border));
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-dropdown);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--text-primary);
|
||||
font-size: 0.875rem;
|
||||
@@ -17,7 +17,7 @@
|
||||
}
|
||||
.custom-select-trigger:hover {
|
||||
border-color: var(--accent);
|
||||
background: var(--bg-hover);
|
||||
background: var(--button-hover);
|
||||
}
|
||||
.custom-select-label {
|
||||
flex: 1;
|
||||
@@ -34,10 +34,10 @@
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.custom-select-dropdown {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-dropdown, var(--border));
|
||||
background: var(--menu-bg);
|
||||
border: 1px solid var(--border-dropdown);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: 0 8px 32px var(--shadow-dropdown, rgba(0, 0, 0, 0.4));
|
||||
box-shadow: 0 8px 32px var(--shadow-dropdown);
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
@@ -49,10 +49,10 @@
|
||||
transition: background 0.1s;
|
||||
}
|
||||
.custom-select-option:hover {
|
||||
background: var(--bg-hover);
|
||||
background: var(--menu-item-hover);
|
||||
}
|
||||
.custom-select-option.selected {
|
||||
color: var(--accent);
|
||||
color: var(--menu-item-active-text);
|
||||
font-weight: 600;
|
||||
background: color-mix(in srgb, var(--accent) 8%, transparent);
|
||||
}
|
||||
@@ -67,7 +67,7 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--text-muted);
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
border-top: 1px solid var(--menu-divider);
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
.custom-select-group-label:first-child {
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding: 5px 8px;
|
||||
background: var(--bg-input);
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
@@ -262,14 +262,14 @@
|
||||
font-size: 0.78rem;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg-input);
|
||||
background: var(--bg-card);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.device-sync-template-preset-btn:hover {
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@
|
||||
font-family: monospace;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--bg-card);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
|
||||
@@ -339,7 +339,7 @@
|
||||
}
|
||||
|
||||
.device-sync-template-token:hover {
|
||||
background: color-mix(in srgb, var(--accent) 15%, var(--ctp-surface0));
|
||||
background: color-mix(in srgb, var(--accent) 15%, var(--bg-card));
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
@@ -531,8 +531,8 @@
|
||||
}
|
||||
|
||||
.device-sync-badge.synced {
|
||||
background: color-mix(in srgb, var(--success, #4ade80) 15%, transparent);
|
||||
color: var(--success, #4ade80);
|
||||
background: color-mix(in srgb, var(--positive, #4ade80) 15%, transparent);
|
||||
color: var(--positive, #4ade80);
|
||||
}
|
||||
|
||||
.device-sync-badge.pending {
|
||||
@@ -573,7 +573,7 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.device-sync-status-icon.synced { color: var(--success, #4ade80); }
|
||||
.device-sync-status-icon.synced { color: var(--positive, #4ade80); }
|
||||
.device-sync-status-icon.pending { color: var(--warning, #f59e0b); }
|
||||
.device-sync-status-icon.deletion { color: var(--danger, #f38ba8); }
|
||||
|
||||
@@ -659,12 +659,12 @@
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: color-mix(in srgb, var(--success, #4ade80) 4%, transparent);
|
||||
background: color-mix(in srgb, var(--positive, #4ade80) 4%, transparent);
|
||||
}
|
||||
|
||||
.device-sync-bg-progress-bar-wrap {
|
||||
height: 3px;
|
||||
background: var(--bg-input);
|
||||
background: var(--bg-card);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -685,7 +685,7 @@
|
||||
}
|
||||
|
||||
.device-sync-stat-error { color: var(--danger); display: flex; align-items: center; gap: 3px; }
|
||||
.color-success { color: var(--success, #4ade80); }
|
||||
.color-success { color: var(--positive, #4ade80); }
|
||||
|
||||
/* ── Browser panel ── */
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
padding: 10px 14px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
background: var(--bg-input, var(--bg-sidebar));
|
||||
background: var(--bg-card, var(--bg-sidebar));
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,5 +17,5 @@
|
||||
}
|
||||
|
||||
.filter-quick-clear--on-active-chip:hover {
|
||||
background: color-mix(in srgb, var(--ctp-crust) 22%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-deep) 22%, transparent);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
margin-left: 0.35rem;
|
||||
border-radius: 9px;
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
@@ -99,7 +99,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 10px;
|
||||
background: var(--ctp-base);
|
||||
border: 1px solid var(--ctp-overlay0);
|
||||
background: var(--bg-app);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
width: 280px;
|
||||
max-width: 100%;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
.hero-placeholder {
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
background: linear-gradient(135deg, var(--ctp-surface0), var(--ctp-mantle));
|
||||
background: linear-gradient(135deg, var(--bg-card), var(--bg-sidebar));
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-3) var(--space-5);
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
|
||||
@@ -89,3 +89,4 @@
|
||||
@import './_banner.css';
|
||||
@import './np-dash.css';
|
||||
@import './orbit-session-top-strip.css';
|
||||
@import './back-to-top.css';
|
||||
|
||||
@@ -93,8 +93,8 @@
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: var(--ctp-base);
|
||||
border: 1px solid var(--ctp-overlay0);
|
||||
background: var(--bg-app);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
|
||||
}
|
||||
@@ -190,7 +190,7 @@
|
||||
top: calc(100% + 8px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
.login-card {
|
||||
width: 100%;
|
||||
max-width: 520px;
|
||||
background: var(--ctp-mantle);
|
||||
background: var(--bg-sidebar);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--space-8);
|
||||
@@ -67,7 +67,7 @@
|
||||
font-family: var(--font-display);
|
||||
font-size: 28px;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, var(--ctp-mauve), var(--ctp-blue));
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
}
|
||||
.mini-player__titlebar-btn--close:hover {
|
||||
background: var(--danger);
|
||||
color: var(--ctp-base);
|
||||
color: var(--bg-app);
|
||||
}
|
||||
|
||||
.mini-player {
|
||||
@@ -213,7 +213,7 @@
|
||||
position: relative;
|
||||
width: 5px;
|
||||
height: 110px;
|
||||
background: var(--ctp-surface1);
|
||||
background: var(--bg-hover);
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
@@ -271,7 +271,7 @@
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
.mini-player__btn--primary:hover {
|
||||
background: var(--accent);
|
||||
@@ -293,7 +293,7 @@
|
||||
flex: 1;
|
||||
height: 3px;
|
||||
border-radius: 2px;
|
||||
background: var(--ctp-surface1);
|
||||
background: var(--bg-hover);
|
||||
overflow: hidden;
|
||||
}
|
||||
.mini-player__progress-fill {
|
||||
@@ -416,11 +416,11 @@
|
||||
cursor: default;
|
||||
}
|
||||
.mini-player__tool--active {
|
||||
color: var(--ctp-base);
|
||||
color: var(--bg-app);
|
||||
background: var(--accent);
|
||||
}
|
||||
.mini-player__tool--active:hover:not(:disabled) {
|
||||
color: var(--ctp-base);
|
||||
color: var(--bg-app);
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
@@ -553,7 +553,7 @@ html[data-perf-disable-home-artwork-clip="true"] .home-lite-artwork .song-card-c
|
||||
.np-info-section {
|
||||
display: block;
|
||||
padding: 18px 0;
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--border-subtle, var(--ctp-surface0)) 70%, transparent);
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--border-subtle, var(--bg-card)) 70%, transparent);
|
||||
}
|
||||
.np-info-section > * + * { margin-top: 12px; }
|
||||
.np-info-section:last-child {
|
||||
@@ -819,7 +819,7 @@ html[data-perf-disable-home-artwork-clip="true"] .home-lite-artwork .song-card-c
|
||||
background: var(--accent);
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
color: var(--ctp-base, #1e1e2e);
|
||||
color: var(--bg-app, #1e1e2e);
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(17, 17, 27, 0.85);
|
||||
background: var(--modal-scrim);
|
||||
backdrop-filter: blur(8px);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--modal-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--space-8);
|
||||
@@ -99,7 +99,7 @@
|
||||
margin: 12px 0 10px;
|
||||
padding: 4px;
|
||||
border-radius: 12px;
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 88%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 88%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 18%, transparent);
|
||||
}
|
||||
|
||||
@@ -122,12 +122,12 @@
|
||||
|
||||
.sidebar-perf-modal__tab:hover {
|
||||
color: var(--text-primary);
|
||||
background: color-mix(in srgb, var(--bg-hover, var(--ctp-surface1)) 70%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-hover, var(--bg-hover)) 70%, transparent);
|
||||
}
|
||||
|
||||
.sidebar-perf-modal__tab--active {
|
||||
color: var(--text-primary);
|
||||
background: color-mix(in srgb, var(--accent) 16%, var(--bg-card, var(--ctp-base)));
|
||||
background: color-mix(in srgb, var(--accent) 16%, var(--bg-card, var(--bg-app)));
|
||||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 28%, transparent);
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 18%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 82%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 82%, transparent);
|
||||
}
|
||||
|
||||
.perf-live-poll__title {
|
||||
@@ -365,7 +365,7 @@
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 18%, transparent);
|
||||
border-radius: 12px;
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 82%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 82%, transparent);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@
|
||||
padding: 10px 10px 9px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 14%, transparent);
|
||||
background: color-mix(in srgb, var(--ctp-mantle, var(--ctp-base)) 72%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-sidebar, var(--bg-app)) 72%, transparent);
|
||||
min-height: 84px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -540,7 +540,7 @@
|
||||
.perf-tree-group {
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 16%, transparent);
|
||||
border-radius: 10px;
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 78%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 78%, transparent);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -634,7 +634,7 @@
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 18%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 82%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 82%, transparent);
|
||||
}
|
||||
|
||||
.perf-overlay-mode__title {
|
||||
@@ -656,7 +656,7 @@
|
||||
padding: 6px 8px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 22%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 70%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 70%, transparent);
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
@@ -670,7 +670,7 @@
|
||||
|
||||
.perf-overlay-mode__segment--active {
|
||||
border-color: color-mix(in srgb, var(--accent) 55%, transparent);
|
||||
background: color-mix(in srgb, var(--accent) 14%, var(--bg-card, var(--ctp-base)));
|
||||
background: color-mix(in srgb, var(--accent) 14%, var(--bg-card, var(--bg-app)));
|
||||
color: var(--text-primary);
|
||||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 24%, transparent);
|
||||
}
|
||||
@@ -687,7 +687,7 @@
|
||||
padding: 10px 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 18%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 82%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 82%, transparent);
|
||||
}
|
||||
|
||||
.perf-overlay-appearance__title {
|
||||
@@ -734,7 +734,7 @@
|
||||
height: 36px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 22%, transparent);
|
||||
background: color-mix(in srgb, var(--ctp-mantle, var(--ctp-base)) 70%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-sidebar, var(--bg-app)) 70%, transparent);
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -815,14 +815,14 @@
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 22%, transparent);
|
||||
border-radius: 10px;
|
||||
padding: 8px 10px 10px;
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 78%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 78%, transparent);
|
||||
}
|
||||
|
||||
.sidebar-perf-modal__phase--nested {
|
||||
margin-left: 10px;
|
||||
margin-right: 2px;
|
||||
padding-top: 6px;
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 68%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 68%, transparent);
|
||||
}
|
||||
|
||||
.sidebar-perf-modal__phase-title {
|
||||
@@ -843,7 +843,7 @@
|
||||
padding: 10px 12px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 22%, transparent);
|
||||
border-radius: 10px;
|
||||
background: color-mix(in srgb, var(--bg-card, var(--ctp-base)) 80%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 80%, transparent);
|
||||
}
|
||||
|
||||
.sidebar-perf-modal__cpu-title {
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
}
|
||||
|
||||
.mp-artist-avatar--placeholder {
|
||||
background: var(--bg-surface);
|
||||
background: var(--card-placeholder-bg);
|
||||
}
|
||||
|
||||
.mp-artist-info {
|
||||
@@ -226,7 +226,7 @@
|
||||
}
|
||||
|
||||
.mp-album-cover--placeholder {
|
||||
background: var(--bg-surface);
|
||||
background: var(--card-placeholder-bg);
|
||||
}
|
||||
|
||||
.mp-album-meta {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
container-type: inline-size;
|
||||
background:
|
||||
radial-gradient(ellipse at 20% 0%, color-mix(in srgb, var(--accent) 10%, var(--bg-main)) 0%, transparent 60%),
|
||||
radial-gradient(ellipse at 80% 100%, color-mix(in srgb, var(--ctp-blue) 8%, var(--bg-main)) 0%, transparent 60%),
|
||||
radial-gradient(ellipse at 80% 100%, color-mix(in srgb, var(--accent-2) 8%, var(--bg-main)) 0%, transparent 60%),
|
||||
var(--bg-main);
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
max-height: 300px;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--ctp-teal) transparent;
|
||||
scrollbar-color: var(--accent-2) transparent;
|
||||
}
|
||||
|
||||
.np-bio-text.expanded::-webkit-scrollbar {
|
||||
@@ -221,7 +221,7 @@
|
||||
}
|
||||
|
||||
.np-bio-text.expanded::-webkit-scrollbar-thumb {
|
||||
background: var(--ctp-teal);
|
||||
background: var(--accent-2);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,8 +73,8 @@
|
||||
}
|
||||
|
||||
.np-badge-hires {
|
||||
background: color-mix(in srgb, var(--ctp-yellow) 30%, transparent);
|
||||
color: var(--ctp-yellow);
|
||||
background: color-mix(in srgb, var(--highlight) 30%, transparent);
|
||||
color: var(--highlight);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
@@ -200,7 +200,7 @@
|
||||
}
|
||||
.np-dash-toolbar-badge {
|
||||
background: var(--accent);
|
||||
color: var(--ctp-base, #1e1e2e);
|
||||
color: var(--bg-app, #1e1e2e);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
padding: 1px 6px;
|
||||
@@ -214,7 +214,7 @@
|
||||
top: calc(100% + 4px);
|
||||
right: 0;
|
||||
min-width: 220px;
|
||||
background: var(--ctp-base, #1e1e2e);
|
||||
background: var(--bg-app, #1e1e2e);
|
||||
border: 1px solid rgba(255, 255, 255, 0.10);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 6px;
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
}
|
||||
|
||||
.offline-library-delete:hover {
|
||||
color: var(--color-error, #e05050);
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.offline-library-delete--spacer {
|
||||
@@ -226,7 +226,7 @@
|
||||
|
||||
.offline-filter-tab.active {
|
||||
background: var(--accent);
|
||||
color: var(--ctp-base);
|
||||
color: var(--bg-app);
|
||||
border-color: var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -187,8 +187,8 @@
|
||||
transition: color 150ms ease, background 150ms ease, transform 180ms ease;
|
||||
}
|
||||
.orbit-bar__exit:hover {
|
||||
color: var(--ctp-red, #f38ba8);
|
||||
background: color-mix(in srgb, var(--ctp-red, #f38ba8) 12%, transparent);
|
||||
color: var(--danger, #f38ba8);
|
||||
background: color-mix(in srgb, var(--danger, #f38ba8) 12%, transparent);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@
|
||||
min-width: 280px;
|
||||
max-width: 380px;
|
||||
padding: 6px;
|
||||
background: var(--ctp-base, #1e1e2e);
|
||||
background: var(--bg-app, #1e1e2e);
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 22%, rgba(255,255,255,0.1));
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||
@@ -228,7 +228,7 @@
|
||||
min-width: 320px;
|
||||
max-width: 380px;
|
||||
padding: 12px 14px 14px;
|
||||
background: var(--ctp-base, #1e1e2e);
|
||||
background: var(--bg-app, #1e1e2e);
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 22%, rgba(255,255,255,0.1));
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||
@@ -356,19 +356,19 @@
|
||||
transition: color 140ms ease, background 140ms ease, border-color 140ms ease;
|
||||
}
|
||||
.orbit-participants-pop__kick:hover {
|
||||
color: var(--ctp-yellow, #f9e2af);
|
||||
background: color-mix(in srgb, var(--ctp-yellow, #f9e2af) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--ctp-yellow, #f9e2af) 35%, transparent);
|
||||
color: var(--highlight, #f9e2af);
|
||||
background: color-mix(in srgb, var(--highlight, #f9e2af) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--highlight, #f9e2af) 35%, transparent);
|
||||
}
|
||||
.orbit-participants-pop__kick--ban:hover {
|
||||
color: var(--ctp-red, #f38ba8);
|
||||
background: color-mix(in srgb, var(--ctp-red, #f38ba8) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--ctp-red, #f38ba8) 35%, transparent);
|
||||
color: var(--danger, #f38ba8);
|
||||
background: color-mix(in srgb, var(--danger, #f38ba8) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--danger, #f38ba8) 35%, transparent);
|
||||
}
|
||||
.orbit-participants-pop__kick.is-active {
|
||||
color: var(--ctp-peach, #fab387);
|
||||
background: color-mix(in srgb, var(--ctp-peach, #fab387) 16%, transparent);
|
||||
border-color: color-mix(in srgb, var(--ctp-peach, #fab387) 45%, transparent);
|
||||
color: var(--accent-2, #fab387);
|
||||
background: color-mix(in srgb, var(--accent-2, #fab387) 16%, transparent);
|
||||
border-color: color-mix(in srgb, var(--accent-2, #fab387) 45%, transparent);
|
||||
}
|
||||
|
||||
/* ── Exit modal ────────────────────────────────────────────────────── */
|
||||
@@ -405,7 +405,7 @@
|
||||
/* ── Topbar "start Orbit" trigger — same form as Live, accent-tinted ── */
|
||||
.orbit-start-trigger {
|
||||
color: var(--accent);
|
||||
border-color: color-mix(in srgb, var(--accent) 45%, var(--ctp-surface1));
|
||||
border-color: color-mix(in srgb, var(--accent) 45%, var(--bg-hover));
|
||||
transition: color 150ms ease, border-color 150ms ease, background 150ms ease, box-shadow 200ms ease;
|
||||
}
|
||||
.orbit-start-trigger__spin { transition: transform 260ms ease; }
|
||||
@@ -520,15 +520,15 @@
|
||||
gap: 4px;
|
||||
margin-top: 10px;
|
||||
padding: 10px 12px;
|
||||
background: color-mix(in srgb, var(--ctp-yellow, #f9e2af) 14%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--ctp-yellow, #f9e2af) 40%, transparent);
|
||||
background: color-mix(in srgb, var(--highlight, #f9e2af) 14%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--highlight, #f9e2af) 40%, transparent);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.orbit-help-modal__warn strong {
|
||||
color: var(--ctp-yellow, #f9e2af);
|
||||
color: var(--highlight, #f9e2af);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@@ -696,15 +696,15 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
.orbit-start-modal__tip--warn {
|
||||
background: color-mix(in srgb, var(--ctp-yellow, #f9e2af) 14%, transparent);
|
||||
border-color: color-mix(in srgb, var(--ctp-yellow, #f9e2af) 45%, transparent);
|
||||
background: color-mix(in srgb, var(--highlight, #f9e2af) 14%, transparent);
|
||||
border-color: color-mix(in srgb, var(--highlight, #f9e2af) 45%, transparent);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.orbit-start-modal__tip--warn svg {
|
||||
color: var(--ctp-yellow, #f9e2af);
|
||||
color: var(--highlight, #f9e2af);
|
||||
}
|
||||
.orbit-start-modal__tip--warn strong {
|
||||
color: var(--ctp-yellow, #f9e2af);
|
||||
color: var(--highlight, #f9e2af);
|
||||
}
|
||||
|
||||
.orbit-start-modal__field {
|
||||
@@ -810,7 +810,7 @@
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 9px 12px;
|
||||
background: var(--ctp-base);
|
||||
background: var(--bg-app);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--text-primary);
|
||||
@@ -848,7 +848,7 @@
|
||||
min-width: 320px;
|
||||
max-width: 380px;
|
||||
padding: 14px;
|
||||
background: var(--ctp-base, #1e1e2e);
|
||||
background: var(--bg-app, #1e1e2e);
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 22%, rgba(255,255,255,0.1));
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||
@@ -919,7 +919,7 @@
|
||||
gap: 4px;
|
||||
padding: 3px 8px;
|
||||
font-size: 11px;
|
||||
background: var(--bg-input);
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--text-primary);
|
||||
@@ -927,7 +927,7 @@
|
||||
transition: background 120ms ease, border-color 120ms ease;
|
||||
}
|
||||
.orbit-diag-pop__btn:hover {
|
||||
background: var(--bg-hover, var(--bg-input));
|
||||
background: var(--bg-hover, var(--bg-card));
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.orbit-diag-pop__log {
|
||||
@@ -937,7 +937,7 @@
|
||||
font-family: var(--font-mono, ui-monospace, monospace);
|
||||
font-size: 10.5px;
|
||||
line-height: 1.45;
|
||||
background: var(--bg-input);
|
||||
background: var(--bg-card);
|
||||
color: var(--text-secondary);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-sm);
|
||||
@@ -1121,20 +1121,20 @@
|
||||
border-style: solid;
|
||||
}
|
||||
.orbit-queue-head__presence--online {
|
||||
color: var(--ctp-green, #a6e3a1);
|
||||
background: color-mix(in srgb, var(--ctp-green, #a6e3a1) 14%, transparent);
|
||||
border-color: color-mix(in srgb, var(--ctp-green, #a6e3a1) 40%, transparent);
|
||||
color: var(--positive, #a6e3a1);
|
||||
background: color-mix(in srgb, var(--positive, #a6e3a1) 14%, transparent);
|
||||
border-color: color-mix(in srgb, var(--positive, #a6e3a1) 40%, transparent);
|
||||
}
|
||||
.orbit-queue-head__presence--online svg {
|
||||
color: var(--ctp-green, #a6e3a1);
|
||||
color: var(--positive, #a6e3a1);
|
||||
}
|
||||
.orbit-queue-head__presence--away {
|
||||
color: var(--ctp-yellow, #f9e2af);
|
||||
background: color-mix(in srgb, var(--ctp-yellow, #f9e2af) 14%, transparent);
|
||||
border-color: color-mix(in srgb, var(--ctp-yellow, #f9e2af) 40%, transparent);
|
||||
color: var(--highlight, #f9e2af);
|
||||
background: color-mix(in srgb, var(--highlight, #f9e2af) 14%, transparent);
|
||||
border-color: color-mix(in srgb, var(--highlight, #f9e2af) 40%, transparent);
|
||||
}
|
||||
.orbit-queue-head__presence--away svg {
|
||||
color: var(--ctp-yellow, #f9e2af);
|
||||
color: var(--highlight, #f9e2af);
|
||||
}
|
||||
.orbit-queue-head__meta {
|
||||
display: flex;
|
||||
@@ -1173,7 +1173,7 @@
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ctp-crust, #11111b);
|
||||
color: var(--text-on-accent, #11111b);
|
||||
background: var(--accent);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
@@ -1384,9 +1384,9 @@
|
||||
transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
|
||||
}
|
||||
.host-approval__btn--approve:hover {
|
||||
background: color-mix(in srgb, var(--ctp-green, #a6e3a1) 28%, transparent);
|
||||
border-color: var(--ctp-green, #a6e3a1);
|
||||
color: var(--ctp-green, #a6e3a1);
|
||||
background: color-mix(in srgb, var(--positive, #a6e3a1) 28%, transparent);
|
||||
border-color: var(--positive, #a6e3a1);
|
||||
color: var(--positive, #a6e3a1);
|
||||
}
|
||||
.host-approval__btn--decline:hover {
|
||||
background: color-mix(in srgb, var(--danger, #f38ba8) 28%, transparent);
|
||||
@@ -1404,10 +1404,10 @@
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
.orbit-guest-queue__section-head--pending {
|
||||
color: var(--ctp-yellow, #f9e2af);
|
||||
color: var(--highlight, #f9e2af);
|
||||
}
|
||||
.orbit-guest-queue__section-head--pending svg {
|
||||
color: var(--ctp-yellow, #f9e2af);
|
||||
color: var(--highlight, #f9e2af);
|
||||
}
|
||||
.orbit-guest-queue__item--pending {
|
||||
opacity: 0.85;
|
||||
@@ -1456,9 +1456,9 @@
|
||||
padding: 8px 10px;
|
||||
font-size: 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: color-mix(in srgb, var(--ctp-red, #f38ba8) 14%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--ctp-red, #f38ba8) 35%, transparent);
|
||||
color: var(--ctp-red, #f38ba8);
|
||||
background: color-mix(in srgb, var(--danger, #f38ba8) 14%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--danger, #f38ba8) 35%, transparent);
|
||||
color: var(--danger, #f38ba8);
|
||||
}
|
||||
|
||||
.orbit-start-modal__actions {
|
||||
@@ -1474,7 +1474,7 @@
|
||||
gap: 8px;
|
||||
margin-bottom: 18px;
|
||||
padding: 10px 12px;
|
||||
background: var(--ctp-base);
|
||||
background: var(--bg-app);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-mono, ui-monospace, 'Courier New', monospace);
|
||||
@@ -1522,7 +1522,7 @@
|
||||
--fps-overlay-opacity: 0.82;
|
||||
background: color-mix(
|
||||
in srgb,
|
||||
var(--ctp-crust, #111) calc(var(--fps-overlay-opacity) * 100%),
|
||||
var(--text-on-accent, #111) calc(var(--fps-overlay-opacity) * 100%),
|
||||
transparent
|
||||
);
|
||||
border: 1px solid color-mix(
|
||||
@@ -1743,7 +1743,7 @@
|
||||
height: 160px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: var(--bg-input, rgba(0, 0, 0, 0.15));
|
||||
background: var(--bg-card, rgba(0, 0, 0, 0.15));
|
||||
}
|
||||
.because-card-cover {
|
||||
width: 100%;
|
||||
@@ -1768,7 +1768,7 @@
|
||||
.because-card--skeleton .because-card-cover-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: color-mix(in srgb, var(--text-primary) 14%, var(--bg-input, rgba(0, 0, 0, 0.15)));
|
||||
background: color-mix(in srgb, var(--text-primary) 14%, var(--bg-card, rgba(0, 0, 0, 0.15)));
|
||||
animation: because-cover-pulse 1.1s ease-in-out infinite;
|
||||
}
|
||||
.because-card-skeleton-line {
|
||||
|
||||
@@ -68,9 +68,9 @@
|
||||
transform: rotate(90deg) scale(0.94);
|
||||
}
|
||||
|
||||
.playback-delay-modal--pause { --pd-accent: var(--ctp-lavender, #b4befe); }
|
||||
.playback-delay-modal--start { --pd-accent: var(--ctp-peach, #fab387); }
|
||||
.playback-delay-modal--idle { --pd-accent: var(--ctp-overlay1, #7f849c); }
|
||||
.playback-delay-modal--pause { --pd-accent: var(--accent-2, #b4befe); }
|
||||
.playback-delay-modal--start { --pd-accent: var(--accent-2, #fab387); }
|
||||
.playback-delay-modal--idle { --pd-accent: var(--border-subtle, #7f849c); }
|
||||
|
||||
.playback-delay-modal__head {
|
||||
display: flex;
|
||||
@@ -127,7 +127,7 @@
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
background: var(--accent);
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
@@ -165,7 +165,7 @@
|
||||
|
||||
.player-btn-preview-ring-track {
|
||||
fill: none;
|
||||
stroke: var(--ctp-overlay0);
|
||||
stroke: var(--border);
|
||||
stroke-width: 4;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@
|
||||
button carries the mode distinction, so the ring stays consistent with
|
||||
the rest of the app. */
|
||||
.playback-schedule-ring__grad-a { stop-color: var(--accent); }
|
||||
.playback-schedule-ring__grad-b { stop-color: var(--ctp-lavender, #b4befe); }
|
||||
.playback-schedule-ring__grad-b { stop-color: var(--accent-2, #b4befe); }
|
||||
|
||||
/* Replaces the Play/Pause icon while a schedule timer is armed. Two-line
|
||||
stack: mode icon (Moon for sleep, Sunrise for delayed-start) above the
|
||||
@@ -358,7 +358,7 @@
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-4);
|
||||
background: color-mix(in srgb, var(--ctp-base) 40%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-app) 40%, transparent);
|
||||
}
|
||||
|
||||
.playback-delay-section--disabled {
|
||||
@@ -406,7 +406,7 @@
|
||||
padding: 7px 12px;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
background: var(--ctp-surface1);
|
||||
background: var(--bg-hover);
|
||||
color: var(--text-primary);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
@@ -419,7 +419,7 @@
|
||||
|
||||
.playback-delay-chip:hover {
|
||||
border-color: color-mix(in srgb, var(--pd-accent, var(--accent)) 55%, var(--border));
|
||||
background: color-mix(in srgb, var(--pd-accent, var(--accent)) 14%, var(--ctp-surface1));
|
||||
background: color-mix(in srgb, var(--pd-accent, var(--accent)) 14%, var(--bg-hover));
|
||||
color: var(--pd-accent, var(--accent));
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 3px 10px color-mix(in srgb, var(--pd-accent, var(--accent)) 22%, transparent);
|
||||
@@ -429,7 +429,7 @@
|
||||
|
||||
.playback-delay-chip--on {
|
||||
border-color: var(--pd-accent, var(--accent));
|
||||
background: color-mix(in srgb, var(--pd-accent, var(--accent)) 22%, var(--ctp-surface1));
|
||||
background: color-mix(in srgb, var(--pd-accent, var(--accent)) 22%, var(--bg-hover));
|
||||
color: var(--pd-accent, var(--accent));
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 8px 10px;
|
||||
font-size: 0.9rem;
|
||||
background: var(--ctp-base);
|
||||
background: var(--bg-app);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
}
|
||||
|
||||
.playlist-edit-cover-menu-item--danger {
|
||||
color: var(--ctp-red, #f38ba8);
|
||||
color: var(--danger, #f38ba8);
|
||||
}
|
||||
|
||||
/* Right side fields */
|
||||
@@ -216,7 +216,7 @@
|
||||
padding: 5px 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border: 1px solid var(--bg-hover);
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
@@ -227,7 +227,7 @@
|
||||
.artist-ext-link:hover {
|
||||
background: var(--bg-hover);
|
||||
color: var(--text-primary);
|
||||
border-color: var(--ctp-overlay0);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
/* Bio section */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* ─ Playlist Search Panel ─ */
|
||||
.playlist-search-panel {
|
||||
background: var(--surface-2);
|
||||
background: var(--bg-elevated, var(--bg-card));
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-3) var(--space-3) var(--space-2);
|
||||
@@ -123,7 +123,7 @@
|
||||
|
||||
.playlist-search-add-btn:hover {
|
||||
background: var(--accent);
|
||||
color: var(--ctp-base);
|
||||
color: var(--bg-app);
|
||||
}
|
||||
|
||||
.playlist-suggestions {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
}
|
||||
|
||||
.playlist-filter-input {
|
||||
background: var(--bg-surface);
|
||||
background: var(--input-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--text-primary);
|
||||
@@ -89,7 +89,7 @@
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
color: var(--ctp-base);
|
||||
color: var(--bg-app);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
.playlist-delete-btn {
|
||||
opacity: 0;
|
||||
color: var(--ctp-red) !important;
|
||||
color: var(--danger) !important;
|
||||
padding: 4px;
|
||||
height: auto;
|
||||
min-height: unset;
|
||||
@@ -146,7 +146,7 @@
|
||||
}
|
||||
|
||||
.fav-remove-btn:hover {
|
||||
color: var(--ctp-red);
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.track-row:hover .fav-remove-btn,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--text-secondary);
|
||||
color: var(--ctp-surface1);
|
||||
color: var(--bg-hover);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.03em;
|
||||
@@ -14,7 +14,7 @@
|
||||
}
|
||||
.radio-card-chip:hover {
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
/* Radio card: buttons row always pinned to bottom */
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
}
|
||||
|
||||
.np-queue-remove:hover {
|
||||
color: var(--ctp-red);
|
||||
color: var(--danger);
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
font-weight: 500;
|
||||
background: var(--bg-card);
|
||||
color: var(--text-secondary);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border: 1px solid var(--bg-hover);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.radio-filter-chip:hover { background: var(--bg-hover); color: var(--text-primary); }
|
||||
.radio-filter-chip.active { background: var(--accent); color: var(--ctp-crust); border-color: var(--accent); }
|
||||
.radio-filter-chip.active { background: var(--accent); color: var(--text-on-accent); border-color: var(--accent); }
|
||||
|
||||
|
||||
.radio-card-drop-before {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
min-height: clamp(200px, 22vh, 320px);
|
||||
padding: var(--space-6);
|
||||
border-radius: 16px;
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--bg-card);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
|
||||
@@ -460,13 +460,13 @@
|
||||
padding: var(--space-3) var(--space-4);
|
||||
margin-bottom: var(--space-4);
|
||||
border-radius: var(--radius-lg);
|
||||
background: color-mix(in srgb, var(--color-warning, #f59e0b) 12%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--color-warning, #f59e0b) 40%, transparent);
|
||||
background: color-mix(in srgb, var(--warning) 12%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.settings-privacy-notice-icon {
|
||||
color: var(--color-warning, #f59e0b);
|
||||
color: var(--warning);
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
}
|
||||
|
||||
.sidebar-customizer-row:hover {
|
||||
background: var(--bg-hover);
|
||||
background: var(--sidebar-item-hover);
|
||||
}
|
||||
|
||||
.sidebar-customizer-row.drag-over {
|
||||
@@ -245,7 +245,7 @@
|
||||
.toggle-track {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: var(--ctp-surface2);
|
||||
background: var(--bg-elevated);
|
||||
border-radius: var(--radius-full);
|
||||
transition: background var(--transition-base);
|
||||
}
|
||||
@@ -264,7 +264,7 @@
|
||||
}
|
||||
|
||||
.toggle-switch:hover .toggle-track {
|
||||
background: var(--ctp-overlay0);
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
.toggle-switch input:checked+.toggle-track {
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
color: var(--col-header-text);
|
||||
border-bottom: 1px solid var(--row-divider);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
.tracklist-total {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
border-top: 1px solid var(--row-divider);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
margin-top: var(--space-1);
|
||||
}
|
||||
@@ -53,7 +53,7 @@
|
||||
.tracklist-total-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
color: var(--row-text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
text-align: right;
|
||||
@@ -62,7 +62,7 @@
|
||||
.tracklist-total-value {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
color: var(--row-text-secondary);
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -89,13 +89,13 @@
|
||||
bottom: 20%;
|
||||
width: 1px;
|
||||
border-radius: 1px;
|
||||
background: var(--ctp-surface1);
|
||||
background: var(--bg-hover);
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.col-resize-handle:hover::after,
|
||||
.col-resize-handle:active::after {
|
||||
background: var(--accent);
|
||||
background: var(--col-resize-active);
|
||||
}
|
||||
|
||||
/* ── Column visibility picker ── */
|
||||
@@ -130,7 +130,7 @@
|
||||
|
||||
.tracklist-col-picker-btn:hover {
|
||||
opacity: 1;
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
/* Positioned inline (fixed) and portalled to <body> so no ancestor overflow
|
||||
can clip it; see TracklistColumnPicker. */
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border: 1px solid var(--bg-hover);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 6px;
|
||||
min-width: 160px;
|
||||
@@ -173,7 +173,7 @@
|
||||
}
|
||||
|
||||
.tracklist-col-picker-item:hover {
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
|
||||
.tracklist-col-picker-divider {
|
||||
height: 1px;
|
||||
background: var(--ctp-surface1);
|
||||
background: var(--bg-hover);
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
}
|
||||
|
||||
.tracklist-col-picker-reset:hover {
|
||||
background: var(--ctp-surface0);
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
color: var(--ctp-crust);
|
||||
color: var(--text-on-accent);
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -347,7 +347,7 @@
|
||||
|
||||
.playlist-suggestion-preview-ring-track {
|
||||
fill: none;
|
||||
stroke: var(--ctp-overlay0);
|
||||
stroke: var(--border);
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
@@ -424,15 +424,15 @@ html[data-track-previews-randommix="off"] [data-preview-loc="randomMix"] .pl
|
||||
|
||||
.track-row:hover,
|
||||
.track-row.context-active {
|
||||
background: var(--bg-hover);
|
||||
background: var(--row-hover);
|
||||
}
|
||||
|
||||
.track-row.active {
|
||||
background: var(--accent-dim);
|
||||
background: var(--row-playing-bg);
|
||||
}
|
||||
|
||||
.track-row.active:hover {
|
||||
background: var(--accent-dim);
|
||||
background: var(--row-playing-bg);
|
||||
}
|
||||
|
||||
.track-row>* {
|
||||
@@ -465,7 +465,7 @@ html[data-track-previews-randommix="off"] [data-preview-loc="randomMix"] .pl
|
||||
/* Default: show track number */
|
||||
.track-num-number {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
color: var(--row-text-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -490,7 +490,7 @@ html[data-track-previews-randommix="off"] [data-preview-loc="randomMix"] .pl
|
||||
|
||||
/* ── Active (currently playing): hide number, show eq-bars ── */
|
||||
.track-num.track-num-active .track-num-number { display: none; }
|
||||
.track-num.track-num-active .track-num-number { color: var(--accent); } /* kept for when visible */
|
||||
.track-num.track-num-active .track-num-number { color: var(--row-playing-text); } /* kept for when visible */
|
||||
|
||||
/* ── Active + hover: hide eq-bars, show play icon ── */
|
||||
.track-row:hover .track-num.track-num-active .track-num-eq { display: none; }
|
||||
@@ -525,7 +525,7 @@ html[data-track-previews-randommix="off"] [data-preview-loc="randomMix"] .pl
|
||||
* compositing (NVIDIA proprietary + WEBKIT_DISABLE_COMPOSITING_MODE=1) and
|
||||
* pegged the WebProcess at ~80% CPU on AlbumDetail with a long tracklist. */
|
||||
.eq-bars {
|
||||
color: var(--accent);
|
||||
color: var(--row-playing-text);
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -574,7 +574,7 @@ html[data-track-previews-randommix="off"] [data-preview-loc="randomMix"] .pl
|
||||
.track-title {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
color: var(--row-text);
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
}
|
||||
@@ -587,7 +587,7 @@ html[data-track-previews-randommix="off"] [data-preview-loc="randomMix"] .pl
|
||||
|
||||
.track-artist {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
color: var(--row-text-secondary);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -626,7 +626,7 @@ html[data-track-previews-randommix="off"] [data-preview-loc="randomMix"] .pl
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
color: var(--row-text-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user