The proof

This page is not part of the system. It is the evidence ABOUT it: what the stage promised, what it actually moved, who found what, and the three places the numbers are still open. A system that cannot be audited is a preference with a stylesheet.

Verification57 components3 patterns105 tokens0 unexplained pixelstwo instruments

The pixel comparison, and why it has no photographs

The obvious form of this page is a wall of before-and-after screenshots, and this project decided against exactly that on 2026-08-11. 120 state snapshots came out of this kit that day, framed as measurements and honest about it, on one argument: a value moves and every picture of it is quietly stale until somebody re-shoots it, and a stale picture is worse than no picture, because it looks checked. A page of proof built from the one artefact the project has already rejected would be the least trustworthy page in the folder. So the comparison here is the thing a screenshot never carried: the element count, the shape of every difference, and the named row that explains it.

The raw material is on disk and re-runnable: screens/pixel-before.json, screens/pixel-after.json, screens/pixel-brand.json, screens/ledger.txt and screens/brand-ledger.txt, each beside the script that produced it.

Round one, step 8: the sample moves onto the system

page-viewports compared element by element52 of 56
elements compared3588
distinct declared shapes of difference83
explained by: consolidated drift (step 3)1 shape, 10 occurrences
explained by: the review of the foundations (step 4)69 shapes, 4074 occurrences
explained by: moved onto system classes (step 6)11 shapes, 69 occurrences
explained by: the founder's review of the components2 shapes, 20 occurrences
UNEXPLAINED0 shapes, 0 occurrences

The proportions are the story. The stage that was not allowed to change the look moved 4074 values, and every one of them is two scales the founder adopted by one rule each: nearest step, ties to the larger, applied mechanically. Nobody decided value by value, which is what makes the result auditable rather than arguable.

Round two, 2026-08-12: the brand

elements matched across the 28 coloured screens3774
added168, which is exactly 3 per page-viewport on all 56
dropped0
moved69: 56 the brand's own slot, 7 the Free chip, 6 the Pro chip
other elements that changed a declared property0

The chips moved because margin-left: auto in chip.css absorbs the slot's 25.235px, and for no other reason. The rows were re-aligned by an LCS on (tag, text) rather than by document order, because the lockup inserts three elements per screen and a fingerprint keyed by position cannot survive an insertion.

Round three, 2026-08-12: the rail from 240 to 220

did not move at all281: the ten .app.flow screens, which replace the grid with a flex column, plus everything inside the rail
slid left, width unchanged301 at -20px, 167 at -10px
slid left and took the width216, 214 and 129 in three shapes
changed height2, and both are one improvement
horizontal overflow anywhere0

The two height changes are on subscription-detail-unrecognized, where the line "All we have is how it appears on your statement" stopped wrapping. A block 21px shorter and the statement descriptor 21px higher. That is what the width was for.

Nothing on this page is unpaired. All 28 coloured screens were compared in all three rounds. There is no screen without a comparison and therefore no row here reading "unverified".

The critique, by class, and who found what

Two instruments, taken independently and merged afterwards, which is this project's rule rather than a flourish. Codex read the source in read-only and owned everything falsifiable in a file; this pass owned what only a browser can answer. The column that matters is the last one.

ClassFoundWhoState
Frozen folder modified1Codexfixed: the system script came off three grey pages, the structural markup stayed, and CLAUDE.md gained the rule that was missing
Registry against reality2 rows, 13 axesCodexfixed in both the inventory and _nav.js
Stale count1Codexfixed: 55 and 18 became 57 and 20
Declared list with no idle control2 + 4 one-offsCodex, and separately Claudefixed: the census re-counted, the one-offs given a status column, two of them found CONSUMED by the renaming map rather than waiting
Shell desync1Codexfixed: four destination icons in shell.html carry their own class again
Primitive with no consumer1CodexKEPT with the reason at the value: a scale is declared whole, and an unused step is not an unused role
Icon coverage1Codexfixed: the brand mark is accounted for on the icons page and pointed at its own
Two roles collapsed in the dark theme2Codexclosed 2026-08-12, the sixth named source. One was real and mirrored: --bg-callout now reads --canvas-dark, which is what the light theme has always said, and its separation from the recess went from 1.00:1 to 1.22:1. The other is identical BY REQUIREMENT and left alone with the reason at the token
One token doing two jobs3Codexclosed 2026-08-12. --control-accent, --bg-chip-accent and --text-chip-accent, each keeping the value it split from, in both themes. Zero pixels
Literal geometry~28 files raised, 18 realCodexclosed 2026-08-12. 11 were widths and positions, exempt by this system's own rule. 16 of the remaining 18 were one thing: the focus ring, written out in 17 files, now the primitive --ring, one name for the width and the offset because they must move together. Two literals stay, both already owed --tap-rail since stage 07
Role surface2Codexopen, and one is contested: a mask painted through background-color IS how ink is drawn
Token comments without origin31Codexopen
Old path still referenced5Codexdropped at verification: all five describe the migration chain in the past tense, and that chain is what the rule requires to be recorded
A role that has never rendered1Claudeopen: --bg-trial and --text-trial paint .chip.trial, whose only wearer is the grey landing
The landing, and .landing2Claudeopen, and the largest: 48 of 57 component files carry a .landing selector that no page loading the system wears. Re-derived at the backlog pass: 44 of the 48 have never rendered anywhere at all
The page against the screen45 raised, 1 survivedClaude44 dropped at verification, listed with reasons
The format of a component page0Claude57 pages, six blocks each, in order
State snapshots0Claudethe class is empty by the founder's decision of 2026-08-11
Accessibility, the measurable half0impeccablesee below

