---
title: Design Tokens
description: Reference for the WireKit CSS variables — colors, typography, spacing, motion, sizing, component-specific tokens, and the chart-theming palette
visibility: guest
draft: false
---

# Design Tokens

The complete CSS-variable surface that every WireKit component reads from. Override any variable in your `:root {}` (light) or `.dark {}` (dark mode) block to retheme the library — no Tailwind config changes, no component overrides, no rebuild needed.

> **Looking for setup help, theme presets, or accessibility guarantees?** See the [Theming guide](/theming). This page is the pure variable reference.

## All Design Tokens

### Colors — Accent

| Variable | Light | Dark | Used for |
| --- | --- | --- | --- |
| `--color-wk-accent` | neutral-900 | white | Accent **fill** — button / badge backgrounds |
| `--color-wk-accent-hover` | neutral-800 | neutral-100 | Accent fill hover |
| `--color-wk-accent-text` | neutral-900 | white | Accent-toned **text** on the page background (links, stepper, callout) — alias of `--color-wk-accent-content` |
| `--color-wk-accent-content` | neutral-900 | white | Readable accent text on the page or a soft-tinted accent surface |
| `--color-wk-accent-fg` | white | neutral-900 | Text/icon **on** an accent fill |

> **Three accent roles, don't mix them.** `--color-wk-accent` is a **fill** — it sits behind other content and can be a bright, saturated brand color. Never use it as a text color: on a light brand accent, text drawn in the fill color fails contrast against the page background. Accent-toned **text** reads `--color-wk-accent-text` (an alias of `--color-wk-accent-content`), which defaults to a near-black/near-white that always clears WCAG AA. Text that sits **on** an accent fill (a button label) reads `--color-wk-accent-fg`. When you re-tint, set `--color-wk-accent` to your brand fill **and** `--color-wk-accent-content` to a readable text tone of it — otherwise links fall back to the safe near-neutral default.

### Colors — Danger

| Variable | Light | Dark | Used for |
| --- | --- | --- | --- |
| `--color-wk-danger` | red-600 | red-600 | Danger button bg |
| `--color-wk-danger-hover` | red-700 | red-700 | Danger button hover |
| `--color-wk-danger-fg` | white | white | Text on danger bg |
| `--color-wk-danger-text` | red-600 | red-400 | Error message text |

### Colors — Success

| Variable | Light | Dark | Used for |
| --- | --- | --- | --- |
| `--color-wk-success` | green-600 | green-500 | Success states |
| `--color-wk-success-hover` | green-700 | green-400 | Success hover |
| `--color-wk-success-fg` | neutral-900 | neutral-900 | Text on success bg |
| `--color-wk-success-text` | green-700 | green-400 | Success message text |

### Colors — Warning

| Variable | Light | Dark | Used for |
| --- | --- | --- | --- |
| `--color-wk-warning` | amber-500 | amber-400 | Warning states |
| `--color-wk-warning-hover` | amber-600 | amber-300 | Warning hover |
| `--color-wk-warning-fg` | neutral-900 | neutral-900 | Text on warning bg |

### Colors — Neutrals

| Variable | Light | Dark | Used for |
| --- | --- | --- | --- |
| `--color-wk-bg` | white | neutral-950 | Page background |
| `--color-wk-bg-elevated` | white | neutral-900 | Cards, modals |
| `--color-wk-bg-subtle` | neutral-50 | neutral-900 | Hover backgrounds |
| `--color-wk-bg-muted` | neutral-100 | neutral-800 | Secondary button bg |
| `--color-wk-bg-input` | white | neutral-900 | Input backgrounds |
| `--color-wk-text` | neutral-900 | neutral-100 | Primary text |
| `--color-wk-text-muted` | neutral-500 | neutral-400 | Hint text |
| `--color-wk-text-subtle` | neutral-500 | neutral-400 | Prefix/suffix text |
| `--color-wk-text-placeholder` | neutral-500 | neutral-400 | Input placeholders |
| `--color-wk-code` | = text | = text | Inline `<code>` text — themeable per preset (Aurora sets it to the brand magenta) |
| `--color-wk-code-bg` | = bg-muted | = bg-muted | Inline `<code>` background — themeable per preset |

