Foundation

Theming

style.css

DOM Studio uses css variable design tokens: base tokens paint skins, and matching -fg tokens keep text readable.

Model

Colour and fg pairs

Use the base token when you are painting a background. Use the matching *-fg token when text or icons need to sit on it.

Filled action

bg-primary

text-primary-fg

Quiet panel

bg-secondary

text-secondary-fg or text-fg

Token naming convention

Bg token
DOM Studio --primary
Fg token
DOM Studio --primary-fg
Added pairs
primary, secondary, muted, accent, status

At a glance

Read the theme as product UI

Project dashboard

Example composition using only semantic tokens.

Saved

Revenue

GBP 42,860

+12.4%

Quiet panel

Secondary skins group nearby controls without demanding attention.

Review needed

Warning tokens should feel noticeable, not alarming.

Command menu

Editor

Tune CSS variable colours

Primary - light

--primary: oklch(0.205 0 0)

Corners

The base radius that feeds the rounded scale.

Shape preview

Radius is still global because it affects every rounded utility.

Rounded frame

Uses the same radius scale as components.

Skin recipes

These Tailwind-like utilities carry material, border, shadow, blur, and gradient from variables.

Base

skin-base

The page canvas and ordinary application background.

Raised

skin-raised

Cards, panels, calendars, and grouped content.

Floating

skin-floating

Dropdowns, popovers, combobox menus, and context menus.

Overlay

skin-overlay

Dialogs, drawers, command palettes, and action sheets.

Inset

skin-inset

Inputs, textareas, and editable recessed controls.

Control

skin-control

Secondary buttons, quiet triggers, and neutral controls.

Action

skin-action

Primary actions and high-emphasis commands.

Light mode

:root

Canvas

Page background and ordinary text.

Canvas

Page background and ordinary text.

Primary

Primary actions and high emphasis selected states.

Primary

Primary actions and high emphasis selected states.

Secondary

Quiet buttons, subtle panels, inactive controls, and helper UI.

Secondary

Quiet buttons, subtle panels, inactive controls, and helper UI.

Muted

Low-emphasis backgrounds and supporting copy.

Muted

Low-emphasis backgrounds and supporting copy.

Accent

Hover, focus, active rows, and soft selected states.

Accent

Hover, focus, active rows, and soft selected states.

Destructive

Delete, remove, error, and irreversible actions.

Destructive

Delete, remove, error, and irreversible actions.

Success

Saved, complete, connected, and positive confirmation states.

Success

Saved, complete, connected, and positive confirmation states.

Warning

Attention, pending review, expiring, and recoverable risk states.

Warning

Attention, pending review, expiring, and recoverable risk states.

Edges and focus

Borders, input chrome, and keyboard focus rings.

Dark mode

[data-theme="dark"]

Canvas

Page background and ordinary text.

Canvas

Page background and ordinary text.

Primary

Primary actions and high emphasis selected states.

Primary

Primary actions and high emphasis selected states.

Secondary

Quiet buttons, subtle panels, inactive controls, and helper UI.

Secondary

Quiet buttons, subtle panels, inactive controls, and helper UI.

Muted

Low-emphasis backgrounds and supporting copy.

Muted

Low-emphasis backgrounds and supporting copy.

Accent

Hover, focus, active rows, and soft selected states.

Accent

Hover, focus, active rows, and soft selected states.

Destructive

Delete, remove, error, and irreversible actions.

Destructive

Delete, remove, error, and irreversible actions.

Success

Saved, complete, connected, and positive confirmation states.

Success

Saved, complete, connected, and positive confirmation states.

Warning

Attention, pending review, expiring, and recoverable risk states.

Warning

Attention, pending review, expiring, and recoverable risk states.

Edges and focus

Borders, input chrome, and keyboard focus rings.

