detector: text-occlusion + first-viewport-column-overflow (57 -> 59)

Two browser-engine quality rules, both warning severity.

text-occlusion / element-overlap fires on three shapes: an opaque
decorated box painted over a text element (elementFromPoint confirms
real coverage, box >= 30%), one text run buried under another when at
least one side is a positioned layer (text >= 45%, so line-box leading
bleed between stacked flow blocks does not count), and an inline element
whose opaque fill leaks past its line onto a neighbour (the class-name
collision bug). A large headline whose edge overhangs a bounded content
card is caught as an element collision even when the text stays on top.
Gradient scrims, decorative SVG emblems, fixed/sticky overlays, floats,
and raw image backdrops (contrast territory, deduped against the pixel
low-contrast rule) are exempt.

first-viewport-column-overflow fires when a multi-column opening section
runs one column past 140% of the viewport while a sibling fits inside
one screen, the stretched-hero signature. Single-column pages and
full-page heroes with no fitting sibling are exempt.

Validated: fires on the diagnosed repros, clean across a 60-sample
sweep. Fixtures + browser tests added.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-07-15 14:53:03 -07:00
co-authored by Claude Fable 5
parent d8eb4d73c7
commit ed7a6fbe4e
10 changed files with 927 additions and 6 deletions
+14
View File
@@ -1563,6 +1563,20 @@ if (IS_BROWSER) {
addBrowserFindings(groupMap, f.el || document.body, [{ type: f.type, detail: f.detail }]);
}
// Text occlusion / element overlap (browser-only: needs real layout +
// elementFromPoint to confirm what actually paints on top)
const occlusionFindings = checkTextOcclusionDOM().filter(f => _ruleOk(f.type));
for (const f of occlusionFindings) {
addBrowserFindings(groupMap, f.el || document.body, [{ type: f.type, detail: f.detail }]);
}
// First-viewport column overflow — the stretched-hero signature
// (browser-only: needs real layout for the content-extent math)
const colOverflowFindings = checkFirstViewportColumnOverflowDOM().filter(f => _ruleOk(f.type));
for (const f of colOverflowFindings) {
addBrowserFindings(groupMap, f.el || document.body, [{ type: f.type, detail: f.detail }]);
}
// Page-level quality checks (headings, etc.)
const qualityFindings = checkPageQualityDOM().filter(f => _ruleOk(f.type));
if (qualityFindings.length > 0) {