openvibers/openvibe.live Commits
Themes v2 re-sync (derived --on-accent etc.), :root on-accent white; audit: TURN now short-lived in production
Changes
@@@ -59,7 +59,7 @@ test/authorization were also run against the previous code and failed there, cas| Low-Medium | Anyone could set the saved playback position of any media request (unauthenticated). | Channel managers only. | authorization || Low-Medium | AI viewer "clone" copied any user's chat history from every channel (and their AI insight) into a bot. | Streamers clone only from what that person said in their own channel; staff unchanged. | authorization || Low-Medium | No limit on chat WebSocket connections per address. | 48 per address (admins exempt); clients back off to 30 s on a 4029 close. | test/chat-connection-cap.test.js |--| Medium | Voice: 1:1 call channels were listed publicly and anyone (anonymous included) could walk into them; `call-user` had no rate limit or block check; anyone could answer any invite; a kicked user could rejoin at once; one host could fill the 8-seat Public channel; TURN was emitted without credentials on a box with no secret; static TURN credentials went to every visitor. | Private calls hidden from strangers and invite-only; call-user 6/min + block check; respond requires the invite; 60 s kick cooldown; 3 sockets per address, duplicate accounts replaced; TURN only with credentials, optional short-lived HMAC credentials (`TURN_AUTH_SECRET`, coturn `use-auth-secret`). | manual + two-client voice test |++| Medium | Voice: 1:1 call channels were listed publicly and anyone (anonymous included) could walk into them; `call-user` had no rate limit or block check; anyone could answer any invite; a kicked user could rejoin at once; one host could fill the 8-seat Public channel; TURN was emitted without credentials on a box with no secret; static TURN credentials went to every visitor. | Private calls hidden from strangers and invite-only; call-user 6/min + block check; respond requires the invite; 60 s kick cooldown; 3 sockets per address, duplicate accounts replaced; TURN only with credentials; production coturn now runs `use-auth-secret` and every ICE list (voice and SFU, `server/net/turn.js`) carries a credential that expires after an hour — the old static pair no longer authenticates. | test/turn-credentials.test.js + relay probe on the host || Low | Slot `control_config_id` accepted other users' profiles; restream viewer counts writable for any destination. | Ownership checks. | manual || Low | ONVIF discovery (LAN scan with default-password probing) available to every user. | Admin only, bounded timeout. | manual || Low | RobotStreamer API calls carrying the user's RS token disabled TLS verification. | Verification on for api.robotstreamer.com (valid certificate). | manual |@@@ -93,7 +93,6 @@ validation, private VOD cache leak, HTTP-FLV bound to loopback, admin bans never| Medium | Inline event handlers keep `'unsafe-inline'` in the enforced CSP. | Progressive migration (see §3). || Medium | Per-address limits (broadcast viewers, rate limits) trust `CF-Connecting-IP`; if the origin is reachable without Cloudflare that header is spoofable. | Firewall the origin to Cloudflare ranges (deploy/cloudflare/checklist.md). || Low | Chat connect/close/join still scan every client to update counts. | Profile under load before indexing clients by room. |--| Low | Voice TURN credentials are still the static pair until `TURN_AUTH_SECRET` is set and coturn switched to `use-auth-secret` (production change). | Configure the secret on the host. || Low | RobotStreamer SFU WebSocket connections still skip certificate verification (hosts are assigned by RS at runtime). | Confirm RS SFU certificates and enable verification. || Low | Analytics roll-ups and the 90-day DELETE run synchronously on the main thread (vendor/openvibe-shared/analytics.js). | Companion change in OpenVibe.Network's openvibe-shared, then re-sync. |@@@ -22,7 +22,7 @@--accent: #3b82f6; /* OpenVibe blue */--accent-light: #60a5fa;--accent-dark: #1d4ed8;-- --on-accent: #0b0d10; /* readable text/icon color on top of --accent (themes override) */++ --on-accent: #ffffff; /* readable text/icon color on top of --accent; every theme sets its own */--live-red: #ef4444;--success: #22c55e;@@@ -5,7 +5,7 @@ const RAW_BUILTIN_THEMES = [name: 'Vibe',slug: 'vibe',mode: 'dark',-- description: 'The OpenVibe default: deep blue night with an electric-blue glow.',++ description: 'OpenVibe\'s default: deep blue night with an electric-blue glow.',tags: ['default', 'cool', 'blue'],variables: {'--bg-primary': '#0a0f1c',@@@ -32,10 +32,10 @@ const RAW_BUILTIN_THEMES = [},},{-- name: 'Classic Vibe',-- slug: 'vibe-classic',++ name: 'Violet Hour',++ slug: 'violet-hour',mode: 'dark',-- description: 'The original OpenVibe look: violet over charcoal.',++ description: 'Charcoal and violet: the colours OpenVibe started with.',tags: ['classic', 'purple', 'warm'],variables: {'--bg-primary': '#0d0d0f',@@@ -65,7 +65,7 @@ const RAW_BUILTIN_THEMES = [name: 'Midnight',slug: 'midnight',mode: 'dark',-- description: 'Deep blue-black with cool steel accents.',++ description: 'Blue-black with steel-indigo light.',tags: ['cool', 'minimal', 'blue'],variables: {'--bg-primary': '#0a0e17',@@@ -85,10 +85,10 @@ const RAW_BUILTIN_THEMES = [},},{-- name: 'Forest',++ name: 'Understory',slug: 'forest',mode: 'dark',-- description: 'Deep greens and earthy tones — nature at night.',++ description: 'Deep greens under the canopy.',tags: ['nature', 'green', 'earthy'],variables: {'--bg-primary': '#0a120a',@@@ -111,7 +111,7 @@ const RAW_BUILTIN_THEMES = [name: 'Neon Tokyo',slug: 'neon-tokyo',mode: 'dark',-- description: 'Cyberpunk neon pink/purple over dark chrome.',++ description: 'Hot pink neon on wet chrome.',tags: ['cyberpunk', 'neon', 'vibrant'],variables: {'--bg-primary': '#0a0a0f',@@@ -134,7 +134,7 @@ const RAW_BUILTIN_THEMES = [name: 'Dracula',slug: 'dracula',mode: 'dark',-- description: 'The beloved Dracula color scheme.',++ description: 'The Dracula scheme, as its authors drew it.',tags: ['popular', 'purple', 'classic'],variables: {'--bg-primary': '#282a36',@@@ -162,7 +162,7 @@ const RAW_BUILTIN_THEMES = [name: 'Monokai',slug: 'monokai',mode: 'dark',-- description: 'Classic Monokai developer palette.',++ description: 'The Monokai editor palette.',tags: ['developer', 'classic', 'warm'],variables: {'--bg-primary': '#272822',@@@ -185,10 +185,10 @@ const RAW_BUILTIN_THEMES = [},},{-- name: 'Ocean Deep',++ name: 'Trench',slug: 'ocean-deep',mode: 'dark',-- description: 'Dark ocean depths with teal highlights.',++ description: 'Pressure-dark water with a teal glow.',tags: ['ocean', 'teal', 'calm'],variables: {'--bg-primary': '#0a1215',@@@ -208,10 +208,10 @@ const RAW_BUILTIN_THEMES = [},},{-- name: 'Sunset',++ name: 'Dusk',slug: 'sunset',mode: 'dark',-- description: 'Warm orange-to-pink gradient vibes at dusk.',++ description: 'Orange fading to rose over dark ground.',tags: ['warm', 'gradient', 'vibrant'],variables: {'--bg-primary': '#120a0a',@@@ -234,7 +234,7 @@ const RAW_BUILTIN_THEMES = [name: 'Arctic',slug: 'arctic',mode: 'dark',-- description: 'Frost: ice-blue surfaces, cyan light and crisp white text.',++ description: 'Frost surfaces, cyan light, crisp white text.',tags: ['cool', 'ice', 'clean'],variables: {'--bg-primary': '#0b1620',@@@ -261,7 +261,7 @@ const RAW_BUILTIN_THEMES = [name: 'Ember',slug: 'ember',mode: 'dark',-- description: 'Smoldering reds and warm charcoal.',++ description: 'Smouldering red on warm charcoal.',tags: ['red', 'warm', 'intense'],variables: {'--bg-primary': '#120808',@@@ -284,7 +284,7 @@ const RAW_BUILTIN_THEMES = [name: 'Vapor',slug: 'vapor',mode: 'dark',-- description: 'Vaporwave aesthetics — pink, purple, and teal.',++ description: 'Magenta and teal, straight off a VHS tape.',tags: ['retro', 'aesthetic', 'neon'],variables: {'--bg-primary': '#0e0a14',@@@ -309,7 +309,7 @@ const RAW_BUILTIN_THEMES = [name: 'Slate',slug: 'slate',mode: 'dark',-- description: 'Neutral gray with subtle blue undertones.',++ description: 'Neutral grey with a cool violet accent.',tags: ['neutral', 'minimal', 'professional'],variables: {'--bg-primary': '#0f1118',@@@ -332,7 +332,7 @@ const RAW_BUILTIN_THEMES = [name: 'Matrix',slug: 'matrix',mode: 'dark',-- description: 'Green terminal text on pitch black.',++ description: 'Green phosphor on black.',tags: ['hacker', 'retro', 'terminal'],variables: {'--bg-primary': '#000000',@@@ -355,7 +355,7 @@ const RAW_BUILTIN_THEMES = [name: 'Nord',slug: 'nord',mode: 'dark',-- description: 'Arctic, north-bluish color palette inspired by the Nord theme.',++ description: 'The Nord palette: muted polar blues.',tags: ['popular', 'blue', 'soft'],variables: {'--bg-primary': '#2e3440',@@@ -379,10 +379,10 @@ const RAW_BUILTIN_THEMES = [},},{-- name: 'Gruvbox Dark',++ name: 'Gruvbox',slug: 'gruvbox-dark',mode: 'dark',-- description: 'Retro groove colors with warm, high-contrast tones.',++ description: 'Warm retro contrast.',tags: ['retro', 'warm', 'developer'],variables: {'--bg-primary': '#1d2021',@@@ -409,7 +409,7 @@ const RAW_BUILTIN_THEMES = [name: 'Abyss',slug: 'abyss',mode: 'dark',-- description: 'The deepest dark — nearly pure black with dim accents.',++ description: 'Nearly black; the interface is the light.',tags: ['minimal', 'ultra-dark', 'oled'],variables: {'--bg-primary': '#000000',@@@ -432,7 +432,7 @@ const RAW_BUILTIN_THEMES = [name: 'Copper',slug: 'copper',mode: 'dark',-- description: 'Rich copper and bronze on dark walnut.',++ description: 'Bronze on dark walnut.',tags: ['metallic', 'warm', 'premium'],variables: {'--bg-primary': '#110d09',@@@ -452,10 +452,10 @@ const RAW_BUILTIN_THEMES = [},},{-- name: 'Sakura Night',++ name: 'Sakura',slug: 'sakura-night',mode: 'dark',-- description: 'Soft pink cherry blossom on dark indigo.',++ description: 'Cherry blossom on indigo.',tags: ['japanese', 'pink', 'soft'],variables: {'--bg-primary': '#0e0a14',@@@ -475,10 +475,10 @@ const RAW_BUILTIN_THEMES = [},},{-- name: 'Hacker',++ name: 'Amber',slug: 'hacker',mode: 'dark',-- description: 'Amber-on-black retro terminal look.',++ description: 'Amber phosphor on black.',tags: ['retro', 'terminal', 'nostalgia'],variables: {'--bg-primary': '#000000',@@@ -501,7 +501,7 @@ const RAW_BUILTIN_THEMES = [name: 'Daylight',slug: 'daylight',mode: 'light',-- description: 'Clean, bright white with warm accents for daytime use.',++ description: 'Bright white with warm accents.',tags: ['clean', 'bright', 'default-light'],variables: {'--bg-primary': '#ffffff',@@@ -526,7 +526,7 @@ const RAW_BUILTIN_THEMES = [name: 'Paper',slug: 'paper',mode: 'light',-- description: 'Warm off-white like aged paper with ink accents.',++ description: 'Aged paper and ink.',tags: ['warm', 'soft', 'minimal'],variables: {'--bg-primary': '#faf8f5',@@@ -551,7 +551,7 @@ const RAW_BUILTIN_THEMES = [name: 'Cloud',slug: 'cloud',mode: 'light',-- description: 'Airy light blue with sky accents.',++ description: 'Airy blue-white with sky accents.',tags: ['blue', 'airy', 'fresh'],variables: {'--bg-primary': '#f0f5ff',@@@ -576,7 +576,7 @@ const RAW_BUILTIN_THEMES = [name: 'Meadow',slug: 'meadow',mode: 'light',-- description: 'Fresh spring greens with natural tones.',++ description: 'Spring greens in daylight.',tags: ['nature', 'green', 'fresh'],variables: {'--bg-primary': '#f2f8f0',@@@ -601,7 +601,7 @@ const RAW_BUILTIN_THEMES = [name: 'Peach',slug: 'peach',mode: 'light',-- description: 'Soft peachy pinks with warm coral accents.',++ description: 'Peach and coral, soft and warm.',tags: ['warm', 'pink', 'soft'],variables: {'--bg-primary': '#fff5f0',@@@ -626,7 +626,7 @@ const RAW_BUILTIN_THEMES = [name: 'Lavender',slug: 'lavender',mode: 'light',-- description: 'Gentle purple hues — calming and elegant.',++ description: 'Calm pale violet.',tags: ['purple', 'calm', 'elegant'],variables: {'--bg-primary': '#f8f5ff',@@@ -651,7 +651,7 @@ const RAW_BUILTIN_THEMES = [name: 'Gruvbox Light',slug: 'gruvbox-light',mode: 'light',-- description: 'Light retro groove — warm cream with bold accents.',++ description: 'Cream with bold retro accents.',tags: ['retro', 'warm', 'developer'],variables: {'--bg-primary': '#fbf1c7',@@@ -680,7 +680,7 @@ const RAW_BUILTIN_THEMES = [name: 'Snow',slug: 'snow',mode: 'light',-- description: 'Pure white with icy blue accents.',++ description: 'Pure white with icy blue.',tags: ['minimal', 'clean', 'blue'],variables: {'--bg-primary': '#ffffff',@@@ -705,7 +705,7 @@ const RAW_BUILTIN_THEMES = [name: 'Sand',slug: 'sand',mode: 'light',-- description: 'Desert sand and warm tan tones.',++ description: 'Desert tan and warm stone.',tags: ['warm', 'earthy', 'desert'],variables: {'--bg-primary': '#f8f4ef',@@@ -730,7 +730,7 @@ const RAW_BUILTIN_THEMES = [name: 'Rose',slug: 'rose',mode: 'light',-- description: 'Delicate rose pink with warm blush tones.',++ description: 'Blush pink, light and delicate.',tags: ['pink', 'romantic', 'soft'],variables: {'--bg-primary': '#fff5f7',@@@ -755,7 +755,7 @@ const RAW_BUILTIN_THEMES = [name: 'Solarized Dark',slug: 'solarized-dark',mode: 'dark',-- description: 'Ethan Schoonover\'s precision color scheme — dark variant.',++ description: 'Ethan Schoonover\'s precision palette, dark.',tags: ['popular', 'developer', 'balanced'],variables: {'--bg-primary': '#002b36',@@@ -782,7 +782,7 @@ const RAW_BUILTIN_THEMES = [name: 'Solarized Light',slug: 'solarized-light',mode: 'light',-- description: 'Ethan Schoonover\'s precision color scheme — light variant.',++ description: 'Ethan Schoonover\'s precision palette, light.',tags: ['popular', 'developer', 'balanced'],variables: {'--bg-primary': '#fdf6e3',@@@ -811,7 +811,7 @@ const RAW_BUILTIN_THEMES = [name: 'Catppuccin Mocha',slug: 'catppuccin-mocha',mode: 'dark',-- description: 'Soothing pastel theme for the high-spirited.',++ description: 'Soothing pastels on mocha.',tags: ['popular', 'pastel', 'soft'],variables: {'--bg-primary': '#1e1e2e',@@@ -839,7 +839,7 @@ const RAW_BUILTIN_THEMES = [name: 'Catppuccin Latte',slug: 'catppuccin-latte',mode: 'light',-- description: 'Soothing pastel theme — light variant.',++ description: 'Soothing pastels on latte.',tags: ['popular', 'pastel', 'soft'],variables: {'--bg-primary': '#eff1f5',@@@ -869,7 +869,7 @@ const RAW_BUILTIN_THEMES = [name: 'High Contrast',slug: 'high-contrast',mode: 'dark',-- description: 'Maximum contrast for accessibility — bold yellow on black.',++ description: 'Bold yellow on black for maximum legibility.',tags: ['accessibility', 'high-contrast', 'bold'],variables: {'--bg-primary': '#000000',@@@ -895,11 +895,45 @@ const RAW_BUILTIN_THEMES = [},];++// ── Derived tokens ──────────────────────────────────────────────────────────────++// Every theme also carries tokens a site cannot guess from the palette alone:++// --on-accent text/icon colour that reads on top of --accent (dark ink for light accents++// such as cyan or lime, white for deep ones) — chosen by WCAG contrast++// --accent-rgb "r,g,b" of the accent, for rgba(var(--accent-rgb), .3) in older stylesheets++// --accent-glow the accent at 35% for glows and focus rings++// --color-scheme dark|light, so native controls and scrollbars follow the theme++// A theme may set any of them explicitly; otherwise they are computed here so all 35 themes,++// and community themes that only define the base palette, stay consistent on every site.++function hexToRgb(hex) {++ const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(String(hex || '').trim());++ if (!m) return null;++ let h = m[1]; if (h.length === 3) h = h.split('').map((c) => c + c).join('');++ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];++}++function luminance(rgb) {++ const f = (v) => { v /= 255; return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); };++ return 0.2126 * f(rgb[0]) + 0.7152 * f(rgb[1]) + 0.0722 * f(rgb[2]);++}++function contrast(a, b) { const [x, y] = [luminance(a), luminance(b)]; return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05); }++function deriveTokens(vars, mode) {++ const out = { ...vars };++ const accent = hexToRgb(vars['--accent']);++ if (accent) {++ // White wherever it reads (>= 3:1, the large-text floor a button label meets); dark ink only++ // on accents too light for it (cyan, lime, amber).++ if (!out['--on-accent']) out['--on-accent'] = contrast([255, 255, 255], accent) >= 3 ? '#ffffff' : '#0b0d10';++ if (!out['--accent-rgb']) out['--accent-rgb'] = accent.join(',');++ if (!out['--accent-glow']) out['--accent-glow'] = `rgba(${accent.join(',')},0.35)`;++ }++ if (!out['--color-scheme']) out['--color-scheme'] = mode === 'light' ? 'light' : 'dark';++ return out;++}++const BUILTIN_THEMES = RAW_BUILTIN_THEMES.map((theme) => ({id: theme.slug,...theme,tags: Array.isArray(theme.tags) ? [...theme.tags] : [],-- variables: { ...(theme.variables || {}) },++ variables: deriveTokens(theme.variables || {}, theme.mode),}));const DEFAULT_THEME = BUILTIN_THEMES.find((theme) => theme.id === 'vibe') || BUILTIN_THEMES[0];@@@ -909,4 +943,7 @@ module.exports = {BUILTIN_THEMES,DEFAULT_THEME,DEFAULT_VARS,++ deriveTokens,++ hexToRgb,++ contrast,};@@@ -21,41 +21,41 @@// Kept in sync with packages/openvibe-shared/builtin-themes.js// THEMES:BEGIN — generated by scripts/build-theme-loader.js from builtin-themes.js; do not edit by handconst THEMES = {-- 'vibe': { '--bg-primary':'#0a0f1c','--bg-secondary':'#101828','--bg-tertiary':'#172238','--bg-card':'#131c2e','--bg-hover':'#1c2a44','--bg-input':'#0d1424','--text-primary':'#e6edf7','--text-secondary':'#96a7c2','--text-muted':'#7386a3','--accent':'#3b82f6','--accent-light':'#60a5fa','--accent-dark':'#1d4ed8','--border':'#1f2d47','--border-light':'#2c3d5c','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'vibe-classic': { '--bg-primary':'#0d0d0f','--bg-secondary':'#16161a','--bg-tertiary':'#1e1e24','--bg-card':'#1a1a20','--bg-hover':'#242430','--bg-input':'#12121a','--text-primary':'#e8e6e3','--text-secondary':'#9a9a9a','--text-muted':'#838282','--accent':'#8b5cf6','--accent-light':'#a78bfa','--accent-dark':'#6d28d9','--border':'#2a2a32','--border-light':'#3a3a44','--live-red':'#e74c3c','--success':'#2ecc71','--warning':'#f39c12','--danger':'#e74c3c','--info':'#3498db','--shadow':'0 2px 12px rgba(0,0,0,0.4)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'midnight': { '--bg-primary':'#0a0e17','--bg-secondary':'#111827','--bg-tertiary':'#1a2235','--bg-card':'#151d2e','--bg-hover':'#1e2a42','--bg-input':'#0d1220','--text-primary':'#e2e8f0','--text-secondary':'#94a3b8','--text-muted':'#78879b','--accent':'#6366f1','--accent-light':'#818cf8','--accent-dark':'#4f46e5','--border':'#1e293b','--border-light':'#334155','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'forest': { '--bg-primary':'#0a120a','--bg-secondary':'#121e12','--bg-tertiary':'#1a2a1a','--bg-card':'#152015','--bg-hover':'#1e3420','--bg-input':'#0d160d','--text-primary':'#d4e8d4','--text-secondary':'#8aaa8a','--text-muted':'#708e70','--accent':'#4ade80','--accent-light':'#86efac','--accent-dark':'#22c55e','--border':'#1a3a1a','--border-light':'#2a4a2a','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'neon-tokyo': { '--bg-primary':'#0a0a0f','--bg-secondary':'#12101a','--bg-tertiary':'#1a1625','--bg-card':'#15111f','--bg-hover':'#221a32','--bg-input':'#0d0b14','--text-primary':'#f0e6ff','--text-secondary':'#b4a0d0','--text-muted':'#87799c','--accent':'#ff006e','--accent-light':'#ff4d94','--accent-dark':'#c9005a','--border':'#2a1a3a','--border-light':'#3a2a4a','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'dracula': { '--bg-primary':'#282a36','--bg-secondary':'#1e1f29','--bg-tertiary':'#343746','--bg-card':'#2c2e3c','--bg-hover':'#3a3d50','--bg-input':'#21222c','--text-primary':'#f8f8f2','--text-secondary':'#bfbfb2','--text-muted':'#8995b8','--accent':'#bd93f9','--accent-light':'#d4b8ff','--accent-dark':'#9b6ddb','--border':'#44475a','--border-light':'#565970','--live-red':'#ff5555','--success':'#50fa7b','--warning':'#f1fa8c','--danger':'#ff5555','--info':'#8be9fd','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'monokai': { '--bg-primary':'#272822','--bg-secondary':'#1e1f1c','--bg-tertiary':'#3e3d32','--bg-card':'#2d2e27','--bg-hover':'#49483e','--bg-input':'#22231e','--text-primary':'#f8f8f2','--text-secondary':'#cfcfc2','--text-muted':'#979484','--accent':'#a6e22e','--accent-light':'#c4ff50','--accent-dark':'#7dac1c','--border':'#49483e','--border-light':'#5b5a50','--live-red':'#ef4444','--success':'#22c55e','--warning':'#e6db74','--danger':'#f92672','--info':'#66d9ef','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'ocean-deep': { '--bg-primary':'#0a1215','--bg-secondary':'#0f1a1f','--bg-tertiary':'#162228','--bg-card':'#121c22','--bg-hover':'#1a2a32','--bg-input':'#0c1418','--text-primary':'#d0e8ef','--text-secondary':'#7aa8ba','--text-muted':'#658896','--accent':'#00bcd4','--accent-light':'#4dd0e1','--accent-dark':'#0097a7','--border':'#1a3040','--border-light':'#2a4050','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'sunset': { '--bg-primary':'#120a0a','--bg-secondary':'#1a1010','--bg-tertiary':'#241616','--bg-card':'#1e1212','--bg-hover':'#2e1a1a','--bg-input':'#140c0c','--text-primary':'#ffe8e0','--text-secondary':'#c49080','--text-muted':'#977970','--accent':'#ff6b35','--accent-light':'#ff8f5e','--accent-dark':'#d04a1a','--border':'#3a2020','--border-light':'#4a3030','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'arctic': { '--bg-primary':'#0b1620','--bg-secondary':'#0f1e2b','--bg-tertiary':'#163040','--bg-card':'#122534','--bg-hover':'#1a3a4c','--bg-input':'#0c1a26','--text-primary':'#eaf6ff','--text-secondary':'#9ec3d8','--text-muted':'#7ea3ba','--accent':'#22d3ee','--accent-light':'#a5f3fc','--accent-dark':'#0891b2','--border':'#1e3f52','--border-light':'#2a5268','--live-red':'#ef4444','--success':'#34d399','--warning':'#f59e0b','--danger':'#ef4444','--info':'#7dd3fc','--shadow':'0 2px 12px rgba(2,12,20,0.5)','--shadow-lg':'0 8px 32px rgba(2,12,20,0.65)' },-- 'ember': { '--bg-primary':'#120808','--bg-secondary':'#1a0e0e','--bg-tertiary':'#241414','--bg-card':'#1e1010','--bg-hover':'#2e1818','--bg-input':'#140a0a','--text-primary':'#f0dada','--text-secondary':'#b0808a','--text-muted':'#95787c','--accent':'#ef4444','--accent-light':'#f87171','--accent-dark':'#b91c1c','--border':'#3a1a20','--border-light':'#4a2a30','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'vapor': { '--bg-primary':'#0e0a14','--bg-secondary':'#14101c','--bg-tertiary':'#1c1628','--bg-card':'#181220','--bg-hover':'#241a34','--bg-input':'#100c16','--text-primary':'#f0e0ff','--text-secondary':'#c090e0','--text-muted':'#8f73b7','--accent':'#e040fb','--accent-light':'#ea80fc','--accent-dark':'#aa00d4','--border':'#2a1a40','--border-light':'#3a2a50','--live-red':'#ef4444','--success':'#69f0ae','--warning':'#f59e0b','--danger':'#ef4444','--info':'#00e5ff','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'slate': { '--bg-primary':'#0f1118','--bg-secondary':'#161820','--bg-tertiary':'#1e2028','--bg-card':'#1a1c24','--bg-hover':'#24262e','--bg-input':'#12141c','--text-primary':'#e4e6ea','--text-secondary':'#a0a4b0','--text-muted':'#828690','--accent':'#a78bfa','--accent-light':'#c4b5fd','--accent-dark':'#7c3aed','--border':'#2a2c38','--border-light':'#3a3c48','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'matrix': { '--bg-primary':'#000000','--bg-secondary':'#050a05','--bg-tertiary':'#0a140a','--bg-card':'#071007','--bg-hover':'#0e1e0e','--bg-input':'#030803','--text-primary':'#00ff41','--text-secondary':'#00b030','--text-muted':'#008f25','--accent':'#00ff41','--accent-light':'#66ff8a','--accent-dark':'#00aa2a','--border':'#0a2a0a','--border-light':'#144014','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'nord': { '--bg-primary':'#2e3440','--bg-secondary':'#272c36','--bg-tertiary':'#3b4252','--bg-card':'#333a48','--bg-hover':'#434c5e','--bg-input':'#2a303c','--text-primary':'#eceff4','--text-secondary':'#d8dee9','--text-muted':'#9ba5b8','--accent':'#88c0d0','--accent-light':'#8fbcbb','--accent-dark':'#5e81ac','--border':'#3b4252','--border-light':'#4c566a','--live-red':'#ef4444','--success':'#a3be8c','--warning':'#ebcb8b','--danger':'#bf616a','--info':'#81a1c1','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'gruvbox-dark': { '--bg-primary':'#1d2021','--bg-secondary':'#282828','--bg-tertiary':'#3c3836','--bg-card':'#32302f','--bg-hover':'#504945','--bg-input':'#242424','--text-primary':'#ebdbb2','--text-secondary':'#d5c4a1','--text-muted':'#a69682','--accent':'#fabd2f','--accent-light':'#fce566','--accent-dark':'#d79921','--border':'#3c3836','--border-light':'#504945','--live-red':'#ef4444','--success':'#b8bb26','--warning':'#fe8019','--danger':'#fb4934','--info':'#83a598','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'abyss': { '--bg-primary':'#000000','--bg-secondary':'#080808','--bg-tertiary':'#111111','--bg-card':'#0a0a0a','--bg-hover':'#181818','--bg-input':'#050505','--text-primary':'#cccccc','--text-secondary':'#888888','--text-muted':'#7a7a7a','--accent':'#ffffff','--accent-light':'#ffffff','--accent-dark':'#aaaaaa','--border':'#1a1a1a','--border-light':'#252525','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'copper': { '--bg-primary':'#110d09','--bg-secondary':'#1a140e','--bg-tertiary':'#231c14','--bg-card':'#1e1710','--bg-hover':'#2c2218','--bg-input':'#13100b','--text-primary':'#e8ddd0','--text-secondary':'#b49a80','--text-muted':'#8e7f6a','--accent':'#cd7f32','--accent-light':'#daa060','--accent-dark':'#a06020','--border':'#2a2016','--border-light':'#3a3020','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'sakura-night': { '--bg-primary':'#0e0a14','--bg-secondary':'#150f1c','--bg-tertiary':'#1c1526','--bg-card':'#181020','--bg-hover':'#221830','--bg-input':'#100c16','--text-primary':'#f0e0f0','--text-secondary':'#c0a0c0','--text-muted':'#927592','--accent':'#f472b6','--accent-light':'#f9a8d4','--accent-dark':'#db2777','--border':'#2a1a30','--border-light':'#3a2a40','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'hacker': { '--bg-primary':'#000000','--bg-secondary':'#0a0800','--bg-tertiary':'#141000','--bg-card':'#0e0c00','--bg-hover':'#1c1800','--bg-input':'#060400','--text-primary':'#ffb000','--text-secondary':'#cc8d00','--text-muted':'#a37100','--accent':'#ffb000','--accent-light':'#ffd050','--accent-dark':'#cc8d00','--border':'#1a1400','--border-light':'#2a2200','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'daylight': { '--bg-primary':'#ffffff','--bg-secondary':'#f7f7f8','--bg-tertiary':'#eeeef0','--bg-card':'#ffffff','--bg-hover':'#f0f0f2','--bg-input':'#f5f5f7','--text-primary':'#1a1a2e','--text-secondary':'#4a4a6a','--text-muted':'#747489','--accent':'#8756f3','--accent-light':'#a78bfa','--accent-dark':'#6d28d9','--border':'#e0e0e6','--border-light':'#d0d0d8','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.08)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.12)' },-- 'paper': { '--bg-primary':'#faf8f5','--bg-secondary':'#f0ece6','--bg-tertiary':'#e8e2d8','--bg-card':'#faf8f5','--bg-hover':'#f0ece6','--bg-input':'#f5f2ed','--text-primary':'#2c2416','--text-secondary':'#5a4e3e','--text-muted':'#7b7061','--accent':'#8b6914','--accent-light':'#b08a30','--accent-dark':'#6a5010','--border':'#ddd6c8','--border-light':'#ccc4b0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,40,0,0.10)' },-- 'cloud': { '--bg-primary':'#f0f5ff','--bg-secondary':'#e8eef8','--bg-tertiary':'#dde5f0','--bg-card':'#f5f8ff','--bg-hover':'#e4ecf8','--bg-input':'#edf2fa','--text-primary':'#1a2040','--text-secondary':'#4a5070','--text-muted':'#6b718c','--accent':'#2867ed','--accent-light':'#60a5fa','--accent-dark':'#2563eb','--border':'#d0d8ea','--border-light':'#bcc8e0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,20,60,0.06)','--shadow-lg':'0 8px 32px rgba(0,20,60,0.10)' },-- 'meadow': { '--bg-primary':'#f2f8f0','--bg-secondary':'#e8f0e4','--bg-tertiary':'#dce8d6','--bg-card':'#f5faf2','--bg-hover':'#e4f0de','--bg-input':'#edf5ea','--text-primary':'#1a2e16','--text-secondary':'#3a5a32','--text-muted':'#5d7a54','--accent':'#15823e','--accent-light':'#22c55e','--accent-dark':'#15803d','--border':'#c8dcc0','--border-light':'#b0ccaa','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(0,40,0,0.10)' },-- 'peach': { '--bg-primary':'#fff5f0','--bg-secondary':'#fbeae2','--bg-tertiary':'#f5ddd2','--bg-card':'#fff7f2','--bg-hover':'#fce8dc','--bg-input':'#fdf0ea','--text-primary':'#2e1a14','--text-secondary':'#6a4438','--text-muted':'#8f6a5c','--accent':'#c04808','--accent-light':'#fb923c','--accent-dark':'#ea580c','--border':'#f0d0c0','--border-light':'#e4bfab','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,20,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,20,0,0.10)' },-- 'lavender': { '--bg-primary':'#f8f5ff','--bg-secondary':'#f0eaf8','--bg-tertiary':'#e6ddf0','--bg-card':'#faf7ff','--bg-hover':'#eee6f8','--bg-input':'#f4f0fa','--text-primary':'#1e1430','--text-secondary':'#4a3a60','--text-muted':'#796a92','--accent':'#844cf2','--accent-light':'#a78bfa','--accent-dark':'#7c3aed','--border':'#ddd0ee','--border-light':'#ccc0dd','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(40,0,60,0.06)','--shadow-lg':'0 8px 32px rgba(40,0,60,0.10)' },-- 'gruvbox-light': { '--bg-primary':'#fbf1c7','--bg-secondary':'#f2e5bc','--bg-tertiary':'#ebdbb2','--bg-card':'#fbf1c7','--bg-hover':'#f2e5bc','--bg-input':'#f5ecc4','--text-primary':'#3c3836','--text-secondary':'#504945','--text-muted':'#766b60','--accent':'#be4707','--accent-light':'#fe8019','--accent-dark':'#af3a03','--border':'#d5c4a1','--border-light':'#bdae93','--live-red':'#ef4444','--success':'#98971a','--warning':'#d79921','--danger':'#cc241d','--info':'#458588','--shadow':'0 2px 12px rgba(40,30,0,0.08)','--shadow-lg':'0 8px 32px rgba(40,30,0,0.12)' },-- 'snow': { '--bg-primary':'#ffffff','--bg-secondary':'#f8fafc','--bg-tertiary':'#f1f5f9','--bg-card':'#ffffff','--bg-hover':'#f1f5f9','--bg-input':'#f8fafc','--text-primary':'#0f172a','--text-secondary':'#334155','--text-muted':'#69768b','--accent':'#027cbb','--accent-light':'#38bdf8','--accent-dark':'#0284c7','--border':'#e2e8f0','--border-light':'#cbd5e1','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.05)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.08)' },-- 'sand': { '--bg-primary':'#f8f4ef','--bg-secondary':'#f0e8de','--bg-tertiary':'#e8ddd0','--bg-card':'#faf6f0','--bg-hover':'#f0e8de','--bg-input':'#f5f0e8','--text-primary':'#2e2418','--text-secondary':'#5a4e3e','--text-muted':'#7a6e5f','--accent':'#8c6707','--accent-light':'#daa520','--accent-dark':'#8b6508','--border':'#ddd0be','--border-light':'#ccc0aa','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,40,0,0.10)' },-- 'rose': { '--bg-primary':'#fff5f7','--bg-secondary':'#fce7ec','--bg-tertiary':'#f5d5de','--bg-card':'#fff7f9','--bg-hover':'#fce0e8','--bg-input':'#fdeef2','--text-primary':'#2e1420','--text-secondary':'#6a3850','--text-muted':'#96617e','--accent':'#de1c47','--accent-light':'#f43f5e','--accent-dark':'#be123c','--border':'#f0c8d4','--border-light':'#e4b0c0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,0,20,0.06)','--shadow-lg':'0 8px 32px rgba(60,0,20,0.10)' },-- 'solarized-dark': { '--bg-primary':'#002b36','--bg-secondary':'#073642','--bg-tertiary':'#0a3f4e','--bg-card':'#053542','--bg-hover':'#0d4a58','--bg-input':'#01303d','--text-primary':'#fdf6e3','--text-secondary':'#93a1a1','--text-muted':'#909c9a','--accent':'#b58900','--accent-light':'#d4a017','--accent-dark':'#8a6a00','--border':'#0a4050','--border-light':'#105060','--live-red':'#ef4444','--success':'#859900','--warning':'#cb4b16','--danger':'#dc322f','--info':'#268bd2','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'solarized-light': { '--bg-primary':'#fdf6e3','--bg-secondary':'#eee8d5','--bg-tertiary':'#e4ddc6','--bg-card':'#fdf6e3','--bg-hover':'#eee8d5','--bg-input':'#f5eedb','--text-primary':'#002b36','--text-secondary':'#586e75','--text-muted':'#5b7478','--accent':'#8d6c00','--accent-light':'#d4a017','--accent-dark':'#8a6a00','--border':'#d6ceb5','--border-light':'#c8c0a5','--live-red':'#ef4444','--success':'#859900','--warning':'#cb4b16','--danger':'#dc322f','--info':'#268bd2','--shadow':'0 2px 12px rgba(0,30,40,0.08)','--shadow-lg':'0 8px 32px rgba(0,30,40,0.12)' },-- 'catppuccin-mocha': { '--bg-primary':'#1e1e2e','--bg-secondary':'#181825','--bg-tertiary':'#313244','--bg-card':'#1e1e2e','--bg-hover':'#313244','--bg-input':'#1a1a2c','--text-primary':'#cdd6f4','--text-secondary':'#bac2de','--text-muted':'#81869e','--accent':'#cba6f7','--accent-light':'#dcc0ff','--accent-dark':'#b07de0','--border':'#313244','--border-light':'#45475a','--live-red':'#f38ba8','--success':'#a6e3a1','--warning':'#fab387','--danger':'#f38ba8','--info':'#89b4fa','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },-- 'catppuccin-latte': { '--bg-primary':'#eff1f5','--bg-secondary':'#e6e9ef','--bg-tertiary':'#dce0e8','--bg-card':'#eff1f5','--bg-hover':'#dce0e8','--bg-input':'#e8ebf0','--text-primary':'#4c4f69','--text-secondary':'#5c5f77','--text-muted':'#696c83','--accent':'#8839ef','--accent-light':'#a05cff','--accent-dark':'#7028d4','--border':'#ccd0da','--border-light':'#bcc0cc','--live-red':'#d20f39','--success':'#40a02b','--warning':'#fe640b','--danger':'#d20f39','--info':'#1e66f5','--shadow':'0 2px 12px rgba(0,0,0,0.06)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.10)' },-- 'high-contrast': { '--bg-primary':'#000000','--bg-secondary':'#0a0a0a','--bg-tertiary':'#1a1a1a','--bg-card':'#0f0f0f','--bg-hover':'#222222','--bg-input':'#0a0a0a','--text-primary':'#ffffff','--text-secondary':'#f0f0f0','--text-muted':'#aaaaaa','--accent':'#ffd700','--accent-light':'#ffed4a','--accent-dark':'#ccac00','--border':'#444444','--border-light':'#666666','--live-red':'#ff0000','--success':'#00ff00','--warning':'#ffff00','--danger':'#ff0000','--info':'#00ffff','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },++ 'vibe': { '--bg-primary':'#0a0f1c','--bg-secondary':'#101828','--bg-tertiary':'#172238','--bg-card':'#131c2e','--bg-hover':'#1c2a44','--bg-input':'#0d1424','--text-primary':'#e6edf7','--text-secondary':'#96a7c2','--text-muted':'#7386a3','--accent':'#3b82f6','--accent-light':'#60a5fa','--accent-dark':'#1d4ed8','--border':'#1f2d47','--border-light':'#2c3d5c','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'59,130,246','--accent-glow':'rgba(59,130,246,0.35)','--color-scheme':'dark' },++ 'violet-hour': { '--bg-primary':'#0d0d0f','--bg-secondary':'#16161a','--bg-tertiary':'#1e1e24','--bg-card':'#1a1a20','--bg-hover':'#242430','--bg-input':'#12121a','--text-primary':'#e8e6e3','--text-secondary':'#9a9a9a','--text-muted':'#838282','--accent':'#8b5cf6','--accent-light':'#a78bfa','--accent-dark':'#6d28d9','--border':'#2a2a32','--border-light':'#3a3a44','--live-red':'#e74c3c','--success':'#2ecc71','--warning':'#f39c12','--danger':'#e74c3c','--info':'#3498db','--shadow':'0 2px 12px rgba(0,0,0,0.4)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'139,92,246','--accent-glow':'rgba(139,92,246,0.35)','--color-scheme':'dark' },++ 'midnight': { '--bg-primary':'#0a0e17','--bg-secondary':'#111827','--bg-tertiary':'#1a2235','--bg-card':'#151d2e','--bg-hover':'#1e2a42','--bg-input':'#0d1220','--text-primary':'#e2e8f0','--text-secondary':'#94a3b8','--text-muted':'#78879b','--accent':'#6366f1','--accent-light':'#818cf8','--accent-dark':'#4f46e5','--border':'#1e293b','--border-light':'#334155','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'99,102,241','--accent-glow':'rgba(99,102,241,0.35)','--color-scheme':'dark' },++ 'forest': { '--bg-primary':'#0a120a','--bg-secondary':'#121e12','--bg-tertiary':'#1a2a1a','--bg-card':'#152015','--bg-hover':'#1e3420','--bg-input':'#0d160d','--text-primary':'#d4e8d4','--text-secondary':'#8aaa8a','--text-muted':'#708e70','--accent':'#4ade80','--accent-light':'#86efac','--accent-dark':'#22c55e','--border':'#1a3a1a','--border-light':'#2a4a2a','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'74,222,128','--accent-glow':'rgba(74,222,128,0.35)','--color-scheme':'dark' },++ 'neon-tokyo': { '--bg-primary':'#0a0a0f','--bg-secondary':'#12101a','--bg-tertiary':'#1a1625','--bg-card':'#15111f','--bg-hover':'#221a32','--bg-input':'#0d0b14','--text-primary':'#f0e6ff','--text-secondary':'#b4a0d0','--text-muted':'#87799c','--accent':'#ff006e','--accent-light':'#ff4d94','--accent-dark':'#c9005a','--border':'#2a1a3a','--border-light':'#3a2a4a','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'255,0,110','--accent-glow':'rgba(255,0,110,0.35)','--color-scheme':'dark' },++ 'dracula': { '--bg-primary':'#282a36','--bg-secondary':'#1e1f29','--bg-tertiary':'#343746','--bg-card':'#2c2e3c','--bg-hover':'#3a3d50','--bg-input':'#21222c','--text-primary':'#f8f8f2','--text-secondary':'#bfbfb2','--text-muted':'#8995b8','--accent':'#bd93f9','--accent-light':'#d4b8ff','--accent-dark':'#9b6ddb','--border':'#44475a','--border-light':'#565970','--live-red':'#ff5555','--success':'#50fa7b','--warning':'#f1fa8c','--danger':'#ff5555','--info':'#8be9fd','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'189,147,249','--accent-glow':'rgba(189,147,249,0.35)','--color-scheme':'dark' },++ 'monokai': { '--bg-primary':'#272822','--bg-secondary':'#1e1f1c','--bg-tertiary':'#3e3d32','--bg-card':'#2d2e27','--bg-hover':'#49483e','--bg-input':'#22231e','--text-primary':'#f8f8f2','--text-secondary':'#cfcfc2','--text-muted':'#979484','--accent':'#a6e22e','--accent-light':'#c4ff50','--accent-dark':'#7dac1c','--border':'#49483e','--border-light':'#5b5a50','--live-red':'#ef4444','--success':'#22c55e','--warning':'#e6db74','--danger':'#f92672','--info':'#66d9ef','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'166,226,46','--accent-glow':'rgba(166,226,46,0.35)','--color-scheme':'dark' },++ 'ocean-deep': { '--bg-primary':'#0a1215','--bg-secondary':'#0f1a1f','--bg-tertiary':'#162228','--bg-card':'#121c22','--bg-hover':'#1a2a32','--bg-input':'#0c1418','--text-primary':'#d0e8ef','--text-secondary':'#7aa8ba','--text-muted':'#658896','--accent':'#00bcd4','--accent-light':'#4dd0e1','--accent-dark':'#0097a7','--border':'#1a3040','--border-light':'#2a4050','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'0,188,212','--accent-glow':'rgba(0,188,212,0.35)','--color-scheme':'dark' },++ 'sunset': { '--bg-primary':'#120a0a','--bg-secondary':'#1a1010','--bg-tertiary':'#241616','--bg-card':'#1e1212','--bg-hover':'#2e1a1a','--bg-input':'#140c0c','--text-primary':'#ffe8e0','--text-secondary':'#c49080','--text-muted':'#977970','--accent':'#ff6b35','--accent-light':'#ff8f5e','--accent-dark':'#d04a1a','--border':'#3a2020','--border-light':'#4a3030','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'255,107,53','--accent-glow':'rgba(255,107,53,0.35)','--color-scheme':'dark' },++ 'arctic': { '--bg-primary':'#0b1620','--bg-secondary':'#0f1e2b','--bg-tertiary':'#163040','--bg-card':'#122534','--bg-hover':'#1a3a4c','--bg-input':'#0c1a26','--text-primary':'#eaf6ff','--text-secondary':'#9ec3d8','--text-muted':'#7ea3ba','--accent':'#22d3ee','--accent-light':'#a5f3fc','--accent-dark':'#0891b2','--border':'#1e3f52','--border-light':'#2a5268','--live-red':'#ef4444','--success':'#34d399','--warning':'#f59e0b','--danger':'#ef4444','--info':'#7dd3fc','--shadow':'0 2px 12px rgba(2,12,20,0.5)','--shadow-lg':'0 8px 32px rgba(2,12,20,0.65)','--on-accent':'#0b0d10','--accent-rgb':'34,211,238','--accent-glow':'rgba(34,211,238,0.35)','--color-scheme':'dark' },++ 'ember': { '--bg-primary':'#120808','--bg-secondary':'#1a0e0e','--bg-tertiary':'#241414','--bg-card':'#1e1010','--bg-hover':'#2e1818','--bg-input':'#140a0a','--text-primary':'#f0dada','--text-secondary':'#b0808a','--text-muted':'#95787c','--accent':'#ef4444','--accent-light':'#f87171','--accent-dark':'#b91c1c','--border':'#3a1a20','--border-light':'#4a2a30','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'239,68,68','--accent-glow':'rgba(239,68,68,0.35)','--color-scheme':'dark' },++ 'vapor': { '--bg-primary':'#0e0a14','--bg-secondary':'#14101c','--bg-tertiary':'#1c1628','--bg-card':'#181220','--bg-hover':'#241a34','--bg-input':'#100c16','--text-primary':'#f0e0ff','--text-secondary':'#c090e0','--text-muted':'#8f73b7','--accent':'#e040fb','--accent-light':'#ea80fc','--accent-dark':'#aa00d4','--border':'#2a1a40','--border-light':'#3a2a50','--live-red':'#ef4444','--success':'#69f0ae','--warning':'#f59e0b','--danger':'#ef4444','--info':'#00e5ff','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'224,64,251','--accent-glow':'rgba(224,64,251,0.35)','--color-scheme':'dark' },++ 'slate': { '--bg-primary':'#0f1118','--bg-secondary':'#161820','--bg-tertiary':'#1e2028','--bg-card':'#1a1c24','--bg-hover':'#24262e','--bg-input':'#12141c','--text-primary':'#e4e6ea','--text-secondary':'#a0a4b0','--text-muted':'#828690','--accent':'#a78bfa','--accent-light':'#c4b5fd','--accent-dark':'#7c3aed','--border':'#2a2c38','--border-light':'#3a3c48','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'167,139,250','--accent-glow':'rgba(167,139,250,0.35)','--color-scheme':'dark' },++ 'matrix': { '--bg-primary':'#000000','--bg-secondary':'#050a05','--bg-tertiary':'#0a140a','--bg-card':'#071007','--bg-hover':'#0e1e0e','--bg-input':'#030803','--text-primary':'#00ff41','--text-secondary':'#00b030','--text-muted':'#008f25','--accent':'#00ff41','--accent-light':'#66ff8a','--accent-dark':'#00aa2a','--border':'#0a2a0a','--border-light':'#144014','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'0,255,65','--accent-glow':'rgba(0,255,65,0.35)','--color-scheme':'dark' },++ 'nord': { '--bg-primary':'#2e3440','--bg-secondary':'#272c36','--bg-tertiary':'#3b4252','--bg-card':'#333a48','--bg-hover':'#434c5e','--bg-input':'#2a303c','--text-primary':'#eceff4','--text-secondary':'#d8dee9','--text-muted':'#9ba5b8','--accent':'#88c0d0','--accent-light':'#8fbcbb','--accent-dark':'#5e81ac','--border':'#3b4252','--border-light':'#4c566a','--live-red':'#ef4444','--success':'#a3be8c','--warning':'#ebcb8b','--danger':'#bf616a','--info':'#81a1c1','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'136,192,208','--accent-glow':'rgba(136,192,208,0.35)','--color-scheme':'dark' },++ 'gruvbox-dark': { '--bg-primary':'#1d2021','--bg-secondary':'#282828','--bg-tertiary':'#3c3836','--bg-card':'#32302f','--bg-hover':'#504945','--bg-input':'#242424','--text-primary':'#ebdbb2','--text-secondary':'#d5c4a1','--text-muted':'#a69682','--accent':'#fabd2f','--accent-light':'#fce566','--accent-dark':'#d79921','--border':'#3c3836','--border-light':'#504945','--live-red':'#ef4444','--success':'#b8bb26','--warning':'#fe8019','--danger':'#fb4934','--info':'#83a598','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'250,189,47','--accent-glow':'rgba(250,189,47,0.35)','--color-scheme':'dark' },++ 'abyss': { '--bg-primary':'#000000','--bg-secondary':'#080808','--bg-tertiary':'#111111','--bg-card':'#0a0a0a','--bg-hover':'#181818','--bg-input':'#050505','--text-primary':'#cccccc','--text-secondary':'#888888','--text-muted':'#7a7a7a','--accent':'#ffffff','--accent-light':'#ffffff','--accent-dark':'#aaaaaa','--border':'#1a1a1a','--border-light':'#252525','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'255,255,255','--accent-glow':'rgba(255,255,255,0.35)','--color-scheme':'dark' },++ 'copper': { '--bg-primary':'#110d09','--bg-secondary':'#1a140e','--bg-tertiary':'#231c14','--bg-card':'#1e1710','--bg-hover':'#2c2218','--bg-input':'#13100b','--text-primary':'#e8ddd0','--text-secondary':'#b49a80','--text-muted':'#8e7f6a','--accent':'#cd7f32','--accent-light':'#daa060','--accent-dark':'#a06020','--border':'#2a2016','--border-light':'#3a3020','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'205,127,50','--accent-glow':'rgba(205,127,50,0.35)','--color-scheme':'dark' },++ 'sakura-night': { '--bg-primary':'#0e0a14','--bg-secondary':'#150f1c','--bg-tertiary':'#1c1526','--bg-card':'#181020','--bg-hover':'#221830','--bg-input':'#100c16','--text-primary':'#f0e0f0','--text-secondary':'#c0a0c0','--text-muted':'#927592','--accent':'#f472b6','--accent-light':'#f9a8d4','--accent-dark':'#db2777','--border':'#2a1a30','--border-light':'#3a2a40','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'244,114,182','--accent-glow':'rgba(244,114,182,0.35)','--color-scheme':'dark' },++ 'hacker': { '--bg-primary':'#000000','--bg-secondary':'#0a0800','--bg-tertiary':'#141000','--bg-card':'#0e0c00','--bg-hover':'#1c1800','--bg-input':'#060400','--text-primary':'#ffb000','--text-secondary':'#cc8d00','--text-muted':'#a37100','--accent':'#ffb000','--accent-light':'#ffd050','--accent-dark':'#cc8d00','--border':'#1a1400','--border-light':'#2a2200','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'255,176,0','--accent-glow':'rgba(255,176,0,0.35)','--color-scheme':'dark' },++ 'daylight': { '--bg-primary':'#ffffff','--bg-secondary':'#f7f7f8','--bg-tertiary':'#eeeef0','--bg-card':'#ffffff','--bg-hover':'#f0f0f2','--bg-input':'#f5f5f7','--text-primary':'#1a1a2e','--text-secondary':'#4a4a6a','--text-muted':'#747489','--accent':'#8756f3','--accent-light':'#a78bfa','--accent-dark':'#6d28d9','--border':'#e0e0e6','--border-light':'#d0d0d8','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.08)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.12)','--on-accent':'#ffffff','--accent-rgb':'135,86,243','--accent-glow':'rgba(135,86,243,0.35)','--color-scheme':'light' },++ 'paper': { '--bg-primary':'#faf8f5','--bg-secondary':'#f0ece6','--bg-tertiary':'#e8e2d8','--bg-card':'#faf8f5','--bg-hover':'#f0ece6','--bg-input':'#f5f2ed','--text-primary':'#2c2416','--text-secondary':'#5a4e3e','--text-muted':'#7b7061','--accent':'#8b6914','--accent-light':'#b08a30','--accent-dark':'#6a5010','--border':'#ddd6c8','--border-light':'#ccc4b0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,40,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'139,105,20','--accent-glow':'rgba(139,105,20,0.35)','--color-scheme':'light' },++ 'cloud': { '--bg-primary':'#f0f5ff','--bg-secondary':'#e8eef8','--bg-tertiary':'#dde5f0','--bg-card':'#f5f8ff','--bg-hover':'#e4ecf8','--bg-input':'#edf2fa','--text-primary':'#1a2040','--text-secondary':'#4a5070','--text-muted':'#6b718c','--accent':'#2867ed','--accent-light':'#60a5fa','--accent-dark':'#2563eb','--border':'#d0d8ea','--border-light':'#bcc8e0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,20,60,0.06)','--shadow-lg':'0 8px 32px rgba(0,20,60,0.10)','--on-accent':'#ffffff','--accent-rgb':'40,103,237','--accent-glow':'rgba(40,103,237,0.35)','--color-scheme':'light' },++ 'meadow': { '--bg-primary':'#f2f8f0','--bg-secondary':'#e8f0e4','--bg-tertiary':'#dce8d6','--bg-card':'#f5faf2','--bg-hover':'#e4f0de','--bg-input':'#edf5ea','--text-primary':'#1a2e16','--text-secondary':'#3a5a32','--text-muted':'#5d7a54','--accent':'#15823e','--accent-light':'#22c55e','--accent-dark':'#15803d','--border':'#c8dcc0','--border-light':'#b0ccaa','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(0,40,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'21,130,62','--accent-glow':'rgba(21,130,62,0.35)','--color-scheme':'light' },++ 'peach': { '--bg-primary':'#fff5f0','--bg-secondary':'#fbeae2','--bg-tertiary':'#f5ddd2','--bg-card':'#fff7f2','--bg-hover':'#fce8dc','--bg-input':'#fdf0ea','--text-primary':'#2e1a14','--text-secondary':'#6a4438','--text-muted':'#8f6a5c','--accent':'#c04808','--accent-light':'#fb923c','--accent-dark':'#ea580c','--border':'#f0d0c0','--border-light':'#e4bfab','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,20,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,20,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'192,72,8','--accent-glow':'rgba(192,72,8,0.35)','--color-scheme':'light' },++ 'lavender': { '--bg-primary':'#f8f5ff','--bg-secondary':'#f0eaf8','--bg-tertiary':'#e6ddf0','--bg-card':'#faf7ff','--bg-hover':'#eee6f8','--bg-input':'#f4f0fa','--text-primary':'#1e1430','--text-secondary':'#4a3a60','--text-muted':'#796a92','--accent':'#844cf2','--accent-light':'#a78bfa','--accent-dark':'#7c3aed','--border':'#ddd0ee','--border-light':'#ccc0dd','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(40,0,60,0.06)','--shadow-lg':'0 8px 32px rgba(40,0,60,0.10)','--on-accent':'#ffffff','--accent-rgb':'132,76,242','--accent-glow':'rgba(132,76,242,0.35)','--color-scheme':'light' },++ 'gruvbox-light': { '--bg-primary':'#fbf1c7','--bg-secondary':'#f2e5bc','--bg-tertiary':'#ebdbb2','--bg-card':'#fbf1c7','--bg-hover':'#f2e5bc','--bg-input':'#f5ecc4','--text-primary':'#3c3836','--text-secondary':'#504945','--text-muted':'#766b60','--accent':'#be4707','--accent-light':'#fe8019','--accent-dark':'#af3a03','--border':'#d5c4a1','--border-light':'#bdae93','--live-red':'#ef4444','--success':'#98971a','--warning':'#d79921','--danger':'#cc241d','--info':'#458588','--shadow':'0 2px 12px rgba(40,30,0,0.08)','--shadow-lg':'0 8px 32px rgba(40,30,0,0.12)','--on-accent':'#ffffff','--accent-rgb':'190,71,7','--accent-glow':'rgba(190,71,7,0.35)','--color-scheme':'light' },++ 'snow': { '--bg-primary':'#ffffff','--bg-secondary':'#f8fafc','--bg-tertiary':'#f1f5f9','--bg-card':'#ffffff','--bg-hover':'#f1f5f9','--bg-input':'#f8fafc','--text-primary':'#0f172a','--text-secondary':'#334155','--text-muted':'#69768b','--accent':'#027cbb','--accent-light':'#38bdf8','--accent-dark':'#0284c7','--border':'#e2e8f0','--border-light':'#cbd5e1','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.05)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.08)','--on-accent':'#ffffff','--accent-rgb':'2,124,187','--accent-glow':'rgba(2,124,187,0.35)','--color-scheme':'light' },++ 'sand': { '--bg-primary':'#f8f4ef','--bg-secondary':'#f0e8de','--bg-tertiary':'#e8ddd0','--bg-card':'#faf6f0','--bg-hover':'#f0e8de','--bg-input':'#f5f0e8','--text-primary':'#2e2418','--text-secondary':'#5a4e3e','--text-muted':'#7a6e5f','--accent':'#8c6707','--accent-light':'#daa520','--accent-dark':'#8b6508','--border':'#ddd0be','--border-light':'#ccc0aa','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,40,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'140,103,7','--accent-glow':'rgba(140,103,7,0.35)','--color-scheme':'light' },++ 'rose': { '--bg-primary':'#fff5f7','--bg-secondary':'#fce7ec','--bg-tertiary':'#f5d5de','--bg-card':'#fff7f9','--bg-hover':'#fce0e8','--bg-input':'#fdeef2','--text-primary':'#2e1420','--text-secondary':'#6a3850','--text-muted':'#96617e','--accent':'#de1c47','--accent-light':'#f43f5e','--accent-dark':'#be123c','--border':'#f0c8d4','--border-light':'#e4b0c0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,0,20,0.06)','--shadow-lg':'0 8px 32px rgba(60,0,20,0.10)','--on-accent':'#ffffff','--accent-rgb':'222,28,71','--accent-glow':'rgba(222,28,71,0.35)','--color-scheme':'light' },++ 'solarized-dark': { '--bg-primary':'#002b36','--bg-secondary':'#073642','--bg-tertiary':'#0a3f4e','--bg-card':'#053542','--bg-hover':'#0d4a58','--bg-input':'#01303d','--text-primary':'#fdf6e3','--text-secondary':'#93a1a1','--text-muted':'#909c9a','--accent':'#b58900','--accent-light':'#d4a017','--accent-dark':'#8a6a00','--border':'#0a4050','--border-light':'#105060','--live-red':'#ef4444','--success':'#859900','--warning':'#cb4b16','--danger':'#dc322f','--info':'#268bd2','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'181,137,0','--accent-glow':'rgba(181,137,0,0.35)','--color-scheme':'dark' },++ 'solarized-light': { '--bg-primary':'#fdf6e3','--bg-secondary':'#eee8d5','--bg-tertiary':'#e4ddc6','--bg-card':'#fdf6e3','--bg-hover':'#eee8d5','--bg-input':'#f5eedb','--text-primary':'#002b36','--text-secondary':'#586e75','--text-muted':'#5b7478','--accent':'#8d6c00','--accent-light':'#d4a017','--accent-dark':'#8a6a00','--border':'#d6ceb5','--border-light':'#c8c0a5','--live-red':'#ef4444','--success':'#859900','--warning':'#cb4b16','--danger':'#dc322f','--info':'#268bd2','--shadow':'0 2px 12px rgba(0,30,40,0.08)','--shadow-lg':'0 8px 32px rgba(0,30,40,0.12)','--on-accent':'#ffffff','--accent-rgb':'141,108,0','--accent-glow':'rgba(141,108,0,0.35)','--color-scheme':'light' },++ 'catppuccin-mocha': { '--bg-primary':'#1e1e2e','--bg-secondary':'#181825','--bg-tertiary':'#313244','--bg-card':'#1e1e2e','--bg-hover':'#313244','--bg-input':'#1a1a2c','--text-primary':'#cdd6f4','--text-secondary':'#bac2de','--text-muted':'#81869e','--accent':'#cba6f7','--accent-light':'#dcc0ff','--accent-dark':'#b07de0','--border':'#313244','--border-light':'#45475a','--live-red':'#f38ba8','--success':'#a6e3a1','--warning':'#fab387','--danger':'#f38ba8','--info':'#89b4fa','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'203,166,247','--accent-glow':'rgba(203,166,247,0.35)','--color-scheme':'dark' },++ 'catppuccin-latte': { '--bg-primary':'#eff1f5','--bg-secondary':'#e6e9ef','--bg-tertiary':'#dce0e8','--bg-card':'#eff1f5','--bg-hover':'#dce0e8','--bg-input':'#e8ebf0','--text-primary':'#4c4f69','--text-secondary':'#5c5f77','--text-muted':'#696c83','--accent':'#8839ef','--accent-light':'#a05cff','--accent-dark':'#7028d4','--border':'#ccd0da','--border-light':'#bcc0cc','--live-red':'#d20f39','--success':'#40a02b','--warning':'#fe640b','--danger':'#d20f39','--info':'#1e66f5','--shadow':'0 2px 12px rgba(0,0,0,0.06)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'136,57,239','--accent-glow':'rgba(136,57,239,0.35)','--color-scheme':'light' },++ 'high-contrast': { '--bg-primary':'#000000','--bg-secondary':'#0a0a0a','--bg-tertiary':'#1a1a1a','--bg-card':'#0f0f0f','--bg-hover':'#222222','--bg-input':'#0a0a0a','--text-primary':'#ffffff','--text-secondary':'#f0f0f0','--text-muted':'#aaaaaa','--accent':'#ffd700','--accent-light':'#ffed4a','--accent-dark':'#ccac00','--border':'#444444','--border-light':'#666666','--live-red':'#ff0000','--success':'#00ff00','--warning':'#ffff00','--danger':'#ff0000','--info':'#00ffff','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'255,215,0','--accent-glow':'rgba(255,215,0,0.35)','--color-scheme':'dark' },};// THEMES:END@@@ -105,6 +105,9 @@for (const [prop, val] of Object.entries(vars)) {if (prop.startsWith('--')) el.style.setProperty(prop, val);}++ // Native controls, scrollbars and form fields follow the theme's light/dark mode.++ const scheme = vars['--color-scheme'];++ if (scheme === 'light' || scheme === 'dark') { el.style.colorScheme = scheme; el.setAttribute('data-theme-mode', scheme); }}/**@@@ -1,6 +1,6 @@'use strict';--const { BUILTIN_THEMES, DEFAULT_VARS } = require('./builtin-themes');++const { BUILTIN_THEMES, DEFAULT_VARS, deriveTokens } = require('./builtin-themes');// ═══════════════════════════════════════════════════════════════// OpenVibe — Theme Sync Engine@@@ -15,6 +15,8 @@ const CSS_VARIABLES = ['--accent', '--accent-light', '--accent-dark','--live-red', '--success', '--warning', '--danger', '--info','--border', '--border-light', '--shadow', '--shadow-lg',++ // Derived on every theme (builtin-themes.js deriveTokens); community themes get them too.++ '--on-accent', '--accent-rgb', '--accent-glow', '--color-scheme',];const NORMALIZED_DEFAULT_VARS = Object.freeze({ ...DEFAULT_VARS });@@@ -44,7 +46,7 @@ function sanitizeCssValue(value) {*/function applyTheme(theme, target) {if (!theme || !theme.variables) return;-- const vars = { ...NORMALIZED_DEFAULT_VARS, ...theme.variables };++ const vars = deriveTokens({ ...NORMALIZED_DEFAULT_VARS, ...theme.variables }, theme.mode);for (const [key, value] of Object.entries(vars)) {if (!CSS_VARIABLES.includes(key)) continue;const safe = sanitizeCssValue(value);
@@ -59,7 +59,7 @@ test/authorization were also run against the previous code and failed there, cas
@@ -59,7 +59,7 @@ test/authorization were also run against the previous code and failed there, cas
| Low-Medium | Anyone could set the saved playback position of any media request (unauthenticated). | Channel managers only. | authorization |
| Low-Medium | Anyone could set the saved playback position of any media request (unauthenticated). | Channel managers only. | authorization |
| Low-Medium | AI viewer "clone" copied any user's chat history from every channel (and their AI insight) into a bot. | Streamers clone only from what that person said in their own channel; staff unchanged. | authorization |
| Low-Medium | AI viewer "clone" copied any user's chat history from every channel (and their AI insight) into a bot. | Streamers clone only from what that person said in their own channel; staff unchanged. | authorization |
| Low-Medium | No limit on chat WebSocket connections per address. | 48 per address (admins exempt); clients back off to 30 s on a 4029 close. | test/chat-connection-cap.test.js |
| Low-Medium | No limit on chat WebSocket connections per address. | 48 per address (admins exempt); clients back off to 30 s on a 4029 close. | test/chat-connection-cap.test.js |
-| Medium | Voice: 1:1 call channels were listed publicly and anyone (anonymous included) could walk into them; `call-user` had no rate limit or block check; anyone could answer any invite; a kicked user could rejoin at once; one host could fill the 8-seat Public channel; TURN was emitted without credentials on a box with no secret; static TURN credentials went to every visitor. | Private calls hidden from strangers and invite-only; call-user 6/min + block check; respond requires the invite; 60 s kick cooldown; 3 sockets per address, duplicate accounts replaced; TURN only with credentials, optional short-lived HMAC credentials (`TURN_AUTH_SECRET`, coturn `use-auth-secret`). | manual + two-client voice test |
+| Medium | Voice: 1:1 call channels were listed publicly and anyone (anonymous included) could walk into them; `call-user` had no rate limit or block check; anyone could answer any invite; a kicked user could rejoin at once; one host could fill the 8-seat Public channel; TURN was emitted without credentials on a box with no secret; static TURN credentials went to every visitor. | Private calls hidden from strangers and invite-only; call-user 6/min + block check; respond requires the invite; 60 s kick cooldown; 3 sockets per address, duplicate accounts replaced; TURN only with credentials; production coturn now runs `use-auth-secret` and every ICE list (voice and SFU, `server/net/turn.js`) carries a credential that expires after an hour — the old static pair no longer authenticates. | test/turn-credentials.test.js + relay probe on the host |
| Low | Slot `control_config_id` accepted other users' profiles; restream viewer counts writable for any destination. | Ownership checks. | manual |
| Low | Slot `control_config_id` accepted other users' profiles; restream viewer counts writable for any destination. | Ownership checks. | manual |
| Low | ONVIF discovery (LAN scan with default-password probing) available to every user. | Admin only, bounded timeout. | manual |
| Low | ONVIF discovery (LAN scan with default-password probing) available to every user. | Admin only, bounded timeout. | manual |
| Low | RobotStreamer API calls carrying the user's RS token disabled TLS verification. | Verification on for api.robotstreamer.com (valid certificate). | manual |
| Low | RobotStreamer API calls carrying the user's RS token disabled TLS verification. | Verification on for api.robotstreamer.com (valid certificate). | manual |
@@ -93,7 +93,6 @@ validation, private VOD cache leak, HTTP-FLV bound to loopback, admin bans never
@@ -93,7 +93,6 @@ validation, private VOD cache leak, HTTP-FLV bound to loopback, admin bans never
| Medium | Inline event handlers keep `'unsafe-inline'` in the enforced CSP. | Progressive migration (see §3). |
| Medium | Inline event handlers keep `'unsafe-inline'` in the enforced CSP. | Progressive migration (see §3). |
| Medium | Per-address limits (broadcast viewers, rate limits) trust `CF-Connecting-IP`; if the origin is reachable without Cloudflare that header is spoofable. | Firewall the origin to Cloudflare ranges (deploy/cloudflare/checklist.md). |
| Medium | Per-address limits (broadcast viewers, rate limits) trust `CF-Connecting-IP`; if the origin is reachable without Cloudflare that header is spoofable. | Firewall the origin to Cloudflare ranges (deploy/cloudflare/checklist.md). |
| Low | Chat connect/close/join still scan every client to update counts. | Profile under load before indexing clients by room. |
| Low | Chat connect/close/join still scan every client to update counts. | Profile under load before indexing clients by room. |
-| Low | Voice TURN credentials are still the static pair until `TURN_AUTH_SECRET` is set and coturn switched to `use-auth-secret` (production change). | Configure the secret on the host. |
| Low | RobotStreamer SFU WebSocket connections still skip certificate verification (hosts are assigned by RS at runtime). | Confirm RS SFU certificates and enable verification. |
| Low | RobotStreamer SFU WebSocket connections still skip certificate verification (hosts are assigned by RS at runtime). | Confirm RS SFU certificates and enable verification. |
| Low | Analytics roll-ups and the 90-day DELETE run synchronously on the main thread (vendor/openvibe-shared/analytics.js). | Companion change in OpenVibe.Network's openvibe-shared, then re-sync. |
| Low | Analytics roll-ups and the 90-day DELETE run synchronously on the main thread (vendor/openvibe-shared/analytics.js). | Companion change in OpenVibe.Network's openvibe-shared, then re-sync. |
@@ -22,7 +22,7 @@
@@ -22,7 +22,7 @@
--accent: #3b82f6; /* OpenVibe blue */
--accent: #3b82f6; /* OpenVibe blue */
--accent-light: #60a5fa;
--accent-light: #60a5fa;
--accent-dark: #1d4ed8;
--accent-dark: #1d4ed8;
- --on-accent: #0b0d10; /* readable text/icon color on top of --accent (themes override) */
+ --on-accent: #ffffff; /* readable text/icon color on top of --accent; every theme sets its own */
--live-red: #ef4444;
--live-red: #ef4444;
--success: #22c55e;
--success: #22c55e;
@@ -5,7 +5,7 @@ const RAW_BUILTIN_THEMES = [
@@ -5,7 +5,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Vibe',
name: 'Vibe',
slug: 'vibe',
slug: 'vibe',
mode: 'dark',
mode: 'dark',
- description: 'The OpenVibe default: deep blue night with an electric-blue glow.',
+ description: 'OpenVibe\'s default: deep blue night with an electric-blue glow.',
tags: ['default', 'cool', 'blue'],
tags: ['default', 'cool', 'blue'],
variables: {
variables: {
'--bg-primary': '#0a0f1c',
'--bg-primary': '#0a0f1c',
@@ -32,10 +32,10 @@ const RAW_BUILTIN_THEMES = [
@@ -32,10 +32,10 @@ const RAW_BUILTIN_THEMES = [
},
},
},
},
{
{
- name: 'Classic Vibe',
- slug: 'vibe-classic',
+ name: 'Violet Hour',
+ slug: 'violet-hour',
mode: 'dark',
mode: 'dark',
- description: 'The original OpenVibe look: violet over charcoal.',
+ description: 'Charcoal and violet: the colours OpenVibe started with.',
tags: ['classic', 'purple', 'warm'],
tags: ['classic', 'purple', 'warm'],
variables: {
variables: {
'--bg-primary': '#0d0d0f',
'--bg-primary': '#0d0d0f',
@@ -65,7 +65,7 @@ const RAW_BUILTIN_THEMES = [
@@ -65,7 +65,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Midnight',
name: 'Midnight',
slug: 'midnight',
slug: 'midnight',
mode: 'dark',
mode: 'dark',
- description: 'Deep blue-black with cool steel accents.',
+ description: 'Blue-black with steel-indigo light.',
tags: ['cool', 'minimal', 'blue'],
tags: ['cool', 'minimal', 'blue'],
variables: {
variables: {
'--bg-primary': '#0a0e17',
'--bg-primary': '#0a0e17',
@@ -85,10 +85,10 @@ const RAW_BUILTIN_THEMES = [
@@ -85,10 +85,10 @@ const RAW_BUILTIN_THEMES = [
},
},
},
},
{
{
- name: 'Forest',
+ name: 'Understory',
slug: 'forest',
slug: 'forest',
mode: 'dark',
mode: 'dark',
- description: 'Deep greens and earthy tones — nature at night.',
+ description: 'Deep greens under the canopy.',
tags: ['nature', 'green', 'earthy'],
tags: ['nature', 'green', 'earthy'],
variables: {
variables: {
'--bg-primary': '#0a120a',
'--bg-primary': '#0a120a',
@@ -111,7 +111,7 @@ const RAW_BUILTIN_THEMES = [
@@ -111,7 +111,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Neon Tokyo',
name: 'Neon Tokyo',
slug: 'neon-tokyo',
slug: 'neon-tokyo',
mode: 'dark',
mode: 'dark',
- description: 'Cyberpunk neon pink/purple over dark chrome.',
+ description: 'Hot pink neon on wet chrome.',
tags: ['cyberpunk', 'neon', 'vibrant'],
tags: ['cyberpunk', 'neon', 'vibrant'],
variables: {
variables: {
'--bg-primary': '#0a0a0f',
'--bg-primary': '#0a0a0f',
@@ -134,7 +134,7 @@ const RAW_BUILTIN_THEMES = [
@@ -134,7 +134,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Dracula',
name: 'Dracula',
slug: 'dracula',
slug: 'dracula',
mode: 'dark',
mode: 'dark',
- description: 'The beloved Dracula color scheme.',
+ description: 'The Dracula scheme, as its authors drew it.',
tags: ['popular', 'purple', 'classic'],
tags: ['popular', 'purple', 'classic'],
variables: {
variables: {
'--bg-primary': '#282a36',
'--bg-primary': '#282a36',
@@ -162,7 +162,7 @@ const RAW_BUILTIN_THEMES = [
@@ -162,7 +162,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Monokai',
name: 'Monokai',
slug: 'monokai',
slug: 'monokai',
mode: 'dark',
mode: 'dark',
- description: 'Classic Monokai developer palette.',
+ description: 'The Monokai editor palette.',
tags: ['developer', 'classic', 'warm'],
tags: ['developer', 'classic', 'warm'],
variables: {
variables: {
'--bg-primary': '#272822',
'--bg-primary': '#272822',
@@ -185,10 +185,10 @@ const RAW_BUILTIN_THEMES = [
@@ -185,10 +185,10 @@ const RAW_BUILTIN_THEMES = [
},
},
},
},
{
{
- name: 'Ocean Deep',
+ name: 'Trench',
slug: 'ocean-deep',
slug: 'ocean-deep',
mode: 'dark',
mode: 'dark',
- description: 'Dark ocean depths with teal highlights.',
+ description: 'Pressure-dark water with a teal glow.',
tags: ['ocean', 'teal', 'calm'],
tags: ['ocean', 'teal', 'calm'],
variables: {
variables: {
'--bg-primary': '#0a1215',
'--bg-primary': '#0a1215',
@@ -208,10 +208,10 @@ const RAW_BUILTIN_THEMES = [
@@ -208,10 +208,10 @@ const RAW_BUILTIN_THEMES = [
},
},
},
},
{
{
- name: 'Sunset',
+ name: 'Dusk',
slug: 'sunset',
slug: 'sunset',
mode: 'dark',
mode: 'dark',
- description: 'Warm orange-to-pink gradient vibes at dusk.',
+ description: 'Orange fading to rose over dark ground.',
tags: ['warm', 'gradient', 'vibrant'],
tags: ['warm', 'gradient', 'vibrant'],
variables: {
variables: {
'--bg-primary': '#120a0a',
'--bg-primary': '#120a0a',
@@ -234,7 +234,7 @@ const RAW_BUILTIN_THEMES = [
@@ -234,7 +234,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Arctic',
name: 'Arctic',
slug: 'arctic',
slug: 'arctic',
mode: 'dark',
mode: 'dark',
- description: 'Frost: ice-blue surfaces, cyan light and crisp white text.',
+ description: 'Frost surfaces, cyan light, crisp white text.',
tags: ['cool', 'ice', 'clean'],
tags: ['cool', 'ice', 'clean'],
variables: {
variables: {
'--bg-primary': '#0b1620',
'--bg-primary': '#0b1620',
@@ -261,7 +261,7 @@ const RAW_BUILTIN_THEMES = [
@@ -261,7 +261,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Ember',
name: 'Ember',
slug: 'ember',
slug: 'ember',
mode: 'dark',
mode: 'dark',
- description: 'Smoldering reds and warm charcoal.',
+ description: 'Smouldering red on warm charcoal.',
tags: ['red', 'warm', 'intense'],
tags: ['red', 'warm', 'intense'],
variables: {
variables: {
'--bg-primary': '#120808',
'--bg-primary': '#120808',
@@ -284,7 +284,7 @@ const RAW_BUILTIN_THEMES = [
@@ -284,7 +284,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Vapor',
name: 'Vapor',
slug: 'vapor',
slug: 'vapor',
mode: 'dark',
mode: 'dark',
- description: 'Vaporwave aesthetics — pink, purple, and teal.',
+ description: 'Magenta and teal, straight off a VHS tape.',
tags: ['retro', 'aesthetic', 'neon'],
tags: ['retro', 'aesthetic', 'neon'],
variables: {
variables: {
'--bg-primary': '#0e0a14',
'--bg-primary': '#0e0a14',
@@ -309,7 +309,7 @@ const RAW_BUILTIN_THEMES = [
@@ -309,7 +309,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Slate',
name: 'Slate',
slug: 'slate',
slug: 'slate',
mode: 'dark',
mode: 'dark',
- description: 'Neutral gray with subtle blue undertones.',
+ description: 'Neutral grey with a cool violet accent.',
tags: ['neutral', 'minimal', 'professional'],
tags: ['neutral', 'minimal', 'professional'],
variables: {
variables: {
'--bg-primary': '#0f1118',
'--bg-primary': '#0f1118',
@@ -332,7 +332,7 @@ const RAW_BUILTIN_THEMES = [
@@ -332,7 +332,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Matrix',
name: 'Matrix',
slug: 'matrix',
slug: 'matrix',
mode: 'dark',
mode: 'dark',
- description: 'Green terminal text on pitch black.',
+ description: 'Green phosphor on black.',
tags: ['hacker', 'retro', 'terminal'],
tags: ['hacker', 'retro', 'terminal'],
variables: {
variables: {
'--bg-primary': '#000000',
'--bg-primary': '#000000',
@@ -355,7 +355,7 @@ const RAW_BUILTIN_THEMES = [
@@ -355,7 +355,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Nord',
name: 'Nord',
slug: 'nord',
slug: 'nord',
mode: 'dark',
mode: 'dark',
- description: 'Arctic, north-bluish color palette inspired by the Nord theme.',
+ description: 'The Nord palette: muted polar blues.',
tags: ['popular', 'blue', 'soft'],
tags: ['popular', 'blue', 'soft'],
variables: {
variables: {
'--bg-primary': '#2e3440',
'--bg-primary': '#2e3440',
@@ -379,10 +379,10 @@ const RAW_BUILTIN_THEMES = [
@@ -379,10 +379,10 @@ const RAW_BUILTIN_THEMES = [
},
},
},
},
{
{
- name: 'Gruvbox Dark',
+ name: 'Gruvbox',
slug: 'gruvbox-dark',
slug: 'gruvbox-dark',
mode: 'dark',
mode: 'dark',
- description: 'Retro groove colors with warm, high-contrast tones.',
+ description: 'Warm retro contrast.',
tags: ['retro', 'warm', 'developer'],
tags: ['retro', 'warm', 'developer'],
variables: {
variables: {
'--bg-primary': '#1d2021',
'--bg-primary': '#1d2021',
@@ -409,7 +409,7 @@ const RAW_BUILTIN_THEMES = [
@@ -409,7 +409,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Abyss',
name: 'Abyss',
slug: 'abyss',
slug: 'abyss',
mode: 'dark',
mode: 'dark',
- description: 'The deepest dark — nearly pure black with dim accents.',
+ description: 'Nearly black; the interface is the light.',
tags: ['minimal', 'ultra-dark', 'oled'],
tags: ['minimal', 'ultra-dark', 'oled'],
variables: {
variables: {
'--bg-primary': '#000000',
'--bg-primary': '#000000',
@@ -432,7 +432,7 @@ const RAW_BUILTIN_THEMES = [
@@ -432,7 +432,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Copper',
name: 'Copper',
slug: 'copper',
slug: 'copper',
mode: 'dark',
mode: 'dark',
- description: 'Rich copper and bronze on dark walnut.',
+ description: 'Bronze on dark walnut.',
tags: ['metallic', 'warm', 'premium'],
tags: ['metallic', 'warm', 'premium'],
variables: {
variables: {
'--bg-primary': '#110d09',
'--bg-primary': '#110d09',
@@ -452,10 +452,10 @@ const RAW_BUILTIN_THEMES = [
@@ -452,10 +452,10 @@ const RAW_BUILTIN_THEMES = [
},
},
},
},
{
{
- name: 'Sakura Night',
+ name: 'Sakura',
slug: 'sakura-night',
slug: 'sakura-night',
mode: 'dark',
mode: 'dark',
- description: 'Soft pink cherry blossom on dark indigo.',
+ description: 'Cherry blossom on indigo.',
tags: ['japanese', 'pink', 'soft'],
tags: ['japanese', 'pink', 'soft'],
variables: {
variables: {
'--bg-primary': '#0e0a14',
'--bg-primary': '#0e0a14',
@@ -475,10 +475,10 @@ const RAW_BUILTIN_THEMES = [
@@ -475,10 +475,10 @@ const RAW_BUILTIN_THEMES = [
},
},
},
},
{
{
- name: 'Hacker',
+ name: 'Amber',
slug: 'hacker',
slug: 'hacker',
mode: 'dark',
mode: 'dark',
- description: 'Amber-on-black retro terminal look.',
+ description: 'Amber phosphor on black.',
tags: ['retro', 'terminal', 'nostalgia'],
tags: ['retro', 'terminal', 'nostalgia'],
variables: {
variables: {
'--bg-primary': '#000000',
'--bg-primary': '#000000',
@@ -501,7 +501,7 @@ const RAW_BUILTIN_THEMES = [
@@ -501,7 +501,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Daylight',
name: 'Daylight',
slug: 'daylight',
slug: 'daylight',
mode: 'light',
mode: 'light',
- description: 'Clean, bright white with warm accents for daytime use.',
+ description: 'Bright white with warm accents.',
tags: ['clean', 'bright', 'default-light'],
tags: ['clean', 'bright', 'default-light'],
variables: {
variables: {
'--bg-primary': '#ffffff',
'--bg-primary': '#ffffff',
@@ -526,7 +526,7 @@ const RAW_BUILTIN_THEMES = [
@@ -526,7 +526,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Paper',
name: 'Paper',
slug: 'paper',
slug: 'paper',
mode: 'light',
mode: 'light',
- description: 'Warm off-white like aged paper with ink accents.',
+ description: 'Aged paper and ink.',
tags: ['warm', 'soft', 'minimal'],
tags: ['warm', 'soft', 'minimal'],
variables: {
variables: {
'--bg-primary': '#faf8f5',
'--bg-primary': '#faf8f5',
@@ -551,7 +551,7 @@ const RAW_BUILTIN_THEMES = [
@@ -551,7 +551,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Cloud',
name: 'Cloud',
slug: 'cloud',
slug: 'cloud',
mode: 'light',
mode: 'light',
- description: 'Airy light blue with sky accents.',
+ description: 'Airy blue-white with sky accents.',
tags: ['blue', 'airy', 'fresh'],
tags: ['blue', 'airy', 'fresh'],
variables: {
variables: {
'--bg-primary': '#f0f5ff',
'--bg-primary': '#f0f5ff',
@@ -576,7 +576,7 @@ const RAW_BUILTIN_THEMES = [
@@ -576,7 +576,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Meadow',
name: 'Meadow',
slug: 'meadow',
slug: 'meadow',
mode: 'light',
mode: 'light',
- description: 'Fresh spring greens with natural tones.',
+ description: 'Spring greens in daylight.',
tags: ['nature', 'green', 'fresh'],
tags: ['nature', 'green', 'fresh'],
variables: {
variables: {
'--bg-primary': '#f2f8f0',
'--bg-primary': '#f2f8f0',
@@ -601,7 +601,7 @@ const RAW_BUILTIN_THEMES = [
@@ -601,7 +601,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Peach',
name: 'Peach',
slug: 'peach',
slug: 'peach',
mode: 'light',
mode: 'light',
- description: 'Soft peachy pinks with warm coral accents.',
+ description: 'Peach and coral, soft and warm.',
tags: ['warm', 'pink', 'soft'],
tags: ['warm', 'pink', 'soft'],
variables: {
variables: {
'--bg-primary': '#fff5f0',
'--bg-primary': '#fff5f0',
@@ -626,7 +626,7 @@ const RAW_BUILTIN_THEMES = [
@@ -626,7 +626,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Lavender',
name: 'Lavender',
slug: 'lavender',
slug: 'lavender',
mode: 'light',
mode: 'light',
- description: 'Gentle purple hues — calming and elegant.',
+ description: 'Calm pale violet.',
tags: ['purple', 'calm', 'elegant'],
tags: ['purple', 'calm', 'elegant'],
variables: {
variables: {
'--bg-primary': '#f8f5ff',
'--bg-primary': '#f8f5ff',
@@ -651,7 +651,7 @@ const RAW_BUILTIN_THEMES = [
@@ -651,7 +651,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Gruvbox Light',
name: 'Gruvbox Light',
slug: 'gruvbox-light',
slug: 'gruvbox-light',
mode: 'light',
mode: 'light',
- description: 'Light retro groove — warm cream with bold accents.',
+ description: 'Cream with bold retro accents.',
tags: ['retro', 'warm', 'developer'],
tags: ['retro', 'warm', 'developer'],
variables: {
variables: {
'--bg-primary': '#fbf1c7',
'--bg-primary': '#fbf1c7',
@@ -680,7 +680,7 @@ const RAW_BUILTIN_THEMES = [
@@ -680,7 +680,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Snow',
name: 'Snow',
slug: 'snow',
slug: 'snow',
mode: 'light',
mode: 'light',
- description: 'Pure white with icy blue accents.',
+ description: 'Pure white with icy blue.',
tags: ['minimal', 'clean', 'blue'],
tags: ['minimal', 'clean', 'blue'],
variables: {
variables: {
'--bg-primary': '#ffffff',
'--bg-primary': '#ffffff',
@@ -705,7 +705,7 @@ const RAW_BUILTIN_THEMES = [
@@ -705,7 +705,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Sand',
name: 'Sand',
slug: 'sand',
slug: 'sand',
mode: 'light',
mode: 'light',
- description: 'Desert sand and warm tan tones.',
+ description: 'Desert tan and warm stone.',
tags: ['warm', 'earthy', 'desert'],
tags: ['warm', 'earthy', 'desert'],
variables: {
variables: {
'--bg-primary': '#f8f4ef',
'--bg-primary': '#f8f4ef',
@@ -730,7 +730,7 @@ const RAW_BUILTIN_THEMES = [
@@ -730,7 +730,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Rose',
name: 'Rose',
slug: 'rose',
slug: 'rose',
mode: 'light',
mode: 'light',
- description: 'Delicate rose pink with warm blush tones.',
+ description: 'Blush pink, light and delicate.',
tags: ['pink', 'romantic', 'soft'],
tags: ['pink', 'romantic', 'soft'],
variables: {
variables: {
'--bg-primary': '#fff5f7',
'--bg-primary': '#fff5f7',
@@ -755,7 +755,7 @@ const RAW_BUILTIN_THEMES = [
@@ -755,7 +755,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Solarized Dark',
name: 'Solarized Dark',
slug: 'solarized-dark',
slug: 'solarized-dark',
mode: 'dark',
mode: 'dark',
- description: 'Ethan Schoonover\'s precision color scheme — dark variant.',
+ description: 'Ethan Schoonover\'s precision palette, dark.',
tags: ['popular', 'developer', 'balanced'],
tags: ['popular', 'developer', 'balanced'],
variables: {
variables: {
'--bg-primary': '#002b36',
'--bg-primary': '#002b36',
@@ -782,7 +782,7 @@ const RAW_BUILTIN_THEMES = [
@@ -782,7 +782,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Solarized Light',
name: 'Solarized Light',
slug: 'solarized-light',
slug: 'solarized-light',
mode: 'light',
mode: 'light',
- description: 'Ethan Schoonover\'s precision color scheme — light variant.',
+ description: 'Ethan Schoonover\'s precision palette, light.',
tags: ['popular', 'developer', 'balanced'],
tags: ['popular', 'developer', 'balanced'],
variables: {
variables: {
'--bg-primary': '#fdf6e3',
'--bg-primary': '#fdf6e3',
@@ -811,7 +811,7 @@ const RAW_BUILTIN_THEMES = [
@@ -811,7 +811,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Catppuccin Mocha',
name: 'Catppuccin Mocha',
slug: 'catppuccin-mocha',
slug: 'catppuccin-mocha',
mode: 'dark',
mode: 'dark',
- description: 'Soothing pastel theme for the high-spirited.',
+ description: 'Soothing pastels on mocha.',
tags: ['popular', 'pastel', 'soft'],
tags: ['popular', 'pastel', 'soft'],
variables: {
variables: {
'--bg-primary': '#1e1e2e',
'--bg-primary': '#1e1e2e',
@@ -839,7 +839,7 @@ const RAW_BUILTIN_THEMES = [
@@ -839,7 +839,7 @@ const RAW_BUILTIN_THEMES = [
name: 'Catppuccin Latte',
name: 'Catppuccin Latte',
slug: 'catppuccin-latte',
slug: 'catppuccin-latte',
mode: 'light',
mode: 'light',
- description: 'Soothing pastel theme — light variant.',
+ description: 'Soothing pastels on latte.',
tags: ['popular', 'pastel', 'soft'],
tags: ['popular', 'pastel', 'soft'],
variables: {
variables: {
'--bg-primary': '#eff1f5',
'--bg-primary': '#eff1f5',
@@ -869,7 +869,7 @@ const RAW_BUILTIN_THEMES = [
@@ -869,7 +869,7 @@ const RAW_BUILTIN_THEMES = [
name: 'High Contrast',
name: 'High Contrast',
slug: 'high-contrast',
slug: 'high-contrast',
mode: 'dark',
mode: 'dark',
- description: 'Maximum contrast for accessibility — bold yellow on black.',
+ description: 'Bold yellow on black for maximum legibility.',
tags: ['accessibility', 'high-contrast', 'bold'],
tags: ['accessibility', 'high-contrast', 'bold'],
variables: {
variables: {
'--bg-primary': '#000000',
'--bg-primary': '#000000',
@@ -895,11 +895,45 @@ const RAW_BUILTIN_THEMES = [
@@ -895,11 +895,45 @@ const RAW_BUILTIN_THEMES = [
},
},
];
];
+// ── Derived tokens ──────────────────────────────────────────────────────────────
+// Every theme also carries tokens a site cannot guess from the palette alone:
+// --on-accent text/icon colour that reads on top of --accent (dark ink for light accents
+// such as cyan or lime, white for deep ones) — chosen by WCAG contrast
+// --accent-rgb "r,g,b" of the accent, for rgba(var(--accent-rgb), .3) in older stylesheets
+// --accent-glow the accent at 35% for glows and focus rings
+// --color-scheme dark|light, so native controls and scrollbars follow the theme
+// A theme may set any of them explicitly; otherwise they are computed here so all 35 themes,
+// and community themes that only define the base palette, stay consistent on every site.
+function hexToRgb(hex) {
+ const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(String(hex || '').trim());
+ if (!m) return null;
+ let h = m[1]; if (h.length === 3) h = h.split('').map((c) => c + c).join('');
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
+}
+function luminance(rgb) {
+ const f = (v) => { v /= 255; return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); };
+ return 0.2126 * f(rgb[0]) + 0.7152 * f(rgb[1]) + 0.0722 * f(rgb[2]);
+}
+function contrast(a, b) { const [x, y] = [luminance(a), luminance(b)]; return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05); }
+function deriveTokens(vars, mode) {
+ const out = { ...vars };
+ const accent = hexToRgb(vars['--accent']);
+ if (accent) {
+ // White wherever it reads (>= 3:1, the large-text floor a button label meets); dark ink only
+ // on accents too light for it (cyan, lime, amber).
+ if (!out['--on-accent']) out['--on-accent'] = contrast([255, 255, 255], accent) >= 3 ? '#ffffff' : '#0b0d10';
+ if (!out['--accent-rgb']) out['--accent-rgb'] = accent.join(',');
+ if (!out['--accent-glow']) out['--accent-glow'] = `rgba(${accent.join(',')},0.35)`;
+ }
+ if (!out['--color-scheme']) out['--color-scheme'] = mode === 'light' ? 'light' : 'dark';
+ return out;
+}
+
const BUILTIN_THEMES = RAW_BUILTIN_THEMES.map((theme) => ({
const BUILTIN_THEMES = RAW_BUILTIN_THEMES.map((theme) => ({
id: theme.slug,
id: theme.slug,
...theme,
...theme,
tags: Array.isArray(theme.tags) ? [...theme.tags] : [],
tags: Array.isArray(theme.tags) ? [...theme.tags] : [],
- variables: { ...(theme.variables || {}) },
+ variables: deriveTokens(theme.variables || {}, theme.mode),
}));
}));
const DEFAULT_THEME = BUILTIN_THEMES.find((theme) => theme.id === 'vibe') || BUILTIN_THEMES[0];
const DEFAULT_THEME = BUILTIN_THEMES.find((theme) => theme.id === 'vibe') || BUILTIN_THEMES[0];
@@ -909,4 +943,7 @@ module.exports = {
@@ -909,4 +943,7 @@ module.exports = {
BUILTIN_THEMES,
BUILTIN_THEMES,
DEFAULT_THEME,
DEFAULT_THEME,
DEFAULT_VARS,
DEFAULT_VARS,
+ deriveTokens,
+ hexToRgb,
+ contrast,
};
};
@@ -21,41 +21,41 @@
@@ -21,41 +21,41 @@
// Kept in sync with packages/openvibe-shared/builtin-themes.js
// Kept in sync with packages/openvibe-shared/builtin-themes.js
// THEMES:BEGIN — generated by scripts/build-theme-loader.js from builtin-themes.js; do not edit by hand
// THEMES:BEGIN — generated by scripts/build-theme-loader.js from builtin-themes.js; do not edit by hand
const THEMES = {
const THEMES = {
- 'vibe': { '--bg-primary':'#0a0f1c','--bg-secondary':'#101828','--bg-tertiary':'#172238','--bg-card':'#131c2e','--bg-hover':'#1c2a44','--bg-input':'#0d1424','--text-primary':'#e6edf7','--text-secondary':'#96a7c2','--text-muted':'#7386a3','--accent':'#3b82f6','--accent-light':'#60a5fa','--accent-dark':'#1d4ed8','--border':'#1f2d47','--border-light':'#2c3d5c','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'vibe-classic': { '--bg-primary':'#0d0d0f','--bg-secondary':'#16161a','--bg-tertiary':'#1e1e24','--bg-card':'#1a1a20','--bg-hover':'#242430','--bg-input':'#12121a','--text-primary':'#e8e6e3','--text-secondary':'#9a9a9a','--text-muted':'#838282','--accent':'#8b5cf6','--accent-light':'#a78bfa','--accent-dark':'#6d28d9','--border':'#2a2a32','--border-light':'#3a3a44','--live-red':'#e74c3c','--success':'#2ecc71','--warning':'#f39c12','--danger':'#e74c3c','--info':'#3498db','--shadow':'0 2px 12px rgba(0,0,0,0.4)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'midnight': { '--bg-primary':'#0a0e17','--bg-secondary':'#111827','--bg-tertiary':'#1a2235','--bg-card':'#151d2e','--bg-hover':'#1e2a42','--bg-input':'#0d1220','--text-primary':'#e2e8f0','--text-secondary':'#94a3b8','--text-muted':'#78879b','--accent':'#6366f1','--accent-light':'#818cf8','--accent-dark':'#4f46e5','--border':'#1e293b','--border-light':'#334155','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'forest': { '--bg-primary':'#0a120a','--bg-secondary':'#121e12','--bg-tertiary':'#1a2a1a','--bg-card':'#152015','--bg-hover':'#1e3420','--bg-input':'#0d160d','--text-primary':'#d4e8d4','--text-secondary':'#8aaa8a','--text-muted':'#708e70','--accent':'#4ade80','--accent-light':'#86efac','--accent-dark':'#22c55e','--border':'#1a3a1a','--border-light':'#2a4a2a','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'neon-tokyo': { '--bg-primary':'#0a0a0f','--bg-secondary':'#12101a','--bg-tertiary':'#1a1625','--bg-card':'#15111f','--bg-hover':'#221a32','--bg-input':'#0d0b14','--text-primary':'#f0e6ff','--text-secondary':'#b4a0d0','--text-muted':'#87799c','--accent':'#ff006e','--accent-light':'#ff4d94','--accent-dark':'#c9005a','--border':'#2a1a3a','--border-light':'#3a2a4a','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'dracula': { '--bg-primary':'#282a36','--bg-secondary':'#1e1f29','--bg-tertiary':'#343746','--bg-card':'#2c2e3c','--bg-hover':'#3a3d50','--bg-input':'#21222c','--text-primary':'#f8f8f2','--text-secondary':'#bfbfb2','--text-muted':'#8995b8','--accent':'#bd93f9','--accent-light':'#d4b8ff','--accent-dark':'#9b6ddb','--border':'#44475a','--border-light':'#565970','--live-red':'#ff5555','--success':'#50fa7b','--warning':'#f1fa8c','--danger':'#ff5555','--info':'#8be9fd','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'monokai': { '--bg-primary':'#272822','--bg-secondary':'#1e1f1c','--bg-tertiary':'#3e3d32','--bg-card':'#2d2e27','--bg-hover':'#49483e','--bg-input':'#22231e','--text-primary':'#f8f8f2','--text-secondary':'#cfcfc2','--text-muted':'#979484','--accent':'#a6e22e','--accent-light':'#c4ff50','--accent-dark':'#7dac1c','--border':'#49483e','--border-light':'#5b5a50','--live-red':'#ef4444','--success':'#22c55e','--warning':'#e6db74','--danger':'#f92672','--info':'#66d9ef','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'ocean-deep': { '--bg-primary':'#0a1215','--bg-secondary':'#0f1a1f','--bg-tertiary':'#162228','--bg-card':'#121c22','--bg-hover':'#1a2a32','--bg-input':'#0c1418','--text-primary':'#d0e8ef','--text-secondary':'#7aa8ba','--text-muted':'#658896','--accent':'#00bcd4','--accent-light':'#4dd0e1','--accent-dark':'#0097a7','--border':'#1a3040','--border-light':'#2a4050','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'sunset': { '--bg-primary':'#120a0a','--bg-secondary':'#1a1010','--bg-tertiary':'#241616','--bg-card':'#1e1212','--bg-hover':'#2e1a1a','--bg-input':'#140c0c','--text-primary':'#ffe8e0','--text-secondary':'#c49080','--text-muted':'#977970','--accent':'#ff6b35','--accent-light':'#ff8f5e','--accent-dark':'#d04a1a','--border':'#3a2020','--border-light':'#4a3030','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'arctic': { '--bg-primary':'#0b1620','--bg-secondary':'#0f1e2b','--bg-tertiary':'#163040','--bg-card':'#122534','--bg-hover':'#1a3a4c','--bg-input':'#0c1a26','--text-primary':'#eaf6ff','--text-secondary':'#9ec3d8','--text-muted':'#7ea3ba','--accent':'#22d3ee','--accent-light':'#a5f3fc','--accent-dark':'#0891b2','--border':'#1e3f52','--border-light':'#2a5268','--live-red':'#ef4444','--success':'#34d399','--warning':'#f59e0b','--danger':'#ef4444','--info':'#7dd3fc','--shadow':'0 2px 12px rgba(2,12,20,0.5)','--shadow-lg':'0 8px 32px rgba(2,12,20,0.65)' },
- 'ember': { '--bg-primary':'#120808','--bg-secondary':'#1a0e0e','--bg-tertiary':'#241414','--bg-card':'#1e1010','--bg-hover':'#2e1818','--bg-input':'#140a0a','--text-primary':'#f0dada','--text-secondary':'#b0808a','--text-muted':'#95787c','--accent':'#ef4444','--accent-light':'#f87171','--accent-dark':'#b91c1c','--border':'#3a1a20','--border-light':'#4a2a30','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'vapor': { '--bg-primary':'#0e0a14','--bg-secondary':'#14101c','--bg-tertiary':'#1c1628','--bg-card':'#181220','--bg-hover':'#241a34','--bg-input':'#100c16','--text-primary':'#f0e0ff','--text-secondary':'#c090e0','--text-muted':'#8f73b7','--accent':'#e040fb','--accent-light':'#ea80fc','--accent-dark':'#aa00d4','--border':'#2a1a40','--border-light':'#3a2a50','--live-red':'#ef4444','--success':'#69f0ae','--warning':'#f59e0b','--danger':'#ef4444','--info':'#00e5ff','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'slate': { '--bg-primary':'#0f1118','--bg-secondary':'#161820','--bg-tertiary':'#1e2028','--bg-card':'#1a1c24','--bg-hover':'#24262e','--bg-input':'#12141c','--text-primary':'#e4e6ea','--text-secondary':'#a0a4b0','--text-muted':'#828690','--accent':'#a78bfa','--accent-light':'#c4b5fd','--accent-dark':'#7c3aed','--border':'#2a2c38','--border-light':'#3a3c48','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'matrix': { '--bg-primary':'#000000','--bg-secondary':'#050a05','--bg-tertiary':'#0a140a','--bg-card':'#071007','--bg-hover':'#0e1e0e','--bg-input':'#030803','--text-primary':'#00ff41','--text-secondary':'#00b030','--text-muted':'#008f25','--accent':'#00ff41','--accent-light':'#66ff8a','--accent-dark':'#00aa2a','--border':'#0a2a0a','--border-light':'#144014','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'nord': { '--bg-primary':'#2e3440','--bg-secondary':'#272c36','--bg-tertiary':'#3b4252','--bg-card':'#333a48','--bg-hover':'#434c5e','--bg-input':'#2a303c','--text-primary':'#eceff4','--text-secondary':'#d8dee9','--text-muted':'#9ba5b8','--accent':'#88c0d0','--accent-light':'#8fbcbb','--accent-dark':'#5e81ac','--border':'#3b4252','--border-light':'#4c566a','--live-red':'#ef4444','--success':'#a3be8c','--warning':'#ebcb8b','--danger':'#bf616a','--info':'#81a1c1','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'gruvbox-dark': { '--bg-primary':'#1d2021','--bg-secondary':'#282828','--bg-tertiary':'#3c3836','--bg-card':'#32302f','--bg-hover':'#504945','--bg-input':'#242424','--text-primary':'#ebdbb2','--text-secondary':'#d5c4a1','--text-muted':'#a69682','--accent':'#fabd2f','--accent-light':'#fce566','--accent-dark':'#d79921','--border':'#3c3836','--border-light':'#504945','--live-red':'#ef4444','--success':'#b8bb26','--warning':'#fe8019','--danger':'#fb4934','--info':'#83a598','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'abyss': { '--bg-primary':'#000000','--bg-secondary':'#080808','--bg-tertiary':'#111111','--bg-card':'#0a0a0a','--bg-hover':'#181818','--bg-input':'#050505','--text-primary':'#cccccc','--text-secondary':'#888888','--text-muted':'#7a7a7a','--accent':'#ffffff','--accent-light':'#ffffff','--accent-dark':'#aaaaaa','--border':'#1a1a1a','--border-light':'#252525','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'copper': { '--bg-primary':'#110d09','--bg-secondary':'#1a140e','--bg-tertiary':'#231c14','--bg-card':'#1e1710','--bg-hover':'#2c2218','--bg-input':'#13100b','--text-primary':'#e8ddd0','--text-secondary':'#b49a80','--text-muted':'#8e7f6a','--accent':'#cd7f32','--accent-light':'#daa060','--accent-dark':'#a06020','--border':'#2a2016','--border-light':'#3a3020','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'sakura-night': { '--bg-primary':'#0e0a14','--bg-secondary':'#150f1c','--bg-tertiary':'#1c1526','--bg-card':'#181020','--bg-hover':'#221830','--bg-input':'#100c16','--text-primary':'#f0e0f0','--text-secondary':'#c0a0c0','--text-muted':'#927592','--accent':'#f472b6','--accent-light':'#f9a8d4','--accent-dark':'#db2777','--border':'#2a1a30','--border-light':'#3a2a40','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'hacker': { '--bg-primary':'#000000','--bg-secondary':'#0a0800','--bg-tertiary':'#141000','--bg-card':'#0e0c00','--bg-hover':'#1c1800','--bg-input':'#060400','--text-primary':'#ffb000','--text-secondary':'#cc8d00','--text-muted':'#a37100','--accent':'#ffb000','--accent-light':'#ffd050','--accent-dark':'#cc8d00','--border':'#1a1400','--border-light':'#2a2200','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'daylight': { '--bg-primary':'#ffffff','--bg-secondary':'#f7f7f8','--bg-tertiary':'#eeeef0','--bg-card':'#ffffff','--bg-hover':'#f0f0f2','--bg-input':'#f5f5f7','--text-primary':'#1a1a2e','--text-secondary':'#4a4a6a','--text-muted':'#747489','--accent':'#8756f3','--accent-light':'#a78bfa','--accent-dark':'#6d28d9','--border':'#e0e0e6','--border-light':'#d0d0d8','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.08)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.12)' },
- 'paper': { '--bg-primary':'#faf8f5','--bg-secondary':'#f0ece6','--bg-tertiary':'#e8e2d8','--bg-card':'#faf8f5','--bg-hover':'#f0ece6','--bg-input':'#f5f2ed','--text-primary':'#2c2416','--text-secondary':'#5a4e3e','--text-muted':'#7b7061','--accent':'#8b6914','--accent-light':'#b08a30','--accent-dark':'#6a5010','--border':'#ddd6c8','--border-light':'#ccc4b0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,40,0,0.10)' },
- 'cloud': { '--bg-primary':'#f0f5ff','--bg-secondary':'#e8eef8','--bg-tertiary':'#dde5f0','--bg-card':'#f5f8ff','--bg-hover':'#e4ecf8','--bg-input':'#edf2fa','--text-primary':'#1a2040','--text-secondary':'#4a5070','--text-muted':'#6b718c','--accent':'#2867ed','--accent-light':'#60a5fa','--accent-dark':'#2563eb','--border':'#d0d8ea','--border-light':'#bcc8e0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,20,60,0.06)','--shadow-lg':'0 8px 32px rgba(0,20,60,0.10)' },
- 'meadow': { '--bg-primary':'#f2f8f0','--bg-secondary':'#e8f0e4','--bg-tertiary':'#dce8d6','--bg-card':'#f5faf2','--bg-hover':'#e4f0de','--bg-input':'#edf5ea','--text-primary':'#1a2e16','--text-secondary':'#3a5a32','--text-muted':'#5d7a54','--accent':'#15823e','--accent-light':'#22c55e','--accent-dark':'#15803d','--border':'#c8dcc0','--border-light':'#b0ccaa','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(0,40,0,0.10)' },
- 'peach': { '--bg-primary':'#fff5f0','--bg-secondary':'#fbeae2','--bg-tertiary':'#f5ddd2','--bg-card':'#fff7f2','--bg-hover':'#fce8dc','--bg-input':'#fdf0ea','--text-primary':'#2e1a14','--text-secondary':'#6a4438','--text-muted':'#8f6a5c','--accent':'#c04808','--accent-light':'#fb923c','--accent-dark':'#ea580c','--border':'#f0d0c0','--border-light':'#e4bfab','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,20,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,20,0,0.10)' },
- 'lavender': { '--bg-primary':'#f8f5ff','--bg-secondary':'#f0eaf8','--bg-tertiary':'#e6ddf0','--bg-card':'#faf7ff','--bg-hover':'#eee6f8','--bg-input':'#f4f0fa','--text-primary':'#1e1430','--text-secondary':'#4a3a60','--text-muted':'#796a92','--accent':'#844cf2','--accent-light':'#a78bfa','--accent-dark':'#7c3aed','--border':'#ddd0ee','--border-light':'#ccc0dd','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(40,0,60,0.06)','--shadow-lg':'0 8px 32px rgba(40,0,60,0.10)' },
- 'gruvbox-light': { '--bg-primary':'#fbf1c7','--bg-secondary':'#f2e5bc','--bg-tertiary':'#ebdbb2','--bg-card':'#fbf1c7','--bg-hover':'#f2e5bc','--bg-input':'#f5ecc4','--text-primary':'#3c3836','--text-secondary':'#504945','--text-muted':'#766b60','--accent':'#be4707','--accent-light':'#fe8019','--accent-dark':'#af3a03','--border':'#d5c4a1','--border-light':'#bdae93','--live-red':'#ef4444','--success':'#98971a','--warning':'#d79921','--danger':'#cc241d','--info':'#458588','--shadow':'0 2px 12px rgba(40,30,0,0.08)','--shadow-lg':'0 8px 32px rgba(40,30,0,0.12)' },
- 'snow': { '--bg-primary':'#ffffff','--bg-secondary':'#f8fafc','--bg-tertiary':'#f1f5f9','--bg-card':'#ffffff','--bg-hover':'#f1f5f9','--bg-input':'#f8fafc','--text-primary':'#0f172a','--text-secondary':'#334155','--text-muted':'#69768b','--accent':'#027cbb','--accent-light':'#38bdf8','--accent-dark':'#0284c7','--border':'#e2e8f0','--border-light':'#cbd5e1','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.05)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.08)' },
- 'sand': { '--bg-primary':'#f8f4ef','--bg-secondary':'#f0e8de','--bg-tertiary':'#e8ddd0','--bg-card':'#faf6f0','--bg-hover':'#f0e8de','--bg-input':'#f5f0e8','--text-primary':'#2e2418','--text-secondary':'#5a4e3e','--text-muted':'#7a6e5f','--accent':'#8c6707','--accent-light':'#daa520','--accent-dark':'#8b6508','--border':'#ddd0be','--border-light':'#ccc0aa','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,40,0,0.10)' },
- 'rose': { '--bg-primary':'#fff5f7','--bg-secondary':'#fce7ec','--bg-tertiary':'#f5d5de','--bg-card':'#fff7f9','--bg-hover':'#fce0e8','--bg-input':'#fdeef2','--text-primary':'#2e1420','--text-secondary':'#6a3850','--text-muted':'#96617e','--accent':'#de1c47','--accent-light':'#f43f5e','--accent-dark':'#be123c','--border':'#f0c8d4','--border-light':'#e4b0c0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,0,20,0.06)','--shadow-lg':'0 8px 32px rgba(60,0,20,0.10)' },
- 'solarized-dark': { '--bg-primary':'#002b36','--bg-secondary':'#073642','--bg-tertiary':'#0a3f4e','--bg-card':'#053542','--bg-hover':'#0d4a58','--bg-input':'#01303d','--text-primary':'#fdf6e3','--text-secondary':'#93a1a1','--text-muted':'#909c9a','--accent':'#b58900','--accent-light':'#d4a017','--accent-dark':'#8a6a00','--border':'#0a4050','--border-light':'#105060','--live-red':'#ef4444','--success':'#859900','--warning':'#cb4b16','--danger':'#dc322f','--info':'#268bd2','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'solarized-light': { '--bg-primary':'#fdf6e3','--bg-secondary':'#eee8d5','--bg-tertiary':'#e4ddc6','--bg-card':'#fdf6e3','--bg-hover':'#eee8d5','--bg-input':'#f5eedb','--text-primary':'#002b36','--text-secondary':'#586e75','--text-muted':'#5b7478','--accent':'#8d6c00','--accent-light':'#d4a017','--accent-dark':'#8a6a00','--border':'#d6ceb5','--border-light':'#c8c0a5','--live-red':'#ef4444','--success':'#859900','--warning':'#cb4b16','--danger':'#dc322f','--info':'#268bd2','--shadow':'0 2px 12px rgba(0,30,40,0.08)','--shadow-lg':'0 8px 32px rgba(0,30,40,0.12)' },
- 'catppuccin-mocha': { '--bg-primary':'#1e1e2e','--bg-secondary':'#181825','--bg-tertiary':'#313244','--bg-card':'#1e1e2e','--bg-hover':'#313244','--bg-input':'#1a1a2c','--text-primary':'#cdd6f4','--text-secondary':'#bac2de','--text-muted':'#81869e','--accent':'#cba6f7','--accent-light':'#dcc0ff','--accent-dark':'#b07de0','--border':'#313244','--border-light':'#45475a','--live-red':'#f38ba8','--success':'#a6e3a1','--warning':'#fab387','--danger':'#f38ba8','--info':'#89b4fa','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
- 'catppuccin-latte': { '--bg-primary':'#eff1f5','--bg-secondary':'#e6e9ef','--bg-tertiary':'#dce0e8','--bg-card':'#eff1f5','--bg-hover':'#dce0e8','--bg-input':'#e8ebf0','--text-primary':'#4c4f69','--text-secondary':'#5c5f77','--text-muted':'#696c83','--accent':'#8839ef','--accent-light':'#a05cff','--accent-dark':'#7028d4','--border':'#ccd0da','--border-light':'#bcc0cc','--live-red':'#d20f39','--success':'#40a02b','--warning':'#fe640b','--danger':'#d20f39','--info':'#1e66f5','--shadow':'0 2px 12px rgba(0,0,0,0.06)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.10)' },
- 'high-contrast': { '--bg-primary':'#000000','--bg-secondary':'#0a0a0a','--bg-tertiary':'#1a1a1a','--bg-card':'#0f0f0f','--bg-hover':'#222222','--bg-input':'#0a0a0a','--text-primary':'#ffffff','--text-secondary':'#f0f0f0','--text-muted':'#aaaaaa','--accent':'#ffd700','--accent-light':'#ffed4a','--accent-dark':'#ccac00','--border':'#444444','--border-light':'#666666','--live-red':'#ff0000','--success':'#00ff00','--warning':'#ffff00','--danger':'#ff0000','--info':'#00ffff','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)' },
+ 'vibe': { '--bg-primary':'#0a0f1c','--bg-secondary':'#101828','--bg-tertiary':'#172238','--bg-card':'#131c2e','--bg-hover':'#1c2a44','--bg-input':'#0d1424','--text-primary':'#e6edf7','--text-secondary':'#96a7c2','--text-muted':'#7386a3','--accent':'#3b82f6','--accent-light':'#60a5fa','--accent-dark':'#1d4ed8','--border':'#1f2d47','--border-light':'#2c3d5c','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'59,130,246','--accent-glow':'rgba(59,130,246,0.35)','--color-scheme':'dark' },
+ 'violet-hour': { '--bg-primary':'#0d0d0f','--bg-secondary':'#16161a','--bg-tertiary':'#1e1e24','--bg-card':'#1a1a20','--bg-hover':'#242430','--bg-input':'#12121a','--text-primary':'#e8e6e3','--text-secondary':'#9a9a9a','--text-muted':'#838282','--accent':'#8b5cf6','--accent-light':'#a78bfa','--accent-dark':'#6d28d9','--border':'#2a2a32','--border-light':'#3a3a44','--live-red':'#e74c3c','--success':'#2ecc71','--warning':'#f39c12','--danger':'#e74c3c','--info':'#3498db','--shadow':'0 2px 12px rgba(0,0,0,0.4)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'139,92,246','--accent-glow':'rgba(139,92,246,0.35)','--color-scheme':'dark' },
+ 'midnight': { '--bg-primary':'#0a0e17','--bg-secondary':'#111827','--bg-tertiary':'#1a2235','--bg-card':'#151d2e','--bg-hover':'#1e2a42','--bg-input':'#0d1220','--text-primary':'#e2e8f0','--text-secondary':'#94a3b8','--text-muted':'#78879b','--accent':'#6366f1','--accent-light':'#818cf8','--accent-dark':'#4f46e5','--border':'#1e293b','--border-light':'#334155','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'99,102,241','--accent-glow':'rgba(99,102,241,0.35)','--color-scheme':'dark' },
+ 'forest': { '--bg-primary':'#0a120a','--bg-secondary':'#121e12','--bg-tertiary':'#1a2a1a','--bg-card':'#152015','--bg-hover':'#1e3420','--bg-input':'#0d160d','--text-primary':'#d4e8d4','--text-secondary':'#8aaa8a','--text-muted':'#708e70','--accent':'#4ade80','--accent-light':'#86efac','--accent-dark':'#22c55e','--border':'#1a3a1a','--border-light':'#2a4a2a','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'74,222,128','--accent-glow':'rgba(74,222,128,0.35)','--color-scheme':'dark' },
+ 'neon-tokyo': { '--bg-primary':'#0a0a0f','--bg-secondary':'#12101a','--bg-tertiary':'#1a1625','--bg-card':'#15111f','--bg-hover':'#221a32','--bg-input':'#0d0b14','--text-primary':'#f0e6ff','--text-secondary':'#b4a0d0','--text-muted':'#87799c','--accent':'#ff006e','--accent-light':'#ff4d94','--accent-dark':'#c9005a','--border':'#2a1a3a','--border-light':'#3a2a4a','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'255,0,110','--accent-glow':'rgba(255,0,110,0.35)','--color-scheme':'dark' },
+ 'dracula': { '--bg-primary':'#282a36','--bg-secondary':'#1e1f29','--bg-tertiary':'#343746','--bg-card':'#2c2e3c','--bg-hover':'#3a3d50','--bg-input':'#21222c','--text-primary':'#f8f8f2','--text-secondary':'#bfbfb2','--text-muted':'#8995b8','--accent':'#bd93f9','--accent-light':'#d4b8ff','--accent-dark':'#9b6ddb','--border':'#44475a','--border-light':'#565970','--live-red':'#ff5555','--success':'#50fa7b','--warning':'#f1fa8c','--danger':'#ff5555','--info':'#8be9fd','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'189,147,249','--accent-glow':'rgba(189,147,249,0.35)','--color-scheme':'dark' },
+ 'monokai': { '--bg-primary':'#272822','--bg-secondary':'#1e1f1c','--bg-tertiary':'#3e3d32','--bg-card':'#2d2e27','--bg-hover':'#49483e','--bg-input':'#22231e','--text-primary':'#f8f8f2','--text-secondary':'#cfcfc2','--text-muted':'#979484','--accent':'#a6e22e','--accent-light':'#c4ff50','--accent-dark':'#7dac1c','--border':'#49483e','--border-light':'#5b5a50','--live-red':'#ef4444','--success':'#22c55e','--warning':'#e6db74','--danger':'#f92672','--info':'#66d9ef','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'166,226,46','--accent-glow':'rgba(166,226,46,0.35)','--color-scheme':'dark' },
+ 'ocean-deep': { '--bg-primary':'#0a1215','--bg-secondary':'#0f1a1f','--bg-tertiary':'#162228','--bg-card':'#121c22','--bg-hover':'#1a2a32','--bg-input':'#0c1418','--text-primary':'#d0e8ef','--text-secondary':'#7aa8ba','--text-muted':'#658896','--accent':'#00bcd4','--accent-light':'#4dd0e1','--accent-dark':'#0097a7','--border':'#1a3040','--border-light':'#2a4050','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'0,188,212','--accent-glow':'rgba(0,188,212,0.35)','--color-scheme':'dark' },
+ 'sunset': { '--bg-primary':'#120a0a','--bg-secondary':'#1a1010','--bg-tertiary':'#241616','--bg-card':'#1e1212','--bg-hover':'#2e1a1a','--bg-input':'#140c0c','--text-primary':'#ffe8e0','--text-secondary':'#c49080','--text-muted':'#977970','--accent':'#ff6b35','--accent-light':'#ff8f5e','--accent-dark':'#d04a1a','--border':'#3a2020','--border-light':'#4a3030','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'255,107,53','--accent-glow':'rgba(255,107,53,0.35)','--color-scheme':'dark' },
+ 'arctic': { '--bg-primary':'#0b1620','--bg-secondary':'#0f1e2b','--bg-tertiary':'#163040','--bg-card':'#122534','--bg-hover':'#1a3a4c','--bg-input':'#0c1a26','--text-primary':'#eaf6ff','--text-secondary':'#9ec3d8','--text-muted':'#7ea3ba','--accent':'#22d3ee','--accent-light':'#a5f3fc','--accent-dark':'#0891b2','--border':'#1e3f52','--border-light':'#2a5268','--live-red':'#ef4444','--success':'#34d399','--warning':'#f59e0b','--danger':'#ef4444','--info':'#7dd3fc','--shadow':'0 2px 12px rgba(2,12,20,0.5)','--shadow-lg':'0 8px 32px rgba(2,12,20,0.65)','--on-accent':'#0b0d10','--accent-rgb':'34,211,238','--accent-glow':'rgba(34,211,238,0.35)','--color-scheme':'dark' },
+ 'ember': { '--bg-primary':'#120808','--bg-secondary':'#1a0e0e','--bg-tertiary':'#241414','--bg-card':'#1e1010','--bg-hover':'#2e1818','--bg-input':'#140a0a','--text-primary':'#f0dada','--text-secondary':'#b0808a','--text-muted':'#95787c','--accent':'#ef4444','--accent-light':'#f87171','--accent-dark':'#b91c1c','--border':'#3a1a20','--border-light':'#4a2a30','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'239,68,68','--accent-glow':'rgba(239,68,68,0.35)','--color-scheme':'dark' },
+ 'vapor': { '--bg-primary':'#0e0a14','--bg-secondary':'#14101c','--bg-tertiary':'#1c1628','--bg-card':'#181220','--bg-hover':'#241a34','--bg-input':'#100c16','--text-primary':'#f0e0ff','--text-secondary':'#c090e0','--text-muted':'#8f73b7','--accent':'#e040fb','--accent-light':'#ea80fc','--accent-dark':'#aa00d4','--border':'#2a1a40','--border-light':'#3a2a50','--live-red':'#ef4444','--success':'#69f0ae','--warning':'#f59e0b','--danger':'#ef4444','--info':'#00e5ff','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'224,64,251','--accent-glow':'rgba(224,64,251,0.35)','--color-scheme':'dark' },
+ 'slate': { '--bg-primary':'#0f1118','--bg-secondary':'#161820','--bg-tertiary':'#1e2028','--bg-card':'#1a1c24','--bg-hover':'#24262e','--bg-input':'#12141c','--text-primary':'#e4e6ea','--text-secondary':'#a0a4b0','--text-muted':'#828690','--accent':'#a78bfa','--accent-light':'#c4b5fd','--accent-dark':'#7c3aed','--border':'#2a2c38','--border-light':'#3a3c48','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'167,139,250','--accent-glow':'rgba(167,139,250,0.35)','--color-scheme':'dark' },
+ 'matrix': { '--bg-primary':'#000000','--bg-secondary':'#050a05','--bg-tertiary':'#0a140a','--bg-card':'#071007','--bg-hover':'#0e1e0e','--bg-input':'#030803','--text-primary':'#00ff41','--text-secondary':'#00b030','--text-muted':'#008f25','--accent':'#00ff41','--accent-light':'#66ff8a','--accent-dark':'#00aa2a','--border':'#0a2a0a','--border-light':'#144014','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'0,255,65','--accent-glow':'rgba(0,255,65,0.35)','--color-scheme':'dark' },
+ 'nord': { '--bg-primary':'#2e3440','--bg-secondary':'#272c36','--bg-tertiary':'#3b4252','--bg-card':'#333a48','--bg-hover':'#434c5e','--bg-input':'#2a303c','--text-primary':'#eceff4','--text-secondary':'#d8dee9','--text-muted':'#9ba5b8','--accent':'#88c0d0','--accent-light':'#8fbcbb','--accent-dark':'#5e81ac','--border':'#3b4252','--border-light':'#4c566a','--live-red':'#ef4444','--success':'#a3be8c','--warning':'#ebcb8b','--danger':'#bf616a','--info':'#81a1c1','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'136,192,208','--accent-glow':'rgba(136,192,208,0.35)','--color-scheme':'dark' },
+ 'gruvbox-dark': { '--bg-primary':'#1d2021','--bg-secondary':'#282828','--bg-tertiary':'#3c3836','--bg-card':'#32302f','--bg-hover':'#504945','--bg-input':'#242424','--text-primary':'#ebdbb2','--text-secondary':'#d5c4a1','--text-muted':'#a69682','--accent':'#fabd2f','--accent-light':'#fce566','--accent-dark':'#d79921','--border':'#3c3836','--border-light':'#504945','--live-red':'#ef4444','--success':'#b8bb26','--warning':'#fe8019','--danger':'#fb4934','--info':'#83a598','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'250,189,47','--accent-glow':'rgba(250,189,47,0.35)','--color-scheme':'dark' },
+ 'abyss': { '--bg-primary':'#000000','--bg-secondary':'#080808','--bg-tertiary':'#111111','--bg-card':'#0a0a0a','--bg-hover':'#181818','--bg-input':'#050505','--text-primary':'#cccccc','--text-secondary':'#888888','--text-muted':'#7a7a7a','--accent':'#ffffff','--accent-light':'#ffffff','--accent-dark':'#aaaaaa','--border':'#1a1a1a','--border-light':'#252525','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'255,255,255','--accent-glow':'rgba(255,255,255,0.35)','--color-scheme':'dark' },
+ 'copper': { '--bg-primary':'#110d09','--bg-secondary':'#1a140e','--bg-tertiary':'#231c14','--bg-card':'#1e1710','--bg-hover':'#2c2218','--bg-input':'#13100b','--text-primary':'#e8ddd0','--text-secondary':'#b49a80','--text-muted':'#8e7f6a','--accent':'#cd7f32','--accent-light':'#daa060','--accent-dark':'#a06020','--border':'#2a2016','--border-light':'#3a3020','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'205,127,50','--accent-glow':'rgba(205,127,50,0.35)','--color-scheme':'dark' },
+ 'sakura-night': { '--bg-primary':'#0e0a14','--bg-secondary':'#150f1c','--bg-tertiary':'#1c1526','--bg-card':'#181020','--bg-hover':'#221830','--bg-input':'#100c16','--text-primary':'#f0e0f0','--text-secondary':'#c0a0c0','--text-muted':'#927592','--accent':'#f472b6','--accent-light':'#f9a8d4','--accent-dark':'#db2777','--border':'#2a1a30','--border-light':'#3a2a40','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'244,114,182','--accent-glow':'rgba(244,114,182,0.35)','--color-scheme':'dark' },
+ 'hacker': { '--bg-primary':'#000000','--bg-secondary':'#0a0800','--bg-tertiary':'#141000','--bg-card':'#0e0c00','--bg-hover':'#1c1800','--bg-input':'#060400','--text-primary':'#ffb000','--text-secondary':'#cc8d00','--text-muted':'#a37100','--accent':'#ffb000','--accent-light':'#ffd050','--accent-dark':'#cc8d00','--border':'#1a1400','--border-light':'#2a2200','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'255,176,0','--accent-glow':'rgba(255,176,0,0.35)','--color-scheme':'dark' },
+ 'daylight': { '--bg-primary':'#ffffff','--bg-secondary':'#f7f7f8','--bg-tertiary':'#eeeef0','--bg-card':'#ffffff','--bg-hover':'#f0f0f2','--bg-input':'#f5f5f7','--text-primary':'#1a1a2e','--text-secondary':'#4a4a6a','--text-muted':'#747489','--accent':'#8756f3','--accent-light':'#a78bfa','--accent-dark':'#6d28d9','--border':'#e0e0e6','--border-light':'#d0d0d8','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.08)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.12)','--on-accent':'#ffffff','--accent-rgb':'135,86,243','--accent-glow':'rgba(135,86,243,0.35)','--color-scheme':'light' },
+ 'paper': { '--bg-primary':'#faf8f5','--bg-secondary':'#f0ece6','--bg-tertiary':'#e8e2d8','--bg-card':'#faf8f5','--bg-hover':'#f0ece6','--bg-input':'#f5f2ed','--text-primary':'#2c2416','--text-secondary':'#5a4e3e','--text-muted':'#7b7061','--accent':'#8b6914','--accent-light':'#b08a30','--accent-dark':'#6a5010','--border':'#ddd6c8','--border-light':'#ccc4b0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,40,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'139,105,20','--accent-glow':'rgba(139,105,20,0.35)','--color-scheme':'light' },
+ 'cloud': { '--bg-primary':'#f0f5ff','--bg-secondary':'#e8eef8','--bg-tertiary':'#dde5f0','--bg-card':'#f5f8ff','--bg-hover':'#e4ecf8','--bg-input':'#edf2fa','--text-primary':'#1a2040','--text-secondary':'#4a5070','--text-muted':'#6b718c','--accent':'#2867ed','--accent-light':'#60a5fa','--accent-dark':'#2563eb','--border':'#d0d8ea','--border-light':'#bcc8e0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,20,60,0.06)','--shadow-lg':'0 8px 32px rgba(0,20,60,0.10)','--on-accent':'#ffffff','--accent-rgb':'40,103,237','--accent-glow':'rgba(40,103,237,0.35)','--color-scheme':'light' },
+ 'meadow': { '--bg-primary':'#f2f8f0','--bg-secondary':'#e8f0e4','--bg-tertiary':'#dce8d6','--bg-card':'#f5faf2','--bg-hover':'#e4f0de','--bg-input':'#edf5ea','--text-primary':'#1a2e16','--text-secondary':'#3a5a32','--text-muted':'#5d7a54','--accent':'#15823e','--accent-light':'#22c55e','--accent-dark':'#15803d','--border':'#c8dcc0','--border-light':'#b0ccaa','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(0,40,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'21,130,62','--accent-glow':'rgba(21,130,62,0.35)','--color-scheme':'light' },
+ 'peach': { '--bg-primary':'#fff5f0','--bg-secondary':'#fbeae2','--bg-tertiary':'#f5ddd2','--bg-card':'#fff7f2','--bg-hover':'#fce8dc','--bg-input':'#fdf0ea','--text-primary':'#2e1a14','--text-secondary':'#6a4438','--text-muted':'#8f6a5c','--accent':'#c04808','--accent-light':'#fb923c','--accent-dark':'#ea580c','--border':'#f0d0c0','--border-light':'#e4bfab','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,20,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,20,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'192,72,8','--accent-glow':'rgba(192,72,8,0.35)','--color-scheme':'light' },
+ 'lavender': { '--bg-primary':'#f8f5ff','--bg-secondary':'#f0eaf8','--bg-tertiary':'#e6ddf0','--bg-card':'#faf7ff','--bg-hover':'#eee6f8','--bg-input':'#f4f0fa','--text-primary':'#1e1430','--text-secondary':'#4a3a60','--text-muted':'#796a92','--accent':'#844cf2','--accent-light':'#a78bfa','--accent-dark':'#7c3aed','--border':'#ddd0ee','--border-light':'#ccc0dd','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(40,0,60,0.06)','--shadow-lg':'0 8px 32px rgba(40,0,60,0.10)','--on-accent':'#ffffff','--accent-rgb':'132,76,242','--accent-glow':'rgba(132,76,242,0.35)','--color-scheme':'light' },
+ 'gruvbox-light': { '--bg-primary':'#fbf1c7','--bg-secondary':'#f2e5bc','--bg-tertiary':'#ebdbb2','--bg-card':'#fbf1c7','--bg-hover':'#f2e5bc','--bg-input':'#f5ecc4','--text-primary':'#3c3836','--text-secondary':'#504945','--text-muted':'#766b60','--accent':'#be4707','--accent-light':'#fe8019','--accent-dark':'#af3a03','--border':'#d5c4a1','--border-light':'#bdae93','--live-red':'#ef4444','--success':'#98971a','--warning':'#d79921','--danger':'#cc241d','--info':'#458588','--shadow':'0 2px 12px rgba(40,30,0,0.08)','--shadow-lg':'0 8px 32px rgba(40,30,0,0.12)','--on-accent':'#ffffff','--accent-rgb':'190,71,7','--accent-glow':'rgba(190,71,7,0.35)','--color-scheme':'light' },
+ 'snow': { '--bg-primary':'#ffffff','--bg-secondary':'#f8fafc','--bg-tertiary':'#f1f5f9','--bg-card':'#ffffff','--bg-hover':'#f1f5f9','--bg-input':'#f8fafc','--text-primary':'#0f172a','--text-secondary':'#334155','--text-muted':'#69768b','--accent':'#027cbb','--accent-light':'#38bdf8','--accent-dark':'#0284c7','--border':'#e2e8f0','--border-light':'#cbd5e1','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(0,0,0,0.05)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.08)','--on-accent':'#ffffff','--accent-rgb':'2,124,187','--accent-glow':'rgba(2,124,187,0.35)','--color-scheme':'light' },
+ 'sand': { '--bg-primary':'#f8f4ef','--bg-secondary':'#f0e8de','--bg-tertiary':'#e8ddd0','--bg-card':'#faf6f0','--bg-hover':'#f0e8de','--bg-input':'#f5f0e8','--text-primary':'#2e2418','--text-secondary':'#5a4e3e','--text-muted':'#7a6e5f','--accent':'#8c6707','--accent-light':'#daa520','--accent-dark':'#8b6508','--border':'#ddd0be','--border-light':'#ccc0aa','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,40,0,0.06)','--shadow-lg':'0 8px 32px rgba(60,40,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'140,103,7','--accent-glow':'rgba(140,103,7,0.35)','--color-scheme':'light' },
+ 'rose': { '--bg-primary':'#fff5f7','--bg-secondary':'#fce7ec','--bg-tertiary':'#f5d5de','--bg-card':'#fff7f9','--bg-hover':'#fce0e8','--bg-input':'#fdeef2','--text-primary':'#2e1420','--text-secondary':'#6a3850','--text-muted':'#96617e','--accent':'#de1c47','--accent-light':'#f43f5e','--accent-dark':'#be123c','--border':'#f0c8d4','--border-light':'#e4b0c0','--live-red':'#ef4444','--success':'#22c55e','--warning':'#f59e0b','--danger':'#ef4444','--info':'#38bdf8','--shadow':'0 2px 12px rgba(60,0,20,0.06)','--shadow-lg':'0 8px 32px rgba(60,0,20,0.10)','--on-accent':'#ffffff','--accent-rgb':'222,28,71','--accent-glow':'rgba(222,28,71,0.35)','--color-scheme':'light' },
+ 'solarized-dark': { '--bg-primary':'#002b36','--bg-secondary':'#073642','--bg-tertiary':'#0a3f4e','--bg-card':'#053542','--bg-hover':'#0d4a58','--bg-input':'#01303d','--text-primary':'#fdf6e3','--text-secondary':'#93a1a1','--text-muted':'#909c9a','--accent':'#b58900','--accent-light':'#d4a017','--accent-dark':'#8a6a00','--border':'#0a4050','--border-light':'#105060','--live-red':'#ef4444','--success':'#859900','--warning':'#cb4b16','--danger':'#dc322f','--info':'#268bd2','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#ffffff','--accent-rgb':'181,137,0','--accent-glow':'rgba(181,137,0,0.35)','--color-scheme':'dark' },
+ 'solarized-light': { '--bg-primary':'#fdf6e3','--bg-secondary':'#eee8d5','--bg-tertiary':'#e4ddc6','--bg-card':'#fdf6e3','--bg-hover':'#eee8d5','--bg-input':'#f5eedb','--text-primary':'#002b36','--text-secondary':'#586e75','--text-muted':'#5b7478','--accent':'#8d6c00','--accent-light':'#d4a017','--accent-dark':'#8a6a00','--border':'#d6ceb5','--border-light':'#c8c0a5','--live-red':'#ef4444','--success':'#859900','--warning':'#cb4b16','--danger':'#dc322f','--info':'#268bd2','--shadow':'0 2px 12px rgba(0,30,40,0.08)','--shadow-lg':'0 8px 32px rgba(0,30,40,0.12)','--on-accent':'#ffffff','--accent-rgb':'141,108,0','--accent-glow':'rgba(141,108,0,0.35)','--color-scheme':'light' },
+ 'catppuccin-mocha': { '--bg-primary':'#1e1e2e','--bg-secondary':'#181825','--bg-tertiary':'#313244','--bg-card':'#1e1e2e','--bg-hover':'#313244','--bg-input':'#1a1a2c','--text-primary':'#cdd6f4','--text-secondary':'#bac2de','--text-muted':'#81869e','--accent':'#cba6f7','--accent-light':'#dcc0ff','--accent-dark':'#b07de0','--border':'#313244','--border-light':'#45475a','--live-red':'#f38ba8','--success':'#a6e3a1','--warning':'#fab387','--danger':'#f38ba8','--info':'#89b4fa','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'203,166,247','--accent-glow':'rgba(203,166,247,0.35)','--color-scheme':'dark' },
+ 'catppuccin-latte': { '--bg-primary':'#eff1f5','--bg-secondary':'#e6e9ef','--bg-tertiary':'#dce0e8','--bg-card':'#eff1f5','--bg-hover':'#dce0e8','--bg-input':'#e8ebf0','--text-primary':'#4c4f69','--text-secondary':'#5c5f77','--text-muted':'#696c83','--accent':'#8839ef','--accent-light':'#a05cff','--accent-dark':'#7028d4','--border':'#ccd0da','--border-light':'#bcc0cc','--live-red':'#d20f39','--success':'#40a02b','--warning':'#fe640b','--danger':'#d20f39','--info':'#1e66f5','--shadow':'0 2px 12px rgba(0,0,0,0.06)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.10)','--on-accent':'#ffffff','--accent-rgb':'136,57,239','--accent-glow':'rgba(136,57,239,0.35)','--color-scheme':'light' },
+ 'high-contrast': { '--bg-primary':'#000000','--bg-secondary':'#0a0a0a','--bg-tertiary':'#1a1a1a','--bg-card':'#0f0f0f','--bg-hover':'#222222','--bg-input':'#0a0a0a','--text-primary':'#ffffff','--text-secondary':'#f0f0f0','--text-muted':'#aaaaaa','--accent':'#ffd700','--accent-light':'#ffed4a','--accent-dark':'#ccac00','--border':'#444444','--border-light':'#666666','--live-red':'#ff0000','--success':'#00ff00','--warning':'#ffff00','--danger':'#ff0000','--info':'#00ffff','--shadow':'0 2px 12px rgba(0,0,0,0.45)','--shadow-lg':'0 8px 32px rgba(0,0,0,0.6)','--on-accent':'#0b0d10','--accent-rgb':'255,215,0','--accent-glow':'rgba(255,215,0,0.35)','--color-scheme':'dark' },
};
};
// THEMES:END
// THEMES:END
@@ -105,6 +105,9 @@
@@ -105,6 +105,9 @@
for (const [prop, val] of Object.entries(vars)) {
for (const [prop, val] of Object.entries(vars)) {
if (prop.startsWith('--')) el.style.setProperty(prop, val);
if (prop.startsWith('--')) el.style.setProperty(prop, val);
}
}
+ // Native controls, scrollbars and form fields follow the theme's light/dark mode.
+ const scheme = vars['--color-scheme'];
+ if (scheme === 'light' || scheme === 'dark') { el.style.colorScheme = scheme; el.setAttribute('data-theme-mode', scheme); }
}
}
/**
/**
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
'use strict';
'use strict';
-const { BUILTIN_THEMES, DEFAULT_VARS } = require('./builtin-themes');
+const { BUILTIN_THEMES, DEFAULT_VARS, deriveTokens } = require('./builtin-themes');
// ═══════════════════════════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════
// OpenVibe — Theme Sync Engine
// OpenVibe — Theme Sync Engine
@@ -15,6 +15,8 @@ const CSS_VARIABLES = [
@@ -15,6 +15,8 @@ const CSS_VARIABLES = [
'--accent', '--accent-light', '--accent-dark',
'--accent', '--accent-light', '--accent-dark',
'--live-red', '--success', '--warning', '--danger', '--info',
'--live-red', '--success', '--warning', '--danger', '--info',
'--border', '--border-light', '--shadow', '--shadow-lg',
'--border', '--border-light', '--shadow', '--shadow-lg',
+ // Derived on every theme (builtin-themes.js deriveTokens); community themes get them too.
+ '--on-accent', '--accent-rgb', '--accent-glow', '--color-scheme',
];
];
const NORMALIZED_DEFAULT_VARS = Object.freeze({ ...DEFAULT_VARS });
const NORMALIZED_DEFAULT_VARS = Object.freeze({ ...DEFAULT_VARS });
@@ -44,7 +46,7 @@ function sanitizeCssValue(value) {
@@ -44,7 +46,7 @@ function sanitizeCssValue(value) {
*/
*/
function applyTheme(theme, target) {
function applyTheme(theme, target) {
if (!theme || !theme.variables) return;
if (!theme || !theme.variables) return;
- const vars = { ...NORMALIZED_DEFAULT_VARS, ...theme.variables };
+ const vars = deriveTokens({ ...NORMALIZED_DEFAULT_VARS, ...theme.variables }, theme.mode);
for (const [key, value] of Object.entries(vars)) {
for (const [key, value] of Object.entries(vars)) {
if (!CSS_VARIABLES.includes(key)) continue;
if (!CSS_VARIABLES.includes(key)) continue;
const safe = sanitizeCssValue(value);
const safe = sanitizeCssValue(value);