:root {
	--radius: 0.625rem;

	--skin-base-bg: var(--background);
	--skin-base-fg: var(--fg);
	--skin-base-border: transparent;
	--skin-base-border-width: 0px;
	--skin-base-border-style: solid;
	--skin-base-shadow: none;
	--skin-base-backdrop: none;
	--skin-base-bg-image: none;
	--skin-raised-bg: color-mix(in oklch, var(--background) 98.5%, var(--fg));
	--skin-raised-fg: var(--fg);
	--skin-raised-border: var(--border);
	--skin-raised-border-width: 1px;
	--skin-raised-border-style: solid;
	--skin-raised-shadow: var(--shadow-sm);
	--skin-raised-backdrop: none;
	--skin-raised-bg-image: linear-gradient(to bottom, color-mix(in oklch, white 7%, transparent), color-mix(in oklch, var(--fg) 1%, transparent));
	--skin-floating-bg: color-mix(in oklch, var(--background) 94%, var(--fg));
	--skin-floating-fg: var(--fg);
	--skin-floating-border: var(--border);
	--skin-floating-border-width: 1px;
	--skin-floating-border-style: solid;
	--skin-floating-shadow: var(--shadow-xl);
	--skin-floating-backdrop: blur(16px) saturate(1.08);
	--skin-floating-bg-image: none;
	--skin-overlay-bg: color-mix(in oklch, var(--background) 95%, var(--fg));
	--skin-overlay-fg: var(--fg);
	--skin-overlay-border: var(--border);
	--skin-overlay-border-width: 1px;
	--skin-overlay-border-style: solid;
	--skin-overlay-shadow: var(--shadow-2xl);
	--skin-overlay-backdrop: blur(20px) saturate(1.12);
	--skin-overlay-bg-image: none;
	--skin-inset-bg: color-mix(in oklch, var(--background) 98%, var(--fg));
	--skin-inset-fg: var(--fg);
	--skin-inset-border: var(--input);
	--skin-inset-border-width: 1px;
	--skin-inset-border-style: solid;
	--skin-inset-shadow: inset 0 1px 2px rgb(15 23 42 / 0.04);
	--skin-inset-backdrop: none;
	--skin-inset-bg-image: none;
	--skin-control-bg: var(--secondary);
	--skin-control-fg: var(--secondary-fg);
	--skin-control-border: var(--border);
	--skin-control-border-width: 1px;
	--skin-control-border-style: solid;
	--skin-control-shadow: var(--shadow-xs);
	--skin-control-backdrop: none;
	--skin-control-bg-image: none;
	--skin-action-bg: var(--primary);
	--skin-action-fg: var(--primary-fg);
	--skin-action-border: color-mix(in oklch, var(--primary) 80%, var(--border));
	--skin-action-border-width: 1px;
	--skin-action-border-style: solid;
	--skin-action-shadow: var(--shadow-sm);
	--skin-action-backdrop: none;
	--skin-action-bg-image: linear-gradient(to bottom, color-mix(in oklch, white 10%, transparent), transparent);
}

:root {
	--background: oklch(1 0 0);
	--fg: oklch(0.145 0 0);
	--primary: oklch(0.205 0 0);
	--primary-fg: oklch(0.985 0 0);
	--secondary: oklch(0.97 0 0);
	--secondary-fg: oklch(0.205 0 0);
	--muted: oklch(0.97 0 0);
	--muted-fg: oklch(0.5 0 0);
	--accent: oklch(0.97 0 0);
	--accent-fg: oklch(0.205 0 0);
	--destructive: oklch(0.583 0.239 28.476);
	--destructive-fg: oklch(0.985 0 0);
	--success: oklch(0.632 0.186 147.369);
	--success-fg: oklch(0.985 0 0);
	--warning: oklch(0.839 0.16 84.07);
	--warning-fg: oklch(0.281 0.07 46.31);
	--border: oklch(0.922 0 0);
	--input: oklch(0.922 0 0);
	--ring: oklch(0.709 0 0);
}

[data-theme="dark"] {
	--background: oklch(0.145 0 0);
	--fg: oklch(0.985 0 0);
	--primary: oklch(0.922 0 0);
	--primary-fg: oklch(0.205 0 0);
	--secondary: oklch(0.269 0 0);
	--secondary-fg: oklch(0.985 0 0);
	--muted: oklch(0.269 0 0);
	--muted-fg: oklch(0.709 0 0);
	--accent: oklch(0.269 0 0);
	--accent-fg: oklch(0.985 0 0);
	--destructive: oklch(0.702 0.189 22.228);
	--destructive-fg: oklch(0.985 0 0);
	--success: oklch(0.702 0.158 160.438);
	--success-fg: oklch(0.145 0 0);
	--warning: oklch(0.772 0.173 65.367);
	--warning-fg: oklch(0.145 0 0);
	--border: oklch(0.269 0 0);
	--input: oklch(0.321 0 0);
	--ring: oklch(0.556 0 0);
}