The overlap between the two instruments was ZERO, and that is the finding this table exists to carry. Codex returned 24 rows and this pass returned 4, and not one of them was the same row. A browser pass cannot see a contradiction between two files; a source pass cannot see a computed value. The rule that says "two instruments" is not redundancy, and the proof is that the single most serious finding of the step, a violated freeze, was invisible to the instrument that runs every session: the standing check looks for UNCOMMITTED changes in wireframes/, and this change had been committed three steps earlier.

What was dropped, and why that number is healthy. Of 45 computed-style disagreements this pass raised, 44 did not survive re-reading: 25 were min-height: auto against 0px, which is whether an element is a flex item and not a paint; two caught the skeleton mid-pulse; the rest compared a host-scoped class against a different host. Seven page-format warnings matched the word :hover INSIDE a comment that says no hover is declared. An instrument that returns the same answer at every input is not measuring the input.

The token audit, was and became

Number
names declared in :root105
primitive, raw values71
semantic, roles read through var()34
semantic roles with a pair in [data-theme="dark"]34 of 34
roles present in only one theme0, verified name by name by the second instrument
semantic roles with no consumer0
semantic roles with exactly one consumer8, each judged: seven are real roles, the eighth has never rendered
primitives with no consumer1, --space-56, kept as a step of a whole scale
levelstwo, not three

--color-focus, the token an entire keyboard depends on, measured in both themes rather than assumed: 6.23:1 on surface and 5.56:1 on canvas in the light theme, 6.82:1 and 7.51:1 in the dark. The non-text threshold is 3:1. Had the pair been left for later, the dark ring would have been the light petrol at 1.9:1: present in the file, invisible on the screen.

Consolidation, in numbers

rows before the consolidation of step 268
components after it57, as 20 atoms, 23 molecules and 14 organisms
of those, arrived from a DECISION rather than from the grey corpus2, the brand mark and the brand wordmark
modifiers deleted for having no wearer2, .btn.inverse and .btn.compact
component files, each with a page, a registry row, an inventory line and an @import in its own level group57 of 57, verified by the second instrument

The counting rule has a blind spot and it is named rather than hidden. This inventory reads what the product already draws, so it can only ever find what has been drawn. A brand, a splash screen, a first-run tour and an error page that nobody wireframed are invisible to it by construction. The brand is the proof: it occurs zero times in the grey corpus and no amount of reading it would ever have produced the mark.

The control census, both measurements

pages walked, in two viewports28
control records594
distinct control forms, as class strings25
families after resolving modifiers24
pages that yielded no control at all1, verified rather than assumed

This reads as the opposite of the pixel comparison, and the pair is the point. The comparison says nothing changed by accident. The census says the set of forms was closed on purpose. One is a promise about the past and the other is a promise about the future, and neither is worth much without the other.

Six forms were tracked across three corpora until they came clean. Re-counted at step 9 and the answer changed: two rows still credited the frozen stand with 2 inverse and 1 .is-disabled that had been deleted underneath them. A census is a measurement and a measurement has a date; those two carried the number and not the date.

The dark theme, and the three instruments that caught it

The theme is not one check, and the three numbers below were produced by three different instruments looking at three different things. That is why they are reported separately rather than summed.

InstrumentWhat it can seeFound
the stress test on the full showcase, step 7NEIGHBOURHOOD: two surfaces that separate in one theme and merge in the otherthe chrome's own ink at 1.09:1 on its own panel, invisible because every row inside happened to declare a colour of its own
the second pass over the screens, step 8a component that reads a primitive directly and so never hears the theme0 escapees in the components
the source pass, step 9a role declared in one theme and not the other, name by name0 in either direction, across all 31, and separately 2 collisions: three fills that are distinct in the light theme and identical in the dark, and one more pair the same shape

