openvibers/openvibe.vip Commits

VIP: filled controls use the theme's readable accent pair (WCAG AA contrast) (#25)

OP OpenVibers committed 10 Oct 2026 · 8ad35f6287 · 1 file, +1 −1

Accessibility (WCAG AA contrast). Filled buttons, chips and badges painted with the plain theme accent and white text now use the theme's readable pair: `background: var(--accent-strong, var(--accent, …))` with `color: var(--on-accent-strong, …)`.

White on the default accent `#3b82f6` is 3.68:1, under AA's 4.5:1 for normal-size text. The strong pair is 4.62:1 in the default theme, and every built-in theme defines it, using dark text on the light accents. The release UX check's axe run flagged this as `color-contrast` (serious), for example on the search buttons of openvibe.trade and openvibe.deals.

The change is mechanical and limited to rule blocks that set both an accent background and a white or `--on-accent` text colour. Bars, dots and outlines are untouched. A border drawn in the same accent follows the fill, and an existing `--on-accent` fallback is kept. Affected tests pass (`ov test`). The matching shared half is openvibe-shared 2.20.3.

Changes

ddiff --git a/server/web/embeds.js b/server/web/embeds.js
iindex 141d91f..93af7f0 100644
---- a/server/web/embeds.js
++++ b/server/web/embeds.js
@@@ -36,7 +36,7 @@ const BASE_CSS = `*{box-sizing:border-box}html,body{margin:0;height:100%}body{fo
.w{height:100%;display:flex;flex-direction:column;justify-content:center;gap:6px;padding:14px 16px;border:1px solid var(--line);border-radius:12px}
.k{margin:0;font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}h1{margin:0;font-size:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.n{margin:0;color:var(--muted)}.n b{color:var(--fg)}ul{margin:0;padding:0;list-style:none;font-size:13px;color:var(--muted)}li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
--.b{align-self:flex-start;margin-top:4px;padding:7px 14px;border-radius:8px;background:var(--accent);color:#fff;font-weight:600;text-decoration:none}.b:focus-visible{outline:2px solid var(--fg);outline-offset:2px}`;
++.b{align-self:flex-start;margin-top:4px;padding:7px 14px;border-radius:8px;background:var(--accent-strong, var(--accent, #3472d8));color:var(--on-accent-strong, var(--on-accent, #fff));font-weight:600;text-decoration:none}.b:focus-visible{outline:2px solid var(--fg);outline-offset:2px}`;
const LIGHT = '--bg:#ffffff;--fg:#0f172a;--muted:#475569;--line:#e2e8f0;--accent:#2563eb';
const DARK = '--bg:#0b1220;--fg:#e6edf7;--muted:#9aa7bd;--line:rgba(255,255,255,.12);--accent:#3b82f6';
const STYLES = {