Tokens

Palette and pairs

Background

bg-background text-fg

The app canvas and ordinary page text.

Bg
Fg

Primary

bg-primary text-primary-fg

Primary actions and high emphasis selected states.

Bg
Fg

Secondary

bg-secondary text-secondary-fg

Quiet buttons, subtle panels, inactive controls, and helper UI.

Bg
Fg

Muted

bg-muted text-muted-fg

Low-emphasis backgrounds and supporting copy.

Bg
Fg

Accent

bg-accent text-accent-fg

Hover, focus, active rows, and soft selected states.

Bg
Fg

Destructive

bg-destructive text-destructive-fg

Delete, remove, error, and irreversible actions.

Bg
Fg

Success

bg-success text-success-fg

Saved, complete, connected, and positive confirmation states.

Bg
Fg

Warning

bg-warning text-warning-fg

Attention, pending review, expiring, and recoverable risk states.

Bg
Fg

Border

--border

Edges, separators, low-emphasis rings, and component outlines.

border-border ring-border divide-border

Input

--input

Input borders and control tracks that should read as editable.

border-input bg-background

Ring

--ring

Keyboard focus, inspector selection, and strong focus affordances.

focus-visible:ring-ring outline-ring

Decision guide

Which token should I use?

IntentUtilityRule of thumb
Page backgroundskin-baseUse once at layout level when the canvas should come from the theme recipe.
Card or panelskin-raisedUse for grouped content that needs the standard raised material.
Popover or menuskin-floatingUse for layers attached to a trigger.
Dialog or drawerskin-overlayUse for modal and app-level overlay panels.
Input chromeskin-insetUse for recessed editable controls.
Primary buttonskin-actionUse for high-emphasis commands.
Secondary buttonskin-controlUse for quiet controls and neutral triggers.
Menu item hoverhover:bg-accent hover:text-accent-fgUse accent for temporary interaction states.
Helper copytext-muted-fgUse for hints, captions, placeholders, and metadata.
Danger actiontext-destructive or bg-destructive text-destructive-fgText-only for subtle danger, filled for destructive confirmation.
Success statusbg-success text-success-fgUse for positive, completed, or saved states.
Warning statusbg-warning text-warning-fgUse when attention is needed but the action is recoverable.
Focus statefocus-visible:ring-ringUse for keyboard focus, usually with a transparent offset.

Code

Define and consume tokens

:root {
	--background: oklch(1 0 0);
	--fg: oklch(0.145 0 0);
	--primary: oklch(0.205 0 0);
	--primary-fg: oklch(0.985 0 0);
	--success: oklch(0.627 0.194 149.214);
	--success-fg: oklch(0.985 0 0);
	--warning: oklch(0.84 0.16 84);
	--warning-fg: oklch(0.28 0.07 46);
	--skin-raised-bg: color-mix(in oklch, var(--background) 98.5%, var(--fg));
	--skin-raised-fg: var(--fg);
	--skin-raised-shadow: var(--shadow-sm);
	--skin-raised-bg-image: linear-gradient(to bottom, color-mix(in oklch, white 7%, transparent), color-mix(in oklch, var(--fg) 1%, transparent));
	--skin-floating-bg: color-mix(in oklch, var(--background) 94%, var(--fg));
	--skin-floating-shadow: 0 24px 64px -26px rgb(15 23 42 / 0.42);
	--skin-floating-backdrop: blur(20px) saturate(1.16);
}
<button class="skin-action rounded-full px-4 py-2">
	Save changes
</button>

<div class="skin-raised rounded-2xl p-4">
	<p class="text-sm text-muted-fg">Use secondary text inside a card.</p>
</div>

<div class="skin-floating rounded-2xl p-2">
	<button class="rounded-xl px-3 py-2 hover:bg-accent hover:text-accent-fg">
		Open project
	</button>
</div>