Chip

The smallest thing the product says out loud: a state, or the plan a person is on. It is the component the consolidation compressed hardest, five class names into one rule, and its axis is tone rather than importance.

Atom20 grey pages36 places1 axis, 3 tonesno states, not interactive

Anatomy

One zone and one content slot, which is what makes it an atom. Everything below is drawn by design/system/components/chip.css through the same entry point a product screen loads, so this page cannot drift from the screens: there is no second copy of the CSS here to drift from. Every chip on this page carries a label that a real screen carries.

Price changed Payment failed Connected Best value

Measured on this page rather than read from the file: every chip above renders 24px tall, 10px at weight 600, line height 16px, padding 4px by 8px, corner 6px. There is no size axis and no second size anywhere in the product.

Those five numbers were 22.8, 10.5, 16.8, 3 by 9 and 6 under kit.css, and four of them moved because the atom went onto the scales rather than because anyone restyled a chip. The founder's review of the foundations folded the half steps out of the type scale, so 10.5px lands on --type-label at 10px and the line box follows it from 16.8 to 16; the spacing grid puts the padding on --space-4 and --space-8, so 3 by 9 becomes 4 by 8. Height is the sum of those two moves, 16 plus 8. The corner did not move. Every chip in the product changed by the same amounts on the same day, which is what a scale is for.

Variants and sizes

One axis, and it is tone. It is chosen by what the chip is, never by how much attention it wants: a tone is a fact about the thing, and a chip that picks its colour by urgency is the finance-app reflex this language was chosen to refuse. Values stand next to each other below, because the question is always comparative.

Tone

Quiet unless the chip names something quiet cannot say. Quiet is not the fallback, it is the answer for every state of a subscription, a connection and a plan

Tokens Where it stands
Quiet .chip --bg-status
--text-status
33 of the 36. DESIGN.md: "Status is a quiet grey badge. Alarm is not a colour we own." 5.77:1, well over the 4.5 a 10px label owes
Active
Accent .tone-accent --bg-selected
--text-action
2 places, and the label is "Best value", not "Pro". Every chip in the product that says Pro or Free renders grey. That is D3 at the smallest scale the product has: petrol marks the recommendation the product is making, never the paywall. 5.26:1
Best value
.tone-attention, .tone-error, .cancelled deleted 2026-08-12 Three tones left, and the count is why. Each occurs 0 times on the 28 coloured screens and 0 times on the 57 grey pages, counted by parsing every class="..." token in both corpora. Attention and error were kept at stage 07 as opt-in modifiers for the day a price change or a failed payment became a chip; the product had already answered otherwise, and both are a full wash block with a sentence, because neither state fits in two words and a chip cannot carry a clause. Cancelled was drawn from the axis for a state node 2.7 has never rendered. An empty role is not a reserve, it is noise the real roles drown in

The count named two corpora and there are three, and the third one carried all three tokens for a day. The 28 coloured screens of stage 08 and the 55 grey pages were both swept and both came back at zero. The stand was not counted, and kit.html, the system's own front page, went on writing chip tone-attention, chip tone-error and chip cancelled after the rules had gone, rendering four quiet chips where four tones were meant. The repair was markup and not a rule brought back to serve one page: step 6 took the three tokens off kit.html, and a grep of that file returns none of them today. docs/inventory.md's renaming map, which lists .tag.cancelled on 1 grey page, is wrong about which page - and so was this sentence, which said the grey landing carries .tag.trial. Re-counted 2026-08-20: zero trial in any class attribute on any of the 114 pages, which is why the tone was retired that day with both its roles and the four teal primitives under them.

The other half of the matrix: four names became one

This component is a five into one consolidation, and four of the five arrived already merged. kit.css folded .tag, .badge, .plan-opt .best, .appbar .plan and .locklabel into a single base rule at stage 07, while docs/inventory.md was still counting two separate atoms. Step 2 of this stage brought the inventory to the code rather than the other way round, and step 6, on 2026-08-12, renamed the four survivors to .chip, here and in the markup of every screen in the same pass, because a rename here and a screen there is how a pixel comparison stops proving anything.

The merge was checked before it was made, and the check is the interesting part. docs/inventory.md opens its findings with "four chip look-alikes with four owners and no base", so the question this table had to answer is what each of the four had that the other three did not. Read out of design/kit/kit.css at line 279: on every paint and every geometry property the four were byte identical, one display, one flex, one padding, one border, one radius, one fill, one ink, one size, one weight, one line height, one tracking, one text-transform, one white-space. Nothing survived as a variant. What did survive is two things and neither is a variant of the atom: a tone, which is a declared modifier, and a placement, which is the host's job. The column below is that reading.

