hyperhive/frontend/packages/shared/src/badge/Badge.css
iris 760e5ad4cc badge: fix quiet-variant regression under an explicit theme override
argus review: the two :root[data-theme='...'] glass-override rules
have specificity 0-3-0 (:root + [data-theme] + .ui-badge), beating
.ui-badge-quiet's 0-1-0 — so whenever a user has an explicit theme
override set (not just relying on prefers-color-scheme), these rules
reintroduced a fill on quiet badges, regressing the settings/links
trigger fix. Scope both overrides with :not(.ui-badge-quiet).

Verified with a real repro (same synthetic striped-bg test page,
before/after) rather than just the specificity arithmetic.
2026-08-29 20:43:11 +02:00

121 lines
5 KiB
CSS

/* <Badge> — pill-shaped status/control chip. Same touch-target floor as
the rest of the shared control set (2.75em ≈ 44px, WCAG 2.5.5) when
interactive; a plain display badge (no `onClick`) stays compact since
it's not a tap target at all. Colours are the shared base16-derived
vars (../theme.css) — `--bg-elev` is the same slot dropdowns/popovers
use, so an open Badge and the Dropdown it triggers read as one surface. */
.ui-badge {
display: inline-flex;
align-items: center;
gap: 0.35em;
padding: 0.15em 0.6em;
border-radius: 1em;
font: inherit;
font-size: 0.85em;
line-height: 1.4;
background: color-mix(in srgb, var(--purple-dim) 65%, transparent);
-webkit-backdrop-filter: blur(6px) saturate(140%);
backdrop-filter: blur(6px) saturate(140%);
color: var(--fg);
border: none;
white-space: nowrap;
}
/* Frosted-glass fill (mara: "make badges look glassy... in dark mode
the added transparency improves readability, bg behind is dark") —
same recipe as the header chrome/terminal glass (`chrome.css`,
`terminal.css`): translucent `color-mix` + `backdrop-filter`. Only
for the default filled badges — `variant="quiet"` (below) already
has no fill at all, nothing to frost.
Dark (mocha) only, deliberately: her own reasoning was conditioned
on a dark surface behind the badge. A light (latte) page has bright,
often busy content behind a badge — the same transparency would
wash out the value text instead of improving it, the opposite of
what this is for — so light mode keeps the plain solid fill. Same
three-way structure `colors.css` uses for every light/dark switch:
this default rule *is* the dark look (mocha is the default palette),
the `@media`/`:root[data-theme]` blocks below revert it for light,
restore it for an explicit dark override. */
@media (prefers-color-scheme: light) {
.ui-badge {
background: var(--purple-dim);
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
}
/* `:not(.ui-badge-quiet)` here, unlike the base rule/`@media` block
above — argus's review: both of these add `:root`+`[data-theme]` to
the selector, so specificity is 0-3-0 vs plain `.ui-badge-quiet`'s
0-1-0. Without the exclusion these would beat quiet's `background:
none` (below) whenever a user has an *explicit* theme override set
(SettingsMenu's dropdown, not just the OS default), reintroducing
the settings/links "should not have the badge bg" bug on those
triggers. Verified against a real repro before landing, not just
the specificity arithmetic. */
:root[data-theme='light'] .ui-badge:not(.ui-badge-quiet) {
background: var(--purple-dim);
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
:root[data-theme='dark'] .ui-badge:not(.ui-badge-quiet) {
background: color-mix(in srgb, var(--purple-dim) 65%, transparent);
-webkit-backdrop-filter: blur(6px) saturate(140%);
backdrop-filter: blur(6px) saturate(140%);
}
.ui-badge-interactive {
cursor: pointer;
min-height: 2.75em;
padding-inline: 0.8em;
}
.ui-badge-interactive:hover {
background: var(--border);
}
.ui-badge-interactive:disabled {
opacity: 0.6;
cursor: default;
}
/* `variant="quiet"` — icon-only header triggers (settings/links), not
status chips: no permanent fill, so it reads as chrome next to the
rest of the header rather than another data pill. The `:hover` and
`[aria-expanded='true']` rules above still apply — quiet only drops
the idle background, which is what mara's report was actually about. */
.ui-badge-quiet {
background: none;
}
.ui-badge-interactive[aria-expanded='true'] {
background: var(--bg-elev);
outline: 1px solid var(--purple);
}
.ui-badge-label {
color: var(--muted-on-dim); /* --muted alone is too low-contrast on this fill, see theme.css */
}
.ui-badge-value {
color: var(--fg);
}
.ui-badge-caret {
font-size: 0.75em;
color: var(--muted-on-dim);
}
/* Blended with `--fg`, not the raw accent — a stylix-fed scheme can pick
any hue/lightness for `--green`/`--amber`/etc., and nothing guarantees
an arbitrary accent clears 4.5:1 against `--purple-dim` the way the two
bundled palettes were hand-tuned to (see colors.css's comment above
`--latte-base08..0F`). `--fg` is the one color the base16 contract
already guarantees is legible on every surface in the theme, so mixing
toward it gives every accent a contrast floor without trying to
compute/fix an operator's own theme (mara, on the low-contrast-badges
report: "we cant fix a broken theme ... we need to follow base16
conventions or css mix new colors" — this is that; stock mocha/latte
keep their existing look, since both accents already sit close to
`--fg` in contrast terms). */
.ui-badge-positive .ui-badge-value {
color: color-mix(in srgb, var(--green) 60%, var(--fg));
}
.ui-badge-warning .ui-badge-value {
color: color-mix(in srgb, var(--amber) 60%, var(--fg));
}
.ui-badge-negative .ui-badge-value {
color: color-mix(in srgb, var(--red) 60%, var(--fg));
}
.ui-badge-accent .ui-badge-value {
color: color-mix(in srgb, var(--purple) 60%, var(--fg));
}