Rollout
Stage 12, closed by the founder on 2026-08-17. The rest of the product in colour, and the account of it: what was built, what each screen does with a wider window, and what is measured rather than remembered.
What this stage is, and why its account came last
The screens of this stage were built before the account of it was written, and across four stages rather than one. Stage 07 coloured a sample of seven screens to prove the language, stage 09 built Alerts out of the system alone to prove the system, the public page arrived on its own in August, and the remaining ten screens were coloured in one pass afterwards, because a screen is built once, when everything it needs already exists. What was missing was never the pixels. It was the thing a stage is judged on: a page of its own, a row per screen, and a number that a script can reproduce.
So this page reports rather than plans. Every figure on it comes from an instrument in
design/kit/screens/, each re-runnable and each deriving its corpus from a
registry rather than from a list somebody typed. rollout12.cjs reads the
source; width12.cjs walks all 55 pages across 58 widths in a browser;
shape12.cjs reads what each screen does between a real 360 and a real 1440;
fp12.cjs fingerprints every box on both sides of a change;
inert12.cjs re-asks the nine "checked rather than assumed" sweeps on the
corpus that exists now. And the counter it inherited was extended rather than trusted:
counts.cjs had read the CSS header alone since stage 11, while the same
sentence lives twice, in the header and on the component's page. It reads both copies now,
and the first run of the second column found 18 pages disagreeing on a corpus the
old run called clean.
The corpus: 55 and 55, and nothing on either side alone
wireframes/design/Both counts exclude overview.html on each side, because a hub is a stand and
not a product screen: the same basis the component counter and the inventory already use.
The pairing is the whole of what "the rollout is built" means, and it is now a
pairing rather than a claim: the two folders are read, matched by filename, and any file
alone on its side is named. The count was 28 coloured pages when stage 09 closed and 32 when
stage 10 did.
The audit row per screen, which stage 10 asked this stage for
Stage 10 wrote one row per screen saying what a wider window should give the person standing there, in three categories and a fourth that stayed empty: SAME, WIDER by grid, WIDER by air, and new behaviour nowhere. Ten of those seventeen rows had no coloured screen to check against at the time. Here is the built product measured against them, at a real 360 and a real 1440, with the scrollbar suppressed so the container is the number it says.
| Screen | Pages | Stage 10 said | The built screen does | Pane 360 → 1440 | What changes arrangement |
|---|---|---|---|---|---|
| Welcome 1.1 | 1 | WIDER grid | as planned | 360 → 1440 | the three steps 1→3, the footer 1→4, and six control rows unwrap |
| Path Choice 1.2 | 1 | SAME | as planned | 360 → 620 | the two doors 1→2 inside the column |
| Connect Bank 1.3 | 5 | SAME | as planned | 360 → 620 | nothing but the action row |
| Add a Subscription 1.4 | 4 | WIDER grid | as planned | 360 → 620 | the preset tiles 2→3, and the grid is inside a 620 column rather than in a wide pane |
| Guided Reveal 1.5 | 2 | SAME | as planned | 360 → 620 | nothing but a two-item list |
| Sign In 1.6 | 3 | SAME | as planned | 360 → 620 | nothing |
| Home 2.6 | 5 | WIDER grid | as planned | 360 → 1220 | the dashboard head 1→2, the doors 1→2, the groups 1→3 |
| Subscription Detail 2.7 | 6 | WIDER grid | as planned | 360 → 1220 | the screen itself 1→2: two columns of 546px, counted rather than placed |
| Alerts 3.8 | 4 | WIDER air | as planned | 360 → 1220 | nothing structural: a list of events is rows, which is what the plan said |
| Cancel Guide 4.9 | 3 | WIDER air | the category was wrong | 360 → 1220 | the screen itself 1→2. Stage 10's own how-column said "point 900, two columns already" and its category said air. The note was right and the category was not |
| Cancel Win 4.10 | 1 | SAME | as planned | 360 → 620 | nothing. One number in the middle, which is the whole screen |
| Share Snapshot 4.11 | 3 | SAME | as planned | 360 → 620 | nothing |
| History and Trends 5.12 | 5 | WIDER grid | wider by air | 360 → 1220 | the chart grows and nothing re-arranges. The plan's reason was "a chart is the one thing that genuinely grows with width", which is air: the word was wrong, the behaviour is the one asked for |
| Upgrade to Pro 5.13 | 4 | WIDER grid | as planned | 360 → 760 | the plan row 1→3 |
| Connections 6.14 | 4 | SAME | wider by grid | 360 → 1220 | the source doors 1→2. SAME was never available to this screen: it stands in the shell, and past the desktop point the shell gives its pane 1220 |
| Data and Privacy 6.15 | 2 | WIDER air | as planned | 360 → 1220 | nothing. Continuous prose, held at the reading measure |
| Settings 6.16 | 2 | SAME | wider by air | 360 → 1220 | nothing re-arranges, but the pane is 1220. The same finding as Connections, without the grid |
--container-column, 620, and stops, which is exactly what "SAME, container"
meant. A screen inside the shell is handed the pane, and past the desktop point that pane is
1220 whatever the screen would prefer. Connections and Settings were written SAME in a table
whose other seven shell screens were all WIDER, and no instrument existed to catch it because
neither screen had been coloured yet. The fourth, Cancel Guide, was a category that contradicted
its own note. New behaviour is still zero, on all seventeen, and that half of the audit
holds exactly as written.A screen carries no style of its own, re-proved on all 55
The rule in CLAUDE.md is four bans and one of them is the width rule stage 10
asked this stage to re-check: no style block, no style attribute, no @media, no
class the system does not define, and no width literal anywhere in a screen file. Stage 10
proved it on 32 pages. It is re-proved here on all 55, by script, over the source rather
than over the render.
| What was looked for | Found | Where |
|---|---|---|
<style> blocks | 0 | all 55 coloured screen files |
style="" attributes | 0 | all 55 |
@media and @container | 0 and 0 | all 55 |
| a width declaration of any kind | 0 | all 55. width, min-width, max-width and inline-size, comments stripped first because a screen is allowed to talk about width |
stylesheets besides system/index.css and _screen.css | 0 | all 55 |
| classes the system does not define | 0 | all 55, matched whole against every selector in design/system/, the reviewer chrome, and the three classes a script writes |
| links leaving the colour for the frozen grey | 0 of 581 | the first sweep, run on a hunch, found four. They were fixed on 2026-08-17 and the check is standing now |
| links whose target does not exist | 0 of 581 | every internal href resolved against the file system |
The width column, recounted on the whole system
Every row of docs/inventory.md carries a "behaviour at width" cell, and an
empty one would mean "behaves unknown on a wide screen". Stage 10 filled it on 60
entries and left a note saying the count would be re-taken when the corpus stopped
moving, which is this stage. The corpus is 72 now: 69 component files and 3
patterns.
| How it adapts | Stage 10, on 60 | Stage 12, on 72 | Which |
|---|---|---|---|
| a point, one of the two registered | 5 | 9 | app bar, category group, chart placeholder, dialog sheet, groups column set, tab bar, landing shell, landing final, list column |
| point + fluid | 4 | 6 | app shell, dashboard head, grid, landing bar, landing plan, landing steps |
| point + fluid + a reading measure | 0 | 5 | faq list, landing facts, landing paths, landing story, site footer |
| a container threshold + fluid | 2 | 2 | save-focus candidate, subscription row |
| container thresholds + fluid + a measure | 0 | 1 | landing orbit, and its three local thresholds ask a named container rather than the page |
| fluid only | 4 | 4 | action row, alert item, meta row, merchant chip group |
| a reading measure, and no query at all | 7 | 12 | readout, text block, empty block, muted line, wash block, promise list, landing hero, and the five this stage added: card, form field, numbered steps, panel, share card |
| a cap and no query | 1 | 0 | the card was the only one and it is in the row above now: 560 stayed as the card's width and the prose inside it took the measure |
| does not adapt | 37 | 33 | the rest, and nothing is written on their pages: an empty "does not adapt" note on thirty-three pages is noise |
flex-wrap: wrap means the arrangement answers the width,
flex: 1 means the component divides whatever it is handed and arranges itself the
same way at 320 and at 1920.Nine cells were wrong and are corrected. Eight of the twelve new entries had their
width cell filled with what the organism is rather than what it does with width, which
is the column answering a different question; the ninth, the FAQ list, said "does not adapt"
while its file carries a desktop point and a reading measure. Both are in
docs/inventory.md now, and the prose that was displaced is under the organisms
table rather than deleted.
The width sweep: 55 pages by 58 widths, and what it caught
Stage 10 swept 32 pages and its argument for sweeping rather than sampling was exact: a defect lives between the points, and the worst width is the one where the content has stopped fitting and the query has not fired. Twenty-three pages had never been walked. The run is 3190 measurements, and it drives the browser itself rather than asking a person to press Run.
Two of those four are not the clean answers they look like, and both are worth the sentence.
The pane check is the one that found the 28px band at stage 10, where a layout scrolled
sideways inside .screen while the document stayed clean; it is asked of every
scroll container on the page here, and it is silent on all 55. And the landing runs 128
elements past the window on purpose: a marquee track is wider than its box and hidden by
it. The first run of the sweep reported all of them at all 58 widths, which is a fault in the
instrument rather than in the page, so a clipped element is now counted separately instead of
being reported or silently dropped.
What it did find is prose, and all six are fixed. Six blocks read past the system's 52ch measure, four of them on screens that had never been swept. Each fix is a measure on the element that holds the words, in the component that owns it, and the re-run reads zero prose leaves past 52ch anywhere in the product, worst 52.0:
| Where | Read | At | What it was, and what closed it | Now |
|---|---|---|---|---|
cancel-guide, a step | 81.2ch | 750 | .steps li had no reading measure at all: the worst line in the product, on the one component whose brief is an instruction being followed on another screen. `numbered-steps.css`, and it is the system's one computed width: calc(var(--container-text) + var(--space-40)), because border-box would otherwise let the numeral's gutter eat eight characters | 52ch |
index, the story head's lead | 80.2ch | 720 | .lp-story.fromcircle .storyhead capped itself at 38rem, a raw literal in no register, and the lead inside it is two type steps smaller, so the same box was 52ch for the heading and 80 for the sentence. `landing-story.css`: the literal is replaced by --container-column, which the same head is already given in the stage form, and the lead took its own measure | 52ch |
connect-bank, the email hint | 77.6ch | 640 | .field .hint had no measure. Six of the twenty fields carry a fragment and this one carries a paragraph, on the screen where a person decides whether to trust us. `form-field.css`, and at --type-meta the same token is 394px rather than 459: ch follows the font | 52ch |
cancel-guide-blocked, a step | 60.8ch | 760 | the same rule as the first row | 52ch |
history-trends-locked, the prose card | 59.5ch | 600 | the card's 560 against the system's 52ch, both deliberate and disagreeing, and open since stage 10 as a founder's question. `card.css`, and it is the first of the two answers it was given: 560 stays as the width of the CARD, the paragraph and the list items inside take the measure | 52ch |
share-snapshot, the privacy paragraph | 58.3ch | 640 | a bare p inside .oncard, a one-off with no component and therefore no measure. `share-card.css`, where the eyebrow already reaches into the same block. A measure is not an owner: the one-off row stays open | 52ch |
cancel-guide, the Pro gate's sentence | 77.3ch | 750 | The seventh, and it was uncovered by fixing the first. The sweep reports the worst leaf per page, and this one stood behind the 81.2ch step on the same screen. A chain rather than a rule anybody broke: the panel takes the screen's width, the gate takes the panel's, and nothing between the words and the shell had ever been asked how long a line should be. `panel.css`, five gates on five screens | 52ch |
--container-text is 52ch, and ch is a unit of the element's own
font: a 52ch cap set on a container at 16px does not give a 12px line inside it a 52ch
measure, it gives it about 69. The story head is that exact shape, and it is the argument for
putting the measure on the line rather than on the box around it. All seven are fixed, on the
founder's word, and the pixels are accounted for both ways. At 360 the difference is
zero on all 55 pages, box for box, which is the half of the promise that is not allowed
to move and which holds by construction: every one of these caps is wider than a phone. At
1440, 16 pages and 137 boxes changed, and every changed WIDTH is one of the seven
rules - 32 boxes, five selectors - while the other 105 are boxes that grew a line taller or
moved down under one that did. Nothing else in the product moved.:where(), at specificity zero, found the seventh: dialog-sheet.css
has said 480px, centred, under the 620 the flow column takes since stage 08, with the
reason written on the rule, and the sheet had never once rendered it past the tablet point -
it ran the full 588 column on all three of its screens. Zero boxes moved at 360; three
pages and 49 boxes moved at 1440, every one of them that sheet. The change restores what
the component already says rather than deciding anything new, and it is one line to
revert.Every row this stage opened, and where it went
The stage began with eight rows addressed to it, four inherited from stages 09 and 10 and four found by its own instruments. All eight are closed, and three of them closed as a decision rather than as a fix, which is the distinction worth keeping: a row that is answered "no, and here is the measurement" is not the same as one quietly dropped.
| What | State | Where it closes |
|---|---|---|
| Seven prose blocks past the reading measure, above | closed | five component files: numbered steps, form field, card, panel, share card. Zero leaves past 52ch in the product now |
38rem, a width literal in no register, in landing-story.css | closed | not registered but replaced, by the --container-column the same head is already given in the stage form. The product now holds no unregistered width number |
.oncard and .lead are one-offs with no component, and both now have a measure declared by a neighbour | closed as a decision | and the answer is that neither is owed one. .oncard has a single host. .lead turned out to carry three meanings, not two: .muted.lead is a declared modifier of the muted line on 9 coloured pages and keeps the word, and bare .lead stands on exactly two pages in two different hosts with two different rules, which by rule 1 of the inventory is two host slots. Promoting a name three rules disagree about is how a collision becomes a component. The true fix is a rename, and a rename is markup behind the freeze |
| The focus order in the rail form: the rail's head takes focus first and its four destinations last, with the whole screen between them | closed as a decision | and the measurement is what closed it. Re-read across all 55 pages at 360 and at 1440: every page tabs bar, then content, then navigation, and not one page changes its order with width. So there is no width-dependent defect - there is one order, and it is content before navigation, which is the order a skip link exists to create artificially. Reordering the DOM would put four destinations in front of the first word on a phone. A skip link stays available and belongs to Voice first, because it is a new product string |
The shell's blanket on .app > .screen > *, which had unbound six measures one at a time | closed | and closing it found the seventh. The named list this row asked for was tried and abandoned - it is fourteen selectors long and one member is a bare <div aria-hidden> that must widen - so both blankets went inside :where() instead, which is specificity zero: anything that declares a measure of its own now wins, anything silent still gets the pane. Zero boxes moved at 360; three pages moved at 1440, all of them the dialog sheet, which has declared 480px since stage 08 and had never once rendered it past the tablet point |
| The count-drift row: every per-component figure written by hand in forty places | closed in part | the instrument arrived at stage 11 (counts.cjs) and its trigger was "when stage 12 stops adding screens". It has stopped: 0 per-component claims disagree with the corpus, and the width column, this table, the README and the two hubs are recounted. What is not closed is the row above it: the sentences on the component pages still describe a 28 or 32 page product |
| The component pages described a 28 or 32 page coloured corpus, 48 times across 24 files | closed | and the pass found a hole in the counter first: counts.cjs had been reading the CSS header alone, while the same sentence lives twice. It reads both copies now and found 18 pages disagreeing where the run had been saying zero. All 18 are recounted with their screen lists regenerated; of the other 28 occurrences, 19 were live claims and are recounted and 9 are stage records that now name the corpus they were measured on. The nine "checked rather than assumed" sweeps were re-run rather than re-typed (inert12.cjs, both corpora, 55 pages each) and every one still reads zero |
Two pages in design/kit/ were in no registry, kit.html and shell.html | closed | both are in the System group of design/kit/_nav.js now, as "The screen template" and "The flat kit, stage 07". The count reads 85 of 85. The other half of kit.html's old row closed with it: a stand owns its chrome, which is the licence design/overview.html already carries in writing and this page uses too |