### Colors — Borders and Focus

| Variable | Light | Dark | Used for |
| --- | --- | --- | --- |
| `--color-wk-border` | neutral-300 | neutral-600 | Decorative borders (cards, dividers, tables) — WCAG 1.4.11-exempt, kept light |
| `--color-wk-border-strong` | oklch(66%) | oklch(51%) | Resting border for every form control — meets WCAG 1.4.11 (3:1) against the input fill |
| `--color-wk-border-strong-hover` | oklch(58%) | oklch(58%) | Hover border for every form control — moves further from the fill (4.28:1 light, 4.62:1 dark) |
| `--color-wk-border-hover` | neutral-400 | neutral-500 | Hover state for decorative borders only — does not meet 3:1, never use it on a control |
| `--color-wk-border-subtle` | neutral-200 | neutral-700 | Subtle dividers |
| `--color-wk-border-error` | red-500 | red-400 | Error state borders |
| `--color-wk-ring` | neutral-900 | white | Focus rings |
| `--color-wk-ring-offset` | white | neutral-950 | Focus ring offset |

### Border Radius

All radius values derive from a single base `--radius-wk`. Change one value, everything scales.

| Variable | Default | Used for |
| --- | --- | --- |
| `--radius-wk` | 0.5rem | Base value |
| `--radius-wk-sm` | calc(base * 0.75) | Small buttons (xs, sm) |
| `--radius-wk-md` | base | Default buttons, inputs |
| `--radius-wk-lg` | calc(base * 1.25) | Large buttons (xl) |
| `--radius-wk-xl` | calc(base * 2) | Cards, modals |
| `--radius-wk-full` | 9999px | Pills, avatars |

### Shadows

| Variable | Default | Used for |
| --- | --- | --- |
| `--shadow-wk-sm` | Subtle 1px shadow | Buttons, inputs |
| `--shadow-wk-md` | Medium elevation | Dropdowns |
| `--shadow-wk-lg` | Strong elevation | Modals |
| `--shadow-wk-none` | transparent | Ghost buttons |

### Typography

| Variable | Default | Used for |
| --- | --- | --- |
| `--font-wk-sans` | Inter, system-ui | All components |
| `--font-wk-mono` | Fira Code, monospace | Code elements |
| `--font-wk-heading-weight` | 600 | Headings |
| `--font-wk-body-weight` | 400 | Body text, buttons |
| `--font-wk-letter-spacing` | 0em | All text |
| `--font-wk-line-height` | 1.5 | All text |

### Motion

| Variable | Default | Used for |
| --- | --- | --- |
| `--transition-wk-duration` | 150ms | All transitions (back-compat name; same value as `--motion-wk-duration-fast`) |
| `--transition-wk-easing` | cubic-bezier(0.4, 0, 0.2, 1) | All transitions |
| `--motion-wk-duration-fast` | 150ms | Fast animations (`<x-wirekit::reveal>`, `.wk-animate-fast`) |
| `--motion-wk-duration-normal` | 300ms | Normal animations (default for `<x-wirekit::reveal>`) |
| `--motion-wk-duration-slow` | 600ms | Slow animations (`.wk-animate-slow`) |
| `--motion-wk-easing-out` | cubic-bezier(0.16, 1, 0.3, 1) | Decelerating easing (elements entering the screen) |
| `--motion-wk-easing-in` | cubic-bezier(0.7, 0, 0.84, 0) | Accelerating easing (elements leaving the screen) |
| `--motion-wk-easing-spring` | cubic-bezier(0.5, 1.5, 0.5, 1) | Spring/overshoot easing (`bounce`, `spring` presets) |
| `--motion-wk-delay-none` | 0ms | `<x-wirekit::reveal delay="none">` |
| `--motion-wk-delay-sm` | 75ms | `<x-wirekit::reveal delay="sm">` (also the default `feature-grid stagger` step) |
| `--motion-wk-delay-md` | 150ms | `<x-wirekit::reveal delay="md">` |
| `--motion-wk-delay-lg` | 300ms | `<x-wirekit::reveal delay="lg">` |
| `--motion-wk-delay-xl` | 500ms | `<x-wirekit::reveal delay="xl">` |

