fn luminance(c: abstracttui::prelude::Rgba) -> f64 {
let chan = |v: u8| {
let s = v as f64 / 255.0;
if s <= 0.04045 {
s / 12.92
} else {
((s + 0.055) / 1.055).powf(2.4)
}
};
0.2126 * chan(c.r) + 0.7152 * chan(c.g) + 0.0722 * chan(c.b)
}
fn contrast(fg: abstracttui::prelude::Rgba, bg: abstracttui::prelude::Rgba) -> f64 {
let (a, b) = (luminance(fg), luminance(bg));
let (hi, lo) = if a > b { (a, b) } else { (b, a) };
(hi + 0.05) / (lo + 0.05)
}
#[test]
fn splash_animation_endpoints_separate_on_every_theme() {
let mut failures: Vec<String> = Vec::new();
for theme in abstracttui::theme::themes() {
let t = theme.tokens;
let (shimmer_hi, mark_hi) = abstractcode::ui::logo::floored_highlights(&t);
let checks: [(&str, f64, f64); 2] = [
(
"shimmer muted→highlight",
contrast(t.text_muted, shimmer_hi),
1.28,
),
("mark faint→highlight", contrast(t.text_faint, mark_hi), 1.5),
];
for (name, ratio, floor) in checks {
if ratio < floor {
failures.push(format!(
"{}: {name} = {ratio:.2}:1 (floor {floor}:1)",
theme.id
));
}
}
}
assert!(
failures.is_empty(),
"splash animation endpoints below their separation floor:\n{}",
failures.join("\n")
);
}
#[test]
fn chrome_ink_pairs_clear_their_floors_on_every_theme() {
let mut failures: Vec<String> = Vec::new();
for theme in abstracttui::theme::themes() {
let t = theme.tokens;
let checks: [(&str, f64, f64); 4] = [
("text_muted/surface", contrast(t.text_muted, t.surface), 3.0),
("warn/surface", contrast(t.warn, t.surface), 3.0),
("error/surface", contrast(t.error, t.surface), 3.0),
("text/surface", contrast(t.text, t.surface), 4.5),
];
for (name, ratio, floor) in checks {
if ratio < floor {
failures.push(format!(
"{}: {name} = {ratio:.2}:1 (floor {floor}:1)",
theme.id
));
}
}
}
assert!(
failures.is_empty(),
"chrome ink pairs below their contrast floor:\n{}",
failures.join("\n")
);
}