Expand Appearance settings with accents, scale, radius, and chrome
Release rolling / release (push) Successful in 7m33s
Release rolling / release (push) Successful in 7m33s
Add twelve accent colors with swatch picker, UI scale, corner radius, and titlebar/sidebar chrome styles. Preferences live-apply and persist in the settings cache for both dark and light themes.
This commit is contained in:
+144
-1
@@ -4604,17 +4604,160 @@ body[data-density='spacious'] .view {
|
||||
padding-top: 1.5rem !important;
|
||||
}
|
||||
|
||||
/* Accent variants (Track G) */
|
||||
/* Accent variants (Settings → Appearance). Default = teal (root vars). */
|
||||
body[data-accent='teal'] {
|
||||
--accent-primary: #34d399;
|
||||
--accent-secondary: #2dd4bf;
|
||||
--accent-glow: rgba(52, 211, 153, 0.35);
|
||||
}
|
||||
body[data-accent='cyan'] {
|
||||
--accent-primary: #22d3ee;
|
||||
--accent-secondary: #67e8f9;
|
||||
--accent-glow: rgba(34, 211, 238, 0.35);
|
||||
}
|
||||
body[data-accent='emerald'] {
|
||||
--accent-primary: #10b981;
|
||||
--accent-secondary: #34d399;
|
||||
--accent-glow: rgba(16, 185, 129, 0.35);
|
||||
}
|
||||
body[data-accent='blue'] {
|
||||
--accent-primary: #60a5fa;
|
||||
--accent-secondary: #93c5fd;
|
||||
--accent-glow: rgba(96, 165, 250, 0.35);
|
||||
}
|
||||
body[data-accent='indigo'] {
|
||||
--accent-primary: #818cf8;
|
||||
--accent-secondary: #a5b4fc;
|
||||
--accent-glow: rgba(129, 140, 248, 0.35);
|
||||
}
|
||||
body[data-accent='violet'] {
|
||||
--accent-primary: #a78bfa;
|
||||
--accent-secondary: #c4b5fd;
|
||||
--accent-glow: rgba(167, 139, 250, 0.35);
|
||||
}
|
||||
body[data-accent='fuchsia'] {
|
||||
--accent-primary: #e879f9;
|
||||
--accent-secondary: #f0abfc;
|
||||
--accent-glow: rgba(232, 121, 249, 0.35);
|
||||
}
|
||||
body[data-accent='rose'] {
|
||||
--accent-primary: #fb7185;
|
||||
--accent-secondary: #fda4af;
|
||||
--accent-glow: rgba(251, 113, 133, 0.35);
|
||||
}
|
||||
body[data-accent='amber'] {
|
||||
--accent-primary: #fbbf24;
|
||||
--accent-secondary: #fcd34d;
|
||||
--accent-glow: rgba(251, 191, 36, 0.35);
|
||||
}
|
||||
body[data-accent='orange'] {
|
||||
--accent-primary: #fb923c;
|
||||
--accent-secondary: #fdba74;
|
||||
--accent-glow: rgba(251, 146, 60, 0.35);
|
||||
}
|
||||
body[data-accent='sky'] {
|
||||
--accent-primary: #38bdf8;
|
||||
--accent-secondary: #7dd3fc;
|
||||
--accent-glow: rgba(56, 189, 248, 0.35);
|
||||
}
|
||||
body[data-accent='lime'] {
|
||||
--accent-primary: #a3e635;
|
||||
--accent-secondary: #bef264;
|
||||
--accent-glow: rgba(163, 230, 53, 0.35);
|
||||
}
|
||||
|
||||
/* UI scale (base type) */
|
||||
body[data-ui-scale='sm'] {
|
||||
font-size: 13px;
|
||||
}
|
||||
body[data-ui-scale='sm'] .nav-link {
|
||||
font-size: 12.5px;
|
||||
}
|
||||
body[data-ui-scale='lg'] {
|
||||
font-size: 16px;
|
||||
}
|
||||
body[data-ui-scale='lg'] .nav-link {
|
||||
font-size: 14.5px;
|
||||
}
|
||||
body[data-ui-scale='lg'] .form-label,
|
||||
body[data-ui-scale='lg'] .form-text {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
/* Corner radius tokens */
|
||||
body[data-radius='sharp'] {
|
||||
--border-radius: 6px;
|
||||
--border-radius-sm: 4px;
|
||||
--border-radius-lg: 8px;
|
||||
}
|
||||
body[data-radius='round'] {
|
||||
--border-radius: 18px;
|
||||
--border-radius-sm: 12px;
|
||||
--border-radius-lg: 24px;
|
||||
}
|
||||
|
||||
/* Chrome surface: titlebar / sidebar material */
|
||||
body[data-chrome='solid'] #titlebar {
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
background: var(--bg-secondary, #0f131a);
|
||||
}
|
||||
body[data-chrome='solid'] #sidebar {
|
||||
background: var(--bg-secondary, #0f131a);
|
||||
}
|
||||
body[data-chrome='flat'] #titlebar {
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
background: var(--bg-primary, #0a0c10);
|
||||
border-bottom-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
body[data-chrome='flat'] #sidebar {
|
||||
background: var(--bg-primary, #0a0c10);
|
||||
border-right-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Accent swatches (Settings → Appearance) */
|
||||
.pd-accent-swatches {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
.pd-accent-swatch {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 999px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.12);
|
||||
background: linear-gradient(135deg, var(--swatch, #34d399), var(--swatch-2, var(--swatch, #2dd4bf)));
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
box-shadow: 0 0 0 0 transparent;
|
||||
transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
.pd-accent-swatch:hover {
|
||||
transform: scale(1.08);
|
||||
border-color: rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
.pd-accent-swatch:focus-visible {
|
||||
outline: 2px solid var(--accent-secondary, #2dd4bf);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.pd-accent-swatch.is-active {
|
||||
border-color: #fff;
|
||||
box-shadow:
|
||||
0 0 0 2px var(--bg-primary, #0a0c10),
|
||||
0 0 0 4px var(--swatch, var(--accent-primary, #34d399));
|
||||
transform: scale(1.06);
|
||||
}
|
||||
.pd-accent-select {
|
||||
max-width: 16rem;
|
||||
}
|
||||
body[data-reduce-motion='1'] .pd-accent-swatch {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/* Sticky table headers in scrollable resource tables */
|
||||
.table-responsive,
|
||||
|
||||
+180
-5
@@ -77,6 +77,75 @@ import {
|
||||
const SIDEBAR_KEY = 'peardock.sidebar.collapsed'
|
||||
const FIRST_CONNECT_KEY = 'peardock.firstConnect.dismissed'
|
||||
|
||||
/**
|
||||
* Accent color presets (dark UI). Light theme overrides live in theme-light.css.
|
||||
* Keys are stored in settings.accent and applied as body[data-accent].
|
||||
*/
|
||||
export const ACCENT_PRESETS = Object.freeze({
|
||||
teal: { label: 'Teal', primary: '#34d399', secondary: '#2dd4bf' },
|
||||
cyan: { label: 'Cyan', primary: '#22d3ee', secondary: '#67e8f9' },
|
||||
emerald: { label: 'Emerald', primary: '#10b981', secondary: '#34d399' },
|
||||
blue: { label: 'Blue', primary: '#60a5fa', secondary: '#93c5fd' },
|
||||
indigo: { label: 'Indigo', primary: '#818cf8', secondary: '#a5b4fc' },
|
||||
violet: { label: 'Violet', primary: '#a78bfa', secondary: '#c4b5fd' },
|
||||
fuchsia: { label: 'Fuchsia', primary: '#e879f9', secondary: '#f0abfc' },
|
||||
rose: { label: 'Rose', primary: '#fb7185', secondary: '#fda4af' },
|
||||
amber: { label: 'Amber', primary: '#fbbf24', secondary: '#fcd34d' },
|
||||
orange: { label: 'Orange', primary: '#fb923c', secondary: '#fdba74' },
|
||||
sky: { label: 'Sky', primary: '#38bdf8', secondary: '#7dd3fc' },
|
||||
lime: { label: 'Lime', primary: '#a3e635', secondary: '#bef264' },
|
||||
})
|
||||
|
||||
export const ACCENT_IDS = Object.freeze(Object.keys(ACCENT_PRESETS))
|
||||
|
||||
const UI_SCALE_IDS = new Set(['sm', 'md', 'lg'])
|
||||
const RADIUS_IDS = new Set(['sharp', 'default', 'round'])
|
||||
const CHROME_IDS = new Set(['glass', 'solid', 'flat'])
|
||||
|
||||
/**
|
||||
* @param {unknown} raw
|
||||
* @returns {string}
|
||||
*/
|
||||
export function normalizeAccent(raw) {
|
||||
const v = String(raw || '')
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
return ACCENT_PRESETS[v] ? v : 'teal'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} raw
|
||||
* @returns {'sm' | 'md' | 'lg'}
|
||||
*/
|
||||
export function normalizeUiScale(raw) {
|
||||
const v = String(raw || '')
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
return UI_SCALE_IDS.has(v) ? /** @type {'sm' | 'md' | 'lg'} */ (v) : 'md'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} raw
|
||||
* @returns {'sharp' | 'default' | 'round'}
|
||||
*/
|
||||
export function normalizeBorderRadius(raw) {
|
||||
const v = String(raw || '')
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
return RADIUS_IDS.has(v) ? /** @type {'sharp' | 'default' | 'round'} */ (v) : 'default'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} raw
|
||||
* @returns {'glass' | 'solid' | 'flat'}
|
||||
*/
|
||||
export function normalizeChromeStyle(raw) {
|
||||
const v = String(raw || '')
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
return CHROME_IDS.has(v) ? /** @type {'glass' | 'solid' | 'flat'} */ (v) : 'glass'
|
||||
}
|
||||
|
||||
/** Defaults for client-side preferences (~/.config/peardock/cache/settings.json). */
|
||||
export const DEFAULT_SETTINGS = {
|
||||
density: 'comfortable', // comfortable | compact | spacious
|
||||
@@ -147,7 +216,26 @@ export const DEFAULT_SETTINGS = {
|
||||
*/
|
||||
theme: 'dark',
|
||||
reduceMotion: false,
|
||||
accent: 'teal', // teal | cyan | violet
|
||||
/**
|
||||
* Brand accent for highlights / focus / active nav.
|
||||
* @type {keyof typeof ACCENT_PRESETS}
|
||||
*/
|
||||
accent: 'teal',
|
||||
/**
|
||||
* Global UI type scale.
|
||||
* @type {'sm' | 'md' | 'lg'}
|
||||
*/
|
||||
uiScale: 'md',
|
||||
/**
|
||||
* Corner radius of cards, buttons, inputs.
|
||||
* @type {'sharp' | 'default' | 'round'}
|
||||
*/
|
||||
borderRadius: 'default',
|
||||
/**
|
||||
* Titlebar / sidebar surface treatment.
|
||||
* @type {'glass' | 'solid' | 'flat'}
|
||||
*/
|
||||
chromeStyle: 'glass',
|
||||
showRefreshStamp: true,
|
||||
/**
|
||||
* Global hide rules for containers that carry matching labels.
|
||||
@@ -440,6 +528,12 @@ export function loadSettings() {
|
||||
}
|
||||
}
|
||||
merged.theme = normalizeThemePreference(raw.theme ?? DEFAULT_SETTINGS.theme)
|
||||
merged.accent = normalizeAccent(raw.accent ?? DEFAULT_SETTINGS.accent)
|
||||
merged.uiScale = normalizeUiScale(raw.uiScale ?? DEFAULT_SETTINGS.uiScale)
|
||||
merged.borderRadius = normalizeBorderRadius(
|
||||
raw.borderRadius ?? DEFAULT_SETTINGS.borderRadius
|
||||
)
|
||||
merged.chromeStyle = normalizeChromeStyle(raw.chromeStyle ?? DEFAULT_SETTINGS.chromeStyle)
|
||||
merged.terminalTheme = normalizeTerminalThemePref(
|
||||
raw.terminalTheme ?? DEFAULT_SETTINGS.terminalTheme
|
||||
)
|
||||
@@ -496,11 +590,20 @@ let listRefreshTimer = null
|
||||
export function applySettings(s = loadSettings()) {
|
||||
document.body.dataset.density = s.density || 'comfortable'
|
||||
document.body.dataset.badgeMode = s.badgeMode || 'alerts'
|
||||
document.body.dataset.accent = s.accent || 'teal'
|
||||
document.body.dataset.accent = normalizeAccent(s.accent)
|
||||
document.body.dataset.uiScale = normalizeUiScale(s.uiScale)
|
||||
document.body.dataset.radius = normalizeBorderRadius(s.borderRadius)
|
||||
document.body.dataset.chrome = normalizeChromeStyle(s.chromeStyle)
|
||||
document.body.dataset.reduceMotion = s.reduceMotion ? '1' : '0'
|
||||
document.body.dataset.refreshStamp = s.showRefreshStamp === false ? '0' : '1'
|
||||
applyColorTheme(s.theme || 'dark')
|
||||
startListAutoRefresh(s.refreshSeconds)
|
||||
try {
|
||||
ensureAccentSwatches()
|
||||
syncAccentSwatches(normalizeAccent(s.accent))
|
||||
} catch {
|
||||
// ignore (DOM not ready)
|
||||
}
|
||||
|
||||
// Fast path for uiUtils / reconnect handlers (avoid re-parsing localStorage every event)
|
||||
try {
|
||||
@@ -2145,6 +2248,71 @@ function setCheckbox(id, checked) {
|
||||
if (el) el.checked = Boolean(checked)
|
||||
}
|
||||
|
||||
/**
|
||||
* Build accent swatch buttons once (Settings → Appearance).
|
||||
* Swatches keep the hidden/select #settings-accent in sync for live apply.
|
||||
*/
|
||||
export function ensureAccentSwatches() {
|
||||
const host = document.getElementById('settings-accent-swatches')
|
||||
const select = document.getElementById('settings-accent')
|
||||
if (!host || host.dataset.ready === '1') return
|
||||
|
||||
// Populate select options from presets (keeps HTML/select in lockstep with JS)
|
||||
if (select && select.tagName === 'SELECT') {
|
||||
const current = normalizeAccent(select.value)
|
||||
select.replaceChildren()
|
||||
for (const id of ACCENT_IDS) {
|
||||
const opt = document.createElement('option')
|
||||
opt.value = id
|
||||
opt.textContent = ACCENT_PRESETS[id].label + (id === 'teal' ? ' (default)' : '')
|
||||
select.appendChild(opt)
|
||||
}
|
||||
select.value = current
|
||||
}
|
||||
|
||||
host.replaceChildren()
|
||||
host.setAttribute('role', 'radiogroup')
|
||||
host.setAttribute('aria-label', 'Accent color')
|
||||
|
||||
for (const id of ACCENT_IDS) {
|
||||
const preset = ACCENT_PRESETS[id]
|
||||
const btn = document.createElement('button')
|
||||
btn.type = 'button'
|
||||
btn.className = 'pd-accent-swatch'
|
||||
btn.dataset.accentValue = id
|
||||
btn.title = preset.label
|
||||
btn.setAttribute('aria-label', preset.label)
|
||||
btn.setAttribute('role', 'radio')
|
||||
btn.style.setProperty('--swatch', preset.primary)
|
||||
btn.style.setProperty('--swatch-2', preset.secondary)
|
||||
btn.addEventListener('click', () => {
|
||||
if (select) {
|
||||
select.value = id
|
||||
select.dispatchEvent(new Event('change', { bubbles: true }))
|
||||
}
|
||||
syncAccentSwatches(id)
|
||||
})
|
||||
host.appendChild(btn)
|
||||
}
|
||||
host.dataset.ready = '1'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} accentId
|
||||
*/
|
||||
export function syncAccentSwatches(accentId) {
|
||||
const id = normalizeAccent(accentId)
|
||||
const host = document.getElementById('settings-accent-swatches')
|
||||
if (!host) return
|
||||
host.querySelectorAll('.pd-accent-swatch').forEach((el) => {
|
||||
const on = el.dataset.accentValue === id
|
||||
el.classList.toggle('is-active', on)
|
||||
el.setAttribute('aria-checked', on ? 'true' : 'false')
|
||||
})
|
||||
const select = document.getElementById('settings-accent')
|
||||
if (select && select.value !== id) select.value = id
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch settings subtab.
|
||||
* @param {string} tab
|
||||
@@ -2367,13 +2535,15 @@ export function readSettingsForm() {
|
||||
const density = ['comfortable', 'compact', 'spacious'].includes(densityRaw)
|
||||
? densityRaw
|
||||
: 'comfortable'
|
||||
const accentRaw = document.getElementById('settings-accent')?.value || 'teal'
|
||||
const accent = ['teal', 'cyan', 'violet'].includes(accentRaw) ? accentRaw : 'teal'
|
||||
const accent = normalizeAccent(document.getElementById('settings-accent')?.value)
|
||||
const theme = normalizeThemePreference(document.getElementById('settings-theme')?.value)
|
||||
return {
|
||||
density,
|
||||
accent,
|
||||
theme,
|
||||
uiScale: normalizeUiScale(document.getElementById('settings-ui-scale')?.value),
|
||||
borderRadius: normalizeBorderRadius(document.getElementById('settings-radius')?.value),
|
||||
chromeStyle: normalizeChromeStyle(document.getElementById('settings-chrome')?.value),
|
||||
reduceMotion: document.getElementById('settings-reduce-motion')?.value === '1',
|
||||
showRefreshStamp: document.getElementById('settings-refresh-stamp')?.value !== '0',
|
||||
sidebarCollapsed: document.getElementById('settings-sidebar')?.value === 'collapsed',
|
||||
@@ -2756,10 +2926,15 @@ export function loadSettingsView(forceTab) {
|
||||
const s = loadSettings()
|
||||
setSelectValue('settings-density', s.density || 'comfortable')
|
||||
setSelectValue('settings-theme', normalizeThemePreference(s.theme))
|
||||
setSelectValue('settings-accent', s.accent || 'teal')
|
||||
setSelectValue('settings-accent', normalizeAccent(s.accent))
|
||||
setSelectValue('settings-ui-scale', normalizeUiScale(s.uiScale))
|
||||
setSelectValue('settings-radius', normalizeBorderRadius(s.borderRadius))
|
||||
setSelectValue('settings-chrome', normalizeChromeStyle(s.chromeStyle))
|
||||
setSelectValue('settings-reduce-motion', s.reduceMotion ? '1' : '0')
|
||||
setSelectValue('settings-refresh-stamp', s.showRefreshStamp === false ? '0' : '1')
|
||||
setSelectValue('settings-sidebar', s.sidebarCollapsed ? 'collapsed' : 'expanded')
|
||||
ensureAccentSwatches()
|
||||
syncAccentSwatches(normalizeAccent(s.accent))
|
||||
setSelectValue('settings-confirm', s.confirmDestructive === false ? '0' : '1')
|
||||
setSelectValue('settings-refresh', s.refreshSeconds ?? 10)
|
||||
setSelectValue('settings-job-dismiss', s.jobSuccessDismissMs ?? 3000)
|
||||
|
||||
+70
-2
@@ -58,18 +58,86 @@ html[data-theme='light'] {
|
||||
--pd-border: var(--border-color);
|
||||
}
|
||||
|
||||
/* Accent variants on light: deeper hues for contrast */
|
||||
/* Accent variants on light: deeper hues for contrast on white surfaces */
|
||||
html[data-theme='light'] body[data-accent='teal'] {
|
||||
--accent-primary: #0f766e;
|
||||
--accent-secondary: #0d9488;
|
||||
--accent-glow: rgba(15, 118, 110, 0.2);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='cyan'] {
|
||||
--accent-primary: #0e7490;
|
||||
--accent-secondary: #0891b2;
|
||||
--accent-glow: rgba(14, 116, 144, 0.22);
|
||||
}
|
||||
|
||||
html[data-theme='light'] body[data-accent='emerald'] {
|
||||
--accent-primary: #047857;
|
||||
--accent-secondary: #059669;
|
||||
--accent-glow: rgba(4, 120, 87, 0.2);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='blue'] {
|
||||
--accent-primary: #1d4ed8;
|
||||
--accent-secondary: #2563eb;
|
||||
--accent-glow: rgba(29, 78, 216, 0.18);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='indigo'] {
|
||||
--accent-primary: #4338ca;
|
||||
--accent-secondary: #4f46e5;
|
||||
--accent-glow: rgba(67, 56, 202, 0.18);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='violet'] {
|
||||
--accent-primary: #6d28d9;
|
||||
--accent-secondary: #7c3aed;
|
||||
--accent-glow: rgba(109, 40, 217, 0.2);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='fuchsia'] {
|
||||
--accent-primary: #a21caf;
|
||||
--accent-secondary: #c026d3;
|
||||
--accent-glow: rgba(162, 28, 175, 0.18);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='rose'] {
|
||||
--accent-primary: #be123c;
|
||||
--accent-secondary: #e11d48;
|
||||
--accent-glow: rgba(190, 18, 60, 0.18);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='amber'] {
|
||||
--accent-primary: #b45309;
|
||||
--accent-secondary: #d97706;
|
||||
--accent-glow: rgba(180, 83, 9, 0.18);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='orange'] {
|
||||
--accent-primary: #c2410c;
|
||||
--accent-secondary: #ea580c;
|
||||
--accent-glow: rgba(194, 65, 12, 0.18);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='sky'] {
|
||||
--accent-primary: #0369a1;
|
||||
--accent-secondary: #0284c7;
|
||||
--accent-glow: rgba(3, 105, 161, 0.18);
|
||||
}
|
||||
html[data-theme='light'] body[data-accent='lime'] {
|
||||
--accent-primary: #4d7c0f;
|
||||
--accent-secondary: #65a30d;
|
||||
--accent-glow: rgba(77, 124, 15, 0.18);
|
||||
}
|
||||
|
||||
html[data-theme='light'] body[data-chrome='solid'] #titlebar {
|
||||
background: #ffffff;
|
||||
}
|
||||
html[data-theme='light'] body[data-chrome='flat'] #titlebar {
|
||||
background: #f3f5f8;
|
||||
}
|
||||
html[data-theme='light'] body[data-chrome='flat'] #sidebar {
|
||||
background: #f3f5f8;
|
||||
}
|
||||
html[data-theme='light'] .pd-accent-swatch {
|
||||
border-color: rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
html[data-theme='light'] .pd-accent-swatch.is-active {
|
||||
border-color: #0f172a;
|
||||
box-shadow:
|
||||
0 0 0 2px #fff,
|
||||
0 0 0 4px var(--swatch, var(--accent-primary));
|
||||
}
|
||||
|
||||
/* ─── Base chrome ─── */
|
||||
html[data-theme='light'] body {
|
||||
|
||||
Reference in New Issue
Block a user