mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-14 15:16:35 +03:00
Three new rules and three widenings, all from confirmed eval-corpus
escapes found by eye:
script-error (quality, error severity, URL engine): pageerror listener
attached before goto catches uncaught exceptions AND parse errors (a
syntax error fires during the initial parse, long before load). Deduped
by message, capped at 3. A JS typo was silently deleting whole pages.
content-hidden-at-rest (quality, error, URL engine): after the main
at-rest scan, an instant-scroll reveal sweep (bypasses scroll-behavior:
smooth, which silently defeated the first sweep design) gives every
IntersectionObserver reveal its chance to fire, returns to top, then
measures the share of text characters still at opacity 0 / visibility
hidden. display:none / [hidden] / aria-hidden subtrees stay out of the
denominator. Fires above 30% with a 200/150-char floor. Calibration on
30 corpus samples: broken repro holds 83% after the sweep, all clean
samples (including 0.75-0.93 at-rest reveal pages) drop to <= 7%.
edge-flush-cards (quality, warning, browser): cards with their own
opaque background or 2+ borders inside a horizontal scroller, flush
against one edge of the clip box at rest (< 8px, > -24px so deliberate
mid-card peeks stay exempt) while keeping a gutter on the other side.
Grouped per scroller. Repro: transit-mobile pager whose first snap
panel is 407px wide inside a 390px clip. New --viewport WxH CLI flag
makes mobile-width URL scans reachable (--viewport 390x844).
Chip/badge contrast widening: the SAFE_TAGS styled-button exception in
checkColors now covers any text-bearing element painting its own opaque
background at >= 9px font, not just a/button. The shipped miss: a span
SEV-2 chip whose white text lost a specificity fight and rendered
muted-on-red at 1.2:1. Static adapter also resolves var() own-bg via
the custom-property map so the gate engages on token backgrounds.
background:none cascade fix: the background shorthand now resets
background-color/-image when it names neither (and no var()). Exposed
by the chip widening: pre code { background: none } left an earlier
surface color standing and manufactured 1.1:1 phantom findings.
text-overflow inline-owner widening: inline elements have no client
geometry (clientWidth 0) so the scrollWidth path never saw them, and
their block parent owns no direct text. New branch measures the inline
rect against the nearest block container's padding box (16px floor,
transform-path exempt). Repro: nowrap span.v spilling 45px past its
grid cell.
The round-3 nav-CTA contrast escape (val-a22-opus obs 003 header CTA)
was verified already covered at HEAD by the earlier parseAnyColor
oklch fallback; both engines fire 3.6:1 on the repro, no change needed.
FP sweep across 36 val-a21/a22/a23 samples: new rules fire only on
their repros (script-error also catches a second genuinely broken
sample); static-engine delta is limited to the chip repro plus two
borderline-but-real chip findings on one sample.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
68 lines
3.0 KiB
HTML
68 lines
3.0 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>Edge-flush cards fixture (browser-only)</title>
|
|
<style>
|
|
body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; background: #f2f2f4; }
|
|
h2 { padding: 16px 24px 0; font-size: 16px; }
|
|
.scroller { width: 600px; margin: 8px 24px 24px; overflow-x: auto; display: flex; scroll-snap-type: x mandatory; background: #e4e4e8; }
|
|
.panel { flex: 0 0 auto; scroll-snap-align: start; }
|
|
.card { background: #fff; border-radius: 10px; height: 90px; padding: 12px; box-sizing: border-box; margin-bottom: 12px; }
|
|
.plain { height: 90px; padding: 12px; box-sizing: border-box; }
|
|
|
|
/* FLAG: first panel is wider than the scroller's clip box, so its cards
|
|
keep a 16px left gutter but end 4px past the right clip edge. */
|
|
.flag-pager .panel-wide { width: 620px; }
|
|
.flag-pager .panel-wide .card { margin-left: 16px; width: 588px; }
|
|
.flag-pager .panel-ok { width: 600px; }
|
|
.flag-pager .panel-ok .card { margin-left: 16px; width: 568px; }
|
|
|
|
/* PASS: every panel keeps a symmetric inset. */
|
|
.pass-even .panel { width: 600px; }
|
|
.pass-even .card { margin-left: 16px; width: 568px; }
|
|
|
|
/* PASS: deliberate peek carousel; the third card is cut mid-card, far
|
|
past the clip edge, which reads as an affordance rather than a bug. */
|
|
.pass-peek { gap: 12px; padding: 12px 0 12px 16px; }
|
|
.pass-peek .card { flex: 0 0 auto; width: 260px; margin: 0; }
|
|
|
|
/* PASS: flush children without card styling are plain content, not cards. */
|
|
.pass-plain .panel { width: 620px; }
|
|
.pass-plain .plain { margin-left: 16px; width: 588px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h2>Flag: first panel wider than its clip box</h2>
|
|
<div class="scroller flag-pager">
|
|
<div class="panel panel-wide">
|
|
<div class="card">Card cut off at the right clip edge while keeping its left gutter.</div>
|
|
<div class="card">Second card in the oversized panel, also flush against the edge.</div>
|
|
</div>
|
|
<div class="panel panel-ok">
|
|
<div class="card">Sibling panel card with the intended inset on both sides.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Pass: symmetric insets</h2>
|
|
<div class="scroller pass-even">
|
|
<div class="panel"><div class="card">Card with an even gutter on both sides of the clip box.</div></div>
|
|
<div class="panel"><div class="card">Second panel card, also properly inset.</div></div>
|
|
</div>
|
|
|
|
<h2>Pass: deliberate peek</h2>
|
|
<div class="scroller pass-peek">
|
|
<div class="card">First peek card fully visible.</div>
|
|
<div class="card">Second peek card fully visible.</div>
|
|
<div class="card">Third card cut mid-card as a scroll affordance.</div>
|
|
<div class="card">Fourth card entirely off-screen.</div>
|
|
</div>
|
|
|
|
<h2>Pass: plain content, not cards</h2>
|
|
<div class="scroller pass-plain">
|
|
<div class="panel"><div class="plain">Unstyled text block flush against the edge is not a card.</div></div>
|
|
<div class="panel"><div class="plain">Second plain block.</div></div>
|
|
</div>
|
|
</body>
|
|
</html>
|