### Spacing and Layout

These tokens drive the gaps and padding inside the layout primitives (`stack`, `row`, `grid`, `section`) and component internals. **WireKit components carry no outer margins** — compose vertical and horizontal rhythm with the layout primitives + their `gap` prop instead of hand-rolling `space-y-*` / `mb-*` utilities.

| Variable | Default | Used for |
| --- | --- | --- |
| `--space-wk-xs` … `--space-wk-2xl` | 0.25 · 0.5 · 1 · 1.5 · 2.5 · 4rem | General spacing scale (`xs`, `sm`, `md`, `lg`, `xl`, `2xl`) |
| `--space-wk-section-sm` / `-md` / `-lg` | 3rem / 5rem / 7rem | Vertical padding for page sections (`section`, `hero`, `cta`) |
| `--gap-wk-xs` … `-2xl` | 0.25 / 0.5 / 0.75 / 1 / 1.5 / 2rem | `stack` / `row` / `grid` gap scale — full `xs` · `sm` · `md` · `lg` · `xl` · `2xl` ladder |
| `--padding-wk-x-xs` … `-xl` | 0.375 · 0.625 · 0.75 · 1 · 1.5rem | Horizontal (inline) padding, axis-split |
| `--padding-wk-y-xs` … `-xl` | 0.25 · 0.375 · 0.5 · 0.75 · 1rem | Vertical (block) padding, axis-split |

The padding scale is axis-split (`-x-` / `-y-`) with no axis-less shorthand; the gap scale runs the full `xs`…`2xl` ladder (a reference to an undefined step would silently collapse the gap to 0, so the ladder is complete).

### Border Width

| Variable | Default | Used for |
| --- | --- | --- |
| `--border-wk-width` | 1px | All component borders |

### States

| Variable | Default | Used for |
| --- | --- | --- |
| `--opacity-wk-hover` | 0.8 | Hover opacity |
| `--opacity-wk-disabled` | 0.5 | Disabled elements |
| `--opacity-wk-loading` | 0.7 | Loading states |

### Focus Ring

| Variable | Default | Used for |
| --- | --- | --- |
| `--ring-wk-width` | 2px | Focus ring width |
| `--ring-wk-offset` | 2px | Focus ring offset |

### Component Sizing

| Variable | Default | Used for |
| --- | --- | --- |
| `--size-wk-sm` | 2rem (32px) | Small button/input height |
| `--size-wk-md` | 2.5rem (40px) | Default button/input height |
| `--size-wk-lg` | 3rem (48px) | Large button/input height |
| `--padding-wk-x-sm` | 0.625rem | Small horizontal padding |
| `--padding-wk-x-md` | 0.75rem | Default horizontal padding |
| `--padding-wk-x-lg` | 1rem | Large horizontal padding |
| `--padding-wk-x-xl` | 1.5rem | Extra-large horizontal padding (overlays) |
| `--padding-wk-y-xs` | 0.25rem | Extra-small vertical padding (tooltip, dropdown) |
| `--padding-wk-y-sm` | 0.375rem | Small vertical padding (textarea) |
| `--padding-wk-y-md` | 0.5rem | Default vertical padding (textarea) |
| `--padding-wk-y-lg` | 0.75rem | Large vertical padding (textarea) |
| `--padding-wk-y-xl` | 1rem | Extra-large vertical padding (overlays) |
| `--gap-wk-xs` | 0.25rem | Extra-small gap (tight groups) |
| `--gap-wk-sm` | 0.5rem | Small gap/spacing (dropdown items) |
| `--gap-wk-md` | 0.75rem | Default gap/spacing (footer buttons) |
| `--gap-wk-lg` | 1rem | Large gap (section groups, sidebars) |
| `--gap-wk-xl` | 1.5rem | Extra-large gap |
| `--gap-wk-2xl` | 2rem | 2x-large gap |

Two ladders share the `xs`…`2xl` rung labels and they are **not** the same values.
`--gap-wk-*` is the tighter one, for space between items inside a component;
`--space-wk-*` is roomier, for space between blocks of a page. Only `xs` and `sm`
happen to agree — reaching for the wrong one gets you 0.75rem where you expected
1rem, and the gap widens as you go up:

