Core
Primary is the anchor
Settings

How the five derived colors are placed around the anchor.

Theme builder

This is the real site restyling itself, not a mock. Navigate away and the theme follows you.

Zoning

Grounds do the work borders would

This band sits on bg-light. The next sits on bg-white. The seam between them reads as a boundary with no hairline drawn anywhere.

Text link

Surfaces

Cards

Radius

Corner shape comes from the convention, using Tailwind's own utilities.

Elevation

Flat by default. Depth is a ground change, not a drop shadow.

Borders

Off by default. Turn them on and every card gains a hairline.

Long-form

Every role in context, as rendered markdown two steps down the ramp: headings h2 through h6 in order, with real paragraphs, lists, a quote, a table, links and code between them. A ratio is judged over a page of reading, not over a specimen sheet — this is the block to watch while you move one.

A scale is judged in paragraphs

Three headings stacked on a swatch page will flatter almost any ratio. The question is whether hierarchy survives a page someone actually reads.

Body copy sits at the base size and everything else is a fixed exponent away from it. Raise the ratio and the headings pull away from the text; lower it and they settle back toward it. Neither is correct on its own — a dense product page wants the headings close, an editorial one wants the air. What you are looking for is the point where an h4 three paragraphs down still reads as a heading, and the h5 under it still reads as something smaller.

Where a ratio usually breaks

Almost always at the bottom. The top of the ramp has room to be dramatic; the last two steps have to be distinguishable from body copy and from each other, in the space of a few percent. Two failure modes, in order of how often they happen:

  1. The tail collapses. At a small ratio the last heading lands within a hair of text-p, so a document outline reads as one long undifferentiated block.
  2. The head runs away. At a large ratio the top step overflows its line on a phone, which is what the second, smaller mobile ratio exists to prevent.

Both are visible here and invisible on a specimen sheet, which is the whole reason this block is on the page. If you want to see the first one, set the ratio to Minor Second and read down to the fifth heading.

Leading does as much work as size

Size separates roles; leading makes them readable once separated. The scale derives it from position on the ramp — the largest step is always the tightest, because a display line at 1.7 falls apart, and body copy at 1.1 is unreadable. Three things follow from that:

  • Headings tighten as they grow, without anyone tuning each one.
  • Changing the step count re-derives every value, so the ramp stays coherent.
  • Control labels sit at leading: 1, which is what lets a button state its height in em and hold its proportions at any size.

A modular scale is a constraint, not a decoration. Its value is that it removes the question — not that the numbers are beautiful.

Everything a page of markdown contains

Inline code like --type-h1-size sizes relative to whatever it sits in, so it never outgrows a table cell or overwhelms a heading. Blocks set on the mono role instead:

.prose h2 {
  font-size:   var(--type-h4-size);
  line-height: var(--type-h4-leading);
}

Tables take the small role, because a dense grid is not reading copy:

RoleExponentUse
text-lead+0.75The opening paragraph of a section
text-p0The default — all body copy, everywhere
text-small−0.4A hint under a field. Never a paragraph
The last step on the ramp

With the shipped six-step scale and a two-step prose offset, an h5 and an h6 in markdown resolve to the same role — the ramp has run out before the document has. That is deliberate and worth seeing: if your content genuinely needs six levels of heading, raise the step count rather than inventing a size.


Every size on this page is fluid. Narrow the window and the whole ramp interpolates toward the mobile ratio — no breakpoints, no responsive prefixes.

Inverse

The same theme on a dark band

Inverse surfaces use white at the same fixed opacity ladder the ink uses on light grounds.

Ground

The card is white at 8%, not a second dark token. Six colors stay six.

Ink

White at the same 58% the light side spends on secondary text.

Edge

Turn borders on and the hairline flips to white/12 — ink would vanish here.

--brand-dark cannot be lightened to make a second dark ground: it is also the body text, and its 55% step already sits at 4.52:1. Two hundredths of a step lighter and meta text drops below AA.

Status

Two grounds carry meaning

Danger — the only status color. Its ground is the same hue at 10%.

Accent carries informational callouts. Never as text on a light ground — the ground carries the meaning.

Your theme

Two files. global.css replaces the one in your project;theme-rules.md goes in the project root and gets pointed at from AGENTS.md. Or take the same two as URLs — see Link.