The two collisions are open and they are here rather than in a backlog file, because this is the page that claims the theme works. Three roles that a person can tell apart in daylight and cannot tell apart at night are a defect the light theme can never show you.

The dry run: the rollout that has not happened yet

The rollout moved to stage 12, and the main test of the system's completeness moved with it. This is the cheap replacement: take the densest screens the system has never been shown, and check on paper whether it could build them. Nothing was built.

Still-grey screenClass tokensIn the systemThrough the renaming mapNot covered
index, the landing6018336
cancel-guide302160
alerts292240
data-privacy292051, a declared one-off
connections251660

Four of the five need nothing. The system covers the densest screens it has never seen, which is the answer this test was built to give and the good one. All 27 still-grey pages were ranked by distinct class tokens and these are the top five.

The whole gap is one page, and the re-run corrected two things this page claimed. It is 36 uncovered, not 37: .stage-flush is a modifier of the reviewer chrome class .stage and counts as chrome. And not all of them are the lp- namespace: 24 of the 36 carry the prefix and 12 do not, so retiring the lp- twins closes two thirds of the gap rather than all of it. All 36 are landing-only, so "the gap is one page" survives. It is not undeclared: the inventory names it twice and ends with the sentence "the kit takes the two-host pattern as the rule and retires the lp- twins". That retirement has not happened, and the number on the other side of it is 48 of 57 component files carrying a .landing selector that the COLOURED corpus never wears (0 of 29). The grey landing does wear it, at wireframes/index.html:14, and that page loads _wf.css rather than the system. Half of forty-eight files is written for a page that does not exist.

The accessibility half, measured on the screens

images with no alt0
inputs with no label0
breaks in the heading hierarchy0
pages with no main landmark0
pages with no lang0
duplicate ids0
onclick on something that is not a control0
:focus where :focus-visible was meant0
tap targets under the floor0 in the product. 35 flags were the reviewer's own chrome, 6 were inline links inside a sentence, which WCAG 2.5.8 exempts by name, and 1 was a 20px checkbox inside a 44px label that is the actual target

28 coloured screens, both accepted viewports, both themes. The eleven ARIA findings raised at the molecule round are not counted here: they were moved to stage 12 by decision, and they are in docs/backlog.md.

Stage 09, the whole of it: three patterns, one screen the system had never seen, two instruments

This section was added on 2026-08-13 and it is the second round of proof on this page, not a second edition of the first. Stage 08 proved that a sample of screens could be moved onto the system without moving a pixel. Stage 09 asked two harder questions and both have a number: can a composition be lifted out of the components without the screens noticing, and can the system build a screen nobody built for it.

Was and became, step 1: eight coloured pages move onto three patterns

MeasuredResult
page-viewports compared, 360 and 128056
element count identical on every oneyes, 56 of 56
elements compared3998
elements with any change137
changes that are the margin changing owner, interruption24 occurrences on 12 page-viewports: marB 24 → 0 on the announcement, marT 0 → 24 on what follows it. Same gap, different owner
changes that are the margin changing owner, act-foot14 occurrences on 12 page-viewports, the same shape at 16px
changes that are the named decision, the 16px foot gap at every width5 occurrences on 4 page-viewports, plus 45 on the one page already taller than its pane, where the 16px goes into the chart instead of off the bottom
changes that are the skeleton pulse caught at another frame56 occurrences on 3 loading pages, opacity 1 against 0.9999. No declared value involved
unexplained0
at 360, the narrow endno geometry moved at all. Under 900 the screen is normal flow, adjacent margins collapse, and 24 with 0 collapses to 24 the same way 0 with 24 does

Re-runnable, beside the script that made it: screens/ledger09.cjs, screens/ledger09.txt, screens/pixel09-before.json, screens/pixel09-after.json.

Step 5: the screen the system had never seen

The self-sufficiency test has no before, so it cannot have a pair, and the number that replaces the pair is what was NOT added. Alerts and its three states were built on 2026-08-13 out of design/system/ alone: 44 distinct system classes across four pages, 0 new CSS files, 0 new tokens, 0 new component variants, 0 new lines of microcopy, 0 style attributes and 0 page-level style blocks. Structure and copy are character-identical to the grey originals, which Voice owns and the wireframes freeze.