| Rung | `--gap-wk-*` | `--space-wk-*` |
| --- | --- | --- |
| `xs` | 0.25rem | 0.25rem |
| `sm` | 0.5rem | 0.5rem |
| `md` | 0.75rem | 1rem |
| `lg` | 1rem | 1.5rem |
| `xl` | 1.5rem | 2.5rem |
| `2xl` | 2rem | 4rem |

| `--text-wk-2xs` | 0.6875rem | Micro text (dense secondary labels) |
| `--text-wk-xs` | 0.75rem | Caption / micro-label |
| `--text-wk-sm` | 0.8125rem | Small font size |
| `--text-wk-md` | 0.875rem | Default body font size |
| `--text-wk-lg` | 1rem | Large body / lede |
| `--text-wk-xl` | 1.25rem | Sub-heading |
| `--text-wk-2xl` | 1.5rem | Section heading |
| `--text-wk-3xl` | 1.875rem | Page heading |

### Overlay Tokens

| Variable | Default (Light) | Default (Dark) | Used for |
| --- | --- | --- | --- |
| `--color-wk-overlay` | oklch(0% 0 0 / 0.5) | oklch(0% 0 0 / 0.7) | Modal/Drawer backdrop |
| `--z-wk-dropdown` | 50 | — | Dropdown z-index |
| `--z-wk-tooltip` | 60 | — | Tooltip z-index |
| `--z-wk-modal` | 70 | — | Modal z-index |
| `--z-wk-drawer` | 70 | — | Drawer z-index |
| `--size-wk-modal-sm` | 24rem | — | Small modal width |
| `--size-wk-modal-md` | 32rem | — | Default modal width |
| `--size-wk-modal-lg` | 42rem | — | Large modal width |
| `--size-wk-modal-xl` | 56rem | — | Extra-large modal width |
| `--size-wk-modal-full` | 100% | — | Full-width modal |
| `--size-wk-drawer-sm` | 20rem | — | Small drawer width/height |
| `--size-wk-drawer-md` | 28rem | — | Default drawer width/height |
| `--size-wk-drawer-lg` | 40rem | — | Large drawer width/height |
| `--size-wk-tooltip-max` | 20rem | — | Tooltip max width |
| `--color-wk-tooltip-bg` | text color | text color | Tooltip background (inverted) |
| `--color-wk-tooltip-text` | bg color | bg color | Tooltip text (inverted) |

### Scrollbar

| Variable | Default (Light) | Default (Dark) | Used for |
| --- | --- | --- | --- |
| `--color-wk-scrollbar-thumb` | neutral-300 | neutral-600 | Scrollbar thumb color |
| `--color-wk-scrollbar-thumb-hover` | neutral-400 | neutral-500 | Scrollbar thumb on hover |
| `--color-wk-scrollbar-track` | transparent | transparent | Scrollbar track background |
| `--size-wk-scrollbar` | 6px | — | Scrollbar width/height |
| `--fade-wk-size` | 2rem | — | Depth of the scroll-area edge fade (`<x-wirekit::scroll-area fade="…">` / `.wk-scroll-fade`) |

Apply the `.wk-scrollbar` CSS class to any scrollable element for a slim, themed scrollbar:

```blade
<div class="wk-scrollbar overflow-auto max-h-64">
    <!-- long content here -->
</div>
```

The class uses `scrollbar-width: thin` for Firefox and `::-webkit-scrollbar` pseudo-elements for Chrome/Safari/Edge.

## Reading Component Tokens

Tokens for the [reading-* component family](/components/reading) — six primitives for long-form content pages. Override any of them in your `:root {}` block to retheme without touching the component source.

### Reading Progress

| Variable | Default | Used for |
| --- | --- | --- |
| `--reading-progress-height-sm` | `2px` | Bar height when `height="sm"` |
| `--reading-progress-height-md` | `3px` | Bar height when `height="md"` (default) |
| `--reading-progress-height-lg` | `5px` | Bar height when `height="lg"` |
| `--reading-progress-dot-size` | `2.5rem` | Diameter of the dot indicator (when `indicator="dot"`) |
| `--reading-progress-fill` | (unset) | Developer-side fill override — set to win over the `variant`-resolved color for theme-wide retheming |

