fix: footer email reflow to zero under all four methods; reopen the skip-link residual as Q61

The footer mailto was the last recorded overflow: `info@smlcompany.ca` demanded
310px of min-content in a 224-243px column. One declaration —
`overflow-wrap: anywhere` on `.footer-contact a[href^='mailto:']`. `anywhere`
and not `break-word`, established with a negative control rather than from the
rule: only `anywhere` reduces min-content, and `break-word` injected in its
place failed the same 88 rows as the unfixed baseline.

Minimum-font-size 32 goes 88/352 -> 0/352. All four methods now read 0 of 352
(22 pages x 16 widths). Normal-settings identity: 0 differences across 8
metrics, with a positive control proving the comparison can detect one. It also
closed 57 element-level cases the page-level table reports as clean, hidden
inside `.wrap`'s 96px gutter.

The item-2 ruling is NOT applied, and this is the deviation to read first. The
acceptance rested on "no CSS mechanism can see minimum-font-size", which is
false: the font-metric units — `ch`, `ex`, `cap`, `lh`, `rlh` — read the used
font size and double, in property values, in `@media` and in `@container`. Only
`rem`, `em`, `ic` and `px` are blind. And the cost is not a convenience loss:
keyboard focus lands entirely behind the opaque header on 290 of 1,455 stops,
36 of them inside `#main`, which is WCAG 2.2 SC 2.4.11 at AA — the same level as
the 1.4.10 failure it was traded against. A build of fce89d4~1 measures 0, so
the header fix created it. Opened as Q61 with a verified candidate; docs/06
restored to unticked.

R20's gate is now a build failure rather than three prose cross-references,
which demonstrably did not gate it: with two articles published the build and
all five checks passed while both header defects shipped. SiteHeader throws.

R11's two majors (@astrojs/mdx 7->8, typescript 6->7) move to a new cutover-prep
group in docs/06 with the 19-pin currency sweep.