Name before

Read from the rendered page, not from the first declaration in the CSS

Needed a host Places What it had that the other three did not, and what it is now
.tagno, it rendered anywhere inside .app15Two tone modifiers of its own, .tag.trial and .tag.cancelled, and one placement, .row .tag. Now .chip, quiet
.badgeno10Three placements, p.badge, .alert .what .badge and .source .badge. No tone, no paint and no size of its own at all. Now .chip, quiet
.appbar .planyes, .appbar. Outside one it rendered as plain 16px text with no fill, measured on this page9One placement, margin-left: auto. Now .chip, quiet, painted by .app .chip because the bar stands inside .app, and pushed by .appbar .chip, which does nothing else
.plan-opt .bestyes for the fill, until 2026-08-12, and it is the defect the fold was after2The accent fill, shared with .tone-accent and .locklabel, and a placement written in plan-option.css. Now class="chip tone-accent": the tone said out loud, the placement left with the host
.locklabeldeleted0Deleted with its proof: declared in the stage 07 base rule and on zero of the 55 grey pages. Nothing moved, because a rule with no markup paints nothing. The same argument retired .tone-info at stage 07

The accent tone stopped being a host's private arrangement, and that is the second half of this round. .plan-opt .best and .tone-accent shared one rule because the tone had never been given a name of its own: one card was reaching in to paint one child. chip.css now leaves .tone-accent alone as the subject, and the markup carries class="chip tone-accent", which is why this page no longer has to borrow a plan card to show an atom.

Paint and placement answer to opposite rules, and this is the line between them. A fill and an ink belong to the tone modifier, because a chip that is petrol is petrol wherever it stands: .plan-opt .chip would be the wrong owner for a colour. A margin belongs to the host, because where a chip sits is a fact about the thing carrying it and about nothing else: .plan-opt .chip { margin... } is exactly right, and the placement block at the foot of chip.css does the same thing five more times, for the row, the app bar, the paragraph, the alert and the card. The plan card keeping the alignment while giving up the colour is not a compromise; it is the line drawn where it belongs.

A sixth placement lives in the wrong file, and it is on the backlog rather than in this round. Five host placements of this atom are in chip.css and the plan card's is in plan-option.css, now written .plan-opt .chip: one atom, six placements, two files. That is a real inconsistency and it was found by the agent that folded the card family. It is not fixed here, because a move should not ride along with a rename: whichever way it settles, it settles once and deliberately, not as a side effect of somebody else's edit.

The cost of doing the tone before the markup was named at the time, and it is now paid. While class="best" was still written, a "Best value" badge rendered quiet grey rather than petrol on five specimens: three on plan-option.html, one on grid.html, one on kit.html. Re-measured in a browser after the sweep, all five read rgb(231, 237, 238) on rgb(28, 106, 118), which is petrol, and so does the one on the Upgrade screen. Nothing was ever unstyled in between: the name kept the base rule and lost only the tone.

One of the four could not stand on its own, and that was the point of renaming rather than deferring. .appbar .plan was a host-scoped selector, so a chip lifted out of its bar lost its rule silently. Under .chip the fill comes from .app .chip, which the bar sits inside, and the bar contributes nothing but the push. Measured on the four screens that carry it: the same 10px, the same weight 600, the same rgb(233, 238, 239) as every other quiet chip, and margin-left resolving to the free space in the bar.

Size is deliberately not an axis. One size, everywhere, on every host: 10px at weight 600, 24px tall. A chip that grew with its host would compete with the merchant name beside it, and the row already has one thing that is allowed to be big.

When to use it

A chip answers "what state is this in" in one or two words, at the end of a row or beside a heading. It is the quietest thing the product can say, and that is why it is allowed to appear at all on a screen whose job is calm. DESIGN.md sets the bar: show it only when the state is not the plain default. Fourteen "Active" chips down a column is noise on the one screen the person came to for reassurance, so Home shows a chip only on the rows where something is actually different.

