openvibers/openvibe.live Commits

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

OP OpenVibers committed 10 Oct 2026 · b405725c11 · 12 files, +53 −53

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/public/css/context-cards.css b/public/css/context-cards.css
iindex 59085fd5..11e953b1 100644
---- a/public/css/context-cards.css
++++ b/public/css/context-cards.css
@@@ -22,7 +22,7 @@
.cc-grade { --g: #a78bfa; flex: 0 0 auto; width: 28px; height: 28px; border-radius: 8px; display: inline-grid; place-items: center; font-weight: 900; font-size: 0.9rem; color: var(--g); border: 1.5px solid color-mix(in srgb, var(--g) 60%, transparent); background: color-mix(in srgb, var(--g) 12%, transparent); text-decoration: none; }
.cc-sub { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 0.82rem; color: var(--text-muted); }
.cc-name { font-weight: 700; color: var(--text-primary); text-decoration: none; }
--.cc-avatar { display: inline-grid; place-items: center; border-radius: 50%; overflow: hidden; background: var(--accent); color: #fff; font-weight: 800; font-size: 0.7rem; flex: 0 0 auto; vertical-align: middle; }
++.cc-avatar { display: inline-grid; place-items: center; border-radius: 50%; overflow: hidden; background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); font-weight: 800; font-size: 0.7rem; flex: 0 0 auto; vertical-align: middle; }
.cc-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cc-when { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cc-badge { display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: 999px; font-weight: 800; font-size: 0.86rem; font-variant-numeric: tabular-nums; color: #fff; background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 60%, #f472b6)); box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 35%, transparent); }
@@@ -150,8 +150,8 @@
.dsc-toggle-text small { font-size: 0.72rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dsc-toggle-count {
flex: none; min-width: 26px; padding: 3px 8px; border-radius: 999px;
-- font-size: 0.76rem; font-weight: 900; text-align: center; color: var(--on-accent, #fff);
-- background: var(--accent);
++ font-size: 0.76rem; font-weight: 900; text-align: center; color: var(--on-accent-strong, var(--on-accent, #fff));
++ background: var(--accent-strong, var(--accent, #3472d8));
box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent);
}
/* A single slow pulse ring on the count, only while the board is closed and only on screens that
ddiff --git a/public/css/features/broadcast.css b/public/css/features/broadcast.css
iindex 95afa20f..8cb42038 100644
---- a/public/css/features/broadcast.css
++++ b/public/css/features/broadcast.css
@@@ -3,8 +3,8 @@
Split by class/id ownership with cascade-order checks; edit freely. */
/* ── from style.css ── */
.bc-ctrl-btn-active {
-- background: var(--accent, #8b5cf6) !important;
-- color: #fff !important;
++ background: var(--accent-strong, var(--accent, #8b5cf6)) !important;
++ color: var(--on-accent-strong, var(--on-accent, #fff)) !important;
}
.bc-call-explainer {
margin: 10px 0 0;
@@@ -72,7 +72,7 @@
font-size: 0.82rem;
transition: background 0.15s;
}
--.bc-pip-btn:hover { background: var(--accent, #8b5cf6); color: #fff; }
++.bc-pip-btn:hover { background: var(--accent-strong, var(--accent, #8b5cf6)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.bc-media-pip-queue {
border-top: 1px solid var(--border);
padding: 8px 12px;
ddiff --git a/public/css/features/chatpage.css b/public/css/features/chatpage.css
iindex 73e22da4..8e7ee735 100644
---- a/public/css/features/chatpage.css
++++ b/public/css/features/chatpage.css
@@@ -55,8 +55,8 @@
}
.vc-create-btn {
-- background: var(--accent);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #3472d8));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
border: none;
width: 28px;
height: 28px;
ddiff --git a/public/css/features/content.css b/public/css/features/content.css
iindex 8390b827..bfb5c79a 100644
---- a/public/css/features/content.css
++++ b/public/css/features/content.css
@@@ -97,7 +97,7 @@
transition: background var(--motion-fast, 120ms), color var(--motion-fast, 120ms), border-color var(--motion-fast, 120ms);
}
.cf-chip:hover { color: var(--text-primary); border-color: color-mix(in srgb, var(--accent) 60%, var(--border-light)); }
--.cf-chip[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--on-accent, #fff); }
++.cf-chip[aria-pressed="true"] { background: var(--accent-strong, var(--accent, #3472d8)); border-color: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.cf-wrap--ai .cf-chip[aria-pressed="true"] { background: var(--cf-ai-fill); border-color: transparent; color: #fff; }
.cf-chip:focus-visible, .cf-seg button:focus-visible { outline: none; box-shadow: var(--focus-ring); }
ddiff --git a/public/css/features/home.css b/public/css/features/home.css
iindex ae383792..03a30707 100644
---- a/public/css/features/home.css
++++ b/public/css/features/home.css
@@@ -47,7 +47,7 @@
.hero-egg-slots.is-right .egg-slot, .hero-egg-slots.is-solved .egg-slot { border-color: #06d6a0; background: color-mix(in srgb, #06d6a0 20%, var(--bg-tertiary)); }
.hero-egg-clues { margin: 0 0 12px; padding: 0; list-style: none; display: grid; gap: 6px; counter-reset: clue; }
.hero-egg-clues li { display: grid; grid-template-columns: 22px 1fr auto; align-items: center; gap: 8px; font-size: 0.84rem; color: var(--text-primary); padding: 6px 8px; border-radius: 10px; background: var(--bg-secondary); border: 1px solid var(--border); }
--.egg-clue-n { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: 0.7rem; font-weight: 800; color: #fff; background: var(--accent); }
++.egg-clue-n { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: 0.7rem; font-weight: 800; color: var(--on-accent-strong, var(--on-accent, #fff)); background: var(--accent-strong, var(--accent, #3472d8)); }
.egg-clue-text { font-style: italic; line-height: 1.35; }
.egg-clue-key { font-weight: 900; font-size: 0.95rem; color: #06d6a0; background: color-mix(in srgb, #06d6a0 15%, transparent); border-radius: 8px; padding: 2px 9px; }
.hero-egg-clues li.is-revealed { border-color: color-mix(in srgb, #06d6a0 45%, var(--border)); }
@@@ -1136,7 +1136,7 @@ body.egg-rainbow { animation: eggRainbow 2.6s linear; }
.cta-btn { display: inline-flex; align-items: center; justify-content: center; gap: 9px; min-height: 48px; padding: 0 22px;
border-radius: 999px; font-weight: 800; font-size: 1rem; text-decoration: none; transition: filter .15s, background .15s, transform .1s; }
.cta-btn:active { transform: translateY(1px); }
--.cta-btn-primary { background: var(--accent, #3b82f6); color: var(--on-accent, #fff);
++.cta-btn-primary { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff));
box-shadow: 0 10px 28px color-mix(in srgb, var(--accent, #3b82f6) 35%, transparent); }
.cta-btn-primary:hover { filter: brightness(1.1); }
.cta-btn-ghost { color: #e8e6e3; background: rgba(255,255,255,0.04); border: 1px solid color-mix(in srgb, var(--accent, #3b82f6) 40%, transparent); }
ddiff --git a/public/css/features/stats.css b/public/css/features/stats.css
iindex a9fb1440..0569ee37 100644
---- a/public/css/features/stats.css
++++ b/public/css/features/stats.css
@@@ -44,7 +44,7 @@
transition: background var(--dur-fast, 160ms), color var(--dur-fast, 160ms);
}
.sn-seg button:hover, .sn-table-btn:hover { color: var(--text-primary); }
--.sn-seg button.is-on { background: var(--accent); color: #fff; }
++.sn-seg button.is-on { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.sn-table-btn { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border); }
.sn-table-btn.is-on { border-color: var(--accent); color: var(--text-primary); background: color-mix(in srgb, var(--accent) 14%, transparent); }
ddiff --git a/public/css/messenger.css b/public/css/messenger.css
iindex bfb49814..a2f73f4a 100644
---- a/public/css/messenger.css
++++ b/public/css/messenger.css
@@@ -11,8 +11,8 @@
width: 52px;
height: 52px;
border-radius: 50%;
-- background: var(--accent);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #3472d8));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
border: none;
cursor: pointer;
font-size: 22px;
@@@ -216,8 +216,8 @@
height: 18px;
padding: 0 5px;
border-radius: 9px;
-- background: var(--accent);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #3472d8));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
font-size: 10px;
font-weight: 700;
display: flex;
@@@ -304,8 +304,8 @@
position: relative;
}
.msg-bubble-row.self .msg-bubble {
-- background: var(--accent);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #3472d8));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
border-bottom-right-radius: 4px;
}
.msg-bubble-row.other .msg-bubble {
@@@ -381,8 +381,8 @@
height: 36px;
border-radius: 50%;
border: none;
-- background: var(--accent);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #3472d8));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
cursor: pointer;
font-size: 14px;
display: flex;
@@@ -493,8 +493,8 @@
padding: 10px;
border-radius: var(--radius);
border: none;
-- background: var(--accent);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #3472d8));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
font-weight: 600;
font-size: 14px;
cursor: pointer;
ddiff --git a/public/css/ov-guide.css b/public/css/ov-guide.css
iindex 90caed76..ae51ceab 100644
---- a/public/css/ov-guide.css
++++ b/public/css/ov-guide.css
@@@ -18,7 +18,7 @@ body.ovg-lock { overflow: hidden; }
.ovg-steps::after { content: ''; position: absolute; left: 12%; top: 15px; height: 3px; width: calc(76% * var(--p) / 100%); background: linear-gradient(90deg, var(--accent), #22d3ee); border-radius: 2px; transition: width .5s cubic-bezier(.2,.9,.3,1); }
.ovg-steps li { position: relative; z-index: 1; display: grid; justify-items: center; gap: 5px; font-size: 0.68rem; font-weight: 700; color: var(--text-muted); text-align: center; }
.ovg-step-dot { width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; background: var(--bg-tertiary); border: 2px solid var(--border); font-size: 0.8rem; color: var(--text-muted); transition: all .3s; }
--.ovg-steps li.now .ovg-step-dot { background: var(--accent); border-color: var(--accent); color: #fff; box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 22%, transparent); transform: scale(1.08); }
++.ovg-steps li.now .ovg-step-dot { background: var(--accent-strong, var(--accent, #3472d8)); border-color: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 22%, transparent); transform: scale(1.08); }
.ovg-steps li.now { color: var(--text-primary); }
.ovg-steps li.done .ovg-step-dot { background: color-mix(in srgb, #06d6a0 25%, var(--bg-tertiary)); border-color: #06d6a0; color: #06d6a0; }
.ovg-body { flex: 1; min-height: 0; overflow: auto; padding: 4px 20px 12px; }
@@@ -45,7 +45,7 @@ body.ovg-lock { overflow: hidden; }
.ovg-form label { display: grid; gap: 6px; font-size: 0.8rem; font-weight: 700; color: var(--text-secondary); }
.ovg-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ovg-chip { padding: 6px 11px; border-radius: 999px; border: 1px solid var(--border); background: var(--bg-tertiary); color: var(--text-primary); font: inherit; font-size: 0.8rem; font-weight: 700; cursor: pointer; transition: all .15s; }
--.ovg-chip:hover { border-color: var(--accent); } .ovg-chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
++.ovg-chip:hover { border-color: var(--accent); } .ovg-chip.on { background: var(--accent-strong, var(--accent, #3472d8)); border-color: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.ovg-detail { margin-top: 4px; }
.ovg-box { padding: 14px; border-radius: 14px; background: var(--bg-secondary); border: 1px solid var(--border); animation: ovgRise .35s both; }
.ovg-box p { margin: 0 0 10px; font-size: 0.86rem; color: var(--text-secondary); line-height: 1.5; }
@@@ -57,12 +57,12 @@ body.ovg-lock { overflow: hidden; }
.ovg-copy:hover { border-color: var(--accent); }
.ovg-obs { margin: 10px 0 6px; padding-left: 0; list-style: none; display: grid; gap: 6px; counter-reset: obs; }
.ovg-obs li { counter-increment: obs; display: flex; gap: 10px; align-items: center; font-size: 0.86rem; }
--.ovg-obs li::before { content: counter(obs); width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: 0.7rem; font-weight: 800; color: #fff; background: var(--accent); flex: none; }
++.ovg-obs li::before { content: counter(obs); width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: 0.7rem; font-weight: 800; color: var(--on-accent-strong, var(--on-accent, #fff)); background: var(--accent-strong, var(--accent, #3472d8)); flex: none; }
.ovg-tips { margin: 8px 0 0; padding-left: 18px; font-size: 0.8rem; color: var(--text-muted); }
.ovg-fine { font-size: 0.76rem; }
.ovg-seg { display: inline-flex; gap: 4px; padding: 4px; border-radius: 999px; background: var(--bg-tertiary); border: 1px solid var(--border); margin: 4px 0 8px; }
.ovg-seg button { border: 0; background: transparent; color: var(--text-secondary); padding: 7px 12px; border-radius: 999px; font: inherit; font-weight: 700; font-size: 0.82rem; cursor: pointer; }
--.ovg-seg button.on { background: var(--accent); color: #fff; }
++.ovg-seg button.on { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.ovg-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 8px; }
.ovg-row .form-input { flex: 1 1 180px; }
.ovg-check { display: flex; align-items: center; gap: 8px; font-size: 0.82rem; margin: 8px 0; }
@@@ -123,7 +123,7 @@ body.ovg-lock { overflow: hidden; }
.ovg-drop img { width: 64px; height: 64px; object-fit: contain; border-radius: 10px; background: var(--bg-tertiary); }
.ovg-drop i { font-size: 1.4rem; color: var(--accent); }
.ovg-profile { display: grid; grid-template-columns: 96px 1fr; gap: 16px; align-items: start; }
--.ovg-avatar-pick { position: relative; width: 96px; height: 96px; border-radius: 50%; overflow: hidden; display: grid; place-items: center; background: var(--accent); color: #fff; font-size: 2.2rem; font-weight: 900; cursor: pointer; }
++.ovg-avatar-pick { position: relative; width: 96px; height: 96px; border-radius: 50%; overflow: hidden; display: grid; place-items: center; background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); font-size: 2.2rem; font-weight: 900; cursor: pointer; }
.ovg-avatar-pick img { width: 100%; height: 100%; object-fit: cover; } .ovg-avatar-pick i { position: absolute; right: 4px; bottom: 4px; width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; font-size: 0.75rem; background: var(--bg-card); color: var(--text-primary); border: 1px solid var(--border); }
.ovg-hub-top { display: grid; grid-template-columns: 96px 1fr; gap: 16px; align-items: center; padding: 14px; border-radius: 16px; background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 14%, var(--bg-secondary)), var(--bg-secondary)); border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border)); margin-bottom: 14px; }
.ovg-hub-title { font-size: 1.05rem; font-weight: 900; margin-bottom: 2px; } .ovg-hub-sub { font-size: 0.82rem; color: var(--text-secondary); margin-bottom: 8px; }
ddiff --git a/public/css/recap.css b/public/css/recap.css
iindex dfb0be6f..28c2c3ad 100644
---- a/public/css/recap.css
++++ b/public/css/recap.css
@@@ -15,7 +15,7 @@
.recap-by-name { font-weight: 800; color: var(--text-primary); text-decoration: none; }
.recap-by b { color: var(--text-primary); }
.recap-by-meta { color: var(--text-muted); font-size: 0.82rem; }
--.recap-avatar { display: inline-grid; place-items: center; border-radius: 50%; overflow: hidden; background: var(--accent); color: #fff; font-weight: 800; font-size: 0.8rem; flex: 0 0 auto; }
++.recap-avatar { display: inline-grid; place-items: center; border-radius: 50%; overflow: hidden; background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); font-weight: 800; font-size: 0.8rem; flex: 0 0 auto; }
.recap-avatar img { width: 100%; height: 100%; object-fit: cover; }
.recap-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.recap-tags span { font-size: 0.74rem; font-weight: 700; padding: 3px 9px; border-radius: 999px; background: color-mix(in srgb, var(--g) 14%, var(--bg-tertiary)); color: var(--text-primary); border: 1px solid color-mix(in srgb, var(--g) 35%, var(--border)); }
ddiff --git a/public/css/style.css b/public/css/style.css
iindex b9951d5e..9e953c90 100644
---- a/public/css/style.css
++++ b/public/css/style.css
@@@ -1051,7 +1051,7 @@ body.ov-nav-overlay .navbar.ovnav-top {
border: 1px solid transparent; transition: all 0.2s; cursor: pointer;
box-shadow: 0 6px 18px rgba(0,0,0,0.14);
}
--.btn-primary { background: var(--accent); color: var(--on-accent, #0b0d10); }
++.btn-primary { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #0b0d10)); }
.btn-primary:hover { background: var(--accent-light); transform: translateY(-1px); }
.btn-outline {
background: transparent; color: var(--text-primary);
@@@ -1086,8 +1086,8 @@ body.ov-nav-overlay .navbar.ovnav-top {
line-height: 1;
}
.btn-openvibe-bucks-mini:hover {
-- background: var(--accent); color: #fff;
-- border-color: var(--accent);
++ background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff));
++ border-color: var(--accent-strong, var(--accent, #3472d8));
}
/* ═══════════════════════════════════════════════════════════════
@@@ -1829,7 +1829,7 @@ body.ov-nav-overlay .navbar.ovnav-top {
.hero-float--live .hero-float-badge { background: #e0245e; border-color: #ff6088; }
.hero-float--vod .hero-float-badge { background: #5865f2; border-color: #8b93ff; }
.hero-float--clip .hero-float-badge { background: #2ecc71; border-color: #6fe0a2; color: #05130a; }
--.hero-float--paste .hero-float-badge { background: var(--accent); border-color: var(--accent-light); color: var(--on-accent, #0b0d10); }
++.hero-float--paste .hero-float-badge { background: var(--accent-strong, var(--accent, #3472d8)); border-color: var(--accent-light); color: var(--on-accent-strong, var(--on-accent, #0b0d10)); }
.hero-float--moment .hero-float-badge { background: linear-gradient(135deg, #a855f7, #ec4899); border-color: #d8b4fe; color: #fff; }
/* Swap = shrink + fade OUT, then the fresh content grows + fades back IN (gentle, no flash) */
/* Hover lift on the inner — eases smoothly, never fights the drift */
@@@ -1950,7 +1950,7 @@ a.pulse-card:hover { border-color: var(--accent); transform: translateY(-2px); }
}
.ov-rail-prev { left: 8px; }
.ov-rail-next { right: 8px; }
--.ov-rail-btn:hover { background: var(--accent); border-color: var(--accent); color: var(--on-accent, #fff); }
++.ov-rail-btn:hover { background: var(--accent-strong, var(--accent, #3472d8)); border-color: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.ov-rail-btn:disabled { opacity: 0; pointer-events: none; }
.ov-rail:not(.is-scrollable) > .ov-rail-btn { display: none; }
.ov-rail-bar {
@@@ -5405,7 +5405,7 @@ textarea.form-input { resize: vertical; min-height: 60px; }
/* ── Offline "most watched" cycler ─────────────────────────── */
.off-cyc-title i { color: var(--accent); }
.off-cyc-chip:hover { color: var(--text-primary); }
--.off-cyc-chip.active { background: var(--accent); color: #fff; }
++.off-cyc-chip.active { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
@keyframes offCycFade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.off-top-thumb { position: relative; aspect-ratio: 16 / 9; background: var(--bg-tertiary); overflow: hidden; }
.off-top-thumb img { width: 100%; height: 100%; object-fit: cover; }
@@@ -5500,7 +5500,7 @@ textarea.form-input { resize: vertical; min-height: 60px; }
/* ── Global chat AI: header strip + insight panel ── */
.gai-badge {
flex-shrink: 0; display: inline-flex; align-items: center; gap: 4px;
-- padding: 2px 8px; border-radius: 999px; background: var(--accent); color: #fff;
++ padding: 2px 8px; border-radius: 999px; background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff));
font-size: 0.7rem; font-weight: 700; letter-spacing: 0.02em;
}
.gai-strip-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@@ -5510,7 +5510,7 @@ textarea.form-input { resize: vertical; min-height: 60px; }
/* Timeline browser: head (title + search), period chips, scrollable list with day dividers. */
.gai-tl-head h4 { margin: 0; }
.gai-tl-chip:hover { color: var(--text-primary); border-color: var(--accent); }
--.gai-tl-chip.active { background: var(--accent); color: #fff; border-color: var(--accent); }
++.gai-tl-chip.active { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); border-color: var(--accent-strong, var(--accent, #3472d8)); }
.gai-tl-day { position: sticky; top: 0; z-index: 1; margin: 4px 0 8px; padding: 3px 0; font-size: 0.7rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); background: linear-gradient(var(--bg-primary), var(--bg-primary) 70%, transparent); }
.gai-timeline { display: flex; flex-direction: column; gap: 0; position: relative; max-height: 460px; overflow-y: auto; padding-right: 6px; scrollbar-width: thin; }
.gai-tl-item { position: relative; padding: 0 0 14px 20px; border-left: 2px solid var(--border); }
@@@ -5607,7 +5607,7 @@ button.uai-tl-more { background: none; border: none; cursor: pointer; padding: 0
/* ── Channel Analytics ───────────────────────────────────── */
.ch-analytics-period-btns .btn { padding:4px 10px; font-size:0.75rem; border-radius:6px; }
--.ch-analytics-period-btns .btn.active { background:var(--accent); color:#fff; }
++.ch-analytics-period-btns .btn.active { background:var(--accent-strong, var(--accent, #3472d8)); color:var(--on-accent-strong, var(--on-accent, #fff)); }
.analytics-stat-card .stat-label {
font-size:0.72rem; color:var(--text-muted,#888); text-transform:uppercase;
letter-spacing:0.04em; margin-top:2px;
@@@ -6111,8 +6111,8 @@ body.theme-light .btn-outline:hover {
color: var(--accent, #8b5cf6);
}
.call-count-badge {
-- background: var(--accent, #8b5cf6);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #8b5cf6));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
font-size: 0.75rem;
font-weight: 700;
padding: 2px 8px;
@@@ -6201,8 +6201,8 @@ body.theme-light .btn-outline:hover {
width: 48px;
height: 48px;
border-radius: 50%;
-- background: var(--accent, #8b5cf6);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #8b5cf6));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
display: flex;
align-items: center;
justify-content: center;
@@@ -7080,8 +7080,8 @@ body.theme-light .btn-outline:hover {
}
.sort-btn:hover { color: var(--text-primary); }
.sort-btn.active {
-- background: var(--accent);
-- color: var(--on-accent, #0b0d10);
++ background: var(--accent-strong, var(--accent, #3472d8));
++ color: var(--on-accent-strong, var(--on-accent, #0b0d10));
}
/* Push page controls to the right when a sort toggle shares the pager row. */
.pastes-pagination .sort-toggle { margin-right: auto; }
@@@ -7095,7 +7095,7 @@ body.theme-light .btn-outline:hover {
#page-documentation ul, #page-documentation ol { margin: 0.5rem 0 1rem 1.5rem; line-height: 1.7; }
/* Endpoint tables have nowrap first columns; on a phone they were up to 100px wider than the screen
and scrolled the whole page sideways. Below tablet width a table scrolls inside its own box. */
--.doc-copy-btn { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.5rem 1rem; background: var(--accent); color: #fff; border: none; border-radius: var(--radius); cursor: pointer; font-size: 0.9rem; font-weight: 600; transition: opacity 0.15s; }
++.doc-copy-btn { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.5rem 1rem; background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); border: none; border-radius: var(--radius); cursor: pointer; font-size: 0.9rem; font-weight: 600; transition: opacity 0.15s; }
.doc-copy-btn:hover { opacity: 0.85; }
.doc-vibe-hero { background: linear-gradient(135deg, var(--surface) 0%, rgba(var(--accent-rgb, 99,102,241), 0.08) 100%); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; margin-bottom: 2rem; }
.doc-vibe-hero h2 { margin-top: 0 !important; border: none !important; padding: 0 !important; }
@@@ -8097,8 +8097,8 @@ body.theme-light .btn-outline:hover {
font-size: 0.7rem;
padding: 1px 5px;
border-radius: 4px;
-- background: var(--accent, #6366f1);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #6366f1));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
margin-right: 4px;
vertical-align: middle;
font-weight: 600;
@@@ -8124,8 +8124,8 @@ body.theme-light .btn-outline:hover {
width: 52px;
height: 52px;
border-radius: 50%;
-- background: var(--accent, #6366f1);
-- color: #fff;
++ background: var(--accent-strong, var(--accent, #6366f1));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
border: none;
font-size: 1.3rem;
cursor: pointer;
@@@ -9722,9 +9722,9 @@ body.theme-light .btn-outline:hover {
.pc-tools-row > button.btn-openvibe-coins-mini:hover,
.chat-tools-row > button.btn-openvibe-bucks-mini:hover,
.pc-tools-row > button.btn-openvibe-bucks-mini:hover {
-- background: var(--accent);
-- color: #fff;
-- border-color: var(--accent);
++ background: var(--accent-strong, var(--accent, #3472d8));
++ color: var(--on-accent-strong, var(--on-accent, #fff));
++ border-color: var(--accent-strong, var(--accent, #3472d8));
}
/* TTS toggle: dim when off, accent when on. */
.chat-tools-row > button.chat-tts-toggle { opacity: 0.5; }
ddiff --git a/public/js/chat.js b/public/js/chat.js
iindex a8014a0b..a78cbafd 100644
---- a/public/js/chat.js
++++ b/public/js/chat.js
@@@ -4040,7 +4040,7 @@ function _deployCss() {
.chat-deploy-a{margin-left:auto;display:flex;align-items:center;gap:12px}
.chat-deploy-f a,.chat-deploy-more{color:var(--accent-light,var(--accent,#60a5fa));text-decoration:none;font:600 .78rem/1 inherit;cursor:pointer;background:none;border:0;padding:4px 0;min-height:24px}
.chat-deploy-more::after{content:' ▾';font-size:.7em}.chat-deploy-more[aria-expanded=true]::after{content:' ▴'}
--.chat-deploy-reload{border:0;border-radius:8px;background:var(--accent,#3b82f6);color:var(--on-accent,#fff);font:700 .76rem/1 inherit;padding:7px 11px;cursor:pointer}
++.chat-deploy-reload{border:0;border-radius:8px;background:var(--accent-strong, var(--accent, #3472d8));color:var(--on-accent-strong, var(--on-accent,#fff));font:700 .76rem/1 inherit;padding:7px 11px;cursor:pointer}
.chat-deploy-f a:focus-visible,.chat-deploy-more:focus-visible,.chat-deploy-reload:focus-visible{outline:2px solid var(--accent,#3b82f6);outline-offset:2px;border-radius:6px}
@container (max-width:300px){.chat-deploy li{grid-template-columns:minmax(0,1fr)}.chat-deploy li a{display:none}.chat-deploy-a{margin-left:0;width:100%;justify-content:space-between}}`;
document.head.appendChild(st);
ddiff --git a/public/whip-publisher.html b/public/whip-publisher.html
iindex 108102aa..b95ba87e 100644
---- a/public/whip-publisher.html
++++ b/public/whip-publisher.html
@@@ -43,7 +43,7 @@
.actions { display: flex; gap: 10px; align-items: center; margin-top: 16px; flex-wrap: wrap; }
button { padding: 10px 18px; border-radius: 8px; border: 1px solid transparent; font: inherit; font-weight: 600; cursor: pointer; }
button:disabled { opacity: 0.45; cursor: not-allowed; }
-- .btn-go { background: var(--accent); color: #fff; }
++ .btn-go { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.btn-go:not(:disabled):hover { background: var(--accent-dark); }
.btn-stop { background: transparent; color: var(--bad); border-color: var(--bad); }
.btn-stop:not(:disabled):hover { background: rgba(231, 76, 60, 0.12); }