What the build changed in the numbers of this systemWasBecame
coloured pages in design/2832
coloured screens78
components with no coloured render at all97
.alert, the largest hole in the sample0 coloured pages2 pages, 12 items, which is every item the grey has
<summary>, the disclosure form of the panel0 coloured pages1, and it is the only one in the product
hosts on the interruption's axis34, and the fourth cost no CSS
the interruption applied to the new column24px gap with the class and 24px without it, at both viewports. Applying it moved nothing and only moved who owns it

Step 6: the critique, by class, and who found what

Two instruments again, taken independently and merged afterwards. Codex read the source read-only and owned everything falsifiable in a file; a browser and scripted pass owned what only a running page can answer. Twelve findings held, two were dropped at verification, and the eleven that look like eleven defects are one defect with eleven addresses.

ClassFoundWhoState
A count that lies about the coloured corpus21 components, ~40 placesCodex found 3, Claude found the rest by recountfixed. The corpus grew 28 to 32 pages and 7 to 8 screens in one commit, and every hand-written footprint went stale with it. The structural half is an open row in docs/backlog.md: nothing recomputes those numbers
Documentation that lies about the system15 occurrences, 12 filesCodexfixed: ten pages and two CSS files said another component "is not built yet" when all 57 are built. Each now links the page that exists
A comment that names a line number in another file1Codexfixed, and it closed the open half of a stage 08 backlog row: chip.css was still describing a repair as pending that had landed
The IA node id of a new page1Codexfixed: the error state was labelled 3.8.2, and ia/docs/sitemap.md gives 3.8.2 to loading and 3.8.3 to the error. My error, caught in the source
A state written with a value2Codex and Claude, independentlyfixed: outline-offset: -2px in two focus rules now reads calc(var(--ring) * -1). Same pixel, derived instead of typed
A callout anchor that is not marked up5 of 257Claudefixed in the stand's own stylesheet, once, rather than five times in markup. Deliberately not by wrapping prose in code
Malformed markup, found by the pass that checked the repair3Claudefixed, and all three predate this stage: a callout closed with </td> and a doubled </section> on Select, a callout list closed with </p> on the Concept stand
A state token with no pair in the other theme0Codex and Claude, counted separately34 of 34 paired. Both instruments walked :root against [data-theme="dark"] name by name and neither found a one-sided token. --color-focus measures 6.23:1 light and 6.82:1 dark against a 3:1 floor
A component that renders differently on its page than on a screen0Claude16 components measured on the stand and in the product, 16 computed properties each: 0 differences. Four apparent ones were min-height and display, both host-derived, and vanished with the hosts matched
A state that moves the layout0Claudeevery :hover, :active, :focus-visible and :disabled in 60 files, checked against the geometric properties
A usage rule with no source, and a component it names with no Limits0 both waysCodex11 rules, 11 sources filled, 11 components named and all 11 carrying the sub-item, and no Limits item without a rule behind it
The format of a page0Codex57 component pages carry all six required ids; 3 pattern pages carry the six with where in place of states
A pattern with a style of its own, or an @import out of order0Codexno colour, font or radius in patterns/; all three imported after all 57 components; the registry group after Organisms
wireframes/ changed by a character0Codex, twicethe frozen folder is byte-identical to HEAD
Accessibility, the measurable half0impeccablethe four new pages carry the same clean result as the 28: no unlabelled image, no unlabelled input, no heading break, no duplicate id

Two findings were dropped at verification, and the reason is on the record so neither returns. range-picker.css:114 writes font-weight: 600 inside a disabled-and-pressed rule, which reads as a state written with a value: it is not, because this system has no weight scale at all. Weight is a literal in every one of the 57 files, by the rule that colour goes through a role and geometry through a primitive and weight is neither, so tokenising one occurrence would have opened a third level to serve one line. The detector's em-dash-overuse, raised on 34 files, counts -- in running text, and the running text of this project is made of custom property names: the colour page holds 378 double hyphens and zero em dashes.

The overlap between the instruments was four rows out of twelve this time, against zero at stage 08, and the change is not noise. At stage 08 Codex read files and the browser read pixels, so they could not meet. At stage 09 both were reading the same thing, a set of claims in prose, and prose is falsifiable from either side. Where they met they agreed; the eight rows they did not share are still split the old way, with the source findings on one side and the running page on the other.

The numbers this stage leaves behind

components in the system57, unchanged: stage 09 added none, which is the point of it
components with declared interactive states21
components that are not interactive, checked rather than assumed36, each with the sweep that found no anchor, no button and no target inside it
patterns extracted3: the interruption, the action foot, the list column
candidates waiting for a third screen4, named on the patterns page with what each is waiting for
usage rules, each with its source filled11
patterns with no coloured render0, and the one host with none is said out loud: the dialog sheet, on three grey pages, proved at the rollout
backlog60 rows, 23 closed, 37 open. The self-sufficiency test added 4 and the verification pass added 2, which is the honest shape: a test that returns an empty backlog was run as a formality

