fix(theme): #130 the chip moves, not the label; #129 pins the pair so it is checkable
All checks were successful
Check / eval (push) Successful in 3m44s
All checks were successful
Check / eval (push) Successful in 3m44s
Light-theme accent buttons sat at 2.72:1 — under AA and under even the 3:1
large-text floor. Bernardo: fix it. The plan on file ("darken the label")
turned out to be IMPOSSIBLE, and measuring all 24 palettes is what showed
it: on a saturated mid-tone accent nothing clears 4.5 — cream base 2.72,
dark text 1.65. That is why adw-gtk3 ships white-on-accent at ~2.7. The
chip has to move.
The chip is now the accent pulled AWAY from the label: toward white when
the label is dark, toward black when it is cream. One factor (0.70), only
the anchor flips, so "solid accent button + base label" stays the design
and just shifts tone. Worst dark 4.86 (nord/bad), worst light 5.59
(summer-day). The old 0.90 chip failed SEVEN themes (miasma/bad 3.43,
rose-pine 2.70) — never only a light-theme bug, contrary to the item.
#129 rides along, and the two are one idea. #98 shipped an invisible button
with every check green because the background was not a palette role —
adw-gtk3 computed it from currentColor. So the guard is not a CSS lint
(which would flag the harmless generic-button rule and get muted) but
arithmetic: pin both ends and the pair becomes checkable.
check-theme-contrast.py now models GTK's own mix(a,b,f) = a + (b-a)*f —
READ from gtkcsscolorvalue.c:234, not assumed — and asserts base-on-chip
>= 4.5 for all 24 themes. Its negative test reproduces the item's reported
2.72/2.74 exactly from an independent model, which is the best evidence
available that the arithmetic matches the pixels.
Invariant to keep: pin the pair, or pin neither. Both chips are pinned now
(suggested + .default + destructive), where #98 pinned only destructive.
tools/dialog-shot.nix deliberately not built: the checker covers the
numbers, and a VM that only ever confirms arithmetic is maintenance for
nothing. Render if a new widget class appears.
Also sweeps #127 with the latch finding (ff5017e): symptom 2 solved, not
DPMS — which raises the odds the mitigation treats the wrong cause.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,31 @@ let
|
||||
c = t.colors;
|
||||
hex = lib.removePrefix "#";
|
||||
|
||||
# Accent-button chips (#130). The label is the palette's base — dark on a
|
||||
# dark theme, cream on a light one — so the chip has to be pulled AWAY from
|
||||
# the label until the label is legible: toward white when the label is dark,
|
||||
# toward black when it is cream. Same factor both ways; only the anchor
|
||||
# flips, so "solid accent button, base label" stays the design and just
|
||||
# shifts tone.
|
||||
#
|
||||
# Why a nudge at all: on a saturated mid-tone accent NOTHING clears 4.5 —
|
||||
# neither the cream base (summer-day: 2.72) nor the dark text (1.65) — which
|
||||
# is why upstream adw-gtk3 ships white-on-accent at ~2.7 and why "darken the
|
||||
# label" was a dead end. The chip must move.
|
||||
#
|
||||
# 0.70 measured across all 24 palettes (tools/check-theme-contrast.py asserts
|
||||
# it): worst dark 4.86 (nord/bad), worst light 5.59 (summer-day). Today's 0.90
|
||||
# fails seven themes — miasma/bad 3.43, rose-pine 2.70 — so this is not only a
|
||||
# light-theme fix, which is what the item assumed.
|
||||
#
|
||||
# GTK's mix(a, b, f) = a + (b - a) * f (gtkcsscolorvalue.c), i.e. f is the
|
||||
# weight of the SECOND colour: 0.70 = 70% accent, 30% anchor. Read it that way
|
||||
# or the ladder below looks inverted.
|
||||
chipAnchor = if t.mode == "light" then "black" else "white";
|
||||
# Each state pulls further from the label, so contrast only ever improves —
|
||||
# rest is the worst case and the one the check pins.
|
||||
chip = role: f: "mix(${chipAnchor}, ${role}, ${f})";
|
||||
|
||||
# Map the Nomarchy palette onto base16 roles.
|
||||
base16 = {
|
||||
base00 = hex c.base; # default background
|
||||
@@ -116,31 +141,57 @@ in
|
||||
button:disabled, button:disabled label {
|
||||
color: alpha(#${base16.base05}, 0.5);
|
||||
}
|
||||
/* Suggested/destructive sit on pastel accent/bad — dark label
|
||||
is intentional and contrast-checked (7.0:1 suggested, 6.2:1
|
||||
destructive on Boreal). */
|
||||
/* Accent buttons: the palette's base as the label, on a chip
|
||||
pulled away from it (#130 — see `chip` above for the why and
|
||||
the measured numbers).
|
||||
|
||||
BOTH chips are pinned, not just destructive as in #98. Two
|
||||
reasons, and the second is the durable one:
|
||||
1. adw-gtk3 builds the destructive background from
|
||||
currentColor — mix(@destructive_color,
|
||||
alpha(currentColor,…)) — so pinning the label alone drags
|
||||
the background with it and the button renders dark-on-dark
|
||||
(1.03:1, invisible). That is the #98 bug.
|
||||
2. A pinned label on an UNPINNED background is unknowable:
|
||||
no static check can see what it renders on, which is
|
||||
exactly why every check was green while #98 shipped. A
|
||||
pinned pair is arithmetic, and
|
||||
tools/check-theme-contrast.py now asserts it for all 24
|
||||
palettes. The rule for anything added here: pin the pair,
|
||||
or pin neither.
|
||||
|
||||
Enabled only — :disabled keeps the sheet's own chrome and
|
||||
already renders legibly. .default is GTK's dialog default and
|
||||
adw-gtk3 styles it as an accent button, which is why it shares
|
||||
the suggested chip rather than inheriting a plain one. */
|
||||
button.suggested-action, button.suggested-action label,
|
||||
button.destructive-action, button.destructive-action label,
|
||||
button.default, button.default label {
|
||||
color: #${base16.base00};
|
||||
}
|
||||
/* adw-gtk3 builds ONLY the destructive background from
|
||||
currentColor — mix(@destructive_color, alpha(currentColor,…)) —
|
||||
where suggested-action uses an opaque mix(white,@accent_bg…).
|
||||
So pinning the label above drags the background down with it
|
||||
and the button renders dark-on-dark (1.03:1, invisible). Pin
|
||||
the background to the same opaque pastel ladder suggested-action
|
||||
uses. Enabled only: :disabled keeps the sheet's dark chrome and
|
||||
already renders legibly. */
|
||||
button.suggested-action:not(.flat):not(:disabled),
|
||||
button.default:not(.flat):not(:disabled) {
|
||||
background-color: ${chip "@accent_bg_color" "0.70"};
|
||||
}
|
||||
button.suggested-action:not(.flat):not(:disabled):hover,
|
||||
button.default:not(.flat):not(:disabled):hover {
|
||||
background-color: ${chip "@accent_bg_color" "0.65"};
|
||||
}
|
||||
button.suggested-action:not(.flat):not(:disabled):active,
|
||||
button.suggested-action:not(.flat):not(:disabled):checked,
|
||||
button.default:not(.flat):not(:disabled):active,
|
||||
button.default:not(.flat):not(:disabled):checked {
|
||||
background-color: ${chip "@accent_bg_color" "0.55"};
|
||||
}
|
||||
button.destructive-action:not(.flat):not(:disabled) {
|
||||
background-color: mix(white, @destructive_bg_color, 0.9);
|
||||
background-color: ${chip "@destructive_bg_color" "0.70"};
|
||||
}
|
||||
button.destructive-action:not(.flat):not(:disabled):hover {
|
||||
background-color: mix(white, @destructive_bg_color, 0.85);
|
||||
background-color: ${chip "@destructive_bg_color" "0.65"};
|
||||
}
|
||||
button.destructive-action:not(.flat):not(:disabled):active,
|
||||
button.destructive-action:not(.flat):not(:disabled):checked {
|
||||
background-color: mix(white, @destructive_bg_color, 0.7);
|
||||
background-color: ${chip "@destructive_bg_color" "0.55"};
|
||||
}
|
||||
button.suggested-action.flat, button.suggested-action.flat label {
|
||||
color: #${base16.base0D};
|
||||
|
||||
Reference in New Issue
Block a user