Blueprint.
Every component on this site descends from one file of tokens. Move a token; the brand moves with it. This page is the receipt.
Section 01 / 06
Foundations
Sixty-eight values. One file. One cascade.
Every pixel on the site is downstream of these. Colour, type, space, motion. Change one in tokens.css and the cascade tells the truth: instantly, here, in production, and in every component below.
Palette
Type
Contrast
··
Spacing
Radius
Motion
Contrast
Signal strength on every text-on-surface pair the site reads against.
Aa
Body text on background
Aa
Body prose
Aa
Labels, secondary
Aa
Button text on accent
Aa
Accent text on bg
Aa
Critical badge text
Colour
Fourteen tokens. Three surfaces of ink. Three of rule. One accent that does most of the editorial work.
Typography
Three families across nine ranks. Fraunces speaks for the brand, Newsreader carries the prose, Inter handles the controls.
Spacing
Thirteen stops on a 4px base. Geometric. Predictable. The page is built out of these gaps.
Radii
Six ranks. Never custom. Pills only where the shape itself is a pill.
Shadows
Four ranks. Used sparingly. A shadow on every card is no shadow at all.
Motion
Four durations. Fast for feedback, slow for transitions, slower for page-level change. Respects prefers-reduced-motion at every step.
Principles
Five rules the page refuses to break. Read these before extending anything.
- 01
One primary per page
cta.singular
The primary names the one decision the page is asking the reader for. Two primaries split the eye and halve the conversion.
- 02
Tokens before components
tokens.css → cascade
Every visible value descends from a token. If you find yourself writing a literal hex or rem in a component, the system has a gap. Fix the token, not the component.
- 03
Accessibility is not a layer
a11y.contract
Focus rings, semantic tags, contrast minimums, reduced-motion fallbacks all ship with the component, not after it. Stripping them means re-implementing them, badly.
- 04
Every claim has a contract
claim.signed
A Badge that says Live must point at a measured behaviour. A Heading that says H1 must be the page's first heading. A button that says Subscribe must take a payment.
- 05
Architecture outlives content
law-iii.active
The scaffold persists. The content turns over. Spend the time on the scaffold, on this file, and the brand earns interest on every page that descends from it.
Section 02 / 06
Atoms
Six components. No exceptions.
Every page on the site is built from these. If a piece of UI on this site can't be built from them, the spec is wrong. The atom isn't. Each one ships with anatomy, props, do / don't, and the accessibility contract it refuses to break.
Button
Badge
Inventory
06Live
Button
Where the page asks the reader to commit. Three variants. Primary for the page's one main decision, secondary for adjacent moves, ghost for inline affordance. If you find yourself reaching for a fourth, it isn't a Button you need.
Change variant, size, label, and disabled state. The code panel regenerates as you do.
Controls
Code
Anatomy
States
default:hover:focus-visible:active[disabled]Variants
primary · base secondary · base ghost · base primary · sm primary · lg primary · disabled Props
variant 'primary' | 'secondary' | 'ghost' 'primary' Visual emphasis. Primary commits the page; secondary supports it; ghost gives an inline link button affordance. size 'sm' | 'base' | 'lg' 'base' Use lg for hero CTAs only. href string — When set, renders as <a> instead of <button>. Use for navigation, never for actions. target string — Pass "_blank" for external links; set rel="noopener" with it. rel string — Required when target="_blank" for security. type 'button' | 'submit' | 'reset' 'button' Ignored when href is set. disabled boolean false Sets aria-disabled and blocks pointer events. fullWidth boolean false Stretches to container width. Use only in tight columns or forms. children • slot — The label. Verb-first, under five words. Do · Don't
One primary per page. The primary names the decision the page is asking for. If two compete, the reader makes neither.
Two primaries on the same screen. The eye splits, the conversion halves, and the page stops being about anything.
Verb-first label, under five words. Start Operator. View free tracker. Read the case.
Sentence-shaped CTAs. Click here to learn more about subscribing is not a button label, it's a meeting.
Accessibility
What this guarantees, and what you must not strip when composing.
Keyboard
Tabfocuses;EnterorSpaceactivates.- Disabled buttons are skipped by the focus order but still announced to screen readers via
aria-disabled.
Screen reader
- Renders as semantic
<button>by default;<a>whenhrefis set. Never override that. - The label slot must contain plain text. Icon-only buttons require
aria-label.
Focus
- 3px
--c-accent-tintring on:focus-visible, visible against every surface in the token system. - Focus survives theme switching; we do not remove the outline to look cleaner.
Contrast
- Primary:
--c-bgon--c-accent, AA verified live on the Foundations grid. - Secondary:
--c-inkon--c-bgat AAA in both themes.
Motion
- Hover translates 1px up. We honour
prefers-reduced-motionby collapsing the lift to zero.
Badge
A status without a sentence. Every Badge is a claim the rest of the page has to back up. Use one. Use it precisely. Critical binds; warn watches; success confirms. The rest are categorisation chrome.
Pick a variant for the semantic role (status, category, ticker), change the size, change the label.
Controls
Code
Anatomy
Variants
accent · primary call-outcritical · bindingwarn · watch listsuccess · confirmedoutline · secondarysubtle · contextdefault · tickeraccent · smProps
variant 'default' | 'accent' | 'critical' | 'warn' | 'success' | 'outline' | 'subtle' 'default' Semantic role. Pick by meaning, not by colour you want. size 'sm' | 'base' 'base' Use sm when the Badge sits inline with body copy. base for standalone chips. uppercase boolean true Opt out for proper nouns and tickers (NVDA, HIMS) where capitalisation already encodes meaning. children • slot — One or two words. If it needs three, it isn't a Badge. Do · Don't
One Badge per surface. The Badge promises the eye that this is what to read first.
A row of Badges across one card. The eye gives up; nothing is first; the surface goes flat.
Pick by semantic meaning. Critical is a binding constraint. Success is something we have measured and confirmed.
Pick by colour. "I want a red Badge here" is not a reason to use critical. The visual register collapses the moment the semantics do.
Accessibility
What this guarantees, and what you must not strip when composing.
Keyboard
- Badges are not focusable; they are decorative or informational, not interactive.
- If a Badge needs to be clickable, it isn't a Badge. Use a Button or a link with appropriate styling.
Screen reader
- Renders as a plain
<span>. Screen readers announce the label as inline text. - For status that isn't obvious from prose, add
role="status"on the parent or wrap in a live region.
Focus
- No focus state by default. Badges cannot be tab targets.
Contrast
- accent, critical, warn, success: AA against the chip surface (verified in token system).
- outline and subtle: AAA on body backgrounds in both themes.
- default: AAA muted-on-soft pair, designed for tickers and tertiary labels.
Motion
- Static. Badges do not animate; movement here would compete with primary CTAs.
Kicker
The line that tells the reader what section they're in without making them read the heading. Small. Uppercase. Always above a Heading, never alone. If the heading carries the section context on its own, the Kicker is editorial decoration. Cut it.
Switch tone between muted and accent. Edit the label.
Section context
Controls
Code
Anatomy
03 — Section
In situ
Foundations
The tokens the brand stands on
The Kicker tells you where you are. The Heading tells you what we are about to say. The pair earns the section break.
Props
tone 'muted' | 'accent' 'muted' Use accent for sections that bind a decision (purchase, conversion, hero CTAs). Use muted everywhere else, and that is most places. children • slot — One short label. Numbered prefix (01 —) is editorial, not structural. Drop it if a section has no siblings. Do · Don't
03 — Section
A clean signpost
Pair every Kicker with a Heading directly beneath it. The two are one structural unit.
Floating context
A standalone Kicker floating in space. Without a Heading underneath, it reads as a typographic mistake.
Foundations
One Kicker per section. The Kicker is a signpost, and you only get one signpost per turn.
Header
Subheader
Note
A Kicker on every sub-block. The uppercase tracking starts to feel like a SaaS dashboard, and the editorial register collapses.
Accessibility
What this guarantees, and what you must not strip when composing.
Keyboard
- Not focusable. Kickers are static labels, never interactive.
Screen reader
- Renders as
<p>. Screen readers announce it as prose preceding the Heading. - Do not use a Kicker as the section's accessible heading; that is the Heading's job. Use both.
Focus
- Inherits no focus state.
Contrast
- muted:
--c-mutedon body surface. AAA in light, AA-large in dark. - accent:
--c-accenton body surface. AA verified across both themes.
Motion
- Static. Kickers should not move; they anchor the section visually.
Check
The smallest possible yes on the site. One glyph, no copy, paired with a line of text that earns it. If a Check needs explanation, you're using the wrong atom. Use a Badge, or rewrite the line.
Pick a tone. Swap the glyph if a list needs ★ emphasis or a bullet.
Controls
Code
Anatomy
Variants
accent · ✓success · ✓muted · ✓accent · ★muted · •In situ
- Live token editor with five presets and full keyboard control.
- Light and dark themes derived from the same primitives, AA verified.
- Anatomy, props, and an accessibility contract for every atom.
Props
tone 'accent' | 'success' | 'muted' 'accent' Use accent for default confirmations, success for items you have personally verified, muted for tertiary lists where the glyph should not lead the eye. symbol string '✓' Swap to ★ for emphasis lines or • when a list should read as bullets rather than affirmations. Do · Don't
Pair every Check with a line of text that names the affirmation in plain language.
A row of standalone Checks without text beside them. Reads as a sticker book, not a claim.
Mix tones with intent. One success line in a list of accent lines tells the reader which item you have proven.
Random tone variation. If every line is a different colour, none of them mean anything.
Accessibility
What this guarantees, and what you must not strip when composing.
Keyboard
- Not focusable. Check is decorative.
Screen reader
aria-hidden="true"on every Check. The list line beside it carries the meaning.- If a list of features must be announced as a list, wrap items in
<ul>. Not Check on its own.
Focus
- No focus state. Check is never a tab target.
Contrast
- accent and success: visible against every surface in the token system.
- muted: meets AA on body surfaces. Never use for status that must be read.
Motion
- Static.
Heading
Every level of the page hierarchy in one component. Semantic level (h1–h6) is decoupled from visual size, because screen readers care about the first and designers care about the second. Use both. Lie about neither.
Switch the visual size, font family, and text-wrap balance. Semantic level stays h1 in this demo; change it in code for real use.
Which bottleneck is binding right now
Controls
Code
Visual scale
Display heading
H1 heading
H2 heading
H3 heading
H4 heading italic
Anatomy
Which bottleneck is binding
Props
level 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' 'h2' Semantic level. Determines the tag. Set by the document structure, not by visual preference. size 'display' | 'h1' | 'h2' | 'h3' | 'h4' — Visual size override. Defaults to match level. Use to render a visually smaller h1 or a visually larger h3 when the layout demands. font 'display' | 'serif' 'display' display is Fraunces (the brand voice). serif is Newsreader, used when the heading wants to read more like an essay than a poster. balance boolean true Applies text-wrap: balance. Kills the one-word last line that always looks broken in display type. children • slot — The heading text. No trailing punctuation in display sizes; periods make sense in body, not in posters. Do · Don't
The Durability Curve
Subsection that follows the H1
Set level by the document hierarchy. One h1 per page. Then style with size if you need to break visual rank.
First H1
Second H1
Third H1
Pick level="h1" because it looks bigger. Three h1s on a page is a screen-reader failure, regardless of how it renders.
Which bottleneck is binding right now
Leave balance on. text-wrap: balance is the cheapest typography upgrade we ship.
Which bottleneck is binding right now
Hard-wrap with <br>. The site is responsive; your line break isn't.
Accessibility
What this guarantees, and what you must not strip when composing.
Keyboard
- Headings build the page outline screen reader users navigate with.
Tabdoesn't apply, butH,1–6, and rotor navigation in VoiceOver and NVDA do.
Screen reader
- Tag matches
levelexactly. There is no path through the API that produces a mismatch. - One
h1per page. Subsequenth2–h6nest under it. We do not skip levels.
Focus
- Inherits none. Headings are not focusable unless explicitly given
tabindex.
Contrast
--c-inkon every body surface in both themes. AAA across the board.
Motion
- Static. We do not animate headings on entry; the size carries the weight already.
ThemeToggle
Light or dark. Persisted. No flash. Boring on purpose. This is one of the most-clicked controls on the site and the contract is: it must not surprise anyone, ever. The interesting behaviour lives in the inline script that runs before the first paint, not in the button.
Click. The whole page switches. Reload; your choice persists.
Anatomy
--c-rule <head> reads storage before render States
default:hover:focus-visibleProps
(none) behaviour-driven — ThemeToggle takes no props. The button reads its aria-label and the inline script handles persistence, OS-preference fallback, and the icon swap. There is nothing to configure; that is the point. Behaviour contract
- 1OS preference on first visit. If
localStorage.tdc-themeis unset, the theme inherits fromprefers-color-scheme. The user's system gets to set the default. - 2Persistence across sessions. Click sets
data-themeon<html>and writes tolocalStorage. Survives reload, survives navigation. - 3No flash of wrong theme. The init script runs in
BaseHead, before the first paint. The page never renders the wrong theme for even a single frame.
Do · Don't
One ThemeToggle in the header, full stop. The control belongs where users expect it on every site they have ever used.
A second toggle in the footer "for convenience". Two toggles, two sources of truth, twice the bugs.
<head>
<script is:inline>
/* read storage,
set data-theme,
before paint */
</script>
</head>Trust the inline script. The flash-free contract depends on the init running synchronously in <head>; do not move it.
document.addEventListener(
'DOMContentLoaded',
() => { /* too late */ }
);Wrap the init in an event listener. DOMContentLoaded fires after first paint. You will ship a flash, and it will not be subtle.
Accessibility
What this guarantees, and what you must not strip when composing.
Keyboard
Tabfocuses;EnterorSpacetoggles.- The toggle lives in the header tab order. Every page has the same shortcut to switch themes.
Screen reader
aria-label="Toggle dark mode"on the button. The current state is implicit in the rendered icon, which isaria-hidden.- Future: consider
aria-pressedto expose the binary state more directly to assistive tech.
Focus
- 3px
--c-accent-tintring on:focus-visible. Identical to Button; keyboard users get one focus vocabulary across the site.
Contrast
- Border
--c-ruleon body surface, visible in both themes. - Hover state shifts to
--c-accent, which is AA against both surface tokens.
Motion
- Border and colour transitions only. We do not animate the theme switch itself; the cross-page flip would create motion sickness on long pages.
Iconography
Stroke-based 24×24 SVGs. 1.5px stroke at base size. currentColor everywhere so they inherit ink and theme correctly. Click any to copy.
Section 03 of 06 · Status Building · 1 of 6 specified
Molecules
Atoms in concert.
A molecule is a fixed composition. Each one declares its rhythm — the gap between its atoms — once, and every instance on the site inherits it. The Hero, the page-frame stamps, the terminal bar: each becomes a molecule with a spec, not a one-off layout.
HeroBlock
Title + lede + scroll cue. One rhythm, used wherever a section opens with a major statement.
Capability accumulates.
Atoms compose into molecules. Molecules compose into organisms. The rhythm is fixed once, then everywhere inherits it.
Continue- 01Title → Lede
var(--space-5)20px- 02Lede → Scroll
var(--space-8)32px- 03Title leading
0.86tight- 04Lede measure
44remmax
Every HeroBlock on the site reads from these tokens. Change --space-5 in Theme Studio and the title → lede gap moves everywhere this molecule is used.
LabelValueStamp
Key + value (+ optional sub) in mono caps. Used as every corner stamp on the page — page-frame corners, hero corners, anywhere a fixed label needs to read as instrument output.
- 01Key → Value · stacked
2pxtight- 02Key → Value · inline
var(--space-2)8px- 03Value → Sub
2pxtight- 04Tracking
0.14emmono caps
All 7 corner stamps on this page render through LabelValueStamp. Edit the key or value via Tinker Mode and the change persists per stamp; edit the spec values here and every stamp moves together.
Queue
The remaining molecules. Each is a known composition pulled from the site; each will land here with the same SPECIMEN + RHYTHM treatment.
- M03MetricRowLabel · value · unit, dot-separated. The terminal bar pattern.
- M04CardSurfaceHeading + lede + footer chips. The reference grid + research cells.
- M05TokenRailMeta column + visual rail + tip readout. Spacing, Motion.
- M06ChromaticTitleThe six-layer title used in Hero and ChapterBreak.
Section 04 of 06 · Status Queued · After molecules
Organisms
Composed surfaces.
Composed sections built from molecules. Building next: Hero, TierGrid, LayerGrid, MigrationFeed, FAQList, FounderNote, Header, Footer.
Organisms ship after molecules. Each will be a single Astro component. Import it once, use it on any page.
Section 05 of 06 · Status Live · BlogTemplate
Templates
Page-level scaffolds.
Page-level scaffolds, thin by design: data plus a template. Live: BlogTemplate, the real article asset, built from every atom above. Building next: TrackerTemplate, IndexTemplate.
BlogTemplate
A full article, rendered through the real layout and built entirely from the atoms above. Open it, then change a token in the studio: the article moves in lockstep with the blueprint. This is the asset the whole system exists to produce.
Section 06 of 06 · Status Live · 8 lineages
Reference
What this stands on.
The design knowledge this blueprint inherits from. Pulled from people who have already solved it, and named here so the lineage is visible.
Atomic Design
Brad Frost — Atomic Design (2016)
The five-tier taxonomy (atoms → molecules → organisms → templates → pages). The blueprint's structural backbone.
Component playgrounds
Storybook · Histoire · Ladle
Args panel, live controls, code snippet generation. We've built the same pattern in vanilla Astro to avoid framework lock-in.
Token systems
Style Dictionary · Tokens Studio · Open Props
Tokens-as-source-of-truth, with mathematical scale derivation. Type and spacing here scale via ratio formulas, not hand-typed values.
Theme builders
Material Theme Builder · Carbon Theme Builder · Adobe Spectrum
Live preset palettes, accessibility-checked colour pairs, export pipeline. The Theme Studio's preset bar comes from here.
Accessibility
WCAG 2.2 · Radix UI
Live contrast ratio checking with AA/AAA badges. Focus-visible rings on every interactive element. Keyboard navigation by default.
Visual register
Vercel Geist · Linear · Stripe Press · Stratechery
Editorial restraint. Confident typography. Sharp focus states. No decoration that doesn't earn its place.
Component libraries
shadcn/ui · Radix Themes · Geist UI
Copy-paste primitives over framework lock-in. Astro components live in the repo, owned by us — not in a node_modules package we can't change.
Pattern documentation
Shopify Polaris · GitHub Primer · Atlassian Design
Do's & don'ts, anatomy diagrams, behavioural notes per component. Pattern shipping next.