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.

Molecule2 grey pages2 content variants3 states, both themes2 coloured pages

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.

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
iCloud+ charges $2.99 tomorrowComing up · iCloud+ · Aug 2 · from ChaseSee iCloud+
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
Tendd found a new subscription, Strava, $11.99 a monthNew subscription · Strava · found Jul 29 · from ChaseSee Strava
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
Netflix went up by $2.50, now $17.99 a monthPrice change · Netflix · Jul 28 · from ChaseWas $15.49Now $17.99Difference $2.50See what changed
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

An event, with its date

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.

Use a subscription row instead

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.

Several at once, in a list

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.

Use a wash block instead

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.

Restlight
no fill of its own, --text-primary on the sentence and the figures, --text-muted on the provenance and the labels
Restdark
the same roles, the other half of each pair. The unread dot reads --text-body, an ink role rather than a fill role, because a 7px mark is a glyph and not a surface
Hoverlight
--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
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, at 2px offset so the ring sits outside the item
Focus visibledark
--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 target
Retake, 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

ReadsWhich tokenGrowing 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-metaprimitive, straight: geometry has nothing to override
gap, padding, the lifts--space-0, --space-4, --space-8, --space-16primitive, straight
the 40px on the inline actionnone, and not --tapa 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 32pxnone / logo.cssa 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 &middot; Netflix &middot; Jul 28 &middot; 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.