Two review rounds, eight findings, all resolved; four of round 2's five were
defects in round 1's own fixes. Stopped at two per D19.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
This commit is contained in:
Pouya Lajevardi
2026-09-01 14:51:37 -04:00
co-authored by Claude Opus 5
parent fce89d46eb
commit ca1c2524e1
8 changed files with 960 additions and 98 deletions
+387 -59
View File
@@ -387,7 +387,28 @@ Not a polish pass. A build requirement.
Command, so the numbers are re-runnable rather than quoted: headless Chrome
over the built `dist`, `document.documentElement.style.fontSize = '32px'`, then
`documentElement.scrollWidth - documentElement.clientWidth`, plus an
enumeration of every element wider than `clientWidth` to name the offender.
enumeration of every element that either **is wider than `clientWidth`** or
**whose own content overflows its own box** (`scrollWidth - clientWidth`), to
name the offender. ⚠️ **Both halves of that predicate are load-bearing and the
second was added on 2026-09-01, after the first half alone reported "no offender"
at three of the four widths that were failing** — the footer email spilled text
out of a box that was itself inside the viewport. A sweep that enumerates only
over-wide *elements* will name no cause for a whole class of real overflow.
⚠️ **AND THE RECIPE ABOVE HAS A UNIFORM-PASS TRAP THAT IS NOT VISIBLE IN IT.**
Run `document.documentElement.style.fontSize = '32px'` with
`prefers-reduced-motion: reduce` in force — launch flag *or* CDP emulation — and
it reports **0 of 352 with the enlargement never applied**: brand width, header
height and document height all byte-identical to root 16. The reduced-motion
reset emits `*,::before,::after{transition-duration:.01ms!important}` over the
initial `transition-property: all`, so the root font-size change becomes a
`CSSTransition` and a synchronous read returns its START value.
`document.getAnimations()` shows `CSSTransition: font-size, running, t=0`; after
one `requestAnimationFrame` it is 32 px. **Kill motion with an injected
`transition:none;animation:none` sheet rather than by emulating reduced motion,
and assert the applied root size per cell** — that assertion is the only thing
that distinguishes this from a clean sweep. Found by `adversarial-reviewer`,
round 2, running this section's own published recipe.
**THE LARGE-TEXT NAV OVERFLOW IS FIXED, 2026-09-01.** Pouya reopened the
step-1 header decision for the purpose — *"its record attributed the residual to
@@ -407,7 +428,7 @@ Not a polish pass. A build requirement.
|---|---|---|---|---|
| `documentElement.style.fontSize='32px'` (root style) | **16 px → `66rem` = 1056 px** | 32 px | 32 px | media query **no**, property **yes** |
| `Page.setFontSizes({standard:32})` (the reader's *default font size*) | 32 px → `66rem` = **2112 px** | 32 px | 32 px | **yes, both** — the breakpoint moves with the type |
| `--blink-settings=minimumFontSize=32` (the reader's *minimum font size*) | 16 px → `66rem` = **1056 px** | **16 px** | **32 px** | **NOTHING IN CSS SEES IT** |
| `--blink-settings=minimumFontSize=32` (the reader's *minimum font size*) | 16 px → `66rem` = **1056 px** | **16 px** | **32 px** | **NO `rem`/`em` CONSTRUCT SEES IT** — the columns of this table are all `rem`/`em`, and that is the limit of what the row measures. ⚠️ **The FONT-METRIC units DO see it** (`ch`, `ex`, `cap`, `lh`, `rlh`); see the table below |
*(Row 1's media-query cell read "32 px → 2112 px" for one revision, which
contradicted its own verdict column, the paragraph below it, and measurement —
@@ -431,9 +452,24 @@ Not a polish pass. A build requirement.
32 px while `em` and `rem` keep resolving at 16 px — so `scroll-padding-top:
6.0625em` computes to **97 px, not 194 px**, a `66em`-wide box measures
**1056 px, not 2112 px**, and `min(0px, calc(100vw - 66em))` is **0px**.
Media queries, container queries and length units are all blind to it.
**Only used-value layout — wrapping — responds**, which is why wrapping had
to be the mechanism and why one residual below cannot be closed in CSS.
⚠️ **AND THE SENTENCE THAT USED TO SIT HERE WAS FALSE AND LOAD-BEARING: it
said "media queries, container queries and length units are all blind to it"
and that "only used-value layout — wrapping — responds".** It is the
`rem`/`em` FAMILY that is blind, not CSS. The **font-metric** units read the
*used* font size and therefore double, and they do so in all three
constructs — measured 2026-09-01 on `/fees/` @1280, headless Chrome, one
probe element per cell:
| construct | `rem`, `em`, `ic`, `px` | `ch`, `ex`, `cap`, `lh`, `rlh` |
|---|---|---|
| property value | blind (16 px → 16 px) | **responds**`ch` 10.608 → 21.216 px, `ex` 8.48 → 16.96, `cap` 11.36 → 22.72, `lh` 25.59 → 51.19 |
| `@media (min-width: N<unit>)` | blind — threshold never flips | **responds**`100ch`, `110ex`, `80cap`, `45lh` all flip |
| `@container (min-width: N<unit>)` | blind | **responds**`45ex`, `32cap` flip |
So wrapping is still the right mechanism for *reflow* — it needs no
threshold and no fitted constant — but **"no CSS can detect this setting" is
not true, and the residual below is therefore not provably unfixable.**
Found by `adversarial-reviewer` and reproduced independently.
**Before and after, 22 pages × 16 widths (320 → 1920 px) = 352 page-widths per
setting, document overflow `documentElement.scrollWidth
@@ -445,7 +481,31 @@ Not a polish pass. A build requirement.
| default (root 16) | 0 of 352 | **0 of 352** |
| root style 32 px | **175 of 352** | **0 of 352** |
| default font size 32 | 0 of 352 | **0 of 352** |
| minimum font size 32 | **219 of 352** | **88 of 352** — all of it the FOOTER, see the residual below |
| minimum font size 32 | **219 of 352** | **0 of 352** the header fix left 88, all of them the footer; the footer fix below closed them, 2026-09-01 |
✅ **SO: ZERO DOCUMENT OVERFLOW UNDER ALL FOUR METHODS AT EVERY WIDTH
MEASURED — AND THE SCOPE OF THAT SENTENCE IS EXACTLY THE GRID ABOVE.** 22 built
pages × those 16 widths × four enlargement methods = **1,408 page-widths**,
document overflow by `documentElement.scrollWidth documentElement.clientWidth`,
webfonts loaded, six nav items, `prefers-reduced-motion` neutralised by an
injected sheet rather than emulated. Plus **762** further points for the sticky
gate (roots 915, roots 1632, the band seam, both thresholds, all five Chrome
presets), 0 failing.
⚠️ **It is not a claim about anything outside that grid, and "no document
overflow" is not "no accessibility defect".** Three known cases sit outside it
deliberately. The **fallback-metrics case** below needs the webfonts blocked and
a seventh nav item. The **focus-obscuring case** below is an **open WCAG 2.2
SC 2.4.11 (AA) failure** — `AGENTS.md` Q61 — and document overflow cannot see it
at all, because nothing overflows: the header simply covers what has focus. And a
**footer nav label** still overruns its own column by 24 px at 640 px under
minimum font size with 7.7 px of clearance, again with zero document overflow.
None of the three is contradicted by the zeros above, and none of them is
measured by them — which is the reason each is recorded in its own right rather
than summarised into the table. Widths
between the sampled ones are not measured either — the grid is 16 columns, not a
continuum, and the two thresholds and the band seam were swept precisely because
a 16-column grid can step over a 36 px band.
**The wide-width figures that were the defect, root style 32 px, and what they
are now.** Every one is 0 of 22 pages after the fix, and the nav items and the
@@ -616,8 +676,8 @@ Not a polish pass. A build requirement.
| condition | header | offset | short by | status |
|---|---|---|---|---|
| `minimumFontSize=32` | 164.58270.56 px | 97 px | **68174 px** | live, unfixable in CSS |
| fallback font metrics + 7th nav item, **default** text size, 10561091 px | 141 px | 97 px | **44 px** | latent on `showInsights` |
| `minimumFontSize=32` | 164.58270.56 px | 97 px | **68174 px** | 🛑 **OPEN — needs a fresh ruling.** The 2026-09-01 acceptance rested on two facts that are both false; and the real cost is **290 entirely-obscured focus stops, SC 2.4.11 AA**, not a short skip-link landing. **A pure-CSS detector DOES exist.** See below |
| fallback font metrics + 7th nav item, **default** text size, 10561091 px | 141 px | 97 px | **44 px** | latent on `showInsights`. **HARD GATE: `AGENTS.md` R20 — the seventh item does not ship until this is fixed** |
| `defaultFontSize=9` | 120 px | 54.56 px | ~~65 px~~ | **fixed** by the `1rem - 16px` term |
| root-style 10 px | 69 px | 60.63 px | ~~8 px~~ | **fixed** by the same term |
@@ -642,9 +702,16 @@ Not a polish pass. A build requirement.
defended forever**, because the reason given is one nobody wants to re-open —
which is exactly what happened for four days.
**TEN FIXES ACROSS THE TWO PASSES — no `overflow-x` was added anywhere.** Eight
are narrow-width (2026-08-31); the last two are the large-text nav (2026-09-01).
All but one are cause-specific; the exception is marked as the backstop it is:
**ELEVEN FIXES ACROSS THREE PASSES, IN TWELVE ROWS — no `overflow-x` was added
anywhere.** Eight are narrow-width (2026-08-31), two are the large-text nav
(2026-09-01), and the eleventh is the footer email (2026-09-01, the pass that
closed the last recorded overflow). ⚠️ **The twelfth row is `.nav-list`, and it
is a row without being a fix:** it is here because its removal was *measured*,
and it is not counted because the measurement was that it changes nothing. Say
so rather than leaving the arithmetic to a reader who counts rows — the heading
read "TEN FIXES" over eleven rows until 2026-09-01 for exactly this reason. All
but one of the eleven are cause-specific; the exception is marked as the
backstop it is:
| Element | Was | 320 px | Cause |
|---|---|---|---|
@@ -656,6 +723,7 @@ Not a polish pass. A build requirement.
| `/ .hero-h` | `overflow-wrap: anywhere` | 36 px | "contract," at 104 px held `.hero-copy` open |
| `/ .feature-body` | `overflow-wrap: anywhere` | 26 px | "party-appointed" at 202 px |
| `CredentialRow .credential-label` | `overflow-wrap: anywhere` | 38 px | "designation" needs 143 px in an 88 px track |
| `SiteFooter .footer-contact a[href^='mailto:']` | `overflow-wrap: anywhere` | **14 px** | `info@smlcompany.ca` has no break opportunity and demands 310 px. Minimum-font-size only; also 38 / 30 / 19 px at 1024 / 1056 / 1100 px, by a different mechanism — see the footer block above |
| `SiteFooter .footer-brand` | `flex-wrap: wrap` | 12 px | Flex item at `min-width: auto` cannot shrink below "Lajevardi" |
| `PracticeCard .card` | `padding` clamped | *(the cause under `Pill`)* | The space scale is rem-based, so `--space-6` is 64 px a side at root 32 — 128 px of padding in a ~224 px box |
| `Pill` | `overflow-wrap: anywhere` | 33 px → **1 px** | ⚠️ **SYMPTOM, NOT CAUSE.** A one-word pill cannot wrap at a space that is not there |
@@ -674,8 +742,14 @@ Not a polish pass. A build requirement.
card, escaping its own rounded border. Two lines is the better of those. The
clamp does not change any normal size: 10vw holds 32 px from 320 px up.
**Six instrument findings, and each one hid a real defect. The last three are
from the 2026-09-01 pass and all three produced a CLEAN-LOOKING result:**
**TEN instrument findings, and each one hid a real defect. Items 46 are from the
2026-09-01 header pass and all three produced a CLEAN-LOOKING result; 710 are
from the footer pass the same day. Each is recorded once — the footer block above
points here rather than restating them.** ⚠️ **Finding 2 RECURRED in that footer
pass**, in a probe written by the person who had written finding 2 down: it is
described where it did its damage, beside the footer fix, and not duplicated as
an eleventh item.
4. ⚠️ **A UNIFORM PASS FROM A TAUTOLOGY.** The skip-link probe reported
`0.0 px of #main covered` on **946 of 946** page-widths, before and after,
@@ -704,6 +778,34 @@ Not a polish pass. A build requirement.
the direction that makes a width test pass. **Clone a real node** and assert
its computed styles match a sibling's.
7. ⚠️ **A CAUSE READ OFF A TRUNCATED LIST.** The header harness capped its
offender array at `slice(0, 20)` while reporting `offenderCount` beside it,
and **44 of the 88 failing rows exceeded the cap** — so the enumeration that
was supposed to name the footer's cause was silently missing 34 of the 54
boxes at 320 px. The truncation was visible only to a reader who compared the
two numbers. Same family as the `tail -3` rule in `CLAUDE.md`, through a
different pipe.
8. ⚠️ **`grep -c` COUNTS LINES, NOT OCCURRENCES, AND MINIFIED CSS IS ONE LINE.**
`grep -c 'overflow-wrap:anywhere' dist/_astro/*.css` returned `1` for a file
that holds **three** such declarations. It was being used to confirm the new
rule had reached `dist/`, which it could not do. Extract and print the bytes
instead — the rule that actually settled it was reading the emitted selector,
`.footer-contact[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if][href^=mailto\:]`.
9. ⚠️ **`getClientRects().length` IS 1 FOR A `display: flex` ELEMENT HOWEVER MANY
LINES OF TEXT IT HOLDS** — it is one block box, not a fragmented inline. The
wrap probe therefore reported `lines=1` for the footer email while its own
`height` said **102.38 px = 2 × 51.19**, i.e. two lines. Line counts come from
`Range` rects over the text, which do fragment per line. **Two metrics of the
same quantity disagreeing is the cheapest defect detector in this section** —
it is what caught this one.
10. ⚠️ **`Page.captureScreenshot`'s `clip` IS IN PAGE COORDINATES, NOT VIEWPORT
COORDINATES.** Given a `getBoundingClientRect()` taken after a scroll, it
captured a **blank cream plate** — of a footer that is ink. The screenshot
existed to be the independent second method for a break the numbers could not
judge, so a silently wrong one is worse than none. Add `window.scrollX/Y`, or
pass `captureBeyondViewport: true` and page coordinates.
The original three:
1. **`overflow-wrap: break-word` permits a break at layout time but does not
@@ -727,51 +829,267 @@ Not a polish pass. A build requirement.
`documentElement.scrollWidth - documentElement.clientWidth`, which is correct
in both modes.
⚠️ **THE ONE RESIDUAL THAT REMAINS, AND IT IS THE FOOTER RATHER THAN THE
HEADER.** Under Chrome's **minimum font size** only, document overflow remains at
four widths — **14 px at 320, 38 px at 1024, 30 px at 1056, 19 px at 1100**, on
all 22 pages, falling to 0 from 1200 px up. Every instance is
`SiteFooter`: `info@smlcompany.ca` has no break opportunity and needs **310 px**
inside a 224243 px footer-contact column, and at 320 px the `.footer-col` box
itself measures 310 px inside a 272 px content area. **The FOOTER'S OWN overflow is
byte-identical before and after** — `div.footer-grid` 78 px at 1056 and 67 px at
1100, `footer.site-footer` 30 px and 19 px, unchanged — and the 320 px and
1024 px *document* figures are unchanged too, at 14 and 38. ⚠️ **The 1056 px and
1100 px document figures DID change, 414 → 30 and 370 → 19, and this sentence
claimed all four were identical.** They changed because the header stopped
contributing its own 414 px and 370 px, not because the footer moved; a document
figure and a footer contribution are different measurements and only the second
is unchanged. Found by `adversarial-reviewer`. It is **out of the scope Pouya set** for this step ("the header and
its consumers"), so it was measured and left rather than improvised: the
10241100 px half looks like one `overflow-wrap: anywhere` on the footer contact
links, the 320 px half is a column-sizing question and is not the same fix.
Not header-side: **no header element extends the document at any width under any
mechanism**, and the nav items and CTA are on-screen in **1408 of 1408**
measurements (four text settings × 22 pages × 16 widths). *(This said "946 of
946" for one revision. 946 is a different sweep — the four runs made with the
tautological skip probe in instrument finding 4 — and reusing it here for the
final build was the two-similar-totals mistake this section keeps warning
about.)* *(The Practice dropdown panel's contents do overflow their own box
by 84 px under this setting, but the panel sits inside a **closed** `<details>`
and never extends the document — checked by taking the furthest-right box rather
than the largest content overflow.)*
**THE FOOTER RESIDUAL IS FIXED, 2026-09-01 — ONE DECLARATION, AND THE
EARLIER RECORD MISDIAGNOSED HALF OF IT.** Under Chrome's minimum font size the
document overflowed at four widths on all 22 pages — **14 px at 320, 38 px at
1024, 30 px at 1056, 19 px at 1100** — and 0 from 1200 px up. One cause at all
four: `info@smlcompany.ca` has no break opportunity, so its **min-content width
is 310 px**.
⚠️ **AND ONE THAT CANNOT BE CLOSED IN CSS AT ALL.** Under minimum font size the
sticky gate above cannot fire — **both** of its terms evaluate to `0` because
`rem` still resolves at 16 px there, so `100vw - 66rem` is positive and
`1rem - 16px` is exactly zero — and the header stays sticky at
**164.58270.56 px** and the skip link lands with **68174 px of `#main` behind
it**, on 22 of 22 pages from 1056 px up. It was **1026 px before**, so this pass
widened it. *(These read "228271 px" and "132174 px" for one revision; both
omitted the single-row band — 68 px at 1200 px and on `/` from 1216 px up.
`adversarial-reviewer` measured the widths the first sweep had not.)* The trade is deliberate and is the right way round: what it bought is the
removal of **830 px of horizontal overflow with four nav items and the CTA
unreachable** under that same setting. Vertical offset leaves every target
reachable by scrolling; the horizontal case did not. **No media query, container
query or length unit can detect this mechanism** (see the table above), the only
candidates left are a fitted magic number tied to the current nav item count or
a normal-settings behaviour change, and Pouya's constraint was to stop and report
rather than ship either. Carried on `docs/06`'s cutover checklist.
| Element | Was | Fix | Effect |
|---|---|---|---|
| `SiteFooter .footer-contact a[href^='mailto:']` | `overflow-wrap: normal` | `overflow-wrap: anywhere` | **88 of 352 → 0 of 352** |
⚠️ **TWO MECHANISMS, ONE CAUSE — and this is the part the earlier record got
wrong.** It said the 10241100 px half "looks like one `overflow-wrap: anywhere`
on the footer contact links" and that "the 320 px half is a column-sizing
question and is not the same fix". **It is the same fix.** The column sizing at
320 px is *driven by* that same 310 px:
- **At 320 px** `.footer-grid`'s implicit track is `auto`, whose minimum is
min-content, so the track — and every `.footer-col` in it — measures **310 px
inside a 272 px content area**. The boxes themselves cross the viewport edge:
**54 elements** did, right edge 334 px against a 320 px client width.
- **At 1024 / 1056 / 1100 px** the contact column is `minmax(0, 1fr)` — a **0**
minimum, so the track does not grow — and the box stays **224 / 232 / 243 px**
while the text spills **86 / 78 / 67 px outside it**. **No element's border box
crosses the viewport edge at all** at those widths.
Reducing one min-content width closes both halves.
⚠️ **AND IT CLOSED A THIRD CASE THAT THE FOUR-METHOD TABLE REPORTED AS CLEAN —
"MEASURE THE ELEMENTS, NOT ONLY THE PAGE", WHICH IS ALREADY A RULE IN THIS
SECTION.** With the fix disabled as a control, over 420 points (3 pages × 10
widths × 6 minimum-font-size presets and 8 root sizes), **69 failed: 12 by
document overflow and 57 by the link overrunning its OWN box while the document
measured 0.** Those 57 sit at **root style 26 / 28 / 30 / 32 px** and at
**`minimumFontSize` 24 and 32** — and root style 32 px is a row the table above
reports as **0 of 352**, truthfully, because it is a document measurement.
**Why it never reached the viewport edge, measured rather than surmised:**
`.wrap` carries a **96 px** right gutter at that size, and the spill is smaller
than the gutter. At root 32 on `/about/` the link's box ends at 928 px and its
text at **1007.3 px** against a **1024 px** client width — 79 px of spill sitting
inside 96 px of padding. The spill shrinks as the viewport widens (79 / 71 / 60 /
35 / 15 / 0 px at 1024 / 1056 / 1100 / 1200 / 1280 / 1440), which is why the case
disappears at 1440 px rather than at a breakpoint.
**After the fix: 0 of 420, and 0 clipping at every preset and every root size.**
The control is what makes that number mean anything — a sweep returning zero on
every cell is the shape this section warns about twice, so it was re-run with the
declaration forced back to `normal` and it failed 69.
⚠️ **AND THE ELEMENT SWEEP THAT LOOKED FOR THE CAUSE REPORTED "NONE" AT THREE
OF THE FOUR WIDTHS** — instrument finding 2 in this section, committed again by
the person who wrote it down. `getBoundingClientRect()` reports **border boxes**,
so a `right > clientWidth` predicate cannot see text spilling out of a box that
is itself inside the viewport, which is precisely the 10241100 px mechanism.
The document figure was right and the offender list was empty, and those two
facts together are the signature of this bug. **Read `scrollWidth clientWidth`
per element as well as per document.**
⚠️ **And the harness's offender list was truncated at 20 entries on 44 of the 88
failing rows**, so it could not have named the cause either — instrument finding
**7** below.
**What the fix costs, measured rather than asserted.** At the default text size,
**nothing**: the address is one line, **44.00 px** tall — exactly the touch-target
floor — at all 16 widths, and the normal-settings identity check is 0 differences
on 352 page-widths. Under minimum font size it wraps to two lines and the break
is mid-token — `info@smlcompany` / `.ca` at 320 px, `info@smlcomp` / `any.ca` at
1024 px, `info@smlcompa` / `ny.ca` at 1100 px — read out of the DOM one character
at a time and confirmed on a screenshot, not inferred from a width. The `href`
is untouched (`mailto:info@smlcompany.ca`), every painted glyph is inside the
viewport in **176 of 176** rows, and the link never clips its own box. A
mid-token break in an address is cosmetic; a document that scrolls sideways is a
WCAG 1.4.10 failure.
**`anywhere`, NOT `break-word` — and that was established with a NEGATIVE
CONTROL rather than from the rule.** `break-word` permits a break at layout time
without reducing min-content size, so it leaves the defect untouched: injected in
place of `anywhere` it failed **88 of 176** rows, the same rows as the unfixed
baseline. Both the baseline and the control had to fail for the trial to mean
anything — **a trial in which every candidate passes is a broken trial**, and
this section already carries five instrument findings of exactly that shape.
**On the link, not on the column, and not in the markup.** Three candidates all
reach 0 of 176: `anywhere` on the email link, on `.footer-contact`, and on
`.footer-col a`. The address is the only string in the footer that produces
**document** overflow, so the rule sits on the address and the two broader
selectors were declined as broader than the cause.
⚠️ **THE REASON FIRST GIVEN FOR THAT SCOPING WAS THE WRONG TEST, AND IT IS WORTH
MORE THAN THE SCOPING.** It said *"the address is the only string in the footer
with no break opportunity — the location line, the response sentence and the
sixteen nav labels all have spaces"*. **A space is not the test. Min-content is
set by the longest WORD**, so a label with spaces still overruns its track when
one of its words does not fit. `adversarial-reviewer` found one that does, and it
reproduced at a width the review had not sampled:
| width | element | own-box overrun | clearance to the next column | document |
|---|---|---|---|---|
| 640 px | `.footer-col a` "Construction & Infrastructure" | **24 px** out of a 176 px box | **7.7 px** | 0 |
| 640 px | `.footer-col a` "Shareholder & Family Business" | 2 px | 7.7 px | 0 |
| 700 px | `.footer-col a` "Construction & Infrastructure" | 4 px out of a 196 px box | 27.7 px | 0 |
`minimumFontSize=32`, all 22 pages, 12 widths from 320 to 1024 px = 264 rows;
clean at every other width sampled, including 768 and 834 px. **"Infrastructure"
is 14 characters and does not fit a 176 px track at 32 px** — the space in the
label is irrelevant to that.
⚠️ **AND THE 12-WIDTH GRID STEPPED OVER TWO MORE**: round 2 found the same label
at **17 px @660 and 11 px @680**, widths this grid does not sample. That is this
section's own caveat holding — *the grid is 16 columns, not a continuum* — and it
is the second time in one session that a between-columns width mattered.
**A FOURTH CASE OF THE SAME FAMILY, and it should be ruled on together with the
footer label rather than separately.** `minimumFontSize=32`,
`/practice/construction/` @320 px: `nav.crumbs > ol` overruns its own 272 px box
by **7 px**, furthest text edge 302.9 px against a 320 px client width,
`overflow-x: visible`, no clipping, **document overflow 0**. Clean at 360 / 390 /
414 px and on the other five practice pages. **No success criterion fails**, so
like the footer label it is recorded rather than fixed — but if
`.footer-col a { overflow-wrap: anywhere }` is ruled in, the same call covers
`.crumbs` and the ruling should be taken once for both. Raised by
`adversarial-reviewer`, round 2.
**Not fixed here, and the reason is a scope judgement rather than a measurement.**
It produces **no document overflow at any width**, so it fails no success
criterion; `.footer-col a { overflow-wrap: anywhere }` is measured to close it
and to be inert at normal settings. What it would change is how six practice-area
names break on a marketing surface under enlargement, which is a copy-adjacent
call. ⚠️ **The maintenance risk is the real finding: 7.7 px of clearance is one
label rename away from two columns colliding**, and nothing in the build measures
it. Pouya's to rule on; `docs/06` carries it. `word-break: break-all` also
reaches 0 and was declined for the same reason: it breaks where a normal
opportunity exists. **And NOT a `<wbr>` after the `@`**, which would give a
prettier break: it splits a §4-registered fact across an element boundary, so
`info@smlcompany.ca` would no longer be greppable in `dist/` — the surface
`npm run check:claims` reads — and its longest unbreakable run (`smlcompany.ca`,
~224 px) does not fit the 224 px column at 1024 px anyway, so it would need
`anywhere` as a backstop regardless.
**Not header-side, and that survives the fix:** no header element extends the
document at any width under any of the four mechanisms, and the nav items and CTA
are on-screen in **1408 of 1408** measurements. *(This said "946 of 946" for one
revision. 946 is a different sweep — the four runs made with the tautological
skip probe in instrument finding 4 — and reusing it for the final build was the
two-similar-totals mistake this section keeps warning about.)* *(The Practice
dropdown panel's contents overflow their own box by 84 px under minimum font
size and 40 px at the default, on all 22 pages — unchanged by this fix, and it
never extends the document because the panel sits inside a **closed**
`<details>`. Re-checked after the fix rather than carried forward.)*
🛑 **THE MINIMUM-FONT-SIZE STICKY RESIDUAL IS BACK OPEN, AND IT IS NOW A
CONFORMANCE FAILURE RATHER THAN A CONVENIENCE LOSS. IT NEEDS A FRESH RULING —
THE ONE OF 2026-09-01 WAS TAKEN ON TWO FACTS THAT ARE BOTH WRONG.** Pouya ruled
it accepted on the basis *"you proved no CSS mechanism can see
minimum-font-size; the only fix is JS and zero-JS is a founding decision."*
`adversarial-reviewer` attacked both halves of that and both attacks reproduced.
**(1) THE PREMISE IS FALSE.** The proof was of `rem`/`em` and of queries written
in them. The font-metric units `ch`, `ex`, `cap`, `lh` and `rlh` all read the
*used* font size and double under the setting — in property values, in `@media`
and in `@container`. The table at the top of this section carries the
measurement. **A pure-CSS detector for this mechanism exists**, so the residual
is not unfixable and "the only fix is JS" does not hold.
**(2) THE COST WAS UNDERSTATED, AND BY A CATEGORY RATHER THAN A NUMBER.** The
record described it as the skip link landing short — 68174 px of `#main` behind
the header — and argued *"one of the two is a WCAG 1.4.10 failure while the other
degrades the convenience of a skip link that still works."* What is actually
happening is that **ordinary keyboard focus lands entirely behind an opaque
sticky header**, which is **WCAG 2.2 SC 2.4.11 Focus Not Obscured (Minimum),
Level AA** — the same conformance level as the 1.4.10 failure it was traded
against. **So the asymmetry that was the whole argument does not exist: both
sides are AA failures.**
**Measured, and the instrument is checked in three ways.** Shift+Tab walk — the
ordinary way a keyboard user returns to a link they passed — 6 pages × 5 widths
≥ 1056 px, 70 steps per cell, elements inside the header excluded:
| build | mode | focus stops | entirely hidden | zones |
|---|---|---|---|---|
| working tree | default | 1,455 | **0** | — |
| working tree | `minimumFontSize=32` | 1,455 | **290** | 254 footer, **36 `#main`** |
| `fce89d4~1` (pre-header-fix) | `minimumFontSize=32` | 1,455 | **0** | — |
| `fce89d4~1` (pre-header-fix) | default | 1,455 | **0** | — |
⚠️ **THE THIRD ROW IS THE ONE THAT MATTERS: THE HEADER FIX CREATED THIS.** Before
it, `flex-wrap: nowrap` kept the masthead one row under this setting, so it was
short enough that focus landed clear; the overflow went sideways instead. After
it the masthead wraps to 164.58270.56 px and covers the 97 px landing. This is
a **regression introduced by the 2026-09-01 header fix**, not a condition it
inherited — and the ruling to accept it was taken without that comparison
existing.
**Instrument checks, because a focus-obscuring count is easy to fake in both
directions.** *(a)* The default-mode run returns **0**, so the predicate is not
tautological. *(b)* ⚠️ **Geometry alone was WRONG and said 43.** All 43 were the
**skip link**, which is stacked deliberately *above* the header and is not
covered by it at all — so `elementFromPoint` at the focused box's centre is
authoritative and geometry only nominates candidates. Under the setting there
are 333 geometric candidates and **290** survive the hit test. *(c)* Sampled
hits agree 6 of 6, e.g. `/` @1056: focused `a` "Technology, AI & Data" at
97 → 199.4 px inside a header at 0 → 228.6 px, `position: sticky`,
`inset-block-start: 0px`, background `rgb(250, 247, 242)` — opaque cream.
**THE RECOMMENDED FIX IS MEASURED AND DELIBERATELY NOT IMPLEMENTED — Q61.** Two
candidates exist, and the second is better on the exact ground that deferred the
first.
*Candidate A, round 1:* a third gate term `calc((15px - 1ch) * 100000)`,
un-sticking the header under the setting while leaving `inset-block-start: 0px`
at the default. **Deferred:** 15 px is fitted to Geist's `ch`, so it needs
checking under fallback metrics and Chrome's other font presets, and the
reviewer's own injection of it was flaky.
*Candidate B, round 2 — recommended:* `scroll-padding-top`, the property that
already exists for this job, rather than un-sticking anything. Two declarations
in the existing `@media (min-width: 66rem)` block:
```css
html {
scroll-padding-top: calc(var(--header-h) + var(--space-4)); /* fallback: no `lh` */
scroll-padding-top: max(
calc(var(--header-h) + var(--space-4)),
calc(10lh - 83px)
);
}
```
**Verified independently — every value read from `getComputedStyle`, not
reasoned:**
| condition | `1lh` on `<html>` | computed offset | header | verdict |
|---|---|---|---|---|
| default, fonts loaded | 18 px | **97 px — byte-identical to shipped** | 81 px | clears |
| `minimumFontSize=32`, fonts loaded | 37 px | **287 px** | 270.56 px | clears |
| default, **every `.woff2` blocked** | **18 px** | **97 px** | 81 px | clears |
| `minimumFontSize=32`, **`.woff2` blocked** | **37 px** | **287 px** | 270.56 px | clears |
| `minimumFontSize=32`, family Georgia | 36 px | 277 px | 270.56 px | clears |
| `minimumFontSize=32`, family Verdana | 39 px | 307 px | 270.56 px | clears |
⚠️ **Rows 3 and 4 are why B beats A: `1lh` on `<html>` is immune to the webfont
fallback.** `<html>` keeps the UA default family — `--font-sans` is set on
`body`, and `<html>`'s computed `font-family` measures `Times` — so blocking every
font file changes nothing, and the fallback-metrics caveat that deferred
candidate A does not apply to B at all.
**Why B is still not implemented, and none of these is a measurement gap.**
`10lh - 83px` is two fitted constants — the difference from A is that a `max()`
ramp degrades by pixels if they are off, where A's `* 100000` step flips
stickiness the wrong way. **The first declaration is load-bearing:** an engine
without `lh` support drops the whole `max()` as invalid and `scroll-padding-top`
falls back to `var(--space-4)` = 16 px, which is *worse* than today. It needs the
full 1,408-cell sweep plus the fallback-metrics and seven-item cases. The focus
probe behind all of this is **Chrome-only**. And **D19 caps the review at two
rounds**, so a header change made now would ship without review — the precise
failure mode the cap exists to prevent. **The findings are the premise and the
cost; the fix is Pouya's ruling.**
**`docs/06` carries this as an OPEN item again**, restored from the `[x]` this
session had written, and the decision is `AGENTS.md` **Q61**.
⚠️ **AND ONE MORE LATENT CASE, AT THE DEFAULT TEXT SIZE — NO READER SETTING
INVOLVED: FALLBACK FONT METRICS PLUS THE SEVENTH NAV ITEM.** With every `.woff2`
@@ -800,8 +1118,18 @@ Not a polish pass. A build requirement.
here, and deliberately:** the two candidates are raising the desktop breakpoint
past 1091 px, which changes the layout at normal settings in that band, or giving
Geist a metric-matched `size-adjust` fallback, which is a font-stack change well
outside "the header and its consumers". Both are Pouya's call; carried on
`docs/06`.
outside "the header and its consumers".
⚠️ **AND IT IS NOW GATED RATHER THAN MERELY PARKED — Pouya's ruling,
2026-09-01: NO SEVENTH NAV ITEM SHIPS UNTIL THIS IS FIXED.** Fixing it is a
**prerequisite of publishing the second Insights article**, because publishing
article #2 is what adds the item — `SiteHeader` computes `showInsights` from the
collection, so nothing else stands between that editorial decision and both
consequences above. The gate is recorded in three places on purpose: `AGENTS.md`
R20, `docs/06`'s `/insights/` state item, and the comment on `showInsights` in
`SiteHeader.astro` — the last of those being the only one a person editing an
article's front matter is likely to be looking at. The fix itself is *"to be
designed then, not now"*.
**What is still latent, measured and not a defect today:** `.hero-h` has **16
scoped rules, one per page, and only 2 carry `overflow-wrap: anywhere`** (`/` and