Door

One of the two ways into this product, drawn as a card that is a link. They always come in pairs, they are always the same size, and neither of them is petrol: D2 makes the manual path an equal second door and not a fallback, so the product may not recommend one.

Molecule4 grey pages8 doors2 axes3 states, both themes

Anatomy

Three content slots in one unit, and no atom inside it at all. That is worth saying, because it means this molecule qualifies on the first clause of the rule rather than the second: a molecule is two or more slots in one unit, OR a host of an atom. Its heading is a bare h2 or h3 and its sentence is a bare p, not the eyebrow and not the muted line. Everything below is drawn by design/system/components/door.css through the same entry point a product screen loads.

Variants and sizes

Two axes, and neither is size: every door in the product is the same object, and its width comes from the grid it stands in, one column at 360px and two past a 760px container. What varies is whether the door carries a pick line, and which heading level the page had left.

Content

The pick line is present when the CHOICE is the whole screen, and absent when the doors are the empty state of a list that has other things on it. If a screen exists to ask which path, every door says which path it is

Values Where it stands
With a pick line .pick + 8px
14px / 600
--text-body
4 doors on 2 pages: the path choice at the start, and adding a second source later. Both are screens whose only question is which path
Without .door heading
+ 4px
sentence
4 doors on 2 pages, both of them empty states: Home with nothing in it yet, and the sources list with nothing in it yet. The screen has already asked its question in the block above
Heading level

Set by the DOCUMENT and never by the component: h2 when the door is a top-level thing on the page, h3 when it sits inside a section whose own heading is already an h2. Both render identically, on purpose

Values Where it stands
h2 16px, the
browser's own bold
--text-primary
4 doors, on the two screens whose subject is the choice itself
h3 identical 4 doors, inside the two empty states. Identical by declaration and not by luck: the group head in this same system broke twice for exactly this reason before the rule was bound to the class
A recommended door - Forbidden with a reason rather than missing. D2 makes the two paths equal, so neither door gets petrol, a heavier edge, a badge or more height. Two petrol objects on one screen is the One Voice Rule failing; one petrol object here would be the product answering the question it promised to leave open

Doors are never alone. All 8 stand in pairs, in a grid that gives them equal tracks, and the pair is the component's real unit. A single door on a screen would be a card with a link in it, which is a different thing and would be built as one.

When to use it

A person meets a pair of doors at the moment the product asks the only question it is allowed to ask before it has earned anything: connect a bank, or add subscriptions by hand. That question is D2, one of the locked decisions, and the whole design of this component is that decision drawn. The audience is 22 to 42 and sceptical about connecting a bank; a screen that leaned on the bank path would lose the people it was built for, and a screen that hid it would be a different product.

Its copy is a fact and never a pitch, from voice/docs/microcopy.md: "Read-only, through Plaid, and about a minute. Tendd cannot move your money" against "Start with one and add more later. No bank is involved, and nothing leaves your control." Both sentences answer the same question, which is what a person is giving up, and the second door's answer is deliberately as strong as the first's.

The rule, and the anti-rule

Two doors, exactly equal

Same edge, same corner, same padding, same heading size, same pick line. What identifies them as choices is the control edge at 3.46:1, which is the same edge a field and an outline button carry. Nothing marks one as the answer, because the product does not have one.

Never make one of them the answer

The moment the second path becomes a line under the first, D2 is gone and so is the audience it was locked for. If one action genuinely IS the recommendation, it is not a door at all: it is a filled button in an action row, which is the component that exists to say "this one".

Use a door

A branch: two ways to reach the same outcome, where the difference between them is worth a sentence and the person has to understand both before choosing. The card is what buys that sentence its space.

Use a nav row instead
Data and privacy   ›

Going somewhere that needs no explanation is the nav row: a line with a label and an arrow, stacked with its siblings inside one container, no edge and no corner of its own. Settings is eight of those and not eight doors. A door costs a person a decision, so a screen that has nothing to decide must not draw one.

Limits

U13, context. ADVANCE and PRESS. The line ends in an arrow that advances right by one nudge on hover, and the card goes down by one on :active. The card does not lift, and never will: a lift needs a shadow to read as one, and the Flat Paper Rule gives this system exactly one shadow which is spent elsewhere. Everything in this product that moves travels exactly one --nudge, which is 2px, and nothing anywhere travels two. Hover and release run at --dur-state (150ms) on --ease-arrive; a press runs at --dur-press (90ms), because it answers a finger that is already down. The full language and the live specimens are on Motion; the table with sources is Usage rules.