Variant rendering: each variant resolves through `var(--reading-progress-fill, var(--color-wk-X))`, so the `--reading-progress-fill` token wins when set. Default variants pull from `--color-wk-accent` (primary, info), `--color-wk-text-muted` (neutral), `--color-wk-success` / `--color-wk-warning` / `--color-wk-danger` (semantic). The `auto` variant falls back to `currentColor` for embedded contexts.

### Reading Spine

| Variable | Default | Used for |
| --- | --- | --- |
| `--reading-spine-width-collapsed` | `1.25rem` | Width of the collapsed (ticks-only) spine |
| `--reading-spine-width-expanded` | `16rem` | Width when expanded on hover/focus |
| `--reading-spine-gap` | `0.625rem` | Vertical gap between ticks |
| `--reading-spine-tick-height` | `2px` | Tick line thickness |
| `--reading-spine-color-idle` | `var(--color-wk-text-subtle)` | Inactive tick / label color |
| `--reading-spine-color-active` | `var(--color-wk-text)` | Active tick / label color |
| `--reading-spine-bg` | `color-mix(in srgb, var(--color-wk-bg-elevated) 92%, transparent)` | Spine panel background |

### Reading Minimap

| Variable | Default | Used for |
| --- | --- | --- |
| `--reading-minimap-width` | `60px` | Column width |
| `--reading-minimap-stripe-height` | `2px` | Stripe height per item |
| `--reading-minimap-stripe-gap` | `1px` | Vertical gap between stripes |
| `--reading-minimap-color-idle` | `var(--reading-spine-color-idle)` | Inactive stripe color (reuses spine color for theme-consistency) |
| `--reading-minimap-color-active` | `var(--reading-spine-color-active)` | Active stripe color (item currently in viewport) |
| `--reading-minimap-viewport-bg` | `color-mix(in oklab, var(--color-wk-accent) 25%, transparent)` | Viewport-overlay background |
| `--reading-minimap-viewport-border` | `2px solid color-mix(in oklab, var(--color-wk-accent) 70%, transparent)` | Viewport-overlay border |
| `--reading-minimap-viewport-radius` | `var(--radius-wk-sm)` | Viewport-overlay corner radius |

#### Rendered-mode canvas colors (`mode="rendered"` only)

The rendered-mode minimap paints an abstract content-texture map onto a canvas — one rectangle per rendered text line, colored by the source element's role. Override any of these tokens at `:root` to retheme the canvas without touching JS.

