Header: right-align EN|FR toggle in .hdr-in (top-right of page)

One CSS line: .lang-toggle{order:99;margin-left:auto}. Spec's literal order:99 alone
failed its own <=2px right-edge acceptance (gap 45.6-467.6px, 18/24 cases — order
reorders, .hdr-in is left-packed; geo-literal-order99.json), so margin-left:auto on
the toggle absorbs the free space; pill/logo untouched (spec-forbidden zone respected).

Battery: A1 gap=0px + rightmost + nothing-past-left in 24/24 (320/360/390/1280 x EN/FR
x intro/quiz/results); A2 header height unchanged 56/66px; A3 320px no overflow/wrap,
FR logo ellipsis intact, elementFromPoint hit-tests lang buttons + Start over pass;
A4 FR/EN clicks switch lang+title+aria-pressed; A5 24 screenshots before/after; A6
engine 36 + i18n 48 + smoke 92 + ps-pension 70 green; A7 desktop pixdiff header-strip-
only, 0 px below header at every device, self-jitter bit-identical; A8 DEPLOY-OK,
origin marker=1 + byte-identical CSS, off-LAN troublebox 200+marker+rule OFFLAN-OK.
This commit is contained in:
krisf committed 2026-10-09 13:32:40 -04:00
1 parent b209a19ae3
commit 043fa8a683
11 files changed
+20636

No files matched your search

+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
"""Desktop pixel-diff for the header lang-toggle move (spec acceptance 7).
Compares two screenshot dirs (intro/results, EN+FR) and proves the ONLY change is
inside the header strip: the diff bbox must sit entirely above `hdr_bottom` (masked),
and everything below the header must be bit-identical. Prints a self-jitter baseline
DIR_A vs DIR_A2 (same version captured twice) for the jitter-controlled comparison.
Usage: python3 audit/lang_right_pixdiff.py BEFORE AFTER HDR_BOTTOM
python3 audit/lang_right_pixdiff.py SELFJITTER DIR DIR2 HDR_BOTTOM
"""
import os, sys
from PIL import Image, ImageChops
# Usage: pixdiff.py BEFORE AFTER HDR_BOTTOM [PREFIX]
# pixdiff.py SELFJITTER DIR DIR2 HDR_BOTTOM [PREFIX]
if sys.argv[1] == 'SELFJITTER':
cross = False
A, B, HB = sys.argv[2], sys.argv[3], int(sys.argv[4])
PREFIX = sys.argv[5] if len(sys.argv) > 5 else None
else:
cross = True
A, B, HB = sys.argv[1], sys.argv[2], int(sys.argv[3])
PREFIX = sys.argv[4] if len(sys.argv) > 4 else None
fa = sorted(f for f in os.listdir(A) if f.endswith('.png') and (PREFIX is None or f.startswith(PREFIX)))
zero, all_in_hdr = True, True
for f in fa:
p = os.path.join(A, f)
q = os.path.join(B, f)
if not os.path.exists(q):
if cross:
print(f'{f}: MISSING in {B}'); zero = False; all_in_hdr = False
else:
print(f'{f}: (no self-jitter pair, skipping)')
continue
ia, ib = Image.open(p).convert('RGB'), Image.open(q).convert('RGB')
if ia.size != ib.size:
print(f'{f}: SIZE DIFF {ia.size} vs {ib.size}'); zero = False; all_in_hdr = False; continue
W, H = ia.size
d = ImageChops.difference(ia, ib)
bbox = d.getbbox()
if bbox is None:
print(f'{f}: 0 px (identical)'); continue
x0, y0, x1, y1 = bbox
# mask the header strip: crop everything below HB and diff that
below = ImageChops.difference(ia.crop((0, HB, W, H)), ib.crop((0, HB, W, H)))
below_bbox = below.getbbox()
hist = d.convert('L').histogram()
ndiff = sum(hist[1:])
below_hist = below.convert('L').histogram()
ndiff_below = sum(below_hist[1:])
if ndiff_below > 0:
print(f'{f}: {ndiff} px total, {ndiff_below} px BELOW header (bbox {bbox}) <-- LEAK')
zero = False; all_in_hdr = False
else:
tag = 'header-only' if cross else 'identical'
print(f'{f}: {ndiff} px total, 0 px below y={HB}, bbox_top={y0} bbox_bot={y1} [{tag}]')
if not cross:
zero = zero and (ndiff == 0)
print('---')
if cross:
print('PIXDIFF-HEADER-ONLY' if all_in_hdr else 'PIXDIFF-LEAK-BELOW-HEADER')
sys.exit(0 if all_in_hdr else 1)
else:
print('SELFJITTER-ZERO' if zero else 'SELFJITTER-NONZERO')
sys.exit(0 if zero else 1)