fix(theme): destructive buttons were invisible after #98 (1.03:1)
All checks were successful
Check / eval (push) Successful in 3m54s

e9dd3d1 pinned dialog button labels to base00 for dark palettes. That is
correct for suggested-action, whose background adw-gtk3 builds opaquely as
mix(white,@accent_bg_color,0.9) — but destructive-action is the one class
whose background is derived from currentColor:

  background-color: mix(@destructive_color, alpha(currentColor, 0.15), 0.9)

so pinning the label dragged the background down with it. On Boreal the
"Delete" button of a GtkMessageDialog rendered #21272F on #252931 —
1.03:1, invisible — and light palettes hit the same 1.03:1. The most
safety-critical button in a confirmation dialog was the one that vanished.

Pin the destructive background to the same opaque pastel ladder
suggested-action uses. Enabled-only (:not(.flat):not(:disabled)): the
sheet's disabled chrome already renders legibly and must keep it.

Boreal 1.03 -> 6.19:1, summer-day 1.03 -> 2.74:1 (= upstream's
white-on-accent convention; the residual light-mode weakness is #130).

V2: GtkMessageDialog rendered under the real HM session and viewed —
boreal before/after, summer-night (whole-swap), summer-day (light).
Scripted checks stayed green throughout and never saw this; only the
render did. Follow-ups #129 (permanent guard) and #130 filed.
This commit is contained in:
2026-07-15 16:56:39 +01:00
parent 060bf524af
commit b4fe4985bf
4 changed files with 74 additions and 1 deletions

View File

@@ -73,6 +73,29 @@ DPMS-while-docked) deferred to the LATER revisit.
## NEXT
### 129. Permanent guard for the GTK button-colour trap (#98 follow-up)
The #98 regression (destructive-action at 1.03:1, invisible) was caught only
by rendering a dialog — every scripted check was green, because the bug lives
in adw-gtk3's `mix(@destructive_color, alpha(currentColor,…))` background, not
in our CSS. `tools/theme-shot.nix` is deliberately not a CI gate (full-desktop
VM), so add the cheap static half: assert that for every theme, any rule that
pins a button label colour also pins that button's `background-color` — i.e.
no pinned label may sit on a `currentColor`-derived background. Guards the
class, not the instance. The scratch render harness that found it is worth
promoting to `tools/dialog-shot.nix` as a maintainer tool alongside theme-shot.
### 130. GTK accent buttons sit at ~2.7:1 in light themes
Fallout noted while fixing #98: in light palettes the suggested/destructive
labels are base00 (cream) on saturated accent/bad — summer-day measures
**2.72:1** (suggested) and **2.74:1** (destructive), under AA 4.5 and even
under the 3:1 large-text floor. Not a regression: upstream adw-gtk3 does the
same (`color: white` on the accent), so we currently match GNOME. Decide
whether Nomarchy holds itself higher — darker label, or a darker accent mix
for light palettes — and note `tools/check-theme-contrast.py` covers palette
pairings only, never GTK widget surfaces. `[human]` for the aesthetic call.
### 120. A netinstall ISO, next to the fat offline one
Bernardo 2026-07-14, after seeing the measured size: **keep the current ISO

View File

@@ -19,6 +19,27 @@ Template:
---
## 2026-07-15 — #98 follow-up: destructive buttons invisible (V2 sweep)
- **Task:** QA sweep of today's ship — V2 the batch that stopped at V1.
- **Did:** Rendered a real GTK3 GtkMessageDialog under the actual HM session
(scratch harness off `tools/theme-shot.nix`). Found e9dd3d1 **regressed
`destructive-action`**: adw-gtk3 derives ONLY the destructive background
from `currentColor` (`mix(@destructive_color, alpha(currentColor,…))`),
so pinning the label to base00 dragged the background dark too — "Delete"
rendered at **1.03:1** (invisible) on Boreal, and in light themes as well.
Fix: pin the destructive background to suggested-action's opaque pastel
ladder, enabled-only (`:not(.flat):not(:disabled)`).
- **Verified:** **V2** — boreal before/after, summer-night (whole-swap) and
summer-day (light) renders viewed; destructive 1.03→6.19:1 (boreal),
1.03→2.74:1 (summer-day, = upstream's white-on-accent convention).
`nix flake check --no-build` + check-theme-contrast green. Screenshots:
`scratchpad/v2-98/boreal-{BEFORE,AFTER}-zoom.png`, `sn-zoom.png`, `sd-zoom.png`.
Two CSS-derived hypotheses (`.default`, disabled suggested/destructive)
did NOT reproduce — rendering overruled the theory, both left alone.
- **Pending:** filed the permanent guard + light-mode ~2.7:1 button contrast
as BACKLOG items. #111/#105/#110 menu IA and #107 rename are still V1.
- **Next suggestion:** V2 the menu IA (#111/#105/#110), or human V3 #115/#127.
## 2026-07-15 — #127 skip DPMS-off when docked (mitigation)
- **Task:** Bernardo: no usable TTY on brick; prefer prevent over dump.
- **Did:** hypridle 10m listener skips `dpms off` when an internal

View File

@@ -432,6 +432,16 @@ Design/decision records and a running log of shipped work (items marked
sheet hardcodes near-black button text → black-on-dark in GTK dialogs
(Boreal). Fix: force `adw-gtk3-dark` / `adw-gtk3` from palette mode,
prefer-dark, and pin dialog button colours in Stylix extraCss.
**Follow-up (same day):** pinning the label colour silently broke
`destructive-action` — adw-gtk3 derives only *that* background from
`currentColor` (`mix(@destructive_color, alpha(currentColor,…))`, where
suggested-action uses an opaque `mix(white,@accent_bg,…)`), so the dark
label dragged the background dark with it: "Delete" at 1.03:1, invisible,
in both polarities. Destructive backgrounds are now pinned to the same
opaque pastel ladder (enabled-only). V2: dialog rendered under boreal,
summer-night and summer-day. Lesson: a config-level assertion
("settings.ini says adw-gtk3-dark") cannot see a colour bug — only a
render can.
- ✓ **Suspend-then-hibernate (#115):** human decision — **1h** delay, **battery
only**, Preferences enable/disable. Mechanism: `suspend-then-hibernate` +
`HibernateDelaySec=1h` + `HibernateOnACPower=false`; lid

View File

@@ -117,12 +117,31 @@ in
color: alpha(#${base16.base05}, 0.5);
}
/* Suggested/destructive sit on pastel accent/bad dark label
is intentional and contrast-checked (~4:1 on Boreal accent). */
is intentional and contrast-checked (7.0:1 suggested, 6.2:1
destructive on Boreal). */
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.destructive-action:not(.flat):not(:disabled) {
background-color: mix(white, @destructive_bg_color, 0.9);
}
button.destructive-action:not(.flat):not(:disabled):hover {
background-color: mix(white, @destructive_bg_color, 0.85);
}
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);
}
button.suggested-action.flat, button.suggested-action.flat label {
color: #${base16.base0D};
}