Button
The primary action. Three variants, three sizes. Ghost is the quietest. Primary is for the one thing the page actually wants you to do.
Beans is the design system this site runs on. Two layers: a raw palette of warm neutrals and a single accent underneath, semantic tokens on top. Plus a small set of components, behaviors, and page shells.
Leans toward print. Long lines, lots of whitespace, headings that breathe.
This page is the reference. Every swatch and sample below is the live token, so what you see is what the site is using right now. Mode toggle's in the header for the dark version.
02.01
The raw palette. Every semantic token below points back to a step on one of these ramps. Cream and roast do the heavy lifting. Accent is the only color in the system.
02.02
Surface, text, border, accent. Each token shows both its light and dark value side by side, so the page makes sense whichever mode you're in.
Surfaces
Text
Borders
Accent
02.03
Three families. Fraunces is the editorial voice, used for display. Inter does the long-form work. JetBrains Mono is the system voice for labels, code, and anything that wants to feel like terminal output.
Display · font-display
Mountain coffee, slowly.
Body sans · font-sans
The quick brown fox jumps over the lazy dog.
Mono · font-mono
const space = { 1: "4px", 10: "128px" }
02.04
Reference sizes for the whole site. Hero text uses clamp() in production so it scales with the viewport; what you see here are the desktop targets.
Display XL
Display LG
Heading 1
Heading 2
Heading 3
Body LG — lede paragraph copy.
Body — long-form prose at the default reading size.
Body MD — the page-level prose default.
Body SM — secondary copy.
Caption — micro labels and helper text.
--space-6: 32px
LABEL · ALL CAPS
02.05
Ten steps, and never anything off the scale. Page-level rhythm pulls from 9 and 10. Everything inside a component sticks to 1 through 7. Bar widths below are literal.
02.06
Six radii. Pill is for things that should be fully round (badges, switches). XL is reserved for hero surfaces. Everything else picks from the middle.
02.07
Five depths. Light and dark shadows are tuned separately because dark surfaces need more contrast to read as raised.
Each component shown once in its baseline form, with the variants and states it supports next to it. Sizes, disabled, invalid, focus, and the per-component oddities (indeterminate checkboxes, slider bubbles) all in one place.
The primary action. Three variants, three sizes. Ghost is the quietest. Primary is for the one thing the page actually wants you to do.
Two wrappers. Label is the semantic one. Field pairs label, control, and help or error text together. Every form input below uses them.
Single-line text input. Three sizes. Invalid and disabled look different from default focus on purpose.
Multi-line input. Same sizes and states as Input. Row count via the rows attribute.
A native select, restyled. Three sizes. The option list is whatever picker the browser hands you, which keeps mobile accessible by default.
Two states, plus indeterminate. Use indeterminate when a parent represents a mix of checked and unchecked children. Clicking it resolves to true or false.
Pick one. Vertical by default. Switch to horizontal when the labels are short enough to read as a row.
On/off, no confirmation. Good for settings that take effect immediately. Don't use it for anything destructive.
Range input. Turn on the bubble and it shows the current value above the thumb while you drag.
Behaviors are the small directives that add interaction patterns to plain elements: keyboard handling, focus management, the kind of thing that's tedious to rewrite per component. The page itself demos two of them quietly: the mode toggle in the header, and the scroll-spy on the left rail of this page.
Light/dark switching, persisted to localStorage. The toggle in the header is the real one. Flip it and every specimen on this page swaps with it.
IntersectionObserver watching for which section is on screen. The left nav on this page is wired to it. Scroll and the active link follows.
Roving tabindex for tablists and toolbars. Tab into the group below, then use the arrow keys: focus moves between items without ever leaving the group. Home and End jump to the ends.
Hover or focus to surface a short label. Viewport-aware: it flips to the other side when it'd clip the edge.
One button, confirms when it lands. Falls back through execCommand if the modern clipboard API isn't available.
--space-6: 32px Page templates are the shells everything else lives inside. Each one owns its own width, gutters, and section rhythm so pages don't have to reinvent layout. The sketches below are abstract, so read them as rhythm, not content.
The bare shell. Sets the width and rhythm that everything else extends.
The top of a page. Tall and single-purpose. Lede, headline, and first action go here.
Repeating content block. Optional title and kicker. There is a rule-line variant for the editorial pages.
A tinted strip across the page. Plain, or a 3-up grid for metrics.
The closing call-to-action. Prose on the left, arrow links on the right, with a top border to separate it from whatever is above.
Marketing variant of Page. Same building blocks, but the column width and section rhythm are tuned for it.
Documentation shape. Sticky nav on the left, scrolling main on the right, scroll-spy on. This page is using it right now.
Where things stand. Stable means the API and visual treatment are settled — go ahead and build against it. WIP means the shape is there but I'm still landing details. Planned means it's on the list but doesn't exist yet.