Every label comes from voice/docs/microcopy.md, and there are fourteen distinct ones in the whole product: Active, Trial, Price changed, Payment failed, Higher, New, Steady, Not identified, Connected, Reconnect needed, Private, Free, Pro, Best value. All of them are a state or a name, none of them is an instruction, and none carries a number: a chip that says "3" is a count, and a count is the thing this product will not do to a person.

Where a person meets it: on Home at the end of the two rows that are not ordinary, on a subscription detail beside the heading, on Connections against each bank, in the app bar as the plan they are on, and on Upgrade as the one petrol chip in the product.

The rule, and the anti-rule

Use a chip
Price changed

Two words at the end of a row, naming a state that is not the default. It is scannable down a column, it costs no vertical space, and it does not ask to be read: the eye either needs it or skips it.

Use a wash block instead
Netflix went up by $2.50 on Jul 28. Your next charge is $17.99 instead of $15.49.

The moment the state needs a sentence, the chip is the wrong object: it cannot carry a clause and it cannot carry the old price beside the new one, which is what turns a surprise into an explanation. That job belongs to the wash block, .wash.attention, which is the amber banner on the detail screen. DESIGN.md is explicit that the banner carries no icon either: the sentence is the alert.

Sentence case, at 10px
Reconnect needed

"Reconnect needed", not "RECONNECT NEEDED". The base rule declares text-transform: none and letter-spacing: 0 as explicit resets, because the grey wireframe it was copied from sets both the other way. DESIGN.md forbids the shout by name: "Don't uppercase or letter-space a badge to make it look designed."

Use an eyebrow instead
WHAT IS ON THIS CARD

Uppercase and tracked out is a real thing in this system, and it is a different component: the eyebrow, .k, the small label that names the section under it. It is 11px, muted, with 0.06em of tracking, and it carries no fill at all. If a label wants to be uppercase, it is not a chip, it is an eyebrow, and the fill is the tell: a chip is a coloured object about one thing, an eyebrow is a caption over a group.

Limits

U19, composition and context. The plan form of this atom is a child of the account link, not a sibling of the lockup, on every page that greets a person by name: chip.css takes back its own margin-left: auto for that case and the link supplies the gap. Past a 760px container it gives the auto back, 2026-08-20: there the bar is a column and app-bar.css stretches the link to the rail's width, so auto stops pushing the chip away from the name inside a 120px control and starts pushing it to the far end of the greeting's own line. Same property, opposite answer, because the two forms of this bar are two different boxes. The four Upgrade screens have no account link and keep the auto at every width, since .app.flow never becomes a rail. Full table with sources and how to check: Usage rules.

States

None, and that is a decision rather than an omission. A chip is a label: no page in the product wraps one in an anchor or a button, so it has no hover, no focus and no disabled, and chip.css declares none. Inventing a hover on a badge is the same defect as inventing a role, because it documents something the product cannot do. Where a chip sits inside something that is interactive, the subscription row on Home, the state belongs to the row and the chip simply travels with it.

The technical half

ReadsWhich tokenGrowing from
the quiet fill and its label--bg-status, --text-status--stone, --stone-ink
~~the trial pair~~, retired 2026-08-20--bg-trial, --text-trial--teal-wash, --teal-ink, the one cool pair, and all four went with the roles
the accent tone--bg-selected, --text-action--petrol-tint, --petrol. The chip has no role of its own here: --bg-selected is the one semantic role on the tint, and DESIGN.md ties the two places together in one sentence
the four roles the deleted tones read--bg-callout / --text-muted, --bg-attention / --text-attention, --bg-failure / --text-failureNot orphaned by the deletion. All six are read by the wash block, which is where a price change and a failed payment actually stand, and --text-muted is the largest role in the system at 59 usages
the corner--radius-xsprimitive, straight: geometry has nothing to override

Lives in design/system/components/chip.css. Stands on 28 grey pages in 65 places and 28 coloured ones in 72. Coloured screens carrying it: Home and all four of its states, Alerts and all three of its, Settings, Subscription Detail and the price change state, History and trends and all four of its, Upgrade and the current plan. Recounted 2026-08-19 by design/kit/screens/counts.cjs: it was 20 pages and 36 places until the founder put the plan chip on every screen that greets a person by name.

<span class="chip">Price changed</span> <span class="chip tone-accent">Best value</span> <span class="chip">Connected</span> it needs no host anywhere, including in the bar: <header class="appbar">... <span class="chip">Free</span></header> and these were the four names it wore until 2026-08-12: .tag .badge .appbar .plan .plan-opt .best