Design System (Phase 4)
Synced read-only from
/home/synnet/mirrors/synvirt-product/docs/modules/web-ux-v2/DESIGN_SYSTEM.md. Edit at the source, not here.
Design System (Phase 4)
Section titled “Design System (Phase 4)”The v2 console ships a tokenised design system that drives every
visual decision through CSS variables. Components consume tokens via
Tailwind utility classes that resolve to rgb(var(--color-x) / <alpha-value>), so alpha modifiers (bg-accent/10) work without
rewriting every component when the palette changes.
Layers
Section titled “Layers”| File | Responsibility |
|---|---|
src/styles/tokens.css |
The chromatic / spatial / motion source of truth. Light + dark + density + reduced-motion variants. |
src/styles/reset.css |
Modern CSS reset on top of Tailwind preflight (form inheritance, custom scrollbars, focus-visible). |
src/styles/typography.css |
Display / heading / mono helpers, tabular-num figures, text-eyebrow. |
src/styles/animations.css |
@keyframes synvirt-* plus reusable utility classes (.status-dot-online, .progress-indeterminate). |
src/styles/main.css |
Imports the four files in order and exposes .surface-card, .surface-inset, .surface-sticky, .kbd-cap. |
Tailwind reads the tokens via tailwind.config.ts::theme.extend.
Adding a new colour means adding a CSS variable in tokens.css
and mapping it under extend.colors so bg-foo / text-foo
become valid utilities.
Palette
Section titled “Palette”The palette mirrors brand/colors.md (the OKLCH source of truth)
translated into RGB triplets so Tailwind’s alpha substitution works.
Surfaces
Section titled “Surfaces”| Token | Light | Dark |
|---|---|---|
bg |
#F8FAFD |
#06090F |
bg-2 |
#F3F5F9 |
#0A0D14 |
surface |
#FFFFFF |
#10141B |
surface-2 |
#F8FAFD |
#171B23 |
surface-3 |
#EFF2F6 |
#20242D |
surface-4 |
#E5E8ED |
#292E38 |
| Token | Light | Dark |
|---|---|---|
accent |
#3362E1 |
#6397FF |
accent-2 |
#3445D7 |
#88A9FF |
accent-3 |
#3725C6 |
#AABCFF |
accent-soft |
#E8F2FF |
#102459 |
accent-ink |
#15197C |
#BED5FF |
5-step scale from text (primary) through text-5 (decorative
hairlines). text-3 is the de-facto secondary in cards.
Status
Section titled “Status”ok, warn, danger, info, idle — each carries a soft variant
suffixed -soft for tinted backgrounds (bg-ok-soft, text-ok).
Themes
Section titled “Themes”Two attribute-driven modes plus a “system” follower:
<html data-theme="light"> <!-- or "dark" --><html data-density="comfortable"> <!-- or "dense" -->The composables in src/composables/ own each attribute:
useTheme—mode(light | dark | system),resolved(light | dark),setMode(...),toggle(). Persists inlocalStorage['synvirt:theme'].useDensity—density,setDensity(...),toggle(). Persists inlocalStorage['synvirt:density'].useReducedMotion—reduceref trackingprefers-reduced-motion.
The inline <script> in index.html runs synchronously before
paint and applies the saved attributes so the page never flashes
the wrong theme on cold load.
Density
Section titled “Density”comfortable is the default. dense shrinks vertical-rhythm
spacing tokens by ~25 % (page padding 24 → 16, input height
40 → 32, etc.). Component visuals don’t change shape — only
breathing room.
Motion
Section titled “Motion”| Token | Value |
|---|---|
--duration-instant |
75ms |
--duration-fast |
150ms |
--duration-normal |
200ms |
--duration-slow |
300ms |
--duration-slower |
500ms |
Easing tokens cover standard, decel, accel, emphasis, and
spring. All durations collapse to 1 ms under
prefers-reduced-motion: reduce or data-reduced-motion="reduce".
Component-level utilities
Section titled “Component-level utilities”main.css exposes these helpers:
.surface-card— bordered + radius + soft shadow card..surface-card-flush— same but withoverflow: hiddenfor tables..surface-sticky— translucent pill that sits above scroll content..surface-inset— recessed sub-card used by the wizard’s per-disk / per-NIC rows..dashed-frame— dashed-outline placeholder for upload / empty zones..kbd-cap— monospace key cap for the command palette and shortcut hints..status-dot-online/.status-dot-offline/.status-dot-warn— animated state indicators..progress-indeterminate— sliding accent bar for indeterminate progress.
- Never write a hex colour in a component. Add a token first.
- Never write
dark:Tailwind variants — the design tokens carry dark mode automatically. Only the dark variant of a non-token value (e.g. one-off SVG fills) needs a manual override. - Spacing comes from the
var(--space-*)scale (4-px base) or the density-awarevar(--density-*)tokens. Don’t hard-codepadding: 17px. - Animations and transitions reference token-driven durations
(
duration-fast,duration-normal) so reduced-motion works without per-component@mediaqueries.