Tokens (light + dark, neumorphism, 54/54 WCAG AA contrast pairs), the self-hosted JetBrains Mono fonts, and interactive mockups of every screen across three iterations. Iteration 3 is final: phone, tablet and desktop tiers, device preview, and "empty spool weight" terminology. The build scripts regenerate the screens byte-identically from source. Implementation is tracked in Maestro feature UI Refresh - V3.0 (224b72a1-8d84-4970-97ea-5dafa4d8ea3b). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
395 lines
20 KiB
CSS
395 lines
20 KiB
CSS
/*
|
||
* CubeCraftLabs Design System v3 (proposal): Soft UI / Neumorphism
|
||
*
|
||
* Built on Design System v2.0 (http://pages.ccl/design-v2.0/, verified
|
||
* identical to Extrudex web/src/theme.css at dev 321ce0d on 2026-09-18).
|
||
*
|
||
* Structure
|
||
* 1. Font faces JetBrains Mono, self-hosted woff2, no CDN
|
||
* 2. v2.0 base scale kept verbatim, so v2 references still resolve
|
||
* 3. v3 theme tokens dark (default, as in v2.0) and light (new)
|
||
* 4. Neumorphism surfaces, raised/inset shadow pairs, intensity, radius
|
||
* 5. State tokens focus, pressed, disabled, error
|
||
* 6. Reference components used by the mockups
|
||
*
|
||
* Accessibility rules this file enforces:
|
||
* - Shadows are decoration. Every control also has a border at 3:1 or more
|
||
* against its surface (WCAG 1.4.11), so it stays visible with shadows off.
|
||
* - Focus, pressed, disabled and error each change something besides shadow
|
||
* direction: the outline, the fill plus a check glyph, a dashed border, or
|
||
* a red border plus an icon plus a message.
|
||
* - The contrast table is in design-system-v3.md.
|
||
*
|
||
* Theme selection: dark is the default because v2.0 is dark. Light applies
|
||
* when the OS prefers it and nothing is forced, or with data-theme="light" on
|
||
* <html>. data-theme="dark" forces dark.
|
||
*/
|
||
|
||
/* ── 1. Font faces ──────────────────────────────────────────────────────── */
|
||
/* The same files @fontsource/jetbrains-mono 5.3.0 ships (the app's dependency). */
|
||
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 400; src: url('./fonts/jetbrains-mono-latin-400-normal.woff2') format('woff2'); }
|
||
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 500; src: url('./fonts/jetbrains-mono-latin-500-normal.woff2') format('woff2'); }
|
||
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 700; src: url('./fonts/jetbrains-mono-latin-700-normal.woff2') format('woff2'); }
|
||
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 800; src: url('./fonts/jetbrains-mono-latin-800-normal.woff2') format('woff2'); }
|
||
|
||
/* ── 2. v2.0 base scale (unchanged) ─────────────────────────────────────── */
|
||
:root {
|
||
--ccl-charcoal: #2c2c30;
|
||
--ccl-charcoal-2: #36363a;
|
||
--ccl-charcoal-3: #1b1b1e;
|
||
--ccl-gold: #8f7ae0;
|
||
--ccl-gold-dim: #7a63cc;
|
||
--ccl-text: #f4f4f6;
|
||
--ccl-text-muted: #b2b2ba;
|
||
--ccl-border: #3d3d44;
|
||
--ccl-border-2: #4e4e57;
|
||
--ccl-green: #a9d88b;
|
||
--ccl-red: #f08b93;
|
||
--ccl-white: #ffffff;
|
||
--ccl-ink: #2a2431;
|
||
|
||
--ccl-grey: var(--ccl-charcoal);
|
||
--ccl-grey-2: var(--ccl-charcoal-2);
|
||
--ccl-grey-3: var(--ccl-charcoal-3);
|
||
--ccl-purple: var(--ccl-gold);
|
||
--ccl-purple-dim: var(--ccl-gold-dim);
|
||
--ccl-purple-wash: rgba(143, 122, 224, 0.12);
|
||
|
||
/* v3 additions to the base scale: tints derived from the v2.0 hues */
|
||
--ccl-gold-light: #a99af0; /* accent lifted to pass 4.5:1 as text on charcoal */
|
||
--ccl-violet-deep: #5b43b8; /* accent darkened to pass 4.5:1 on the light surface */
|
||
--ccl-charcoal-inset:#232327; /* between charcoal and charcoal-3: dark wells */
|
||
--ccl-amber: #e8c170; /* new: warning (v2.0 had none) */
|
||
--ccl-blue: #8fc3f0; /* new: informational / provenance */
|
||
--ccl-mist: #e4e2ea; /* light page: charcoal's hue, inverted */
|
||
--ccl-mist-2: #f1f0f5; /* light high surface */
|
||
--ccl-mist-3: #d9d6e1; /* light inset */
|
||
|
||
/* Typography, spacing and motion: unchanged from v2.0 */
|
||
--font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
||
--font-body: var(--font-mono);
|
||
--font-display: var(--font-mono);
|
||
--fw-regular: 400; --fw-medium: 500; --fw-bold: 700; --fw-display: 800;
|
||
--fs-caption: 11px; --fs-label: 12px; --fs-body: 14px; --fs-body-lg: 15px;
|
||
--fs-h3: 18px; --fs-h2: 22px; --fs-h1: 28px; --fs-display: 40px;
|
||
--lh-tight: 1.15; --lh-snug: 1.35; --lh-body: 1.7;
|
||
--tracking-wordmark: 0.02em; --tracking-caps: 0.08em; --tracking-caps-wide: 0.14em;
|
||
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px;
|
||
--space-6: 24px; --space-8: 32px; --space-10: 40px; --space-14: 56px; --space-16: 64px;
|
||
--ease-out: cubic-bezier(0.2, 0, 0, 1);
|
||
--dur-fast: 100ms; --dur-base: 160ms;
|
||
--dur-press: 60ms; /* v3: pressing reacts faster than hover */
|
||
--scrollbar-width: 6px;
|
||
|
||
/* ── 4a. Radius scale (v3; replaces v2.0's "0 is the rule") ── */
|
||
--radius-none: 0px; /* tables, code, grid lines: square stays available */
|
||
--radius-xs: 4px; /* chips, swatches, inline code */
|
||
--radius-sm: 8px; /* inputs, small buttons */
|
||
--radius-md: 12px; /* buttons, list rows */
|
||
--radius-lg: 18px; /* cards, panels */
|
||
--radius-xl: 26px; /* dialogs, the app shell */
|
||
--radius-pill: 999px; /* toggles, progress tracks, badges */
|
||
|
||
/* ── 4b. Shadow geometry: distance + blur per intensity level ── */
|
||
--nm-d-1: 2px; --nm-b-1: 5px; /* level 1: chips, small controls */
|
||
--nm-d-2: 4px; --nm-b-2: 10px; /* level 2: buttons, rows */
|
||
--nm-d-3: 8px; --nm-b-3: 18px; /* level 3: cards, panels */
|
||
--nm-d-4: 14px; --nm-b-4: 30px; /* level 4: dialogs */
|
||
|
||
/* Focus ring geometry: identical in both themes */
|
||
--focus-width: 2px;
|
||
--focus-offset: 3px;
|
||
--border-control-width: 1px;
|
||
--border-error-width: 2px;
|
||
}
|
||
|
||
/* ── 3. Theme tokens: DARK (default) ───────────────────────────────────── */
|
||
:root,
|
||
:root[data-theme="dark"] {
|
||
color-scheme: dark;
|
||
|
||
/* Surfaces */
|
||
--surface-page: var(--ccl-charcoal); /* #2c2c30 */
|
||
--surface-raised: var(--ccl-charcoal); /* v3: same as page; the lift comes from the shadow */
|
||
--surface-high: var(--ccl-charcoal-2); /* #36363a dialogs, menus */
|
||
--surface-inset: var(--ccl-charcoal-inset); /* #232327 inputs, wells, progress tracks */
|
||
--surface-code: var(--ccl-charcoal-3);
|
||
|
||
/* Text */
|
||
--text-primary: var(--ccl-text); /* 12.66:1 on page */
|
||
--text-secondary: var(--ccl-text-muted); /* 6.60:1 on page */
|
||
--text-accent: var(--ccl-gold-light); /* 5.67:1 on page */
|
||
--text-on-accent: var(--ccl-ink); /* on --accent-fill */
|
||
--text-on-gold: var(--ccl-ink);
|
||
|
||
/* Accent */
|
||
--accent: var(--ccl-gold); /* brand hue, for large marks only */
|
||
--accent-hover: var(--ccl-gold-dim);
|
||
--accent-fill: var(--ccl-gold-light); /* primary button fill; ink on it: 6.14:1 */
|
||
--accent-fill-press: #9785e6;
|
||
--accent-wash: rgba(169, 154, 240, 0.10);
|
||
|
||
/* Status: the v2.0 hues plus two new ones */
|
||
--status-success: var(--ccl-green);
|
||
--status-error: var(--ccl-red);
|
||
--status-warning: var(--ccl-amber);
|
||
--status-info: var(--ccl-blue);
|
||
--wash-success: rgba(169, 216, 139, 0.10);
|
||
--wash-error: rgba(240, 139, 147, 0.10);
|
||
--wash-warning: rgba(232, 193, 112, 0.10);
|
||
--wash-info: rgba(143, 195, 240, 0.10);
|
||
|
||
/* Borders */
|
||
--border-hairline: var(--ccl-border); /* decorative card edges */
|
||
--border-strong: var(--ccl-border-2);
|
||
--border-control: #85858f; /* 1.4.11: 3.81:1 page, 4.29:1 inset, 3.29:1 high */
|
||
--focus-ring: var(--ccl-gold-light); /* 5.67:1 on page */
|
||
|
||
/* ── 4c. Neumorphism shadow pairs, DARK ──
|
||
Dark soft UI fails when the "dark" shadow is only a darker charcoal:
|
||
nothing on #2c2c30 is visibly darker than #1b1b1e. Four rules make it
|
||
work here:
|
||
a. The dark half is true black at high alpha, not a darker gray.
|
||
b. The light half is white at 4–7% alpha. It reads as sheen, not glow.
|
||
c. Raised surfaces add a 1px top rim light (inset, white 6%). The rim
|
||
stays visible even where the drop shadow merges into the background.
|
||
d. Every control has a 3:1 border anyway, so the shadow never carries
|
||
structure on its own. */
|
||
--nm-shadow-dark: rgba(0, 0, 0, 0.62);
|
||
--nm-shadow-light: rgba(255, 255, 255, 0.055);
|
||
--nm-rim: inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
||
--nm-inset-dark: rgba(0, 0, 0, 0.55);
|
||
--nm-inset-light: rgba(255, 255, 255, 0.045);
|
||
--nm-raised-gradient: linear-gradient(145deg, #313136, #29292d);
|
||
}
|
||
|
||
/* ── 3. Theme tokens: LIGHT (new in v3) ────────────────────────────────── */
|
||
@media (prefers-color-scheme: light) {
|
||
:root:not([data-theme="dark"]) {
|
||
color-scheme: light;
|
||
--surface-page: var(--ccl-mist);
|
||
--surface-raised: var(--ccl-mist);
|
||
--surface-high: var(--ccl-mist-2);
|
||
--surface-inset: var(--ccl-mist-3);
|
||
--surface-code: #d2cfdb;
|
||
--text-primary: var(--ccl-ink);
|
||
--text-secondary: #55505f;
|
||
--text-accent: var(--ccl-violet-deep);
|
||
--text-on-accent: var(--ccl-white);
|
||
--text-on-gold: var(--ccl-white);
|
||
--accent: var(--ccl-gold);
|
||
--accent-hover: var(--ccl-gold-dim);
|
||
--accent-fill: var(--ccl-violet-deep);
|
||
--accent-fill-press: #4d37a3;
|
||
--accent-wash: rgba(91, 67, 184, 0.10);
|
||
--status-success: #2c6619;
|
||
--status-error: #a8202f;
|
||
--status-warning: #7c5100;
|
||
--status-info: #1d5e94;
|
||
--wash-success: rgba(44, 102, 25, 0.10);
|
||
--wash-error: rgba(168, 32, 47, 0.10);
|
||
--wash-warning: rgba(124, 81, 0, 0.10);
|
||
--wash-info: rgba(29, 94, 148, 0.10);
|
||
--border-hairline: #cfccd8;
|
||
--border-strong: #b9b5c6;
|
||
--border-control: #736e86;
|
||
--focus-ring: var(--ccl-violet-deep);
|
||
--nm-shadow-dark: rgba(88, 80, 120, 0.30);
|
||
--nm-shadow-light: rgba(255, 255, 255, 0.95);
|
||
--nm-rim: inset 0 1px 0 rgba(255, 255, 255, 0.7);
|
||
--nm-inset-dark: rgba(88, 80, 120, 0.28);
|
||
--nm-inset-light: rgba(255, 255, 255, 0.9);
|
||
--nm-raised-gradient: linear-gradient(145deg, #eceaf1, #dcd9e3);
|
||
}
|
||
}
|
||
:root[data-theme="light"] {
|
||
color-scheme: light;
|
||
--surface-page: var(--ccl-mist);
|
||
--surface-raised: var(--ccl-mist);
|
||
--surface-high: var(--ccl-mist-2);
|
||
--surface-inset: var(--ccl-mist-3);
|
||
--surface-code: #d2cfdb;
|
||
--text-primary: var(--ccl-ink);
|
||
--text-secondary: #55505f;
|
||
--text-accent: var(--ccl-violet-deep);
|
||
--text-on-accent: var(--ccl-white);
|
||
--text-on-gold: var(--ccl-white);
|
||
--accent: var(--ccl-gold);
|
||
--accent-hover: var(--ccl-gold-dim);
|
||
--accent-fill: var(--ccl-violet-deep);
|
||
--accent-fill-press: #4d37a3;
|
||
--accent-wash: rgba(91, 67, 184, 0.10);
|
||
--status-success: #2c6619;
|
||
--status-error: #a8202f;
|
||
--status-warning: #7c5100;
|
||
--status-info: #1d5e94;
|
||
--wash-success: rgba(44, 102, 25, 0.10);
|
||
--wash-error: rgba(168, 32, 47, 0.10);
|
||
--wash-warning: rgba(124, 81, 0, 0.10);
|
||
--wash-info: rgba(29, 94, 148, 0.10);
|
||
--border-hairline: #cfccd8;
|
||
--border-strong: #b9b5c6;
|
||
--border-control: #736e86;
|
||
--focus-ring: var(--ccl-violet-deep);
|
||
--nm-shadow-dark: rgba(88, 80, 120, 0.30);
|
||
--nm-shadow-light: rgba(255, 255, 255, 0.95);
|
||
--nm-rim: inset 0 1px 0 rgba(255, 255, 255, 0.7);
|
||
--nm-inset-dark: rgba(88, 80, 120, 0.28);
|
||
--nm-inset-light: rgba(255, 255, 255, 0.9);
|
||
--nm-raised-gradient: linear-gradient(145deg, #eceaf1, #dcd9e3);
|
||
}
|
||
|
||
/* ── 4d. Composed shadows: theme-agnostic, built from the pairs above ── */
|
||
:root {
|
||
--nm-raised-1: calc(var(--nm-d-1) * -1) calc(var(--nm-d-1) * -1) var(--nm-b-1) var(--nm-shadow-light),
|
||
var(--nm-d-1) var(--nm-d-1) var(--nm-b-1) var(--nm-shadow-dark), var(--nm-rim);
|
||
--nm-raised-2: calc(var(--nm-d-2) * -1) calc(var(--nm-d-2) * -1) var(--nm-b-2) var(--nm-shadow-light),
|
||
var(--nm-d-2) var(--nm-d-2) var(--nm-b-2) var(--nm-shadow-dark), var(--nm-rim);
|
||
--nm-raised-3: calc(var(--nm-d-3) * -1) calc(var(--nm-d-3) * -1) var(--nm-b-3) var(--nm-shadow-light),
|
||
var(--nm-d-3) var(--nm-d-3) var(--nm-b-3) var(--nm-shadow-dark), var(--nm-rim);
|
||
--nm-raised-4: calc(var(--nm-d-4) * -1) calc(var(--nm-d-4) * -1) var(--nm-b-4) var(--nm-shadow-light),
|
||
var(--nm-d-4) var(--nm-d-4) var(--nm-b-4) var(--nm-shadow-dark), var(--nm-rim);
|
||
--nm-inset-1: inset var(--nm-d-1) var(--nm-d-1) var(--nm-b-1) var(--nm-inset-dark),
|
||
inset calc(var(--nm-d-1) * -1) calc(var(--nm-d-1) * -1) var(--nm-b-1) var(--nm-inset-light);
|
||
--nm-inset-2: inset var(--nm-d-2) var(--nm-d-2) var(--nm-b-2) var(--nm-inset-dark),
|
||
inset calc(var(--nm-d-2) * -1) calc(var(--nm-d-2) * -1) var(--nm-b-2) var(--nm-inset-light);
|
||
--nm-flat: none;
|
||
/* v2.0 names kept so old rules still resolve */
|
||
--shadow-none: none;
|
||
--shadow-raised: var(--nm-raised-2);
|
||
/* Borders, v2.0 names */
|
||
--border-width: 1px;
|
||
--border: var(--border-width) solid var(--border-hairline);
|
||
--border-strong-rule: var(--border-width) solid var(--border-strong);
|
||
--border-accent: 1.5px solid var(--accent);
|
||
--scrollbar-thumb: var(--border-strong);
|
||
--scrollbar-thumb-hover: var(--accent);
|
||
}
|
||
|
||
/* ── 6. Reference components ────────────────────────────────────────────── */
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
html { background: var(--surface-page); }
|
||
body {
|
||
margin: 0;
|
||
background: var(--surface-page);
|
||
color: var(--text-primary);
|
||
font-family: var(--font-body);
|
||
font-size: var(--fs-body);
|
||
line-height: var(--lh-body);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
|
||
|
||
/* Surfaces */
|
||
.nm-raised { background: var(--nm-raised-gradient); box-shadow: var(--nm-raised-3); border: 1px solid var(--border-hairline); border-radius: var(--radius-lg); }
|
||
.nm-raised-sm { background: var(--surface-raised); box-shadow: var(--nm-raised-2); border: 1px solid var(--border-hairline); border-radius: var(--radius-md); }
|
||
.nm-inset { background: var(--surface-inset); box-shadow: var(--nm-inset-2); border: 1px solid var(--border-hairline); border-radius: var(--radius-md); }
|
||
.nm-dialog { background: var(--surface-high); box-shadow: var(--nm-raised-4); border: 1px solid var(--border-strong); border-radius: var(--radius-xl); }
|
||
|
||
/* Buttons
|
||
* rest raised-2 + 1px control border
|
||
* hover border takes the accent color
|
||
* pressed inset shadow + accent wash fill + accent border (+ ✓ on toggles)
|
||
* focus 2px solid outline, offset 3px, in the focus color
|
||
* disabled no shadow, dashed border, secondary text, not-allowed cursor
|
||
*/
|
||
.btn {
|
||
font: var(--fw-medium) var(--fs-body)/1 var(--font-body);
|
||
color: var(--text-primary);
|
||
background: var(--surface-raised);
|
||
border: var(--border-control-width) solid var(--border-control);
|
||
border-radius: var(--radius-md);
|
||
padding: 10px 16px;
|
||
min-height: 40px;
|
||
box-shadow: var(--nm-raised-2);
|
||
cursor: pointer;
|
||
display: inline-flex; align-items: center; gap: var(--space-2);
|
||
transition: box-shadow var(--dur-base) var(--ease-out), border-color var(--dur-fast), background var(--dur-fast);
|
||
}
|
||
.btn:hover { border-color: var(--text-accent); }
|
||
.btn:active, .btn[aria-pressed="true"], .btn.is-pressed {
|
||
box-shadow: var(--nm-inset-1);
|
||
background: var(--accent-wash);
|
||
border-color: var(--text-accent);
|
||
transition-duration: var(--dur-press);
|
||
}
|
||
.btn[aria-pressed="true"]::before, .btn.is-pressed::before { content: "✓"; font-weight: var(--fw-bold); color: var(--text-accent); }
|
||
.btn:focus-visible, .btn.is-focused, .input:focus-visible, .input.is-focused, .select:focus-visible, .select.is-focused {
|
||
outline: var(--focus-width) solid var(--focus-ring);
|
||
outline-offset: var(--focus-offset);
|
||
}
|
||
.btn:disabled, .btn.is-disabled {
|
||
box-shadow: none;
|
||
border-style: dashed;
|
||
color: var(--text-secondary);
|
||
background: transparent;
|
||
cursor: not-allowed;
|
||
}
|
||
.btn-primary { background: var(--accent-fill); color: var(--text-on-accent); border-color: var(--accent-fill); font-weight: var(--fw-bold); }
|
||
.btn-primary:hover { border-color: var(--text-primary); }
|
||
.btn-primary:active, .btn-primary.is-pressed { background: var(--accent-fill-press); color: var(--text-on-accent); border-color: var(--text-primary); }
|
||
.btn-primary.is-pressed::before { color: var(--text-on-accent); }
|
||
.btn-danger { color: var(--status-error); border-color: var(--status-error); }
|
||
.btn-sm { min-height: 32px; padding: 6px 12px; font-size: var(--fs-label); border-radius: var(--radius-sm); box-shadow: var(--nm-raised-1); }
|
||
.btn-icon { width: 40px; padding: 0; justify-content: center; }
|
||
|
||
/* Inputs: always inset, always bordered */
|
||
.input, .select {
|
||
font: var(--fw-regular) var(--fs-body)/1.4 var(--font-body);
|
||
color: var(--text-primary);
|
||
background: var(--surface-inset);
|
||
border: var(--border-control-width) solid var(--border-control);
|
||
border-radius: var(--radius-sm);
|
||
box-shadow: var(--nm-inset-1);
|
||
padding: 9px 12px;
|
||
min-height: 40px;
|
||
width: 100%;
|
||
}
|
||
.input::placeholder { color: var(--text-secondary); }
|
||
.input:disabled, .input.is-disabled, .select:disabled {
|
||
box-shadow: none; border-style: dashed; color: var(--text-secondary); background: transparent;
|
||
}
|
||
/* Error: 2px red border + icon in the label + message. Never color alone. */
|
||
.field.has-error .input, .field.has-error .select, .input.is-error {
|
||
border: var(--border-error-width) solid var(--status-error);
|
||
padding: 8px 11px;
|
||
}
|
||
.field-error {
|
||
display: flex; gap: var(--space-2); align-items: flex-start;
|
||
color: var(--status-error); font-size: var(--fs-label); line-height: var(--lh-snug); margin-top: var(--space-1);
|
||
}
|
||
.field-error::before { content: "⚠"; font-weight: var(--fw-bold); }
|
||
|
||
/* Chips / badges: text + wash + border + glyph */
|
||
.chip {
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
font-size: var(--fs-caption); font-weight: var(--fw-bold);
|
||
letter-spacing: var(--tracking-caps); text-transform: uppercase;
|
||
padding: 2px 9px; border-radius: var(--radius-pill);
|
||
border: 1px solid currentColor; line-height: 1.6;
|
||
white-space: nowrap;
|
||
}
|
||
.chip-ok { color: var(--status-success); background: var(--wash-success); }
|
||
.chip-err { color: var(--status-error); background: var(--wash-error); }
|
||
.chip-warn { color: var(--status-warning); background: var(--wash-warning); }
|
||
.chip-info { color: var(--status-info); background: var(--wash-info); }
|
||
.chip-accent { color: var(--text-accent); background: var(--accent-wash); }
|
||
.chip-neutral { color: var(--text-secondary); background: transparent; }
|
||
.chip-dashed { border-style: dashed; }
|
||
|
||
/* Progress track (inset) + fill (raised) */
|
||
.track { height: 10px; border-radius: var(--radius-pill); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-hairline); overflow: hidden; }
|
||
.track > span { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--text-accent); }
|
||
.track.is-low > span { background: var(--status-error); }
|
||
|
||
/* Swatch: 1–3 colors, a hairline so white/black filament shows on either theme */
|
||
.swatch { display: inline-flex; width: 26px; height: 26px; border-radius: 50%; overflow: hidden; border: 1px solid var(--border-control); box-shadow: var(--nm-raised-1); flex: none; }
|
||
.swatch > i { flex: 1; }
|
||
.swatch-sm { width: 18px; height: 18px; }
|
||
|
||
/* Text helpers */
|
||
.muted { color: var(--text-secondary); }
|
||
.accent { color: var(--text-accent); }
|
||
.caps { text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); font-size: var(--fs-caption); font-weight: var(--fw-bold); }
|
||
.num { font-variant-numeric: tabular-nums; }
|