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.
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.
.doorthe molecule: anaset todisplay: block, with the container corner, the control edge and 16px of padding. The whole card is one link with one accessible name, so a screen reader reads one destination and not a heading followed by a stray sentence.door h2/h3the path's name, at 16px in primary ink. BOTH levels are declared, because a component whose typography depends on which heading the document happened to need is not a component.door pwhat the path costs you, in muted ink. One sentence, and it is always a fact rather than a promise: "Read-only, through Plaid, and about a minute".pickthe declared variant, on 4 of the 8 doors. Body ink at weight 600 with an arrow, and deliberately not the accentborder-radiusreads--radiusand not--radius-sm, which is the one place a control-edged object in this system takes the container corner. A door is a card the size of a card
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: |
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
Connect your bank
Read-only, through Plaid, and about a minute. Tendd cannot move your money.
Choose this pathAdd them yourself
Start with one and add more later. No bank is involved, and nothing leaves your control.
Choose this pathSame 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.
Connect your bank
Read-only, through Plaid, and about a minute. Tendd cannot move your money.
Choose this pathOr add them yourself
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".
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.
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
Connect your bank
Read-only, through Plaid, and about a minute. Tendd cannot move your money.
Choose this pathAdd them yourself
Start with one and add more later. No bank is involved, and nothing leaves your control.
Choose this pathBoth 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.
--bg-surface, --line-control, --text-primary and --text-muted--bg-hover, --line-control-hover. The edge STRENGTHENS: 3.46:1 at rest, 5.78:1 here--color-focus, 6.23:1 as a line, offset 2px so it never sits on the door's own edge--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 targetRetake, 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
| Reads | Which token | Growing 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-4 | primitive: a spacing has nothing to override |
| the corner | --radius | primitive, and the container corner rather than the control one |
| the heading size | --type-sub | primitive, 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>