Stage 10, Responsive: the promise is asymmetric, and both halves are measured

Added 2026-08-13, and it is the first round of proof on this page whose promise is not "nothing moved". Stages 08 and 09 owed zero difference at both viewports. A stage about width cannot owe that: at 360 the mobile layout is the base of a mobile-first product and it must not move at all, and on a wide screen the whole point is that things move. So the promise splits, and the second half is enforced differently: every desktop difference must be explained by a named row, and an unexplained one is exactly as much a defect as any difference at 360.

The narrow end: 32 pages, zero difference, box and ink

Measured at a real 360Result
coloured pages compared against the pre-stage baseline32, every one
how a page is comparedthe position and size of every element inside the shell, plus the rectangle the text itself paints, which catches a re-wrap that leaves the box alone
pages identical on the box32 of 32
pages identical on the ink32 of 32
horizontal scroll anywherenone
the baselinegit archive HEAD into a second served copy, so the two versions render side by side from the same browser on the same origin
where the instrument livesscreens/width10-harness.html, and its output as run on 2026-08-13 in screens/width10.txt. No screenshots, on the decision of 2026-08-11 recorded at the head of this page: a picture of a measurement goes stale silently and then looks checked. Open the harness over a local server and press Run

It failed once, and that is why it is worth running. The first pass lit up on six pages. Two of the four reading-measure fixes had been written as a comment appended after an already-closed comment block, which left prose in the stylesheet and a stray */ after it; the browser dropped what followed. The 360 check caught a broken stylesheet that the eye read as a normal page. A comment-balance check now runs over all 65 stylesheets and is clean.

The wide end: 32 pages changed, and every change has a row

Measured at 1440Result
pages whose geometry changed32, and 688 element boxes among them
pages where the ink moved, meaning a line actually re-wrapped19, and 277 text rectangles
causes, all named on the width pagefour reading measures folded into one token; four prose blocks that had no measure at all; two dead caps repaired; two grids that stopped declaring a count; the groups column set; the detail screen's columns
unexplained0
the biggest single movethe muted line under the chart on History and Trends: 1300px to 459px, from 150 characters a line to 53

The instrument: a sweep, because a defect lives between the points

The width sweepResult
widths per page50: 320 to 1600 in steps of 40, with 10px steps around both points, around the container threshold and around the two widths where the column set changes its count
total measurements1600
document-level horizontal scrollnone at any stop, and that check alone would have found nothing: the pane is its own scroller past the tablet point, so a layout that does not fit scrolls inside it while the document stays clean
elements leaving the viewport18 stops before the fix, all on the six Subscription Detail pages at 900, 910 and 920. 0 after
the carrier of top-level navigationexactly one at every stop on every app-frame screen, four links, never two. Confirmed in the markup: 22 screens carry one .tabbar, the 10 flow screens carry none
the worst reading measure found150ch (History and Trends at 1600), then 82.8, 78.9, 72, 69, 67.8
the worst reading measure now60.7ch, the prose card, which is a named 560px decision and is written up in docs/backlog.md rather than quietly changed. Everything else is 53ch or below

Two instruments, and what each one was blind to

Found byWhatVerdict
Claude, in a browserfive defects: the 78.9ch card, the unmeasured muted line at 150ch, the unmeasured wash paragraph and promise item, the 900-to-927 valley, and a sixth element needing the > .screen > bindingall five confirmed and fixed. None of them is visible in the source: every one needed a rendered page at a specific width
Codex, read-only in the sourceten findings across ten mechanical classes7 confirmed (a literal repeating a token, four inventory rows, a stale register claim, a comment contradicting its own rule), 2 dropped at verification with the reason written into the code, 1 resolved by the stage closing
Claude, by grep, after Codexeight stale claims naming 1340, the number this stage removed, in the kit pages, the shell template, the review chrome and DESIGN.mdall eight repaired. This is the class Codex was asked for and did not return, and it is the reason the two instruments are run and merged rather than trusted one at a time
The a11y passthe shell template declared <main class="app"> around <main class="screen">, a main inside a main, while all 32 built screens use a divrepaired in the template. Nobody would have seen it until stage 12 built twenty screens from it, each with two landmarks
The a11y pass, not this stage's materialthe project sidebar's section links read 2.65:1 on white at 13px, and the dimmed roadmap rows 3.37:1. Light theme only; the dark theme is cleanreported, not fixed. It is /_nav.css, the project registry chrome, and it is on every stage page of the project: a colour decision for the founder rather than a stage-10 edit