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:
co-authored by
Claude Opus 5
parent
fce89d46eb
commit
ca1c2524e1
+387
-59
@@ -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 9–15, roots 16–32, 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.58–270.56 px | 97 px | **68–174 px** | live, unfixable in CSS |
|
||||
| fallback font metrics + 7th nav item, **default** text size, 1056–1091 px | 141 px | 97 px | **44 px** | latent on `showInsights` |
|
||||
| `minimumFontSize=32` | 164.58–270.56 px | 97 px | **68–174 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, 1056–1091 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 4–6 are from the
|
||||
2026-09-01 header pass and all three produced a CLEAN-LOOKING result; 7–10 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 224–243 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
|
||||
1024–1100 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.58–270.56 px** and the skip link lands with **68–174 px of `#main` behind
|
||||
it**, on 22 of 22 pages from 1056 px up. It was **10–26 px before**, so this pass
|
||||
widened it. *(These read "228–271 px" and "132–174 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 1024–1100 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 1024–1100 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 — 68–174 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.58–270.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
|
||||
|
||||
+123
-24
@@ -364,6 +364,32 @@ Then invalidate `/*`.
|
||||
|
||||
## Cutover checklist — D11 is a single shot, so run all of it
|
||||
|
||||
**Cutover prep — deferred maintenance, done BEFORE the checklist below**
|
||||
|
||||
This group exists because deferring a thing and forgetting it look identical
|
||||
three weeks later. Each item carries the date it was deferred and the reason, so
|
||||
the decision is re-readable rather than re-litigated.
|
||||
|
||||
- [ ] ⚠️ **TWO DEPENDENCY MAJORS ARE ONE BEHIND, DEFERRED 2026-09-01 BY RULING.**
|
||||
`@astrojs/mdx` **^7.0.8 → 8.0.0** and `typescript` **^6.0.3 → 7.0.2**.
|
||||
Pouya's reasoning: *"npm audit is clean and majors mid-walkthrough add churn
|
||||
without user value."* `npm audit` reports **0 vulnerabilities**
|
||||
`[verified 2026-09-01]`, so this is a churn decision and not a security one —
|
||||
and it would become a security decision the moment that stops being true.
|
||||
**Take both majors here, before cutover, and read the changelogs rather than
|
||||
the version numbers**: an MDX major can change how `docs/03`'s copy renders,
|
||||
and a TypeScript major can change what `astro check` accepts, which is a
|
||||
gate on both deploy paths. **`AGENTS.md` R11 keeps firing at every phase
|
||||
boundary as designed** — this item is the deferral, not a replacement for the
|
||||
reminder, and R11 is what will raise the next pin that drifts.
|
||||
**The sweep behind this item, `npm view <pkg> version` across all 19 pins
|
||||
`[verified 2026-09-01]`:** those two are the only majors behind. Four are a
|
||||
minor or patch behind and are already satisfied by their own carets, so they
|
||||
need no edit — `astro` 7.2.9 → **7.2.10**, `@astrojs/sitemap` 3.7.3 → 3.7.4,
|
||||
`globals` 17.11.0 → 17.12.0, `typescript-eslint` 8.68.0 → 8.69.0. The
|
||||
remaining 13 are current. Re-run the sweep here rather than trusting this
|
||||
list: it is dated for that reason
|
||||
|
||||
**Content and compliance**
|
||||
|
||||
> ⚠️ **THE FIRST TWO ITEMS ARE THE PROJECT'S ONLY FULL CLAIMS PASS — D20, Pouya,
|
||||
@@ -425,6 +451,15 @@ Then invalidate `/*`.
|
||||
- [ ] `/fees/` carries the rates confirmed in D14 and `docs/07-fees.md`, or the page does not ship. **And the reservation sentence sits adjacent to the overtime row** — Q59, ruled 2026-08-31: a reader who takes the $500 and skips *"a full day reserves the day; half-day overtime is subject to availability"* has read a different offer, and the arithmetic then makes the full-day rate look strictly worse
|
||||
- [ ] Privacy policy matches the backend as actually built. **Three of its statements are derived and cannot drift** — the collected-data list from `INTAKE_FIELDS`, the retention period from the handler's own figure, the analytics paragraph from `ANALYTICS.installed`. **If analytics are installed, that flag flips and the policy's last-updated date moves on the same build**; a policy naming a processor that processes nothing is a false disclosure
|
||||
- [ ] **`/insights/` — check which state it is in.** While no article is published the page emits `noindex` (derived from the collection) and `SiteHeader` keeps Insights out of the primary nav until **two** are live. Both clear themselves on publication. D9 means the flip is Pouya's: `src/content.config.ts` refuses `draft: false` without `reviewedByPouya: true`
|
||||
- [ ] ⚠️ **AND PUBLISHING THE SECOND ARTICLE IS GATED — `AGENTS.md` R20, ruled
|
||||
2026-09-01.** The flip that makes `/insights/` indexable is the same flip that
|
||||
adds the **seventh nav item**, and with seven items under fallback font
|
||||
metrics the masthead measures 141 px across 1056–1091 px: a 60 px layout shift
|
||||
on every page and 44 px of `#main` behind the sticky header after the skip
|
||||
link, both at the **default** text size. **No seventh nav item ships until
|
||||
that is fixed**, so the fix is a prerequisite of article #2 — not a follow-up
|
||||
to it. The measurements and the two candidate fixes are on the
|
||||
seventh-nav-item item under **Technical** below
|
||||
- [ ] **The five drafted articles are `draft: true` and therefore invisible to `check:claims`**, which reads `dist/`. They were checked once, on 2026-08-31, by temporarily publishing all five and running it — clean on 27 pages. **Re-run it that way before any of them publishes**, because a draft that changes in between is unchecked
|
||||
|
||||
**Technical**
|
||||
@@ -560,29 +595,77 @@ Then invalidate `/*`.
|
||||
roots 9–15 (70), roots 16–32 (300), the band seam (198), both thresholds
|
||||
(144) and all five default-font-size presets (50). Both findings by
|
||||
`adversarial-reviewer`; `docs/02` §Reflow carries all of it
|
||||
- [ ] ⚠️ **TWO REFLOW RESIDUALS SURVIVE, BOTH UNDER CHROME'S MINIMUM-FONT-SIZE
|
||||
SETTING ONLY, AND BOTH NEED A RULING RATHER THAN A RE-MEASUREMENT.**
|
||||
*(a) The footer, and it is OUT OF the scope Pouya set for the header step.*
|
||||
Document overflow of **14 px at 320, 38 px at 1024, 30 px at 1056 and 19 px
|
||||
at 1100 CSS px**, on all 22 pages, 0 from 1200 px up. Cause:
|
||||
`info@smlcompany.ca` has no break opportunity and needs 310 px inside a
|
||||
224–243 px footer-contact column; at 320 px the `.footer-col` box itself is
|
||||
310 px in a 272 px content area. **Pre-existing: the footer's OWN overflow is
|
||||
byte-identical before and after** (`div.footer-grid` 78 px at 1056, 67 px at
|
||||
1100). The 1056/1100 *document* figures did change, 414 → 30 and 370 → 19,
|
||||
because the header stopped contributing its own — a document figure and a
|
||||
footer contribution are different measurements.
|
||||
*(b) The skip link, and it CANNOT be fixed in CSS.* The header stays sticky
|
||||
at **164.58–270.56 px** under that setting, so "Skip to content" lands with
|
||||
**68–174 px of `#main` behind the header** on 22 of 22 pages from 1056 px
|
||||
up — it was 10–26 px before, so the header fix widened it, deliberately, to
|
||||
buy the removal of 830 px of horizontal overflow with four nav items and the
|
||||
CTA unreachable. **Nothing in CSS can detect that mechanism**: media queries,
|
||||
container queries AND length units all keep resolving `rem`/`em` at 16 px
|
||||
while `getComputedStyle` reports 32 px (measured; `docs/02` §Reflow). The
|
||||
remaining candidates are a fitted constant tied to the nav item count, or a
|
||||
behaviour change at normal settings. **Ticked by Pouya fixing (a) and ruling
|
||||
on (b) — not by re-measuring with a method that reports zero**
|
||||
- [x] ✅ **THE FOOTER REFLOW RESIDUAL IS FIXED, 2026-09-01.** Document overflow of
|
||||
**14 px at 320, 38 px at 1024, 30 px at 1056 and 19 px at 1100 CSS px** on all
|
||||
22 pages under Chrome's minimum-font-size setting, 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**. One declaration closes it —
|
||||
`.footer-contact a[href^='mailto:'] { overflow-wrap: anywhere }` — measured
|
||||
**88 of 352 → 0 of 352**, the other three enlargement methods unchanged at 0
|
||||
of 352, and the normal-settings identity check at **0 differences on 352
|
||||
page-widths across 8 metrics**. It also closed **57 cases of the link
|
||||
overrunning its own box** at root style 26–32 px that the document-level
|
||||
table reports as clean. ⚠️ **The earlier note here said the 320 px half "is a
|
||||
column-sizing question and is not the same fix" — that was wrong**; the
|
||||
column sizing at 320 px *is* that same 310 px min-content, arriving through
|
||||
`.footer-grid`'s `auto` track instead of through text spilling out of a
|
||||
`minmax(0, 1fr)` one. `docs/02` §Reflow carries both mechanisms, the negative
|
||||
control proving `break-word` would not have worked, and the candidates
|
||||
declined as broader than the cause
|
||||
|
||||
- [ ] 🛑 **THE MINIMUM-FONT-SIZE STICKY RESIDUAL — REOPENED THE SAME DAY IT WAS
|
||||
TICKED, AND IT IS A WCAG 2.2 SC 2.4.11 (AA) FAILURE RATHER THAN THE
|
||||
SKIP-LINK INCONVENIENCE IT WAS ACCEPTED AS. NEEDS A FRESH RULING.**
|
||||
It was ruled accepted on 2026-09-01 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"*, and this checklist item was ticked accordingly. Both
|
||||
supporting facts are wrong, and `adversarial-reviewer` found it the same day.
|
||||
**(1) The premise.** The proof covered `rem`/`em` and queries written in them.
|
||||
The font-metric units **`ch`, `ex`, `cap`, `lh`, `rlh`** read the *used* font
|
||||
size and double under the setting — in property values, in `@media` **and** in
|
||||
`@container`. A pure-CSS detector exists, so "the only fix is JS" does not
|
||||
hold. **(2) The cost.** Not a short skip-link landing but **ordinary keyboard
|
||||
focus landing entirely behind an opaque sticky header**: a Shift+Tab walk over
|
||||
6 pages × 5 widths ≥ 1056 px gives **290 entirely-hidden focus stops of 1,455**
|
||||
under the setting — **254 in the footer and 36 inside `#main`** — against **0**
|
||||
at the default size. Hit-tested with `elementFromPoint`, not inferred from
|
||||
geometry: geometry alone said 43 at the default size and all 43 were the skip
|
||||
link, which is stacked *above* the header on purpose. **(3) And the header fix
|
||||
created it:** a build of `fce89d4~1` measures **0** under the same setting,
|
||||
because `flex-wrap: nowrap` kept the masthead one row and short. So the trade
|
||||
was **830 px of horizontal overflow (SC 1.4.10) for 290 obscured focus stops
|
||||
(SC 2.4.11)** — both Level AA, and the asymmetry that was the whole argument
|
||||
does not exist. **A candidate fix is measured but deliberately not
|
||||
implemented:** a third gate term in the shipping idiom, `calc((15px - 1ch) *
|
||||
100000)`, un-sticks the header under the setting and leaves
|
||||
`inset-block-start: 0px` at the default — but 15 px is fitted to Geist's `ch`
|
||||
and needs checking under fallback metrics and Chrome's other font presets.
|
||||
**This item is ticked only by a ruling from Pouya, not by a re-measurement.**
|
||||
The decision is `AGENTS.md` **Q61**; `docs/02` §Reflow carries the measurements
|
||||
|
||||
- [ ] ⚠️ **A FOOTER NAV LABEL OVERRUNS ITS COLUMN BY 24 px AT 640 px UNDER
|
||||
MINIMUM FONT SIZE, WITH 7.7 px OF CLEARANCE TO THE NEXT COLUMN.** No document
|
||||
overflow at any width, so it fails no success criterion and is cosmetic
|
||||
today — filed because **7.7 px is one label rename away from two columns
|
||||
colliding**, and nothing in the build measures it. `.footer-col a`
|
||||
"Construction & Infrastructure" overruns its 176 px box by **24 px** at
|
||||
640 px and by 4 px at 700 px (clearance 27.7 px); "Shareholder & Family
|
||||
Business" by 2 px at 640 px, and — at widths that 12-column grid steps over —
|
||||
**17 px at 660 px and 11 px at 680 px**. Clean at every other width sampled,
|
||||
including 768 and 834 px; `minimumFontSize=32`, 22 pages × 12 widths = 264
|
||||
rows. **A fourth case of the same family: `nav.crumbs > ol` on
|
||||
`/practice/construction/` @320 px overruns its own 272 px box by 7 px**, also
|
||||
with zero document overflow. **Rule on both together** — if
|
||||
`.footer-col a { overflow-wrap: anywhere }` is ruled in, the same call covers
|
||||
`.crumbs`; if it is declined, decline both and the record is complete.
|
||||
**`.footer-col a { overflow-wrap: anywhere }` is measured to close it and to
|
||||
be inert at normal settings**, and is not applied because it changes how six
|
||||
practice-area names break on a marketing surface under enlargement — a
|
||||
copy-adjacent call, not a technical one. ⚠️ **And it falsified the reason
|
||||
given for scoping the email fix to the address** (*"every other footer string
|
||||
has spaces"*): min-content is set by the longest **word**, not by whether a
|
||||
space exists. Corrected in `docs/02` §Reflow. Raised by
|
||||
`adversarial-reviewer`, 2026-09-01
|
||||
|
||||
- [ ] ⚠️ **THE SEVENTH NAV ITEM PLUS FALLBACK FONT METRICS — A LAYOUT SHIFT *AND*
|
||||
A SKIP-LINK FAILURE, AT THE DEFAULT TEXT SIZE, ARMING ITSELF WHEN THE SECOND
|
||||
@@ -602,7 +685,23 @@ Then invalidate `/*`.
|
||||
because both are outside "the header and its consumers": raise the desktop
|
||||
breakpoint past 1091 px, which changes the normal-settings layout in that
|
||||
band, or give Geist a metric-matched `size-adjust` fallback. Raised by
|
||||
`adversarial-reviewer`, 2026-09-01; `docs/02` §Reflow carries the measurements
|
||||
`adversarial-reviewer`, 2026-09-01; `docs/02` §Reflow carries the measurements.
|
||||
|
||||
⚠️ **THIS IS NOT A CUTOVER BLOCKER AND IT IS NOT TICKABLE HERE — IT IS A HARD
|
||||
PRE-PUBLICATION GATE. Pouya's ruling, 2026-09-01: no seventh nav item ships
|
||||
until the fallback-metrics defect is fixed**, which makes fixing it a
|
||||
**prerequisite of publishing the second Insights article**, since that is what
|
||||
adds the item. It is left unchecked on purpose: a checklist that fires once, at
|
||||
cutover, cannot discharge a defect that arms itself later on an editorial
|
||||
decision. ⚠️ **AND THE GATE IS A BUILD FAILURE, NOT THIS CHECKLIST AND NOT A
|
||||
COMMENT.** `SiteHeader.astro` throws when `published.length >= 2`, with the
|
||||
measurements and the instruction in the message, so it fires on both deploy
|
||||
paths on the machine of whoever publishes. **Proven rather than assumed:** two
|
||||
articles were temporarily flipped to `draft: false` and `npm run build` exited
|
||||
**1** naming R20; the files were restored and the restoration verified by
|
||||
`git diff --exit-code` and an unchanged `dist` digest. It was first written as
|
||||
three prose cross-references and **did not gate** — the build and all five
|
||||
checks passed while both defects shipped. **Owner: `AGENTS.md` R20**
|
||||
|
||||
**Infrastructure**
|
||||
- [ ] S3 versioning enabled
|
||||
|
||||
Reference in New Issue
Block a user