The gallery is generated (gallery.mjs) from the Pages manifest and each page's log, so its words and numbers are held by sites.test.mjs; what nobody has checked is how it looks and whether it works. Judged at its published URL (http://127.0.0.1:4190/sites/, the intro server's Pages layout), because its landing and solitaire cards reach ../judgment/ and ../demo-solitaire.png, which only exist in that layout — from file:// two of its eight pictures would be broken for reasons that are not the page's. Gate set, from markup-assist (a static page, no behaviour beyond links): 1. check integrity (1280/768/375) and check a11y contrast — the page's floor. 2. check design, check composition, check color — eight cards must be one component, the headings a real hierarchy, and the purple/blue "by eye / by gate" numbers must not be colour-only meaning. 3. check a11y focus (1280, 375), check a11y touch (AA, AAA), check interactions — about 30 links and nothing else to operate. 4. check breakpoints --sweep and scan scroll (375, 1280) — an auto-fill grid of cards at every width. 5. scan handlers — the protocol's minimum; the page has no script, so it should find nothing. Not gated: dark mode. The page follows prefers-color-scheme alone and no gate can emulate a colour scheme, so its dark theme is judged by eye (shot --dark) and by a computed contrast table of its dark tokens.
vlmkit demo · judgment log
Demo-site gallery
How this index page, generated from the logs was judged, in the order it happened: every gate run with its whole output, every screenshot that was looked at with what was seen in it, and where each defect came from. Each finished round keeps the pictures of one full-page walk per width; the other shots keep what was seen in them. Open the site.
- 4rounds
- 48gate runs, 2 failing
- 92screens in 21 shots, 63 kept
- 21looks recorded
- 8defects found by eye
- 1defects found by a gate
- 2gate false positives
Defects
| Defect | Found by | What | Fix | Checked by |
|---|---|---|---|---|
| D1 | eye L1 on S1 |
The lede says 'Each site was built from a one-page brief by an agent', and the first two cards contradict it: the landing page was reviewed, not built from a brief, and solitaire predates the log (its own card says so). A page whose job is to state how things were judged cannot open with a claim that is wrong for a quarter of its cards. | The lede now reads 'Each demo site was built from a one-page brief by an agent using vlmkit's gates and its own eyes, and the landing page was reviewed the same way. Next to each page is its judgment log…' — true of every logged card; solitaire's card already says it predates the log. | L6 |
| D2 | eye L3 on S3 |
The stat label 'found by a gate' wraps to two lines at 768 and 375 in every logged card, so its number drops a full line below the other two numbers in that row (S3, S2: '31' and '108' on one line, '3' under them) — the same class as the landing page's D31, where stat figures had to share a line. | Each stat cell is a column with its label at the top and its number at the foot (flex, space-between); grid rows stretch, so the three numbers in a row share a line whichever label wraps. | L7 |
| D3 | eye L1 on S1 |
Solitaire's record link breaks 'What the gates and screenshots / found', leaving 'found' alone, at every width (S1, S2, S3), and its two links stack while every other card's sit on one row, so the card feet do not match across a row. | Solitaire's record link is 'The README's record' (short enough to share the row with 'Open the site'), and card links are white-space: nowrap, so a link that does not fit moves whole to the next row instead of leaving a word behind. Second fix: solitaire's record link uses the label every card uses, 'How it was judged' — the note above it already says the record is its README's table — so its link row is the same width as its neighbours' at every card width, instead of 'The README's record', which was 5px too wide to share the row at 768. | L14 |
| D4 | eye L3 on S3 |
The Japanese titles break inside words: '夜だ / け店を開ける理由' at 768, '夜 / だけ' at 375. The page is lang=en and the titles carry no lang, so Chromium breaks them as English text would, character by character; and a screen reader would read them with an English voice (WCAG 3.1.2, language of parts). | A title in another language carries it: the magazine's and the shop's h2 are lang="ja" (from the log's page language), and :lang(ja) sets word-break: auto-phrase, so they break between phrases and a screen reader switches voice. | L7 |
| D5 | eye L2 on S2 |
The footer's 'How this page was judged' breaks across lines at 768 ('How this page / was judged') and 375 ('How / this page was judged') — the landing footer's D32 again, one line of fine print that reads as two links. | Footer links are white-space: nowrap; the link moves to the next line whole. | L7 |
| D6 | gate G9 |
At AAA (G9) 22 targets are under 44px: every card's title link and both action links, and the kicker's link back to vlmkit. The landing page holds AAA (its demo band shows 'check a11y touch --level AAA' as a deploy gate), and this page is where a visitor arrives from it on a phone. | Card title links, the action links and the kicker's link are inline-flex with min-height: 44px, the landing page's construction; the link row's gap and the kicker's margin were tightened by the same amount so the cards and the header do not grow looser. | G23 |
| D7 | eye L1 on S1 |
The kicker's text-transform: uppercase turns the brand into 'VLMKIT'; it is lowercase 'vlmkit' on the landing page, in every log and in the docs. | The kicker keeps the brand's case: no text-transform or letter-spacing, 15px muted text reading 'vlmkit · demo sites'. | L6 |
| D8 | eye L6 on S6 |
F6's 44px title boxes add space only when a title is shorter than 44px, so one-line titles now sit about 10px further from their pattern line than two-line ones — side by side in row 3 (the magazine tight, the shop loose, S6/S7/S8). The cards in a row no longer share one rhythm. | Card title links are back to their own line height; the 44px construction stays on the action links and the kicker. The title link goes where 'Open the site' goes, which is 44px, so WCAG 2.5.5/2.5.8's 'equivalent' exception covers it — declared to the touch gate with --allow rather than measured away. | L12 |
| D9 | eye L10 on S10 |
The keyboard ring is the browser default drawn flush on the link's box, touching the first and last glyphs (S10 on a title, S11 on 'How it was judged'); on 44px boxes it reads as a box pressed onto the text rather than a ring around a target. | a:focus-visible draws a 2px ring in the page's accent (#1f5f8b light, #8cc4ea dark) 3px outside the link's box; the link row's top padding went from 0.25rem to 0.5rem so a focused action link's ring clears the stats above it. | L16 |
Rounds
R1 · first look: the gallery as generated
reviewervlmkit check integrity http://127.0.0.1:4190/sites/verdict: CLEAN (0 fail, 0 warn, 0 exempted)
verdict clean · findings 0 · fails 0 · warns 0 · exempted 0 · viewports 3
output, 10 line(s), 5.1s
vlmkit check integrity source: http://127.0.0.1:4190/sites/ verdict: CLEAN (0 fail, 0 warn, 0 exempted) 1280x800: 8 component(s), ink 46.6%, 131 text block(s) 768x900: 8 component(s), ink 59.0%, 131 text block(s) 375x700: 8 component(s), ink 67.2%, 131 text block(s) No integrity defects detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check a11y contrast http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-contrast/galleryinspected 147 · failures 0
output, 6 line(s), 1.6s
vlmkit check a11y contrast html: http://127.0.0.1:4190/sites/ inspected 147 text-bearing element(s) ✓ 0 contrast failure(s) report: examples/sites/test-results/a11y-contrast/gallery/report.md http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check design http://127.0.0.1:4190/sites/verdict: COHERENT (0 finding(s))
verdict coherent · drifting 0 · roles 2
output, 20 line(s), 1.6s
vlmkit check design
source: http://127.0.0.1:4190/sites/
verdict: COHERENT (0 finding(s))
roles judged: 1 of 2 seen, spacing values: 13
coverage: 10 of 244 visible element(s) carried an inferable role
no role: div x50, dd x42, dt x42, a x36, p x20, li x16, +8 more tag(s)
A role comes from role="..." or from button/input/select/textarea/h1-h6. Layout elements
(div, span, p, a) have none, so a large skip count is normal — this gate judges components,
not every box. Add role="..." where an element IS a component to widen the coverage.
Role reuse (instances / distinct styles; drift below 3x from 3 instances)
h2 9 inst 2 styles reuse 4.5x 1 one-off ok
h1 1 inst 1 styles reuse 1x 1 one-off not judged
not judged: h1 (1) — under --min-instances 3, so no finding can come from it.
To keep judging it: --min-instances 2 --min-reuse 2 (both — a 2-instance role cannot reach 3x however many instances the floor allows).
No design drift detected.
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check composition http://127.0.0.1:4190/sites/verdict: COMPOSED (0 finding(s))
verdict composed · proximity 0 · flatSteps 0 · railNearMisses 0
output, 17 line(s), 1.7s
vlmkit check composition source: http://127.0.0.1:4190/sites/ verdict: COMPOSED (0 finding(s)) measured: 1 label(s), 2 heading level(s), 14 wide block(s) on 2 left / 2 right rail(s) — from 244 visible box(es) 9 label(s) not judged: they open a box that paints its own group edge, so nothing above them could be mis-grouped with Type hierarchy (largest instance of each declared level) h1 44px / 700 main>h1 h2 22px / 700 h2#method-title body 13px, largest 44px (3.38x), heaviest +300 weight Group gaps: 0px between heading-led groups vs 0px inside them (0x, 11 sample(s)). Context only — intact pages measure 0.86-3.00x, so this cannot carry a verdict. Proximity, alignment and type hierarchy all read consistently. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check color http://127.0.0.1:4190/sites/verdict: CONSISTENT (0 finding(s))
verdict consistent · base #f6f5f1 · bodyInk #5d5b55 · linkInk #1d1d1b · invisibleControls 0 · colorOnlyLinks 0 · unreadableColors 0
output, 21 line(s), 1.6s
vlmkit check color
source: http://127.0.0.1:4190/sites/
verdict: CONSISTENT (0 finding(s))
measured: 0 control(s), 36 link(s) in a text flow — from 246 visible box(es)
Palette (by painted area; reported, never judged — see the rejected candidates in the module docs)
surfaces 2 distinct
#f6f5f1 66.0% 1 el
#ffffff 34.0% 8 el main>ul.grid>li.card
ink 4 distinct
#5d5b55 59.5% 69 el main>p.kicker
#1d1d1b 35.4% 59 el main>h1
#7a3fb0 2.5% 7 el dl.stats>div.eye>dd
#1f5f8b 2.5% 7 el dl.stats>div.gate>dd
marks 1 distinct
#dcd9d0 100.0% 40 el main>ul.grid>li.card
base #f6f5f1, body ink #5d5b55, link ink #1d1d1b on 32 element(s)
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y focus http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-focus/gallerysteps 28 · findings 11
output, 13 line(s), 1.6s
vlmkit check a11y focus
source: http://127.0.0.1:4190/sites/
captured 28 focus step(s)
! 11 finding(s)
[skip-row] Focus jumped down by 600px (from `main>p.kicker>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 259px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 259px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 320px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 215px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
… 6 more (see the report, or --json for all)
report: examples/sites/test-results/a11y-focus/gallery/report.md
exits 0 — 11 warn(s) did not fail this command. To gate on one: --rule skip-row=suspect
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y focus http://127.0.0.1:4190/sites/ --viewport 375x812 --output-dir test-results/a11y-focus/gallery-mobilesteps 28 · findings 17
output, 13 line(s), 1.6s
vlmkit check a11y focus
source: http://127.0.0.1:4190/sites/
captured 28 focus step(s)
! 17 finding(s)
[skip-row] Focus jumped down by 801px (from `main>p.kicker>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 212px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 296px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 224px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 321px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
… 12 more (see the report, or --json for all)
report: examples/sites/test-results/a11y-focus/gallery-mobile/report.md
exits 0 — 17 warn(s) did not fail this command. To gate on one: --rule skip-row=suspect
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y touch http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-touch/gallerylevel AA · inspected 28 · failures 0 · wcagExempt 11
output, 7 line(s), 1.4s
vlmkit check a11y touch source: http://127.0.0.1:4190/sites/ level: WCAG AA (24×24 min) inspected 28 interactive element(s) ✓ 0 undersized target(s) 11 undersized target(s) excused by WCAG 2.5.8 itself (4 in a sentence, 7 with clear spacing) report: examples/sites/test-results/a11y-touch/gallery/report.md http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check a11y touch http://127.0.0.1:4190/sites/ --level AAA --output-dir test-results/a11y-touch/gallery-aaalevel AAA · inspected 28 · failures 22 · wcagExempt 4
output, 13 line(s), 1.5s
vlmkit check a11y touch
source: http://127.0.0.1:4190/sites/ level: WCAG AAA (44×44 min)
inspected 28 interactive element(s)
✗ 22 undersized target(s)
4 undersized target(s) excused by WCAG 2.5.5 itself (4 in a sentence)
ul.grid>li.card>div.body>h2>a — 213×22 — "vlmkit landing page"
ul.grid>li.card>div.body>h2>a — 188×22 — "Klondike solitaire"
ul.grid>li.card>div.body>h2>a — 228×22 — "Pantry Club checkout"
ul.grid>li.card>div.body>h2>a — 284×22 — "Keel Analytics — Overview"
ul.grid>li.card>div.body>h2>a — 242×22 — "Quarry documentation"
… 17 more (see the report, or --json for all)
report: examples/sites/test-results/a11y-touch/gallery-aaa/report.md
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har.card h2 a, .card .links a, .kicker aAt AAA (G9) 22 targets are under 44px: every card's title link and both action links, and the kicker's link back to vlmkit. The landing page holds AAA (its demo band shows 'check a11y touch --level AAA' as a deploy gate), and this page is where a visitor arrives from it on a phone.
vlmkit check interactions http://127.0.0.1:4190/sites/elements 30 · suspects 0 · warns 8
output, 48 line(s), 1.7s
vlmkit check interactions source: http://127.0.0.1:4190/sites/ status: ok exits 0 — 8 warn(s) did not fail this command. To gate on one: --rule not-tab-reachable=suspect interactive elements: 30 (+6 beyond the cap — NOT probed) - [link] "VLMKIT" focus✓ - [link] "" unreachable - [link] "vlmkit landing page" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Klondike solitaire" focus✓ - [link] "Open the site" focus✓ - [link] "What the gates and screenshots found" focus✓ - [link] "" unreachable - [link] "Pantry Club checkout" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Keel Analytics — Overview" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Quarry documentation" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Sprintboard" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "ほとり — 海辺の町の古本屋が、夜だけ店を開ける理由" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable Issues: warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check breakpoints http://127.0.0.1:4190/sites/ --sweepbreakpoints 0 · issues 0 · sweepRanges 0
output, 7 line(s), 2.7s
vlmkit check breakpoints source: http://127.0.0.1:4190/sites/ status: ok width sweep: 320-1280px step 25 (39 widths) — clean breakpoints: none discovered — nothing to check (pass --breakpoints to force widths) http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan scroll http://127.0.0.1:4190/sites/ --viewport 375x812containers 0 · overflowX 0 · issues 0
output, 9 line(s), 1.3s
vlmkit scan scroll source: http://127.0.0.1:4190/sites/ (375x812) status: ok page: 375x5691 — horizontal overflow 0px, vertical scroll 4879px scroll containers: 0 (dead scrollports 0, clipped 0) No scroll issues detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan scroll http://127.0.0.1:4190/sites/ --viewport 1280x800containers 0 · overflowX 0 · issues 0
output, 9 line(s), 1.4s
vlmkit scan scroll source: http://127.0.0.1:4190/sites/ (1280x800) status: ok page: 1280x2453 — horizontal overflow 0px, vertical scroll 1653px scroll containers: 0 (dead scrollports 0, clipped 0) No scroll issues detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan handlers http://127.0.0.1:4190/sites/registrations 0 · elements 0 · suspects 0
output, 11 line(s), 1.7s
vlmkit scan handlers source: http://127.0.0.1:4190/sites/ status: 1 warn(s) exits 0 — 1 warn(s) did not fail this command. To gate on one: --rule no-handlers-found=suspect registrations: 0 across 0 element(s), on a page presenting 36 control(s) Issues: warn [no-handlers-found] 36 visible interactive control(s) and ZERO handler registrations — no listeners, no on* attributes, no on* properties, nothing on window/document. Either the controls are inert (check interactions reports that as inert-control), or they are wired somewhere this gate cannot see, or the page genuinely needs none (links, a form that posts). This gate cannot tell which; it can only tell you that a clean result here is not evidence of anything. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
gallery as generated
http://127.0.0.1:4190/sites/ · 1280×800 · full page, 4 screen(s)
Gallery at 1280, 2453px, 4 screens. Screen 1: kicker "VLMKIT · DEMO SITES" — text-transform uppercases the brand, which is lowercase "vlmkit" on every other page — then the h1 in two balanced lines, "Sites built by agents, and / how each one was judged", and the lede: "Each site was built from a one-page brief by an agent using vlmkit's gates and its own eyes." That is not true of the first two cards: the landing page was reviewed, not built from a brief, and solitaire predates the log (its own card says so). Totals on one line: 7 logged pages, 645 gate runs, 1342 screens looked at, 127 by eye, 43 by a gate. Then the grid, three cards per row: the landing page (dark hero thumbnail), solitaire, the checkout; titles, "pattern · language", the six stats with eye numbers purple and gate numbers blue (the labels say which, so colour is not the only carrier). Screen 2: row 1's links at the card feet on one line — except solitaire, whose two links stack and whose second one breaks "What the gates and screenshots / found", leaving "found" alone. Row 2: dashboard, docs, kanban; stats and links aligned across the row. Screens 3–4: row 3 with the magazine ("ほとり — 海辺の町の古本屋が、夜だけ / 店を開ける理由", a clean break at this width) and the shop, the third column empty; "How the logs were kept" with its three-item list; the footer line with the new "How this page was judged".
main > p.ledeThe lede says 'Each site was built from a one-page brief by an agent', and the first two cards contradict it: the landing page was reviewed, not built from a brief, and solitaire predates the log (its own card says so). A page whose job is to state how things were judged cannot open with a claim that is wrong for a quarter of its cards.
.card .linksSolitaire's record link breaks 'What the gates and screenshots / found', leaving 'found' alone, at every width (S1, S2, S3), and its two links stack while every other card's sit on one row, so the card feet do not match across a row.
.kickerThe kicker's text-transform: uppercase turns the brand into 'VLMKIT'; it is lowercase 'vlmkit' on the landing page, in every log and in the docs.
gallery as generated
http://127.0.0.1:4190/sites/ · 375×812 · full page, 8 screen(s)
Gallery at 375, 5691px, 8 screens. Screen 1: the kicker (uppercased brand), the h1 in three lines, the seven-line lede, and the totals as four lines ("7 logged pages 645 gate runs" / "1342 screens looked at" / …). Then the landing card's thumbnail. Screens 2–6: one card per row. In every card the stat label "found by a gate" wraps to "found by a / gate", so that cell's number sits a full line below its neighbours' ("31" and "108" on one line, "3" under them) — the numbers row is ragged in all seven logged cards. The two links stack, each whole ("Open the site" / "How it was judged"). Solitaire's record link again ends with "found" alone. The magazine title breaks inside a phrase: "…古本屋が、夜 / だけ店を開ける理由" (夜だけ split). Screens 7–8: "How the logs were kept" and the list read well at this width; the footer breaks its link across lines, "…judgment/log.jsonl. How / this page was judged." — the same defect as the landing footer's D32.
footer aThe footer's 'How this page was judged' breaks across lines at 768 ('How this page / was judged') and 375 ('How / this page was judged') — the landing footer's D32 again, one line of fine print that reads as two links.
gallery as generated
http://127.0.0.1:4190/sites/ · 768×1024 · full page, 3 screen(s)
Gallery at 768, 3024px, 3 screens. Two cards per row. The ragged numbers row is here too: "found by a / gate" wraps in every card and drops the gate count a line below the others. Solitaire's links stack and its record link ends on "found" alone, while the landing card beside it has both links on one row — the two cards' feet do not match. The magazine title breaks inside a word, "…古本屋が、夜だ / け店を開ける理由" — worse than at 375. The footer link breaks "How this page / was judged." The totals wrap to two lines cleanly; the lede and list are fine.
.card .statsThe stat label 'found by a gate' wraps to two lines at 768 and 375 in every logged card, so its number drops a full line below the other two numbers in that row (S3, S2: '31' and '108' on one line, '3' under them) — the same class as the landing page's D31, where stat figures had to share a line.
.card h2 (magazine, shop)The Japanese titles break inside words: '夜だ / け店を開ける理由' at 768, '夜 / だけ' at 375. The page is lang=en and the titles carry no lang, so Chromium breaks them as English text would, character by character; and a screen reader would read them with an English voice (WCAG 3.1.2, language of parts).
gallery, dark scheme
http://127.0.0.1:4190/sites/ · 1280×800 · full page, 4 screen(s) · dark
4 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Gallery at 1280, dark scheme, 4 screens (same geometry as S1). Near-black page (#161614), cards a step lighter (#1f1f1c) with a faint border; ink off-white, muted text grey; eye numbers lilac and gate numbers light blue, both clearly legible on the card. The light-themed thumbnails (checkout, docs, kanban, magazine, shop) sit as bright rectangles on dark cards — expected for screenshots, and their bottom border separates them. Underlined links in the ink colour. Same content defects as S1 (the lede, solitaire's record link).
gallery, dark scheme
http://127.0.0.1:4190/sites/ · 375×812 · full page, 8 screen(s) · dark
8 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Gallery at 375, dark scheme, 8 screens (same geometry as S2). Colours as S4; every text legible. The same layout defects as S2: the ragged numbers row from the wrapped "found by a / gate" in every card, solitaire's "found" alone, "夜 / だけ" in the magazine title, and the footer link split "How / this page was judged".
The 8 not-tab-reachable warns are the cards' thumbnail links, tabindex=-1 and aria-hidden on purpose: each duplicates its card's title link (same href), which Tab reaches, as does 'Open the site'. A duplicate kept out of the tab order is the pattern, not a gap — G6/G7's focus walks show every card's title and links reached in order.
11 skip-row warns at 1280 (17 at 375 in G7): focus jumps from the kicker over the h1, lede and totals to the first card's title, and inside every card from the title over the stats to the links. The only focusables between are the thumbnail links, which are tabindex=-1 (the note on G10).
scan handlers' one warn is no-handlers-found: the page has no script at all, so there is nothing to scan — the expected answer for a generated static page.
No gate can emulate prefers-color-scheme: check a11y contrast, check color and check integrity measure the light scheme only, so a page that follows the OS theme (this one) cannot have its dark theme gated — the demo-site builders all added ?theme=dark parameters to get round it. Here the dark theme was judged by eye (S4, S5) and by computing its tokens (output/gallery-dark-contrast.mjs): on the page #161614, ink 15.18:1, muted 7.44:1, eye 9.20:1, gate 9.66:1; on a card #1f1f1c, 13.84, 6.78, 8.39 and 8.81 — all above AA's 4.5:1.
The lede now reads 'Each demo site was built from a one-page brief by an agent using vlmkit's gates and its own eyes, and the landing page was reviewed the same way. Next to each page is its judgment log…' — true of every logged card; solitaire's card already says it predates the log.
Each stat cell is a column with its label at the top and its number at the foot (flex, space-between); grid rows stretch, so the three numbers in a row share a line whichever label wraps.
Solitaire's record link is 'The README's record' (short enough to share the row with 'Open the site'), and card links are white-space: nowrap, so a link that does not fit moves whole to the next row instead of leaving a word behind.
A title in another language carries it: the magazine's and the shop's h2 are lang="ja" (from the log's page language), and :lang(ja) sets word-break: auto-phrase, so they break between phrases and a screen reader switches voice.
Footer links are white-space: nowrap; the link moves to the next line whole.
Card title links, the action links and the kicker's link are inline-flex with min-height: 44px, the landing page's construction; the link row's gap and the kicker's margin were tightened by the same amount so the cards and the header do not grow looser.
The kicker keeps the brand's case: no text-transform or letter-spacing, 15px muted text reading 'vlmkit · demo sites'.
R2 · final check after D1-D7
reviewervlmkit check integrity http://127.0.0.1:4190/sites/verdict: CLEAN (0 fail, 0 warn, 0 exempted)
verdict clean · findings 0 · fails 0 · warns 0 · exempted 0 · viewports 3
output, 10 line(s), 5.1s
vlmkit check integrity source: http://127.0.0.1:4190/sites/ verdict: CLEAN (0 fail, 0 warn, 0 exempted) 1280x800: 8 component(s), ink 46.1%, 132 text block(s) 768x900: 8 component(s), ink 59.4%, 132 text block(s) 375x700: 8 component(s), ink 67.8%, 132 text block(s) No integrity defects detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check a11y contrast http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-contrast/galleryinspected 147 · failures 0
output, 6 line(s), 1.5s
vlmkit check a11y contrast html: http://127.0.0.1:4190/sites/ inspected 147 text-bearing element(s) ✓ 0 contrast failure(s) report: examples/sites/test-results/a11y-contrast/gallery/report.md http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check design http://127.0.0.1:4190/sites/verdict: COHERENT (0 finding(s))
verdict coherent · drifting 0 · roles 2
output, 20 line(s), 1.6s
vlmkit check design
source: http://127.0.0.1:4190/sites/
verdict: COHERENT (0 finding(s))
roles judged: 1 of 2 seen, spacing values: 13
coverage: 10 of 244 visible element(s) carried an inferable role
no role: div x50, dd x42, dt x42, a x36, p x20, li x16, +8 more tag(s)
A role comes from role="..." or from button/input/select/textarea/h1-h6. Layout elements
(div, span, p, a) have none, so a large skip count is normal — this gate judges components,
not every box. Add role="..." where an element IS a component to widen the coverage.
Role reuse (instances / distinct styles; drift below 3x from 3 instances)
h2 9 inst 2 styles reuse 4.5x 1 one-off ok
h1 1 inst 1 styles reuse 1x 1 one-off not judged
not judged: h1 (1) — under --min-instances 3, so no finding can come from it.
To keep judging it: --min-instances 2 --min-reuse 2 (both — a 2-instance role cannot reach 3x however many instances the floor allows).
No design drift detected.
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check composition http://127.0.0.1:4190/sites/verdict: COMPOSED (0 finding(s))
verdict composed · proximity 0 · flatSteps 0 · railNearMisses 0
output, 17 line(s), 1.7s
vlmkit check composition source: http://127.0.0.1:4190/sites/ verdict: COMPOSED (0 finding(s)) measured: 1 label(s), 2 heading level(s), 14 wide block(s) on 2 left / 2 right rail(s) — from 244 visible box(es) 9 label(s) not judged: they open a box that paints its own group edge, so nothing above them could be mis-grouped with Type hierarchy (largest instance of each declared level) h1 44px / 700 main>h1 h2 22px / 700 h2#method-title body 13px, largest 44px (3.38x), heaviest +300 weight Group gaps: 0px between heading-led groups vs 0px inside them (0x, 9 sample(s)). Context only — intact pages measure 0.86-3.00x, so this cannot carry a verdict. Proximity, alignment and type hierarchy all read consistently. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check color http://127.0.0.1:4190/sites/verdict: CONSISTENT (0 finding(s))
verdict consistent · base #f6f5f1 · bodyInk #5d5b55 · linkInk #1d1d1b · invisibleControls 0 · colorOnlyLinks 0 · unreadableColors 0
output, 21 line(s), 1.7s
vlmkit check color
source: http://127.0.0.1:4190/sites/
verdict: CONSISTENT (0 finding(s))
measured: 0 control(s), 36 link(s) in a text flow — from 246 visible box(es)
Palette (by painted area; reported, never judged — see the rejected candidates in the module docs)
surfaces 2 distinct
#f6f5f1 66.3% 1 el
#ffffff 33.7% 8 el main>ul.grid>li.card
ink 4 distinct
#5d5b55 57.5% 69 el main>p.kicker
#1d1d1b 38.0% 59 el main>h1
#7a3fb0 2.3% 7 el dl.stats>div.eye>dd
#1f5f8b 2.3% 7 el dl.stats>div.gate>dd
marks 1 distinct
#dcd9d0 100.0% 40 el main>ul.grid>li.card
base #f6f5f1, body ink #5d5b55, link ink #1d1d1b on 32 element(s)
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y focus http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-focus/gallerysteps 28 · findings 12
output, 13 line(s), 1.6s
vlmkit check a11y focus
source: http://127.0.0.1:4190/sites/
captured 28 focus step(s)
! 12 finding(s)
[skip-row] Focus jumped down by 647px (from `main>p.kicker>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 216px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 216px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 216px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 337px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
… 7 more (see the report, or --json for all)
report: examples/sites/test-results/a11y-focus/gallery/report.md
exits 0 — 12 warn(s) did not fail this command. To gate on one: --rule skip-row=suspect
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y focus http://127.0.0.1:4190/sites/ --viewport 375x812 --output-dir test-results/a11y-focus/gallery-mobilesteps 28 · findings 17
output, 13 line(s), 1.6s
vlmkit check a11y focus
source: http://127.0.0.1:4190/sites/
captured 28 focus step(s)
! 17 finding(s)
[skip-row] Focus jumped down by 875px (from `main>p.kicker>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 228px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 313px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 240px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 313px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
… 12 more (see the report, or --json for all)
report: examples/sites/test-results/a11y-focus/gallery-mobile/report.md
exits 0 — 17 warn(s) did not fail this command. To gate on one: --rule skip-row=suspect
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y touch http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-touch/gallerylevel AA · inspected 28 · failures 0 · wcagExempt 3
output, 7 line(s), 1.5s
vlmkit check a11y touch source: http://127.0.0.1:4190/sites/ level: WCAG AA (24×24 min) inspected 28 interactive element(s) ✓ 0 undersized target(s) 3 undersized target(s) excused by WCAG 2.5.8 itself (3 in a sentence) report: examples/sites/test-results/a11y-touch/gallery/report.md http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check a11y touch http://127.0.0.1:4190/sites/ --level AAA --output-dir test-results/a11y-touch/gallery-aaalevel AAA · inspected 28 · failures 0 · wcagExempt 3
output, 7 line(s), 1.6s
vlmkit check a11y touch source: http://127.0.0.1:4190/sites/ level: WCAG AAA (44×44 min) inspected 28 interactive element(s) ✓ 0 undersized target(s) 3 undersized target(s) excused by WCAG 2.5.5 itself (3 in a sentence) report: examples/sites/test-results/a11y-touch/gallery-aaa/report.md http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check interactions http://127.0.0.1:4190/sites/elements 30 · suspects 0 · warns 8
output, 48 line(s), 1.8s
vlmkit check interactions source: http://127.0.0.1:4190/sites/ status: ok exits 0 — 8 warn(s) did not fail this command. To gate on one: --rule not-tab-reachable=suspect interactive elements: 30 (+6 beyond the cap — NOT probed) - [link] "vlmkit" focus✓ - [link] "" unreachable - [link] "vlmkit landing page" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Klondike solitaire" focus✓ - [link] "Open the site" focus✓ - [link] "The README's record" focus✓ - [link] "" unreachable - [link] "Pantry Club checkout" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Keel Analytics — Overview" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Quarry documentation" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Sprintboard" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "ほとり — 海辺の町の古本屋が、夜だけ店を開ける理由" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable Issues: warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check breakpoints http://127.0.0.1:4190/sites/ --sweepbreakpoints 0 · issues 0 · sweepRanges 0
output, 7 line(s), 2.7s
vlmkit check breakpoints source: http://127.0.0.1:4190/sites/ status: ok width sweep: 320-1280px step 25 (39 widths) — clean breakpoints: none discovered — nothing to check (pass --breakpoints to force widths) http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan scroll http://127.0.0.1:4190/sites/ --viewport 375x812containers 0 · overflowX 0 · issues 0
output, 9 line(s), 1.4s
vlmkit scan scroll source: http://127.0.0.1:4190/sites/ (375x812) status: ok page: 375x6071 — horizontal overflow 0px, vertical scroll 5259px scroll containers: 0 (dead scrollports 0, clipped 0) No scroll issues detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan scroll http://127.0.0.1:4190/sites/ --viewport 1280x800containers 0 · overflowX 0 · issues 0
output, 9 line(s), 1.4s
vlmkit scan scroll source: http://127.0.0.1:4190/sites/ (1280x800) status: ok page: 1280x2521 — horizontal overflow 0px, vertical scroll 1721px scroll containers: 0 (dead scrollports 0, clipped 0) No scroll issues detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan handlers http://127.0.0.1:4190/sites/registrations 0 · elements 0 · suspects 0
output, 11 line(s), 1.7s
vlmkit scan handlers source: http://127.0.0.1:4190/sites/ status: 1 warn(s) exits 0 — 1 warn(s) did not fail this command. To gate on one: --rule no-handlers-found=suspect registrations: 0 across 0 element(s), on a page presenting 36 control(s) Issues: warn [no-handlers-found] 36 visible interactive control(s) and ZERO handler registrations — no listeners, no on* attributes, no on* properties, nothing on window/document. Either the controls are inert (check interactions reports that as inert-control), or they are wired somewhere this gate cannot see, or the page genuinely needs none (links, a form that posts). This gate cannot tell which; it can only tell you that a clean result here is not evidence of anything. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
gallery after D1-D7
http://127.0.0.1:4190/sites/ · 1280×800 · full page, 4 screen(s)
Gallery at 1280 after D1–D7, 2521px, 4 screens. Screen 1: the kicker now reads "vlmkit · demo sites" in the brand's own case (D7). The lede reads "Each demo site was built from a one-page brief by an agent using vlmkit's gates and its own eyes, and the landing page was reviewed the same way. Next to each page is its judgment log: …" (D1), five lines. Totals unchanged on one line. Row 1 cards: the titles now sit in 44px boxes, and in a one-line title that puts about 10px more air between the title and its pattern line than before. Screen 2: row 1's feet: every card's two links on one row, solitaire's "Open the site The README's record" included. Row 2: stats in all three cards with numbers on shared lines. Screens 3–4: row 3 shows the spacing problem side by side: the magazine's two-line title "ほとり — 海辺の町の古本屋が、/ 夜だけ店を開ける理由" (a phrase break, D4) sits tight on its pattern line, while the shop's one-line "汐見窯 マグカップ 青磁" has the extra 10px — the two cards' subtitles are at different distances from their titles. "How the logs were kept" and the footer as before, the footer link whole.
.card h2 aF6's 44px title boxes add space only when a title is shorter than 44px, so one-line titles now sit about 10px further from their pattern line than two-line ones — side by side in row 3 (the magazine tight, the shop loose, S6/S7/S8). The cards in a row no longer share one rhythm.
gallery after D1-D7
http://127.0.0.1:4190/sites/ · 375×812 · full page, 8 screen(s)
Gallery at 375 after D1–D7, 6071px, 8 screens. Screen 1: lowercase kicker, three-line h1, the new lede (nine lines; "one- / page" breaks at the hyphen, which is where a compound may break), totals in four lines. Screens 2–7: in every card the numbers now share a line — "31 3 108" on one line under "found by eye / found by a gate / looks", even though "found by a / gate" still wraps (D2). The two links stack, each whole. Solitaire's pair: "Open the site" / "The README's record", each whole. The magazine title breaks between phrases ("…古本屋が、/ 夜だけ店を開ける理由"). One-line titles again sit further from their pattern line than the magazine's two-line one. Screen 8: the footer puts "How this page was judged" whole on its own line (D5).
gallery after D1-D7
http://127.0.0.1:4190/sites/ · 768×1024 · full page, 4 screen(s)
Gallery at 768 after D1–D7, 3169px, 4 screens. Two cards per row. The numbers rows are aligned in every card (D2). Row 1 is where D3 is still visible: the landing card's two links share a row while solitaire's stack — "Open the site" then "The README's record" on the next line — so the two card feet do not match. "The README's record" is a few pixels too wide to sit beside "Open the site" at this card width. Row 3: magazine title with a phrase break (D4), the shop's one-line title with the extra gap. Footer: "…judgment/log.jsonl." then "How this page was judged." whole on the next line.
gallery after D1-D7, dark
http://127.0.0.1:4190/sites/ · 375×812 · full page, 8 screen(s) · dark
8 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Gallery at 375 after D1–D7, dark scheme, 8 screens. Same geometry as S7; the dark palette holds: lilac eye numbers and light-blue gate numbers legible on the dark cards, underlined links in the ink colour, muted labels readable. The numbers share lines, the Japanese title breaks between phrases, the footer link is whole, solitaire's two links stack whole. The one-line titles' extra gap is visible here too.
focus on the first card's title
http://127.0.0.1:4190/sites/ · 1280×800 · element ul.grid > li:nth-of-type(1) · @2x · press Tab · press Tab
1 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Keyboard focus after two Tabs at 1280 (2x): the first card's title "vlmkit landing page" has the browser's default ring — a dark rounded 2px line drawn right on the 44px box with no offset. The box is only as wide as the text, so the ring touches the "v" and the final "e"; it reads as a box pressed onto the glyphs rather than a ring around a target. Its top edge is a few px under the thumbnail.
a:focus-visibleThe keyboard ring is the browser default drawn flush on the link's box, touching the first and last glyphs (S10 on a title, S11 on 'How it was judged'); on 44px boxes it reads as a box pressed onto the text rather than a ring around a target.
focus on the first card's log link, phone
http://127.0.0.1:4190/sites/ · 375×812 · element ul.grid > li:nth-of-type(1) · @2x · press Tab · press Tab · press Tab · press Tab
1 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Keyboard focus after four Tabs at 375 (2x): "How it was judged", the first card's second link, has the same default ring: the 44px box drawn flush, the ring touching the "H" and the "d". The link above ("Open the site") and the card's edge are clear of it.
Screen 1 of S6: the lede says each demo site was built from a brief and the landing page was reviewed the same way — true of every logged card.
S7 (375) and S8 (768): the three numbers in every stat row share a line, with 'found by a / gate' still wrapping above its number.
S7 and S8: the magazine title breaks between phrases, '…古本屋が、/ 夜だけ店を開ける理由', at 375 and 768.
S7 screen 8 and S8: the footer link sits whole on its own line.
G22 (AA) and G23 (AAA): 0 undersized targets; 3 excused, all links inside sentences (the method paragraph and the footer).
S6 screen 1: 'vlmkit · demo sites', the brand lowercase.
Second fix: solitaire's record link uses the label every card uses, 'How it was judged' — the note above it already says the record is its README's table — so its link row is the same width as its neighbours' at every card width, instead of 'The README's record', which was 5px too wide to share the row at 768.
Card title links are back to their own line height; the 44px construction stays on the action links and the kicker. The title link goes where 'Open the site' goes, which is 44px, so WCAG 2.5.5/2.5.8's 'equivalent' exception covers it — declared to the touch gate with --allow rather than measured away.
a:focus-visible draws a 2px ring in the page's accent (#1f5f8b light, #8cc4ea dark) 3px outside the link's box; the link row's top padding went from 0.25rem to 0.5rem so a focused action link's ring clears the stats above it.
R3 · final check after D3, D8, D9
reviewervlmkit check integrity http://127.0.0.1:4190/sites/verdict: CLEAN (0 fail, 0 warn, 0 exempted)
verdict clean · findings 0 · fails 0 · warns 0 · exempted 0 · viewports 3
output, 10 line(s), 5.1s
vlmkit check integrity source: http://127.0.0.1:4190/sites/ verdict: CLEAN (0 fail, 0 warn, 0 exempted) 1280x800: 8 component(s), ink 45.6%, 132 text block(s) 768x900: 8 component(s), ink 58.6%, 132 text block(s) 375x700: 8 component(s), ink 67.4%, 132 text block(s) No integrity defects detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check a11y contrast http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-contrast/galleryinspected 147 · failures 0
output, 6 line(s), 1.6s
vlmkit check a11y contrast html: http://127.0.0.1:4190/sites/ inspected 147 text-bearing element(s) ✓ 0 contrast failure(s) report: examples/sites/test-results/a11y-contrast/gallery/report.md http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check design http://127.0.0.1:4190/sites/verdict: COHERENT (0 finding(s))
verdict coherent · drifting 0 · roles 2
output, 20 line(s), 1.6s
vlmkit check design
source: http://127.0.0.1:4190/sites/
verdict: COHERENT (0 finding(s))
roles judged: 1 of 2 seen, spacing values: 13
coverage: 10 of 244 visible element(s) carried an inferable role
no role: div x50, dd x42, dt x42, a x36, p x20, li x16, +8 more tag(s)
A role comes from role="..." or from button/input/select/textarea/h1-h6. Layout elements
(div, span, p, a) have none, so a large skip count is normal — this gate judges components,
not every box. Add role="..." where an element IS a component to widen the coverage.
Role reuse (instances / distinct styles; drift below 3x from 3 instances)
h2 9 inst 2 styles reuse 4.5x 1 one-off ok
h1 1 inst 1 styles reuse 1x 1 one-off not judged
not judged: h1 (1) — under --min-instances 3, so no finding can come from it.
To keep judging it: --min-instances 2 --min-reuse 2 (both — a 2-instance role cannot reach 3x however many instances the floor allows).
No design drift detected.
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check composition http://127.0.0.1:4190/sites/verdict: COMPOSED (0 finding(s))
verdict composed · proximity 0 · flatSteps 0 · railNearMisses 0
output, 17 line(s), 1.7s
vlmkit check composition source: http://127.0.0.1:4190/sites/ verdict: COMPOSED (0 finding(s)) measured: 1 label(s), 2 heading level(s), 14 wide block(s) on 2 left / 2 right rail(s) — from 244 visible box(es) 9 label(s) not judged: they open a box that paints its own group edge, so nothing above them could be mis-grouped with Type hierarchy (largest instance of each declared level) h1 44px / 700 main>h1 h2 22px / 700 h2#method-title body 13px, largest 44px (3.38x), heaviest +300 weight Group gaps: 0px between heading-led groups vs 0px inside them (0x, 11 sample(s)). Context only — intact pages measure 0.86-3.00x, so this cannot carry a verdict. Proximity, alignment and type hierarchy all read consistently. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check color http://127.0.0.1:4190/sites/verdict: CONSISTENT (0 finding(s))
verdict consistent · base #f6f5f1 · bodyInk #5d5b55 · linkInk #1d1d1b · invisibleControls 0 · colorOnlyLinks 0 · unreadableColors 0
output, 21 line(s), 1.7s
vlmkit check color
source: http://127.0.0.1:4190/sites/
verdict: CONSISTENT (0 finding(s))
measured: 0 control(s), 36 link(s) in a text flow — from 246 visible box(es)
Palette (by painted area; reported, never judged — see the rejected candidates in the module docs)
surfaces 2 distinct
#f6f5f1 66.5% 1 el
#ffffff 33.5% 8 el main>ul.grid>li.card
ink 4 distinct
#5d5b55 59.8% 69 el main>p.kicker
#1d1d1b 35.5% 59 el main>h1
#7a3fb0 2.3% 7 el dl.stats>div.eye>dd
#1f5f8b 2.3% 7 el dl.stats>div.gate>dd
marks 1 distinct
#dcd9d0 100.0% 40 el main>ul.grid>li.card
base #f6f5f1, body ink #5d5b55, link ink #1d1d1b on 32 element(s)
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y focus http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-focus/gallerysteps 28 · findings 9
output, 13 line(s), 1.6s
vlmkit check a11y focus
source: http://127.0.0.1:4190/sites/
captured 28 focus step(s)
! 9 finding(s)
[skip-row] Focus jumped down by 648px (from `main>p.kicker>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 338px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 215px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 215px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 215px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
… 4 more (see the report, or --json for all)
report: examples/sites/test-results/a11y-focus/gallery/report.md
exits 0 — 9 warn(s) did not fail this command. To gate on one: --rule skip-row=suspect
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y focus http://127.0.0.1:4190/sites/ --viewport 375x812 --output-dir test-results/a11y-focus/gallery-mobilesteps 28 · findings 17
output, 13 line(s), 1.6s
vlmkit check a11y focus
source: http://127.0.0.1:4190/sites/
captured 28 focus step(s)
! 17 finding(s)
[skip-row] Focus jumped down by 876px (from `main>p.kicker>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 212px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 314px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 224px (from `ul.grid>li.card>div.body>h2>a` to `ul.grid>li.card>div.body>p.links>a`). Confirm no focusable element was unintentionally skipped.
[skip-row] Focus jumped down by 314px (from `ul.grid>li.card>div.body>p.links>a` to `ul.grid>li.card>div.body>h2>a`). Confirm no focusable element was unintentionally skipped.
… 12 more (see the report, or --json for all)
report: examples/sites/test-results/a11y-focus/gallery-mobile/report.md
exits 0 — 17 warn(s) did not fail this command. To gate on one: --rule skip-row=suspect
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y touch http://127.0.0.1:4190/sites/ --allow '.card h2 a;Equivalent: the same card'\''s "Open the site" link goes to the same page and is 44px tall' --output-dir test-results/a11y-touch/gallerylevel AA · inspected 28 · failures 0 · wcagExempt 10
output, 9 line(s), 1.5s
vlmkit check a11y touch
source: http://127.0.0.1:4190/sites/ level: WCAG AA (24×24 min)
inspected 28 interactive element(s)
✓ 0 undersized target(s)
10 undersized target(s) excused by WCAG 2.5.8 itself (3 in a sentence, 7 with clear spacing)
1 --allow rule(s) matched nothing: .card h2 a;Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
Delete them: an exemption kept past what it covered only widens the blind spot.
report: examples/sites/test-results/a11y-touch/gallery/report.md
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y touch http://127.0.0.1:4190/sites/ --level AAA --allow '.card h2 a;Equivalent: the same card'\''s "Open the site" link goes to the same page and is 44px tall' --output-dir test-results/a11y-touch/gallery-aaalevel AAA · inspected 28 · failures 7 · wcagExempt 3
output, 15 line(s), 1.6s
vlmkit check a11y touch
source: http://127.0.0.1:4190/sites/ level: WCAG AAA (44×44 min)
inspected 28 interactive element(s)
✗ 7 undersized target(s)
3 undersized target(s) excused by WCAG 2.5.5 itself (3 in a sentence)
ul.grid>li.card>div.body>h2>a — 213×22 — "vlmkit landing page"
ul.grid>li.card>div.body>h2>a — 188×22 — "Klondike solitaire"
ul.grid>li.card>div.body>h2>a — 228×22 — "Pantry Club checkout"
ul.grid>li.card>div.body>h2>a — 284×22 — "Keel Analytics — Overview"
ul.grid>li.card>div.body>h2>a — 242×22 — "Quarry documentation"
… 2 more (see the report, or --json for all)
1 --allow rule(s) matched nothing: .card h2 a;Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
Delete them: an exemption kept past what it covered only widens the blind spot.
report: examples/sites/test-results/a11y-touch/gallery-aaa/report.md
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check interactions http://127.0.0.1:4190/sites/elements 30 · suspects 0 · warns 8
output, 48 line(s), 1.7s
vlmkit check interactions source: http://127.0.0.1:4190/sites/ status: ok exits 0 — 8 warn(s) did not fail this command. To gate on one: --rule not-tab-reachable=suspect interactive elements: 30 (+6 beyond the cap — NOT probed) - [link] "vlmkit" focus✓ - [link] "" unreachable - [link] "vlmkit landing page" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Klondike solitaire" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Pantry Club checkout" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Keel Analytics — Overview" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Quarry documentation" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "Sprintboard" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable - [link] "ほとり — 海辺の町の古本屋が、夜だけ店を開ける理由" focus✓ - [link] "Open the site" focus✓ - [link] "How it was judged" focus✓ - [link] "" unreachable Issues: warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. warn [not-tab-reachable] link "" (main>ul.grid>li.card>a) was never reached by Tab — keyboard users cannot operate it. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check breakpoints http://127.0.0.1:4190/sites/ --sweepbreakpoints 0 · issues 0 · sweepRanges 0
output, 7 line(s), 2.7s
vlmkit check breakpoints source: http://127.0.0.1:4190/sites/ status: ok width sweep: 320-1280px step 25 (39 widths) — clean breakpoints: none discovered — nothing to check (pass --breakpoints to force widths) http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan scroll http://127.0.0.1:4190/sites/ --viewport 375x812containers 0 · overflowX 0 · issues 0
output, 9 line(s), 1.4s
vlmkit scan scroll source: http://127.0.0.1:4190/sites/ (375x812) status: ok page: 375x5968 — horizontal overflow 0px, vertical scroll 5156px scroll containers: 0 (dead scrollports 0, clipped 0) No scroll issues detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan scroll http://127.0.0.1:4190/sites/ --viewport 1280x800containers 0 · overflowX 0 · issues 0
output, 9 line(s), 1.4s
vlmkit scan scroll source: http://127.0.0.1:4190/sites/ (1280x800) status: ok page: 1280x2494 — horizontal overflow 0px, vertical scroll 1694px scroll containers: 0 (dead scrollports 0, clipped 0) No scroll issues detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit scan handlers http://127.0.0.1:4190/sites/registrations 0 · elements 0 · suspects 0
output, 11 line(s), 1.6s
vlmkit scan handlers source: http://127.0.0.1:4190/sites/ status: 1 warn(s) exits 0 — 1 warn(s) did not fail this command. To gate on one: --rule no-handlers-found=suspect registrations: 0 across 0 element(s), on a page presenting 36 control(s) Issues: warn [no-handlers-found] 36 visible interactive control(s) and ZERO handler registrations — no listeners, no on* attributes, no on* properties, nothing on window/document. Either the controls are inert (check interactions reports that as inert-control), or they are wired somewhere this gate cannot see, or the page genuinely needs none (links, a form that posts). This gate cannot tell which; it can only tell you that a clean result here is not evidence of anything. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check a11y touch http://127.0.0.1:4190/sites/ --allow 'ul.grid>li.card>div.body>h2>a;Equivalent: the same card'\''s "Open the site" link goes to the same page and is 44px tall' --output-dir test-results/a11y-touch/gallerylevel AA · inspected 28 · failures 0 · wcagExempt 10
output, 9 line(s), 1.5s
vlmkit check a11y touch
source: http://127.0.0.1:4190/sites/ level: WCAG AA (24×24 min)
inspected 28 interactive element(s)
✓ 0 undersized target(s)
10 undersized target(s) excused by WCAG 2.5.8 itself (3 in a sentence, 7 with clear spacing)
1 --allow rule(s) matched nothing: ul.grid>li.card>div.body>h2>a;Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
Delete them: an exemption kept past what it covered only widens the blind spot.
report: examples/sites/test-results/a11y-touch/gallery/report.md
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harvlmkit check a11y touch http://127.0.0.1:4190/sites/ --level AAA --allow 'ul.grid>li.card>div.body>h2>a;Equivalent: the same card'\''s "Open the site" link goes to the same page and is 44px tall' --output-dir test-results/a11y-touch/gallery-aaalevel AAA · inspected 28 · failures 0 · wcagExempt 3
output, 14 line(s), 1.5s
vlmkit check a11y touch
source: http://127.0.0.1:4190/sites/ level: WCAG AAA (44×44 min)
inspected 28 interactive element(s)
✓ 0 undersized target(s), 7 exempted
3 undersized target(s) excused by WCAG 2.5.5 itself (3 in a sentence)
- ul.grid>li.card>div.body>h2>a — 213×22: user exemption (ul.grid>li.card>div.body>h2>a): Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
- ul.grid>li.card>div.body>h2>a — 188×22: user exemption (ul.grid>li.card>div.body>h2>a): Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
- ul.grid>li.card>div.body>h2>a — 228×22: user exemption (ul.grid>li.card>div.body>h2>a): Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
- ul.grid>li.card>div.body>h2>a — 284×22: user exemption (ul.grid>li.card>div.body>h2>a): Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
- ul.grid>li.card>div.body>h2>a — 242×22: user exemption (ul.grid>li.card>div.body>h2>a): Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
- ul.grid>li.card>div.body>h2>a — 128×22: user exemption (ul.grid>li.card>div.body>h2>a): Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
- ul.grid>li.card>div.body>h2>a — 203×22: user exemption (ul.grid>li.card>div.body>h2>a): Equivalent: the same card's "Open the site" link goes to the same page and is 44px tall
report: examples/sites/test-results/a11y-touch/gallery-aaa/report.md
http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.harG37's --allow was written as a CSS selector ('.card h2 a'), and the gate matches the path as it prints it, so the rule matched nothing — which the gate said in its own output. Re-run with the printed path in the two runs that follow.
Same mistake as G37 at AA (where the title links were excused anyway by spacing); re-run with the printed path.
gallery, final
http://127.0.0.1:4190/sites/ · 1280×800 · full page, 4 screen(s)
Final gallery at 1280, 2494px, 4 screens. Screen 1: "vlmkit · demo sites", the two-line h1, the corrected lede, the totals on one line, row 1's cards. Titles are back to their own height: each card reads title, then its pattern line about 8px below, then the stats — the same rhythm in every card. Screen 2: every card's feet show "Open the site How it was judged" on one row, solitaire's included; row 2 with numbers on shared lines. Screen 3: row 3 side by side — the magazine's two-line title and the shop's one-line title now sit the same distance from their pattern lines (D8); the method section. Screen 4: the footer with its link whole.
gallery, final
http://127.0.0.1:4190/sites/ · 375×812 · full page, 8 screen(s)
Final gallery at 375, 5968px, 8 screens. The header, lede and totals as in S7. Every card: title, pattern 8px below, the stats with numbers sharing a line under wrapped labels, then the two links stacked, each whole. Solitaire's second link now reads "How it was judged", like every card's. The magazine title breaks between phrases. The method list and the footer with "How this page was judged" whole on its own line. Nothing overflows the 343px column.
gallery, final
http://127.0.0.1:4190/sites/ · 768×1024 · full page, 4 screen(s)
Final gallery at 768, 3095px, 4 screens. Row 1: the landing card and solitaire now end the same way — "Open the site How it was judged" on one row in both, the feet level with each other (D3). Rows 2–3 likewise; numbers aligned in every card; the one-line and two-line titles keep the same gap to their pattern lines. Footer: the link whole on the second line.
gallery, final, dark
http://127.0.0.1:4190/sites/ · 1280×800 · full page, 4 screen(s) · dark
4 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Final gallery at 1280 in the dark scheme, 4 screens. Same geometry as S12: near-black page, lighter cards, lilac eye counts and light-blue gate counts legible, ink links underlined, the light thumbnails framed by the card border. Solitaire's links match the others. Nothing in the dark palette falls under the computed table in N5.
focus ring on a title, final
http://127.0.0.1:4190/sites/ · 1280×800 · element ul.grid > li:nth-of-type(1) · @2x · press Tab · press Tab
1 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Final focus on the first card's title at 1280 (2x, two Tabs): a 2px ring in the page's blue accent, 3px outside the link and rounded, sitting clear of "vlmkit landing page" on all four sides and above the pattern line; the thumbnail above is untouched.
focus ring on an action link, phone, final
http://127.0.0.1:4190/sites/ · 375×812 · element ul.grid > li:nth-of-type(1) · @2x · press Tab · press Tab · press Tab · press Tab
1 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Final focus on "How it was judged" at 375 (2x, four Tabs): the blue ring encloses the link's 44px box with its 3px offset; it clears "Open the site" above and the card's inner edge, and the text inside keeps its underline.
focus ring, dark, final
http://127.0.0.1:4190/sites/ · 1280×800 · element ul.grid > li:nth-of-type(1) · @2x · dark · press Tab · press Tab · press Tab · press Tab
1 screen(s), looked at when taken; not kept once the round was done — a round keeps one full-page walk per width.
Final focus in the dark scheme at 1280 (2x, four Tabs): "How it was judged" in the first card has the light-blue ring (#8cc4ea) around its 44px box, clear of "Open the site" beside it and of the stats above.
S14 at 768: solitaire's 'Open the site How it was judged' shares one row like the landing card beside it; S12 and S13 agree at 1280 and 375.
S12 screen 3: the one-line and two-line titles sit the same distance from their pattern lines; S13 and S14 agree.
S16–S18: the accent ring sits 3px outside the link in both schemes, clear of every glyph.
The gallery had never been looked at: it is generated from the logs, and a test holds its words and numbers to them, but nothing had checked how it reads. Three rounds, 9 defects — 8 found by eye, 1 by a gate — all fixed and verified: - D1 the lede claimed every page was built from a brief (the landing page was reviewed; solitaire predates the log). - D2 a wrapped "found by a / gate" label dropped its number below its neighbours'; each stat now keeps its number at the foot of the cell. - D3 solitaire's record link left "found" alone on a line and its links stacked; it now uses the label every card uses (two fixes: "The README's record" was still 5px too wide at 768). - D4 the Japanese titles broke inside words and had no lang; they carry lang="ja" and break between phrases. - D5 the footer link broke across lines. - D6 (gate, G9) 22 targets under 44px at AAA; the action links and the kicker link are 44px, and the title links are exempted by WCAG's equivalent-target exception, declared with --allow (G44). - D7 the kicker uppercased the brand. - D8 D6's first fix put 44px boxes round the titles, which loosened one-line titles only; reverted in favour of the exception. - D9 the default focus ring sat flush on the text; an accent ring 3px outside the target. Final gates: integrity CLEAN (1280/768/375), contrast 0 failures, design COHERENT, composition COMPOSED, color CONSISTENT, touch 0 undersized at AA and AAA, interactions ok, breakpoints and scroll clean. Warns classified: skip-row (N3), the thumbnail links kept out of the tab order on purpose (N2), no handlers on a page without script (N4). The dark scheme is outside every gate (N5), so it was judged by eye in each round and by the computed token table.
R4 · the storage change: the footer and the method list name judgment.sqlite and the pictures a round keeps
reviewervlmkit check integrity http://127.0.0.1:4190/sites/verdict: CLEAN (0 fail, 0 warn, 0 exempted)
verdict clean · findings 0 · fails 0 · warns 0 · exempted 0 · viewports 3
output, 10 line(s), 5.2s
vlmkit check integrity source: http://127.0.0.1:4190/sites/ verdict: CLEAN (0 fail, 0 warn, 0 exempted) 1280x800: 8 component(s), ink 45.2%, 132 text block(s) 768x900: 8 component(s), ink 58.2%, 132 text block(s) 375x700: 8 component(s), ink 66.9%, 132 text block(s) No integrity defects detected. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check a11y contrast http://127.0.0.1:4190/sites/ --output-dir test-results/a11y-contrast/galleryinspected 147 · failures 0
output, 6 line(s), 1.6s
vlmkit check a11y contrast html: http://127.0.0.1:4190/sites/ inspected 147 text-bearing element(s) ✓ 0 contrast failure(s) report: examples/sites/test-results/a11y-contrast/gallery/report.md http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check composition http://127.0.0.1:4190/sites/verdict: COMPOSED (0 finding(s))
verdict composed · proximity 0 · flatSteps 0 · railNearMisses 0
output, 17 line(s), 1.7s
vlmkit check composition source: http://127.0.0.1:4190/sites/ verdict: COMPOSED (0 finding(s)) measured: 1 label(s), 2 heading level(s), 14 wide block(s) on 2 left / 2 right rail(s) — from 244 visible box(es) 9 label(s) not judged: they open a box that paints its own group edge, so nothing above them could be mis-grouped with Type hierarchy (largest instance of each declared level) h1 44px / 700 main>h1 h2 22px / 700 h2#method-title body 13px, largest 44px (3.38x), heaviest +300 weight Group gaps: 0px between heading-led groups vs 0px inside them (0x, 11 sample(s)). Context only — intact pages measure 0.86-3.00x, so this cannot carry a verdict. Proximity, alignment and type hierarchy all read consistently. http://127.0.0.1:4190/sites/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/ --out app.har, then --har app.har
vlmkit check integrity http://127.0.0.1:4190/sites/judgment/verdict: CLEAN (0 fail, 0 warn, 0 exempted)
verdict clean · findings 0 · fails 0 · warns 0 · exempted 0 · viewports 3
output, 10 line(s), 22.2s
vlmkit check integrity source: http://127.0.0.1:4190/sites/judgment/ verdict: CLEAN (0 fail, 0 warn, 0 exempted) 1280x800: 8 component(s), ink 67.7%, 618 text block(s) 768x900: 8 component(s), ink 76.6%, 618 text block(s) 375x700: 8 component(s), ink 77.3%, 613 text block(s) No integrity defects detected. http://127.0.0.1:4190/sites/judgment/ is live and not pinned — a re-run may measure different data. Pin it: vlmkit snapshot record-har http://127.0.0.1:4190/sites/judgment/ --out app.har, then --har app.har
http://127.0.0.1:4190/sites/ · 1280×800 · full page, 4 screen(s)
Gallery at 1280, 2520px, 4 screens (26px taller than R3's 2494: the method list's second bullet is a line longer). Screen 1: "vlmkit · demo sites" kicker, the two-line h1, the five-line lede, the totals row (7 logged pages, 645 gate runs, 1342 screens looked at, 127 by eye, 43 by a gate — unchanged, since a screen looked at is still counted when its picture is not kept), then the first row of cards: the landing page's dark hero, solitaire's green table, checkout's step 1. Every thumbnail is drawn — they are now served out of each log's judgment.sqlite, and none is a broken image. Screen 2: the first row's stats and links, then Keel Analytics (dark dashboard), Quarry docs and Sprintboard with their six stats each, and the tops of the ほとり and 汐見窯 thumbnails. Screen 3: the two Japanese cards, then "How the logs were kept": the second bullet now reads "…a look is recorded against the image it describes; each finished round keeps the pictures of one full-page walk per width, so you can open them and disagree;" on three lines, the others on two; the list keeps its even rhythm and the 44rem measure. Screen 4 (flush with the end): the footer on one line, "Generated by examples/sites/gallery.mjs from each page's judgment.sqlite. How this page was judged." — both code spans monospaced, the link underlined. Nothing overlaps or clips.
http://127.0.0.1:4190/sites/ · 768×1024 · full page, 4 screen(s)
Gallery at 768, 3121px, 4 screens. Screen 1: header and lede as at desktop in a narrower column; the totals wrap to two lines with "43 defects found by a gate" alone on the second, as in R3; the landing and solitaire cards side by side, both thumbnails drawn. Screen 2: checkout and Keel Analytics, then Quarry and Sprintboard; "found by a gate" wraps to two lines in every card and the three numbers of each row still share a baseline. Screen 3: ほとり and 汐見窯 (their thumbnails drawn), then "How the logs were kept" — the longer second bullet wraps to three lines at this width too — and the footer, which breaks after "judgment.sqlite." so "How this page was judged." sits whole on its own line (the nowrap on footer links doing its job; no break inside the link). Screen 4 sits flush with the end: the same method section and footer, 49px higher. No clipping, no overlap, no horizontal scroll.
http://127.0.0.1:4190/sites/ · 375×812 · full page, 8 screen(s)
Gallery at 375, 6019px, 8 screens (51px taller than R3's 5968: two more lines in the method list). Screen 1: kicker, the three-line h1, the lede, and the totals stacked two, one, one, one; the landing card's dark thumbnail starts at the bottom. Screens 2-6: one card per screen-and-a-bit — landing (4 / 119 / 624, 31 / 3 / 108), solitaire with its note, checkout, Keel Analytics, Quarry, Sprintboard, ほとり, 汐見窯 — every thumbnail drawn, "Open the site" and "How it was judged" stacked on their own lines at 44px each. Screen 7: 汐見窯's stats and links, then "How the logs were kept" begins. Screen 8 (flush): the three bullets, the second now six lines ("…each finished round keeps / the pictures of one full-page walk per / width, so you can open them and / disagree;") with the hanging indent intact, and the footer on three lines: "Generated by examples/sites/gallery.mjs / from each page's judgment.sqlite. / How this page was judged." Nothing is cut off at the right edge; the page ends on the footer.
The gallery's text followed the storage change: its footer names judgment.sqlite, where every number and thumbnail on it now comes from, and the method list says what a log keeps — each finished round the pictures of one full-page walk per width. Integrity, contrast and composition are clean on the gallery, and integrity on this log's own page (served, like every log page, out of its database) found no broken image. Every thumbnail on the gallery is drawn at all three widths.






























































