diff --git a/sites/allainallain.de/index.html b/sites/allainallain.de/index.html index 417f35a..22bcbd4 100644 --- a/sites/allainallain.de/index.html +++ b/sites/allainallain.de/index.html @@ -21,8 +21,8 @@ --bg: #1a1d2e; --bg-light: #1e2235; --text: #c8cad7; - --text-dim: #6b6e82; - --text-faint: #3d4056; + --text-dim: #a6aaca; + --text-faint: #8086b5; --ai: #7b8aad; --ai-glow: rgba(123, 138, 173, 0.12); } diff --git a/sites/allaisonme.com/index.html b/sites/allaisonme.com/index.html index 7b1ca54..1c65b28 100644 --- a/sites/allaisonme.com/index.html +++ b/sites/allaisonme.com/index.html @@ -22,7 +22,7 @@ --border: #1e1e26; --text: #f0f0f5; --text-dim: #8a8a99; - --text-muted: #55555f; + --text-muted: #7b7b8a; --gold: #d4af37; --gold-light: #e8c84a; --gold-glow: rgba(212, 175, 55, 0.15); diff --git a/sites/billableaua.de/index.html b/sites/billableaua.de/index.html index f5154e1..372af36 100644 --- a/sites/billableaua.de/index.html +++ b/sites/billableaua.de/index.html @@ -20,8 +20,8 @@ :root { --bg: #0a0a0a; --text: #e8e8e8; - --text-dim: #777; - --text-muted: #444; + --text-dim: #9b9b9b; + --text-muted: #7a7a7a; --red: #cc2222; --red-glow: rgba(204, 34, 34, 0.15); } diff --git a/sites/deinesei.de/index.html b/sites/deinesei.de/index.html index a77d146..7269a7c 100644 --- a/sites/deinesei.de/index.html +++ b/sites/deinesei.de/index.html @@ -16,8 +16,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #6366f1; --accent-glow: rgba(99, 102, 241, 0.2); --accent-subtle: rgba(99, 102, 241, 0.08); diff --git a/sites/fragina.de/index.html b/sites/fragina.de/index.html index 0d31c56..5512281 100644 --- a/sites/fragina.de/index.html +++ b/sites/fragina.de/index.html @@ -17,8 +17,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #a78bfa; --accent-glow: rgba(167, 139, 250, 0.15); --accent-subtle: rgba(167, 139, 250, 0.08); diff --git a/sites/ichbinaufbali.de/index.html b/sites/ichbinaufbali.de/index.html index e62dcfd..10d7fdd 100644 --- a/sites/ichbinaufbali.de/index.html +++ b/sites/ichbinaufbali.de/index.html @@ -13,8 +13,8 @@ :root { --bg: #0a0a0c; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #2dd4a8; --accent-glow: rgba(45, 212, 168, 0.15); } diff --git a/sites/ichbinaufbarley.de/index.html b/sites/ichbinaufbarley.de/index.html index 9a75e7f..4a01324 100644 --- a/sites/ichbinaufbarley.de/index.html +++ b/sites/ichbinaufbarley.de/index.html @@ -16,8 +16,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #d4a843; --accent-glow: rgba(212, 168, 67, 0.15); } diff --git a/sites/ichbinotto.de/index.html b/sites/ichbinotto.de/index.html index e6f2b7c..7cba2c0 100644 --- a/sites/ichbinotto.de/index.html +++ b/sites/ichbinotto.de/index.html @@ -16,8 +16,8 @@ --bg-card: #0e0e1a; --border: #1a1a2e; --text: #e8e8f0; - --text-dim: #7070a0; - --text-muted: #404068; + --text-dim: #9797d8; + --text-muted: #7373bb; --octopus: #e85040; --octopus-glow: rgba(232, 80, 64, 0.2); --octopus-subtle: rgba(232, 80, 64, 0.06); diff --git a/sites/insain.de/index.html b/sites/insain.de/index.html index c986169..de84f32 100644 --- a/sites/insain.de/index.html +++ b/sites/insain.de/index.html @@ -9,7 +9,7 @@ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } :root { - --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #6e6e7a; --text-muted: #44444f; + --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #9a9aab; --text-muted: #7a7a8e; --accent: #e04848; --accent-glow: rgba(224, 72, 72, 0.15); } body { diff --git a/sites/julietensity.de/index.html b/sites/julietensity.de/index.html index de7de06..88fd618 100644 --- a/sites/julietensity.de/index.html +++ b/sites/julietensity.de/index.html @@ -16,7 +16,7 @@ --border: #2a1a3e; --text: #f0e8f8; --text-dim: #8a7a9e; - --text-muted: #4a3d5e; + --text-muted: #8971ae; --pink: #ff2d78; --pink-glow: rgba(255, 45, 120, 0.25); --pink-soft: rgba(255, 45, 120, 0.08); diff --git a/sites/kainco.de/index.html b/sites/kainco.de/index.html index d5149dd..1e46853 100644 --- a/sites/kainco.de/index.html +++ b/sites/kainco.de/index.html @@ -20,7 +20,7 @@ --border-hover: #252830; --text: #e4e5ea; --text-secondary: #9496a1; - --text-muted: #505264; + --text-muted: #787b96; --accent: #2dd4bf; --accent-light: #5eead4; --accent-glow: rgba(45, 212, 191, 0.15); diff --git a/sites/kainefrage.de/index.html b/sites/kainefrage.de/index.html index e4dc9b3..5ff3829 100644 --- a/sites/kainefrage.de/index.html +++ b/sites/kainefrage.de/index.html @@ -22,8 +22,8 @@ --bg-card: #12141b; --border: #1a1d28; --text: #e4e6ed; - --text-dim: #6b7084; - --text-muted: #3d4155; + --text-dim: #969db9; + --text-muted: #71789d; --accent: #06b6d4; --accent-glow: rgba(6, 182, 212, 0.15); --accent-subtle: rgba(6, 182, 212, 0.06); diff --git a/sites/kainstress.de/index.html b/sites/kainstress.de/index.html index 0ffa25c..4718c29 100644 --- a/sites/kainstress.de/index.html +++ b/sites/kainstress.de/index.html @@ -21,8 +21,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #10b981; --accent-glow: rgba(16, 185, 129, 0.15); --accent-subtle: rgba(16, 185, 129, 0.08); diff --git a/sites/keinefreun.de/index.html b/sites/keinefreun.de/index.html index bf958ed..dd2652b 100644 --- a/sites/keinefreun.de/index.html +++ b/sites/keinefreun.de/index.html @@ -19,10 +19,10 @@ --bg-card: #151519; --bg-card-hover: #1a1a20; --text: #e8e6e3; - --text-dim: #7a7880; - --text-dimmer: #4a4850; + --text-dim: #9f9ca6; + --text-dimmer: #7e7a88; --accent: #8b5cf6; - --accent-dim: #6d3fd4; + --accent-dim: #9355ff; --accent-glow: rgba(139, 92, 246, 0.15); --warm: #f59e0b; --border: #222228; diff --git a/sites/kilitaer.de/index.html b/sites/kilitaer.de/index.html index 291ce65..8ed50b6 100644 --- a/sites/kilitaer.de/index.html +++ b/sites/kilitaer.de/index.html @@ -17,8 +17,8 @@ --bg-card: #141a10; --border: #1e2818; --text: #c8d0b8; - --text-dim: #707860; - --text-muted: #404830; + --text-dim: #97a282; + --text-muted: #738256; --olive: #6b8e23; --olive-light: #8fbc3c; --olive-glow: rgba(107, 142, 35, 0.15); diff --git a/sites/killegal.de/index.html b/sites/killegal.de/index.html index 70fd4d7..f2c43d2 100644 --- a/sites/killegal.de/index.html +++ b/sites/killegal.de/index.html @@ -18,7 +18,7 @@ --border: #2a2a1e; --text: #e8e8d8; --text-dim: #808070; - --text-muted: #505040; + --text-muted: #7c7c63; --yellow: #eab308; --yellow-dark: #a17b06; --black: #1a1a14; diff --git a/sites/killionaer.de/index.html b/sites/killionaer.de/index.html index 9d99146..41819ef 100644 --- a/sites/killionaer.de/index.html +++ b/sites/killionaer.de/index.html @@ -18,7 +18,7 @@ --border: #2a2418; --text: #f5f0e0; --text-dim: #a09070; - --text-muted: #605040; + --text-muted: #907860; --gold: #d4a017; --gold-light: #f0c040; --gold-glow: rgba(212, 160, 23, 0.2); diff --git a/sites/killions.de/index.html b/sites/killions.de/index.html index 4cad71c..1322031 100644 --- a/sites/killions.de/index.html +++ b/sites/killions.de/index.html @@ -17,8 +17,8 @@ --bg-card: #12121a; --border: #1a1a28; --text: #e0e0f0; - --text-dim: #7070a0; - --text-muted: #404060; + --text-dim: #9797d8; + --text-muted: #7676b2; --accent: #6366f1; --accent-light: #818cf8; --accent-glow: rgba(99, 102, 241, 0.15); diff --git a/sites/killuminati.de/index.html b/sites/killuminati.de/index.html index 54da33d..316d60f 100644 --- a/sites/killuminati.de/index.html +++ b/sites/killuminati.de/index.html @@ -17,8 +17,8 @@ --bg-card: #0e0e18; --border: #181830; --text: #d0d0e8; - --text-dim: #606088; - --text-muted: #383858; + --text-dim: #9595d3; + --text-muted: #7373b4; --accent: #7c3aed; --accent-light: #a78bfa; --accent-glow: rgba(124, 58, 237, 0.2); diff --git a/sites/killusion.de/index.html b/sites/killusion.de/index.html index 1c51158..b3bcc82 100644 --- a/sites/killusion.de/index.html +++ b/sites/killusion.de/index.html @@ -17,8 +17,8 @@ --bg-card: #121216; --border: #1c1c24; --text: #e0e0e8; - --text-dim: #707080; - --text-muted: #404050; + --text-dim: #9d9db3; + --text-muted: #7a7a98; --pink: #ec4899; --cyan: #06b6d4; --purple: #8b5cf6; diff --git a/sites/kinowhow.de/index.html b/sites/kinowhow.de/index.html index 09746fb..bdf0b78 100644 --- a/sites/kinowhow.de/index.html +++ b/sites/kinowhow.de/index.html @@ -21,8 +21,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #f97316; --accent-glow: rgba(249, 115, 22, 0.15); --accent-subtle: rgba(249, 115, 22, 0.08); diff --git a/sites/knzlmgmt.de/index.html b/sites/knzlmgmt.de/index.html index e8cc7f4..6265236 100644 --- a/sites/knzlmgmt.de/index.html +++ b/sites/knzlmgmt.de/index.html @@ -9,7 +9,7 @@ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } :root { - --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #6e6e7a; --text-muted: #44444f; + --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #9a9aab; --text-muted: #7a7a8e; --accent: #9b7ed8; --accent-glow: rgba(155, 126, 216, 0.15); } body { diff --git a/sites/kopffrai.de/index.html b/sites/kopffrai.de/index.html index c9f5d97..0b194d9 100644 --- a/sites/kopffrai.de/index.html +++ b/sites/kopffrai.de/index.html @@ -9,7 +9,7 @@ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } :root { - --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #6e6e7a; --text-muted: #44444f; + --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #9a9aab; --text-muted: #7a7a8e; --accent: #6b8cce; --accent-glow: rgba(107, 140, 206, 0.15); } body { diff --git a/sites/legalais.de/index.html b/sites/legalais.de/index.html index f6c98a9..5e93f4c 100644 --- a/sites/legalais.de/index.html +++ b/sites/legalais.de/index.html @@ -17,8 +17,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #3b82f6; --accent-glow: rgba(59, 130, 246, 0.15); --accent-subtle: rgba(59, 130, 246, 0.08); diff --git a/sites/mai-otto.de/index.html b/sites/mai-otto.de/index.html index 5df9a65..05cfb80 100644 --- a/sites/mai-otto.de/index.html +++ b/sites/mai-otto.de/index.html @@ -16,8 +16,8 @@ --bg-card: #0e0e1a; --border: #1a1a2e; --text: #e8e8f0; - --text-dim: #7070a0; - --text-muted: #404068; + --text-dim: #9797d8; + --text-muted: #7373bb; --octopus: #e85040; --octopus-glow: rgba(232, 80, 64, 0.2); --octopus-subtle: rgba(232, 80, 64, 0.06); diff --git a/sites/martinsiebels.de/index.html b/sites/martinsiebels.de/index.html index 1cd69e5..3ed1c89 100644 --- a/sites/martinsiebels.de/index.html +++ b/sites/martinsiebels.de/index.html @@ -17,8 +17,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #3b82f6; --accent-glow: rgba(59, 130, 246, 0.15); --accent-subtle: rgba(59, 130, 246, 0.08); diff --git a/sites/orakil.de/index.html b/sites/orakil.de/index.html index 976bce2..5eba299 100644 --- a/sites/orakil.de/index.html +++ b/sites/orakil.de/index.html @@ -23,8 +23,8 @@ --violet-glow: rgba(107, 76, 154, 0.2); --violet-mist: rgba(107, 76, 154, 0.08); --text: #d4cbb8; - --text-dim: #7a7060; - --text-muted: #3d3830; + --text-dim: #a59782; + --text-muted: #837867; } html { scroll-behavior: smooth; } diff --git a/sites/paragraphenraiter.de/index.html b/sites/paragraphenraiter.de/index.html index faefdb7..9471018 100644 --- a/sites/paragraphenraiter.de/index.html +++ b/sites/paragraphenraiter.de/index.html @@ -16,7 +16,7 @@ :root { --gold: #c9a84c; --gold-light: #e8d48b; - --gold-dim: #8a7235; + --gold-dim: #c1a04a; --dark: #0a0a0f; --dark-surface: #12121a; --dark-card: #1a1a26; diff --git a/sites/schulfrai.de/index.html b/sites/schulfrai.de/index.html index e13e185..86ef732 100644 --- a/sites/schulfrai.de/index.html +++ b/sites/schulfrai.de/index.html @@ -9,7 +9,7 @@ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } :root { - --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #6e6e7a; --text-muted: #44444f; + --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #9a9aab; --text-muted: #7a7a8e; --accent: #e8a838; --accent-glow: rgba(232, 168, 56, 0.15); } body { diff --git a/sites/slopschild.de/index.html b/sites/slopschild.de/index.html index 2ac8bc0..3d7455e 100644 --- a/sites/slopschild.de/index.html +++ b/sites/slopschild.de/index.html @@ -21,7 +21,7 @@ --red-glow: #ef4444; --bg: #0a0a0a; --text: #e5e5e5; - --text-dim: #737373; + --text-dim: #9b9b9b; --white: #fafafa; } diff --git a/sites/smartin3.de/index.html b/sites/smartin3.de/index.html index 1da93c2..dd2601b 100644 --- a/sites/smartin3.de/index.html +++ b/sites/smartin3.de/index.html @@ -17,8 +17,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --orange: #f97316; --orange-glow: rgba(249, 115, 22, 0.2); --orange-subtle: rgba(249, 115, 22, 0.08); diff --git a/sites/sorgenfrai.de/index.html b/sites/sorgenfrai.de/index.html index c47388b..5e3ca9e 100644 --- a/sites/sorgenfrai.de/index.html +++ b/sites/sorgenfrai.de/index.html @@ -9,7 +9,7 @@ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } :root { - --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #6e6e7a; --text-muted: #44444f; + --bg: #0a0a0c; --text: #e8e8ed; --text-dim: #9a9aab; --text-muted: #7a7a8e; --accent: #7c9885; --accent-glow: rgba(124, 152, 133, 0.15); } body { diff --git a/sites/vonschraitter.de/index.html b/sites/vonschraitter.de/index.html index d81b5a9..8b16cc0 100644 --- a/sites/vonschraitter.de/index.html +++ b/sites/vonschraitter.de/index.html @@ -21,8 +21,8 @@ --bg-card: #16161b; --border: #1e1e26; --text: #e8e8ed; - --text-dim: #6e6e7a; - --text-muted: #44444f; + --text-dim: #9a9aab; + --text-muted: #7a7a8e; --accent: #c9a84c; --accent-glow: rgba(201, 168, 76, 0.15); --accent-subtle: rgba(201, 168, 76, 0.08); diff --git a/tools/contrast-audit.py b/tools/contrast-audit.py new file mode 100755 index 0000000..67a9eb2 --- /dev/null +++ b/tools/contrast-audit.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +"""Quick contrast audit across all onepager sites. + +Extracts CSS custom properties for backgrounds and text colors, +computes WCAG contrast ratio for likely text-on-bg pairs, flags +violations. +""" +import re +import sys +from pathlib import Path + +SITES_DIR = Path(__file__).resolve().parent.parent / "sites" + +HEX_RE = re.compile(r"#([0-9a-fA-F]{3,8})\b") +VAR_DECL_RE = re.compile(r"--([\w-]+)\s*:\s*([^;]+);") + +def hex_to_rgb(h): + h = h.lstrip("#") + if len(h) == 3: + h = "".join(c * 2 for c in h) + if len(h) == 8: + h = h[:6] + if len(h) != 6: + return None + try: + return tuple(int(h[i:i+2], 16) for i in (0, 2, 4)) + except ValueError: + return None + +def relative_luminance(rgb): + def channel(c): + c /= 255 + return c / 12.92 if c <= 0.03928 else ((c + 0.055) / 1.055) ** 2.4 + r, g, b = (channel(c) for c in rgb) + return 0.2126 * r + 0.7152 * g + 0.0722 * b + +def contrast_ratio(rgb1, rgb2): + l1 = relative_luminance(rgb1) + l2 = relative_luminance(rgb2) + lighter, darker = max(l1, l2), min(l1, l2) + return (lighter + 0.05) / (darker + 0.05) + +# Variable names that suggest "background" or "text" +BG_KEYS = ("bg", "background", "surface") +TEXT_KEYS = ("text", "fg", "foreground", "color", "muted", "dim", "subtle", "secondary") + +def is_bg_var(name): + n = name.lower() + return any(k in n for k in BG_KEYS) and "border" not in n + +def is_text_var(name): + n = name.lower() + return any(k in n for k in TEXT_KEYS) and "border" not in n and "bg" not in n.split("-")[0] + +def audit(site): + html = (SITES_DIR / site / "index.html") + if not html.exists(): + return None + css = html.read_text(errors="ignore") + # Only look at the ", css, re.DOTALL | re.IGNORECASE) + if not style_blocks: + return None + css_only = "\n".join(style_blocks) + + vars_ = {} + for m in VAR_DECL_RE.finditer(css_only): + name, val = m.group(1), m.group(2).strip() + # only resolve to hex + hm = HEX_RE.search(val) + if hm: + rgb = hex_to_rgb(hm.group(0)) + if rgb: + vars_[name] = rgb + + bg_vars = {n: c for n, c in vars_.items() if is_bg_var(n)} + text_vars = {n: c for n, c in vars_.items() if is_text_var(n)} + + if not bg_vars or not text_vars: + return None + + # Find primary bg (the darkest one is usually --bg) + primary_bg_name = min(bg_vars, key=lambda n: relative_luminance(bg_vars[n])) + bg_rgb = bg_vars[primary_bg_name] + bg_lum = relative_luminance(bg_rgb) + + # Only audit dark backgrounds (lum < 0.05 = near-black) + if bg_lum > 0.1: + return None # not a dark site + + findings = [] + for tname, trgb in text_vars.items(): + ratio = contrast_ratio(trgb, bg_rgb) + if ratio < 4.5: # WCAG AA for body text + findings.append((tname, trgb, ratio)) + + if not findings: + return None + return { + "site": site, + "bg_name": primary_bg_name, + "bg_rgb": bg_rgb, + "findings": findings, + } + +results = [] +for site in sorted(p.name for p in SITES_DIR.iterdir() if p.is_dir()): + r = audit(site) + if r: + results.append(r) + +print(f"Sites with sub-AA text on dark bg: {len(results)}/59\n") +for r in results: + bg = r["bg_rgb"] + print(f"{r['site']} (bg --{r['bg_name']} = #{bg[0]:02x}{bg[1]:02x}{bg[2]:02x})") + for name, rgb, ratio in sorted(r["findings"], key=lambda x: x[2]): + flag = "FAIL" if ratio < 3.0 else ("WEAK" if ratio < 4.5 else "OK") + print(f" {flag:4} ratio {ratio:5.2f} --{name:24} #{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}") + print() + +# Summary: how many distinct sites have FAIL (< 3.0) somewhere +fails = [r for r in results if any(ratio < 3.0 for _, _, ratio in r["findings"])] +print(f"\n=== SUMMARY ===") +print(f"Dark-bg sites with at least one FAIL (<3:1): {len(fails)}") +print(f"Dark-bg sites with WEAK (<4.5 but >=3): {len(results) - len(fails)}")