Design System
zudo-doc's tight token strategy — spacing, typography, colors, and more.
zudo-doc uses a tight token strategy — instead of importing the full Tailwind framework, only preflight and utilities are loaded, skipping the default theme entirely. A small, intentional set of design tokens is defined from scratch. This page covers the full system: spacing, typography, colors, border radius, and breakpoints.
Tight Token Strategy
Tailwind CSS ships with hundreds of built-in values — colors, spacing scales, font sizes, and more. In a themeable project, these defaults cause problems: hardcoded values ignore theme changes and create inconsistency.
zudo-doc solves this with selective imports in src/styles/global.css — only preflight (reset) and utilities (functional classes) are imported, while the default theme layer is skipped entirely:
@import "tailwindcss/preflight";
@import "tailwindcss/utilities";
@theme {
/* Only define what we need — no resets necessary */
--color-bg: var(--zd-bg);
--color-fg: var(--zd-fg);
/* ... */
}
Because the default theme is never loaded, no --*: initial reset block is needed. Only explicitly defined tokens in @theme work. Using an undefined token (like p-4 or bg-gray-500) produces no effect — the value simply doesn’t exist. This gives you a guarantee: invalid tokens cause build errors or missing styles, not visual bugs.
ℹ️ Info
This is the core philosophy: define only what the project needs. Every value in the system is intentional, and accidental use of Tailwind defaults is immediately visible.
Spacing
zudo-doc separates spacing into two axes: horizontal (hsp) and vertical (vsp). They serve different purposes in layout — horizontal spacing controls inline rhythm and gutters, while vertical spacing controls content flow and section separation. The vertical scale is stretched at larger sizes to give content more breathing room.
Horizontal Spacing (hsp)
| Token | Value | Example Class |
|---|---|---|
hsp-2xs | 0.25rem (4px) | px-hsp-2xs |
hsp-xs | 0.375rem (6px) | px-hsp-xs |
hsp-sm | 0.5rem (8px) | gap-x-hsp-sm |
hsp-md | 0.75rem (12px) | px-hsp-md |
hsp-lg | 1rem (16px) | px-hsp-lg |
hsp-xl | 1.5rem (24px) | px-hsp-xl |
hsp-2xl | 2rem (32px) | px-hsp-2xl |
Vertical Spacing (vsp)
| Token | Value | Example Class |
|---|---|---|
vsp-2xs | 0.25rem (4px) | py-vsp-2xs |
vsp-xs | 0.5rem (8px) | py-vsp-xs |
vsp-sm | 0.75rem (12px) | gap-y-vsp-sm |
vsp-md | 1rem (16px) | py-vsp-md |
vsp-lg | 1.5rem (24px) | py-vsp-lg |
vsp-xl | 2rem (32px) | py-vsp-xl |
vsp-2xl | 3rem (48px) | py-vsp-2xl |
Both axes also include 0 (0px) and px (1px) utility values.
<!-- Horizontal padding + vertical padding -->
<div class="px-hsp-lg py-vsp-md">Content with asymmetric spacing</div>
<!-- Grid with dual-axis gaps -->
<div class="grid gap-x-hsp-md gap-y-vsp-lg">Grid items</div>
💡 Tip
Notice that hsp-lg is 1rem while vsp-lg is 1.5rem — the vertical axis is stretched at larger sizes. This is intentional — vertical flow needs more room than horizontal rhythm.
Typography
Font Sizes
| Token | Value | Example |
|---|---|---|
caption | 0.75rem / 12px | text-caption |
small | 0.875rem / 14px | text-small |
body | 1rem / 16px | text-body |
subheading | 1.125rem / 18px | text-subheading |
heading | 1.875rem / 30px | text-heading |
display | 3.75rem / 60px | text-display |
Font Weights
| Token | Value | Example |
|---|---|---|
normal | 400 | font-normal |
medium | 500 | font-medium |
semibold | 600 | font-semibold |
bold | 700 | font-bold |
Line Heights
| Token | Value | Example |
|---|---|---|
tight | 1.25 | leading-tight |
snug | 1.375 | leading-snug |
normal | 1.5 | leading-normal |
relaxed | 1.625 | leading-relaxed |
Font Families
| Token | Stack | Example |
|---|---|---|
sans | System sans-serif stack | font-sans |
mono | System monospace stack | font-mono |
<h1 class="text-heading font-bold leading-tight">Page Title</h1>
<p class="text-body font-normal leading-normal">Body text</p>
<code class="text-small font-mono">inline code</code>
Border Radius
| Token | Value | Example |
|---|---|---|
DEFAULT | 0.25rem (4px) | rounded |
lg | 0.5rem (8px) | rounded-lg |
full | 9999px | rounded-full |
<button class="rounded bg-accent text-bg">Default radius</button>
<div class="rounded-lg bg-surface">Card with larger radius</div>
<span class="rounded-full bg-muted">Pill badge</span>
Breakpoints
| Token | Value | Example |
|---|---|---|
sm | 640px | sm:flex |
lg | 1024px | lg:grid-cols-2 |
xl | 1280px | xl:max-w-5xl |
<div class="px-hsp-sm sm:px-hsp-md lg:px-hsp-lg xl:px-hsp-xl">
Responsive horizontal padding
</div>
Colors
Colors use a three-tier strategy: raw palette values (Tier 1) flow into semantic tokens (Tier 2), which feed into component-scoped tokens (Tier 3). Each tier only references the tier above it, so swapping a color scheme updates the entire site at once.
See the Color guide for full details on the color token system, color schemes, and customization.
Usage Rules
⚠️ Tailwind defaults are disabled
The default Tailwind theme is not imported — only tailwindcss/preflight and tailwindcss/utilities are loaded. Only project-defined tokens work.
Do
<!-- Semantic color tokens -->
<p class="text-fg">Primary text</p>
<div class="bg-surface border border-muted">Panel</div>
<a class="text-accent hover:text-accent-hover">Link</a>
<!-- Spacing tokens -->
<div class="px-hsp-lg py-vsp-md">Proper spacing</div>
<div class="gap-x-hsp-sm gap-y-vsp-md">Grid gaps</div>
<!-- Typography tokens -->
<h2 class="text-subheading font-semibold leading-tight">Heading</h2>
Don’t
<!-- DON'T: Tailwind defaults — not defined and produce nothing -->
<div class="p-4 bg-gray-500 text-sm">Broken</div>
<!-- DON'T: Hardcoded hex — breaks theming -->
<div class="bg-[#1e1e2e] text-[#f8f8f2]">Breaks on theme switch</div>
All tokens are defined in src/styles/global.css. That file is the single source of truth for the design system.