Writing
Building a Design System with Tailwind CSS v4
Tailwind v4 changes the authoring model in a meaningful way. Configuration that previously lived in `tailwind.config.js` now lives in CSS via the `@theme` directive. That might sound like a step backwards, but in practice it means your design tokens are just CSS custom properties — which opens up patterns that weren't possible before.
The design system for this site is built entirely in OKLCH color space. OKLCH is perceptually uniform, meaning equal numeric steps produce equal-looking color differences across the spectrum. That makes it much easier to construct accessible color palettes without manually tweaking individual stops.
Every custom token is defined once in `:root` and `.dark`, then surfaced as a Tailwind utility via `@theme inline`. Mapping `--color-forest-ink: var(--forest-ink)` makes `text-forest-ink` and `bg-forest-ink` available as utilities automatically.
The `@layer base` block is important for predictable cascade behavior. Unlayered CSS wins over Tailwind's utility layer, so global element selectors like `a { color: ... }` need to live inside `@layer base` to let utilities override them when needed. This is a subtle but important detail if you're mixing component styles with utility classes.
For Shadcn UI integration, the key is mapping Shadcn's semantic tokens (`--primary`, `--secondary`, etc.) to values in your design system rather than hard-coding colors. That way every Shadcn component inherits the theme automatically, and switching from light to dark mode is a single class toggle on `<html>`.