scripts/contrast-check.py
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env python3
"""WCAG contrast of the landing's text tokens on its backgrounds, read from global.css.
Body text needs 4.5:1 (anti-slop gate item 25). Exit 1 if any text pair is below it."""
import re, sys, pathlib
css = pathlib.Path(__file__).resolve().parent.parent / "landing/src/styles/global.css"
text = css.read_text()
def block(selector):
m = re.search(re.escape(selector) + r"\s*\{(.*?)\n\}", text, re.S)
return dict(re.findall(r"--([a-z-]+):\s*(#[0-9a-fA-F]{6})", m.group(1)))
def lum(h):
c = [int(h[i:i + 2], 16) / 255 for i in (1, 3, 5)]
c = [x / 12.92 if x <= 0.03928 else ((x + 0.055) / 1.055) ** 2.4 for x in c]
return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]
def ratio(a, b):
hi, lo = sorted((lum(a), lum(b)), reverse=True)
return (hi + 0.05) / (lo + 0.05)
bad = 0
for name, sel in (("dark", ":root"), ("light", ':root[data-theme="light"]')):
t = block(sel)
for fg in ("ink", "muted", "subtle", "indigo-text", "redline-text", "verify"):
if fg not in t:
continue
for bg in ("bg", "surface"):
r = ratio(t[fg], t[bg])
ok = r >= 4.5
bad += not ok
print(f"{name:5} {fg:13} on {bg:8} {t[fg]} {t[bg]} {r:5.2f}:1 {'PASS' if ok else 'FAIL'}")
demo = (css.parent.parent.parent.parent / "examples/demo/index.html").read_text()
for name, sel in (("dark", ":root{"), ("light", ':root[data-theme="light"]{')):
i = demo.index(sel)
t = {k.lower(): v.upper() for k, v in re.findall(r"--([a-z-]+):\s*(#[0-9a-fA-F]{6})", demo[i:demo.index("}", i)])}
if name == "light":
t = {**dark_demo, **t}
else:
dark_demo = t
for fg in ("ink", "muted", "dim"):
for bg in ("bg", "surface"):
r = ratio(t[fg], t[bg])
ok = r >= 4.5
bad += not ok
print(f"demo {name:5} {fg:13} on {bg:8} {t[fg]} {t[bg]} {r:5.2f}:1 {'PASS' if ok else 'FAIL'}")
sys.exit(1 if bad else 0)