Alert item
One thing worth knowing about, said in a sentence that names who did it. It is the object the whole Alerts screen is made of, it is GC5 in the globals, and until stage 09 it had never been rendered in colour: zero of the 28 coloured screens carried it, which made it the largest hole in the sample. That is why Alerts was the screen chosen for the self-sufficiency test on 2026-08-13, and the hole closed with it: the component now stands in colour, 12 items across 2 pages, exactly as it stands in the grey.
Anatomy
Read this page knowing what it is. Every other component in this kit was measured on a coloured screen before it was written down. This one was not, because when it was written no coloured screen carried it. Its form here was read off kit.css and off the grey markup on alerts.html, line by line, and nothing in it is invented. What follows is therefore correct and unproven, which is a different thing from correct and checked, and it is worth saying out loud on the page rather than discovering at the rollout.
.alertthe molecule itself, and it is thea: the whole item is one target with one accessible name, exactly like the subscription row. It draws no floor, because every alert carries at least three lines and clears 44px on content alone.logoan atom. The merchant's mark at 32px, sized for this host by logo.css and never by this file.newdotthe unread mark, 7px, quiet, and never a count. It sits inside the sentence rather than at the edge, so it reads as part of the line and not as a badge.whatthe sentence, and it is the alert.--type-body, weight 600,--text-primary. It names the actor: "Netflix went up by $2.50", not "a price change has been detected".metathe provenance, always the same shape: kind, merchant, date, source.--type-meta,--text-muted.pricesthe old figure beside the new one. Three labels muted, three figures primary, so the numbers are what the eye lands on.gothe inline action with its arrow. It stays ink and never petrol, because a list renders eight at once.chipan atom. The Pro chip, on two of the eight items, with its 4px left margin living in chip.css alongside the other host placements of that atom. It was.badgeuntil step 6
Behaviour at width
Fluid, and it has no point and no threshold. The body is flex: 1 with a min-width: 0 floor and the row wraps, so an alert reflows continuously instead of at a chosen width. See Width.
Variants and sizes
One form and two content variants, which is what the consolidation recorded: .prices and .newdot, both optional slots inside the filled item. Neither changes the shape of the alert, and both exist on exactly one page. Size is not an axis: there is one alert and it is one size everywhere.
| Content Chosen by what is TRUE of the alert, never by how much attention it wants. The dot means unread; the price pair means a number changed and the old one is worth showing |
Where it stands | The rule |
|---|---|---|
Plain .alert |
5 of 8 items alerts.html |
The default. Sentence, provenance, action, and nothing else |
Unread .newdot |
3 of 8 items 1 grey page |
New since the last visit, and the screen's own copy says so: "A quiet dot marks what is new since your last visit". aria-hidden on the dot, and the word "New" at the front of the item's accessible name instead, because a dot cannot be read aloud |
With the price pair .prices |
1 of 8 items 1 grey page |
Only where a figure moved. Every product shows the new number; the old one beside it is what turns a surprise into an explanation, and that is the whole reason this slot exists |
Loading div.alert |
4 items alerts-loading.html |
Rendered as a div and not an anchor, with two skeleton lines and a skeleton square. It needs no rule of its own at all: the alert's box does the work and skeleton-bar.css draws the bars |
| A tone: attention, or failure | - | Forbidden with a reason rather than missing. Eight alerts stand on one screen and three of them are about money that did not move. An amber or clay wash on each would turn the screen into a wall of coloured blocks, which is the thing this product exists not to be. Tone belongs to the Wash block, which appears once per screen above content that still works. Here the sentence is the alert, and the chip beside it carries the only label the item needs |
Both content variants are grey-only. .prices and .newdot are two of the seventeen forms docs/census.md lists as existing in the wireframes and nowhere else, and this page is the first time either has been drawn in Petrol and Paper. That is also why they are drawn from the grey markup rather than designed here: a variant invented at step 5 and a variant invented again at the rollout are two variants.
When to use it
An alert item is something that happened, on a date. Eight of them stand on node 3.8 under headings that do the sorting for a person: two under "Needs you", five under "Just so you know", and one older item inside a disclosure. A price went up, a payment did not go through, a charge is coming, a subscription was found, a trial is ending, a charge looked unusual. That is the whole set, and the screen's own line frames it: "The few things worth knowing about."
It carries mechanism 1, active voice, and that is a strategic decision rather than a style preference. "Netflix went up by $2.50, now $17.99 a month" names who did the thing and by how much. "A price change has been detected" names nobody, and for a person who is anxious about money the missing actor is filled in with something worse than the truth. The same sentence appears as the attention row on Home, which wireframes/docs/screens.md names as one of the three elements carrying trust and first-time clarity.
Nothing here shouts. The dot is quiet and there is never a count; the inline action stays ink rather than petrol, because eight petrol links on one screen is the One Voice Rule failing by repetition; and the two Pro alerts are shown rather than hidden, with no blur over the text, because a blur pretends something is being withheld and an anxious person fills the gap in with the worst thing they can imagine. Every line comes from voice/docs/microcopy.md.
The rule, and the anti-rule
Something occurred, it has a date, and there is one thing to do about it. The sentence names the actor, the meta line says where the fact came from, and the action goes to the screen that explains it.
A thing you pay for, standing in a list with its price and its next date, is the Subscription row. The two carry the same merchant and look alike from a distance, and they answer different questions: the row is a state, the alert is an event. The tell is the text. If the line reads as a noun with a number ("Amazon Prime, $14.99"), it is a row; if it reads as a sentence with a verb ("did not go through"), it is an alert. globals.md already caught this confusion once, on the trend row.
The component is built for repetition, which is why nothing in it is loud: no fill, no border, no tone, no petrol, one quiet chip. Eight of these read as a list a person can scan and leave.
Netflix went up by $2.50, now $17.99 a month. See what changed
One message standing above content that still works, on a screen that is about something else, is the Wash block: an amber fill for a price change, a clay one for our own failure, and it appears once. That is the attention row on Home, carrying the very same sentence as the first alert on this page. The Wash block molecule owns that amber fill, which is why the specimen above carries the copy without it. The difference is the host and not the words: a wash tells a person to look up from what they were doing, and a list of eight things telling you to look up is a screen nobody opens twice.
Limits
U12, context. A state change is colour over --dur-state, and a component declares a transition only where its host is not a native interactive element. base.css puts the one transition on :where(a, button, input, select, textarea, summary, label) and moves four properties: background-color, border-color, color, text-decoration-color. Nothing on that list moves an object, and the focus ring is deliberately off it. This component is one of the three the rule names, and it declares the transition itself because its host is an a eight times and a div four: background-color, reading the same two tokens so the two can never drift. Full table with sources and how to check: Usage rules, and the register is on Motion.
U13, context. ADVANCE and PRESS. The item’s line ends in an arrow that advances right by one nudge on hover, and the item goes down by one on :active. Both are scoped to the anchor form, so the loading form answers nothing. 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 the item is a link. Each is a token override rather than a style of its own, so the dark theme costs nothing in this file.
The hover FADES since 2026-08-16, and this file declares it. The item is an a eight times on alerts.html and a div four times on alerts-loading.html, which is the loading state, so the element default base.css carries would fade one form and cut the other: one class behaving two ways. The rule and its tokens are in Limits above. Worth naming separately: the loading form takes the hover fill at all, and there is a precedent that says it should not. .row.is-skel in skeleton-bar.css was given cursor: default on the written ground that a skeleton must not look hovered, focused or pressed; no equivalent exists here or on the preset tile, whose loading form is a span. It is a row in the backlog and a rollout question rather than a motion one.
Three rather than four. There is no disabled alert. Every alert in the product goes somewhere, including the two Pro ones, which lead to the upgrade screen rather than being greyed out. And there is no :active, because kit.css declared none and writing one here would be a new decision about how the product answers a press.
Rest, live
Real anchors with a real href, which is the only way the states below can be reached. The divider a person sees between two alerts is not here: it belongs to the Divided list organism, which draws it in the product.
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.
--text-primary on the sentence and the figures, --text-muted on the provenance and the labels--text-body, an ink role rather than a fill role, because a 7px mark is a glyph and not a surface--bg-hover, and nothing else: no border, no shift, no size change. Eight items stack and a border under the pointer would move the seven below it--color-focus, 6.23:1 as a line, at 2px offset so the ring sits outside the item--color-focus, 6.82:1. The ring wraps the whole item, including the inline action inside it, which is correct: .go is a span and not a second targetRetake, and this is the whole recipe, because there is no node Playwright in this repo and a
command that does not run is worse than no command:
serve the repo, then for theme in (none, data-theme="dark" on <html>):
goto /design/kit/alert-item.html
move the pointer away -> screenshot #live-rest -> screens/alert-item-rest-<theme>.png
hover #shot-alert -> screenshot #live-rest -> screens/alert-item-hover-<theme>.png
focus #shot-alert by Tab, assert :focus-visible
-> screenshot #live-rest -> screens/alert-item-focus-<theme>.png
These six are the FIRST colour record of this component, so shoot them before the rollout
colours node 3.8 and not after: a snapshot taken from a screen is a check, a snapshot taken
from the kit is the reference the screen is checked against.
The technical half
| Reads | Which token | Growing from |
|---|---|---|
| the sentence, the figures, the action | --text-primary | --ink |
| the provenance and the price labels | --text-muted | --muted, the single secondary tier |
| the unread dot | --text-body | --slate. An INK role painting a drawn mark: tokens.css puts icon glyphs on the ink side with the text, and a 7px dot is a glyph and not a surface |
| hover fill | --bg-hover | --panel, and --panel-dark in the dark theme, which is lighter and not darker |
| the focus ring | --color-focus | --petrol |
| the two text sizes | --type-body, --type-meta | primitive, straight: geometry has nothing to override |
| gap, padding, the lifts | --space-0, --space-4, --space-8, --space-16 | primitive, straight |
| the 40px on the inline action | none, and not --tap | a literal, and it is a line box rather than a target: .go is a span inside the anchor, so the target is the whole item |
| the dot's 7px, the mark's 32px | none / logo.css | a diameter and a host size, neither of them a spacing |
Two of its parts are atoms and this file paints neither. Logo owns the 32px square, Chip owns the Pro label and its 4px left margin, and Skeleton bar owns the loading form. Three declarations of kit.css were dropped because they repeat what those files already say, and each one is named in the CSS where it would have gone.
One figure in the sources does not hold, and the code and the markup win. docs/census.md reports "Alert item at twelve grey pages is the largest hole". Twelve is the number of items, not pages: class="alert" occurs 12 times across 2 grey pages, 8 on alerts.html and 4 on alerts-loading.html, which is what docs/inventory.md and _nav.js both record as its page count. The finding underneath was the important half: zero coloured pages, the largest hole in the sample by a distance. It was closed on 2026-08-13 and the count is now 12 items across 2 coloured pages, which is every item the grey has.
Lives in design/system/components/alert-item.css. Stands on 2 grey pages, 12 items: wireframes/alerts.html (8: two under "Needs you", five under "Just so you know", one inside the "Older" disclosure) and wireframes/alerts-loading.html (4 skeletons). Both are coloured as of 2026-08-13, 12 items again: Alerts (8) and its loading state (4). Node 3.8 did not wait for the rollout, because the system needed a screen it had never seen.
<li><a class="alert" href="subscription-detail-price-change.html"
aria-label="New. Netflix went up by $2.50, now $17.99 a month. Price change from Chase, Jul 28. See what changed.">
<span class="logo"><img src="visuals/logos/netflix.svg" alt=""></span>
<span class="body">
<span class="what"><span class="newdot" aria-hidden="true"></span>Netflix went up by $2.50, now $17.99 a month</span>
<span class="meta">Price change · Netflix · Jul 28 · from Chase</span>
<span class="prices"><span>Was <b>$15.49</b></span><span>Now <b>$17.99</b></span><span>Difference <b>$2.50</b></span></span>
<span class="go">See what changed</span>
</span>
</a></li>
The aria-label starts with the word "New" because the dot carries aria-hidden and a 7px circle cannot be read aloud. It ends with the action text for the same reason the subscription row's does: the item is one target, so it needs one sentence.