From 84f47e8ee05b76d9d0b5d5e4fa3440de3f380843 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Tue, 28 Jul 2026 00:56:15 +0200 Subject: [PATCH] fix(skins): keep tinted badges readable on light skins, pin OG modals The light skins themed the app chrome, but a class of status badges and accent-tinted pills still hardcode pale light-on-dark ink (#cdddff, #9dc0ff, #ffc107, #fff) over a low-alpha tint. Measured on a rendered page, that lands at 1.0 to 1.9:1 under all four light skins: the search filter chips (Sessions / Events / Files) render as empty blue pills. Re-point the ink at each skin's own dark tokens and keep the tint as the category signal, which moves the same components to 3.2 to 14:1. Also pin --floating-bg on the OG skin. The new :root default is slate rgba(31,38,48,.96), which suits the Daylight palettes (their glass header is already rgba(31,38,48,.85)) but repaints OG's modals, command palette and floating windows away from the neutral near-black that skin is built on. Verified against a live instance across all seven skins, plus a real shell session for terminal ANSI output. Full suite green. Co-Authored-By: Claude Opus 5 (1M context) --- .changeset/light-skins.md | 10 ++++++++-- src/web/public/styles.css | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/.changeset/light-skins.md b/.changeset/light-skins.md index 6e1f7a33..1244e69b 100644 --- a/.changeset/light-skins.md +++ b/.changeset/light-skins.md @@ -1,5 +1,11 @@ --- -"aicodeman": patch +'aicodeman': patch --- -Add four light UI and terminal skins—Paper Gray, Solarized Light, Catppuccin Latte, and Rosé Pine Dawn—with readable native controls, xterm palettes, and stateful mobile/response-viewer surfaces. +Add four light UI and terminal skins: Paper Gray, Solarized Light, Catppuccin Latte, and Rosé Pine Dawn. The Skin picker now groups Light and Dark options, and each light skin ships a matching xterm ANSI palette plus `color-scheme: light` so native selects, date pickers and scrollbars stop rendering as dark OS widgets on a light page. Terminals set `minimumContrastRatio: 4.5` under a light skin (main terminal and teammate terminals both), which keeps CLI output that assumes a dark background readable, and `applyTerminalSkin()` now refreshes the zero-lag input overlay so typed-but-unflushed text does not keep the previous theme's colors. + +Elevated surfaces (modals, command palette, dropdowns, subagent and ultracode windows, file preview, attachment tray, mobile sheets) now resolve through shared `--floating-bg` / `--control-*` / `--banner-bg-*` / `--modal-backdrop` / `--elevated-shadow` tokens instead of hardcoded near-black rgba, so they follow whichever skin is active. On the Daylight skins this lifts modals slightly off the page background; OG Codeman pins its own near-black value to keep that palette neutral. + +Also defines twelve CSS compatibility aliases (`--bg-primary`, `--bg-secondary`, `--bg-tertiary`, `--text-primary`, `--text-secondary`, `--border-color`, `--accent-color`, `--success`, `--error`, `--danger`, `--font-mono`, `--shadow-lg`) that panels and overlays already referenced in about 79 places but which were never actually declared, so those rules silently resolved to nothing. Status badges and accent-tinted pills (search filter chips and result badges, session tab mode pills, respawn state, Ralph priority and circuit-breaker badges, tunnel and voice status, mobile case picker) no longer keep their pale light-on-dark ink under a light skin, where it measured 1.0 to 1.9:1 and made the search filter chips invisible. + +New static regression `test/skin-themes.test.ts` guards the four-way parity between the CSS token block, the xterm palette, the pre-paint allowlist and the Settings picker. diff --git a/src/web/public/styles.css b/src/web/public/styles.css index b06f6f03..83f61194 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -159,6 +159,10 @@ html[data-skin="og"] { --term-bg: #0d0d0d; --green: #22c55e; --yellow: #eab308; --red: #ef4444; --glass-bg: rgba(19, 19, 22, 0.85); --glass-border: rgba(255, 255, 255, 0.06); + /* OG is a neutral near-black palette with no blue in it. Without this the + :root slate default would repaint every modal/palette/floating window + rgba(31,38,48,.96) and quietly break the skin's identity. */ + --floating-bg: rgba(19, 19, 22, 0.96); /* daylight-only extras left at sane neutral defaults (unused — override block does not apply to og) */ --accent-d: #3b82f6; --emerald: #3b82f6; --teal: #2563eb; --accent-soft: #22c55e; --accent-ink: #0b1220; @@ -315,6 +319,43 @@ html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="cat border-color: var(--control-border-hover); } +/* Status badges and accent-tinted pills bake in pale light-on-dark ink + (#cdddff, #9dc0ff, #ffc107, #fff, …) over a low-alpha tint. That reads at + 1.0–1.9:1 once the tint sits on a light surface — the search filter chips + literally vanish. Re-point the ink at each skin's own dark tokens and keep + the tint as the category signal. */ +html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( + .search-filter-chip.active, + .search-badge-session, + .history-view-all-btn, + .session-tab .tab-mode.gemini +) { + color: var(--accent-d); +} +html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( + .search-badge-file, + .tunnel-panel-btn.btn-start, + .voice-provider-status.active +) { + color: var(--green); +} +html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( + .ralph-task-priority.priority-p1, + .ralph-circuit-breaker.half-open +) { + color: var(--yellow); +} +html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( + .search-badge-event, + .respawn-state, + .history-detail-path, + .mobile-case-item, + .mobile-case-picker-header h3, + .btn-toolbar.btn-case-mobile:hover +) { + color: var(--text); +} + * { box-sizing: border-box; margin: 0; padding: 0; } /* ========== Accessibility: Focus Styles ========== */