| Variable | Default | Used for |
| --- | --- | --- |
| `--reading-minimap-color-h1` | `rgba(15, 23, 42, 0.85)` | h1 lines (densest — top of structural hierarchy) |
| `--reading-minimap-color-h2` | `rgba(15, 23, 42, 0.75)` | h2 lines |
| `--reading-minimap-color-h3` | `rgba(15, 23, 42, 0.65)` | h3 lines |
| `--reading-minimap-color-h4` | `rgba(15, 23, 42, 0.55)` | h4 lines |
| `--reading-minimap-color-h5` | `rgba(15, 23, 42, 0.48)` | h5 lines |
| `--reading-minimap-color-h6` | `rgba(15, 23, 42, 0.42)` | h6 lines |
| `--reading-minimap-color-code` | `rgba(99, 102, 241, 0.55)` | `<pre>`, `<code>`, `<kbd>`, `<samp>` |
| `--reading-minimap-color-table` | `rgba(244, 63, 94, 0.50)` | `<table>`, `<td>`, `<th>`, `<caption>` |
| `--reading-minimap-color-blockquote` | `rgba(71, 85, 105, 0.55)` | `<blockquote>` |
| `--reading-minimap-color-prose` | `rgba(71, 85, 105, 0.42)` | `<p>`, `<li>`, `<dd>`, `<dt>`, `<figcaption>` |
| `--reading-minimap-color-wirekit` | `rgba(16, 185, 129, 0.50)` | Any WireKit component (`[class*="wk-"]`, excluding the minimap's own `wk-reading-*` siblings) |
| `--reading-minimap-color-image` | `rgba(245, 158, 11, 0.55)` | `<img>`, `<picture>`, `<figure>`, `<svg>`, `<video>`, `<canvas>` (drawn as block rectangles at natural element bounds) |
| `--reading-minimap-color-default` | `rgba(71, 85, 105, 0.32)` | Anything else (fallback) |

### Reading TOC

| Variable | Default | Used for |
| --- | --- | --- |
| `--reading-toc-bg` | `color-mix(in srgb, var(--color-wk-bg-elevated) 92%, transparent)` | Strip background — slightly translucent so backdrop-filter blur reads as glass |
| `--reading-toc-color-idle` | `var(--reading-spine-color-idle)` | Inactive link color (reuses spine color for theme-consistency) |
| `--reading-toc-color-active` | `var(--reading-spine-color-active)` | Active link color (current section per IntersectionObserver) |
| `--reading-toc-padding-y` | `0.5rem` | Vertical padding inside the strip |
| `--reading-toc-padding-x` | `1rem` | Horizontal padding inside the strip |
| `--reading-toc-gap` | `1rem` | Gap between adjacent links |
| `--reading-toc-link-max-width` | `24ch` | Per-link max-width — long heading text gets ellipsis-truncated rather than overflowing the strip |

### Reading Bookmark

| Variable | Default | Used for |
| --- | --- | --- |
| `--reading-bookmark-pill-bg` | `var(--color-wk-bg-elevated)` | "Resume reading?" pill background |
| `--reading-bookmark-pill-radius` | `var(--radius-wk-full, 9999px)` | Pill border radius |
| `--reading-bookmark-pill-shadow` | `var(--shadow-wk-md)` | Pill drop shadow |

### Reading Meta

| Variable | Default | Used for |
| --- | --- | --- |
| `--reading-meta-text-size` | `0.875rem` | Time-to-read text size |
| `--reading-meta-color` | `var(--color-wk-text-muted)` | Time-to-read text color |
| `--reading-meta-paragraph-color` | `var(--color-wk-text-subtle)` | Per-paragraph annotation color (perParagraph mode) |
| `--reading-meta-paragraph-spacing` | `0.25em` | Gap between annotation and the paragraph below it (perParagraph mode) |

### Reduced Motion

All reading-* components honor `prefers-reduced-motion: reduce` via the global `@media` block in `dist/wirekit.css`. Every transition (bar fill `transform: scaleX`, dot stroke `dashoffset`, spine width / label opacity / tick color, bookmark pill enter/leave, minimap stripe color transitions, smooth-scroll on link click) collapses to `0.01ms` — values still update on scroll, just without easing.

### Print Stylesheet

All five UI primitives (`reading-progress`, `reading-spine`, `reading-minimap`, `reading-bookmark`, `reading-meta`) carry a `@media print { display: none !important }` rule scoped via marker classes (`.wk-reading-progress`, `.wk-reading-spine`, `.wk-reading-minimap`, `.wk-reading-bookmark`, `.wk-reading-meta`). Print-friendly for blog-to-PDF workflows — only the article body prints, not the reading chrome.

## Chart Theming

When charts are enabled, the `<x-wirekit-chart>` component automatically reads WireKit CSS variables for consistent theming:

| Variable | Chart Usage |
| --- | --- |
| `--color-wk-accent` | Primary dataset color |
| `--color-wk-danger` | Second dataset color |
| `--color-wk-success` | Third dataset color |
| `--color-wk-warning` | Fourth dataset color |
| `--color-wk-info` | Fifth dataset color (not in `wirekit.css` — define in your `@theme` block or the JS fallback `#06b6d4` is used) |
| `--color-wk-text` | Legend text color |
| `--color-wk-text-muted` | Axis tick labels |
| `--color-wk-border` | Grid line color |
| `--font-wk-sans` | Chart font family |

Overriding these tokens in your `@theme` block automatically updates chart colors. See the [Chart documentation](/components/chart) for details.

## See Also

- [Theming](/theming) — setup guide, theme presets, accent-color, accessibility guarantees
- [Customization](/customization) — when to override tokens vs. tweak PHP defaults vs. apply scope-based personalization
- [Variants & Intents](/variants-and-intents) — cross-component reference for color/severity props