States

Three states, and they exist because a door is an a. Each one is a token override rather than a style of its own, and each one changes fill and edge colour and nothing else. No lift, no scale, no shadow: the Flat Paper Rule holds under the pointer as well as at rest, and a card that rises when you touch it is exactly the ranking this product takes away from the person.

There is no disabled form and that is a decision. None of the 8 doors is ever unavailable. Greying one of two equal choices would answer the question D2 exists to leave open, so a path that cannot be taken right now is not a grey door: it is a screen that says what happened and offers the other one.

Rest, live

Both are real anchors. Hover either one, then tab to it: the ring wraps the whole card, because the whole card is the target. That is also the answer to why the pick line is not a button. A button inside a link is not a control a browser can express.

The three, in both themes

The states are described, not photographed. Founder's decision, 2026-08-11: the snapshot strip went from every page in this kit, 120 images across 18 pages. They were framed as measurements rather than illustrations, and that framing was honest, but the bill came due all session: a value moves, and every picture of it is quietly stale until somebody re-shoots it. A stale picture is worse than no picture, because it looks checked. What is left is what a picture never carried anyway: the state, and the token it reads. The resting component is live and interactive above, so hover it, tab to it, and read the value off the real thing rather than off a photograph of it.

Restlight
--bg-surface, --line-control, --text-primary and --text-muted
Restdark
the same roles, the other half of each pair. The control edge is 5.15:1 here against 3.46:1 in the light theme, which is the ramp doing its job rather than a different decision
Hoverlight
--bg-hover, --line-control-hover. The edge STRENGTHENS: 3.46:1 at rest, 5.78:1 here
Hoverdark
the fill goes LIGHTER here and darker in the light theme: a hover moves away from its ground, and the ground swapped ends
Focus visiblelight
--color-focus, 6.23:1 as a line, offset 2px so it never sits on the door's own edge
Focus visibledark
--color-focus, 6.82:1. The ring is the full card, which is what tells a keyboard user that the sentence is part of the target
Retake, and this is the whole recipe, because there is no node Playwright in this repo: serve the repo, then for theme in (none, data-theme="dark" on <html>): goto /design/kit/door.html move the pointer away -> screenshot #live-rest -> screens/door-rest-<theme>.png hover #shot-door -> screenshot #live-rest -> screens/door-hover-<theme>.png focus #shot-door, press Tab, assert :focus-visible -> screens/door-focus-<theme>.png Three states and not four: there is no disabled door in this product, and a fourth cell would document something it cannot do.

The technical half

ReadsWhich tokenGrowing from
the card fill--bg-surface--paper
the edge--line-control--edge. A door is identified BY its edge, and DESIGN.md names it on the control side of that split
the heading--text-primary--ink
the sentence--text-muted--muted, the single secondary tier
the pick line--text-body--slate. NOT the accent: two petrol objects on one screen is the One Voice Rule failing
hover fill and edge--bg-hover, --line-control-hover--panel, --muted
the focus ring--color-focus--petrol
the padding, the gaps--space-16, --space-8, --space-4primitive: a spacing has nothing to override
the corner--radiusprimitive, and the container corner rather than the control one
the heading size--type-subprimitive, the 16px step: a door is on the reading line, beside a merchant name

Lives in design/system/components/door.css. Stands on 4 grey pages and 1 coloured one, Home with nothing in it yet, which carries the pair without the pick line. The pick line has no coloured render at all yet, so its form on this page is read from the grey. The grid around it (.grid.roomy, one column and then two) is the Grid organism, and it was .doors until step 6.

<div class="grid roomy"> <a class="door" href="connect-bank.html"> <h2>Connect your bank</h2> <p>Read-only, through Plaid, and about a minute. Tendd cannot move your money.</p> <span class="pick">Choose this path</span> </a> <a class="door" href="add-subscription.html"> <h2>Add them yourself</h2> <p>Start with one and add more later. No bank is involved, and nothing leaves your control.</p> <span class="pick">Choose this path</span> </a> </div>