Remove the duplication of the ~18 per-hue dynamic tokens between
theme.css and buildThemeTokens(): theme.css now only defines fixed
neutrals, surfaces, layout and z-index; hue/mode-dependent values
come solely from tokens.ts, injected via SSR as an inline <style> in
+layout.svelte (tokensToCss helper) and reapplied on every hue
change. app.html sets data-theme before first paint by reading
localStorage, removing the dark flash when light mode was saved.
The two inline-style backgrounds become @utility
app-backdrop/app-vignette; the main's bottom padding becomes
@utility app-main, driven by --mf-dock-h via [data-has-track].
Note: <style>{expr}</style> doesn't interpolate in Svelte (it
compiles as component-scoped CSS) — the SSR block is injected with
{@html `<style>${css}</style>`} since the content is fully generated
(no user input).
Verified in the browser: --mf-accent/--mf-bg resolve correctly during
SSR, data-theme='light' applies before the first render with no
flash.
119 lines
3.6 KiB
CSS
119 lines
3.6 KiB
CSS
:root {
|
|
/* Hue-based tokens (--mf-accent*, --mf-bg/elevated/panel-bg/bar-bg/hairline,
|
|
--mf-ambient, --mf-hero-bg/spotlight-bg/modal-glow, --mf-logo-grad,
|
|
--mf-cover-grad) are NOT defined here: they come only from
|
|
buildThemeTokens() in theme/tokens.ts, inlined as SSR <style> by
|
|
+layout.svelte and reapplied on every hue change. A duplicate default
|
|
here could never be overridden by a light-mode selector (see A.2). */
|
|
--mf-liked-grad: linear-gradient(150deg, oklch(0.4 0.09 330), oklch(0.18 0.04 10));
|
|
--mf-accent-dim: color-mix(in oklch, var(--mf-accent) 22%, transparent);
|
|
--mf-tile-l: 0.34;
|
|
--mf-tile-c: 0.1;
|
|
--mf-tile-shade-l: 0.14;
|
|
--mf-tile-shade-c: 0.035;
|
|
|
|
/* Fixed neutrals: deliberately hue-less, so only the accent carries color. */
|
|
--mf-text: #d9d8dc;
|
|
--mf-text-2: #8a8a8e;
|
|
--mf-text-3: #7d7d81;
|
|
--mf-text-4: #646468;
|
|
|
|
--mf-surface: rgba(255, 255, 255, 0.022);
|
|
--mf-surface-2: rgba(255, 255, 255, 0.045);
|
|
--mf-surface-hover: rgba(255, 255, 255, 0.06);
|
|
--mf-btn-bg: var(--mf-surface-2);
|
|
--mf-btn-bg-hover: var(--mf-surface-hover);
|
|
--mf-btn-secondary-bg: rgba(255, 255, 255, 0.045);
|
|
--mf-btn-secondary-bg-hover: rgba(255, 255, 255, 0.07);
|
|
|
|
--mf-border: rgba(255, 255, 255, 0.04);
|
|
--mf-border-strong: rgba(255, 255, 255, 0.09);
|
|
--mf-track: rgba(255, 255, 255, 0.09);
|
|
|
|
--mf-scrim: #000000;
|
|
--mf-on-art: #fefdfb;
|
|
--mf-on-art-2: #cac8c3;
|
|
--mf-ink: #0a0a0d;
|
|
--mf-cta-strong-bg: #ffffff;
|
|
|
|
--mf-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
|
|
|
--mf-sidebar-w: 254px;
|
|
--mf-queue-w: 304px;
|
|
--mf-nav-h: 66px;
|
|
--mf-player-h: 78px;
|
|
--mf-safe-b: env(safe-area-inset-bottom, 0px);
|
|
--mf-player-side-w: 16rem;
|
|
--mf-menu-w: 15rem;
|
|
--mf-submenu-w: 16rem;
|
|
--mf-range-h: 3.5px;
|
|
--mf-range-thumb: 11px;
|
|
--mf-volume-w: 84px;
|
|
|
|
--mf-scrollbar: rgba(255, 255, 255, 0.18);
|
|
--mf-scrollbar-hover: rgba(255, 255, 255, 0.32);
|
|
|
|
--z-raised: 10;
|
|
--z-sticky: 20;
|
|
--z-backdrop: 30;
|
|
--z-menu: 40;
|
|
--z-submenu: 50;
|
|
--z-modal: 60;
|
|
--z-grain: 80;
|
|
}
|
|
|
|
/* PlayerBar switches from its compact row to the full layout at `sm` (640px). */
|
|
@media (width >= 40rem) {
|
|
:root {
|
|
--mf-player-h: 100px;
|
|
}
|
|
}
|
|
|
|
/* TabsBar (mobile/tablet nav) is replaced by the Sidebar at `lg` (1024px). */
|
|
@media (width >= 64rem) {
|
|
:root {
|
|
--mf-nav-h: 0px;
|
|
}
|
|
}
|
|
|
|
@media (width < 73.75rem) {
|
|
:root {
|
|
--mf-queue-w: 258px;
|
|
}
|
|
}
|
|
|
|
/* "Modo blanco" — flips the neutral canvas/surface/text tokens to a light
|
|
palette. Components that reference these tokens re-theme correctly;
|
|
components hardcoding literal dark-mode hex colors do not. */
|
|
:root[data-theme='light'] {
|
|
--mf-text: #17171a;
|
|
--mf-text-2: #4a4a4e;
|
|
--mf-text-3: #6b6b6f;
|
|
--mf-text-4: #8c8c90;
|
|
|
|
--mf-surface: rgba(0, 0, 0, 0.035);
|
|
--mf-surface-2: rgba(0, 0, 0, 0.06);
|
|
--mf-surface-hover: #e8eceb;
|
|
--mf-btn-bg: var(--mf-surface-2);
|
|
--mf-btn-bg-hover: var(--mf-surface-hover);
|
|
--mf-btn-secondary-bg: rgba(0, 0, 0, 0.09);
|
|
--mf-btn-secondary-bg-hover: rgba(0, 0, 0, 0.14);
|
|
|
|
--mf-scrollbar: rgba(0, 0, 0, 0.18);
|
|
--mf-scrollbar-hover: rgba(0, 0, 0, 0.32);
|
|
|
|
--mf-border: rgba(0, 0, 0, 0.08);
|
|
--mf-border-strong: rgba(0, 0, 0, 0.14);
|
|
--mf-track: rgba(0, 0, 0, 0.12);
|
|
|
|
--mf-scrim: #ffffff;
|
|
--mf-ink: #ffffff;
|
|
--mf-cta-strong-bg: #17171a;
|
|
|
|
--mf-tile-l: 0.58;
|
|
--mf-tile-c: 0.085;
|
|
--mf-tile-shade-l: 0.42;
|
|
--mf-tile-shade-c: 0.05;
|
|
--mf-liked-grad: linear-gradient(150deg, oklch(0.62 0.12 330), oklch(0.46 0.08 10));
|
|
}
|