The button drew its text from --status-danger, which is tuned as a FILL colour — the confirm button in the remove modal sits white text on top of it, and there it is correct. Reused as text on the app's own background it measures 3.79:1 on nebula, 3.84 on dark-blue and 3.95 on the example theme, all under the 4.5:1 AA floor, which is why the control read as barely there. Light is the only theme where the same value passes, at 4.53:1, so brightening it globally would have fixed three themes by breaking the fourth. Two jobs, two values. --status-danger-text is now defined per theme: #f87171 on the dark ones (6.29-6.47:1) and #c92a37 on light (5.43:1, up from 4.53). #f87171 is not a new invention — it is the red the CVE severity chips already use for exactly this job, so danger-as-text now looks the same wherever it appears. The border follows the text so the two stay coherent, and both fall back to --status-danger, leaving any theme without the token no worse off than before. The filled modal button is deliberately untouched: white on #dc3545 was never the problem. Other danger-as-text call sites exist (loading screen, network notifier) and would likely benefit, but they render on their own backgrounds rather than the app surface, so they are not assumed to share the measurement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
109 lines
4.2 KiB
CSS
109 lines
4.2 KiB
CSS
/* ============================================================
|
|
Example custom theme — "Example".
|
|
Copy this folder to frontend/themes/<your-name>/ and edit the
|
|
token values below. The frontend scans frontend/themes/ on each
|
|
page load and any folder containing a theme.css shows up in the
|
|
topbar dropdown automatically.
|
|
|
|
You can override any token defined in themes.css. Anything you
|
|
leave out inherits from the user's previous palette (which is
|
|
probably not what you want for surface / text / accent — the
|
|
visible essentials are listed at the top here).
|
|
|
|
Optional: drop a meta.json next to this file with
|
|
{ "displayName": "Pretty Name", "author": "Your Name" }
|
|
to control how the theme is labelled in the dropdown.
|
|
============================================================ */
|
|
|
|
[data-theme="example"] {
|
|
/* Three gradient stops used by the body bg and the loading screen. */
|
|
--gradient-from: #2a1a40;
|
|
--gradient-mid: #2e1a55;
|
|
--gradient-to: #1a0f3a;
|
|
|
|
/* Surfaces */
|
|
--surface-bg: linear-gradient(135deg, var(--gradient-from) 0%, var(--gradient-mid) 50%, var(--gradient-to) 100%);
|
|
--surface-bg-solid: #1a0f3a;
|
|
--surface-elevated: rgba(255, 255, 255, 0.05);
|
|
--surface-sunken: rgba(0, 0, 0, 0.25);
|
|
--surface-hover: rgba(255, 255, 255, 0.08);
|
|
--surface-selected: rgba(190, 130, 255, 0.18);
|
|
|
|
/* Borders */
|
|
--border: rgba(255, 255, 255, 0.12);
|
|
--border-strong: rgba(255, 255, 255, 0.20);
|
|
--border-subtle: rgba(255, 255, 255, 0.06);
|
|
|
|
/* Text */
|
|
--text-primary: #ffffff;
|
|
--text-secondary: rgba(255, 255, 255, 0.75);
|
|
--text-muted: rgba(255, 255, 255, 0.55);
|
|
--text-on-accent: #1a0f3a;
|
|
|
|
/* Accent — the theme's signature colour. */
|
|
--accent: #c08bff;
|
|
--accent-hover: #a16fe5;
|
|
--accent-soft: rgba(192, 139, 255, 0.18);
|
|
--accent-rgb: 192, 139, 255;
|
|
|
|
/* Status — stable across themes (greens, reds, oranges, teals). */
|
|
--status-success: #28a745;
|
|
--status-success-hover: #218838;
|
|
--status-success-rgb: 40, 167, 69;
|
|
--status-danger: #dc3545;
|
|
--status-danger-hover: #c82333;
|
|
--status-danger-rgb: 220, 53, 69;
|
|
/* Danger as TEXT on this theme's own background. --status-danger is tuned as a
|
|
FILL (white sits on top of it); reused as text it drops to 3.8:1 here, under
|
|
the 4.5:1 AA floor. Two jobs, two values. */
|
|
--status-danger-text: #f87171;
|
|
--status-danger-text-rgb: 248, 113, 113;
|
|
--status-warning: #ffc107;
|
|
--status-warning-rgb: 255, 193, 7;
|
|
--status-info: #17a2b8;
|
|
--status-info-rgb: 23, 162, 184;
|
|
|
|
/* Theme-aware overlay triplets. Use rgba(var(--text-rgb), 0.X)
|
|
anywhere you need an overlay tinted toward the foreground. */
|
|
--text-rgb: 255, 255, 255;
|
|
--bg-rgb: 0, 0, 0;
|
|
|
|
/* Components */
|
|
--card-bg: rgba(255, 255, 255, 0.05);
|
|
--card-border: rgba(255, 255, 255, 0.10);
|
|
--card-shadow: 0 2px 8px rgba(0, 0, 0, 0.30);
|
|
--card-shadow-hover: 0 6px 24px rgba(0, 0, 0, 0.45);
|
|
--input-bg: rgba(0, 0, 0, 0.30);
|
|
--input-border: rgba(255, 255, 255, 0.15);
|
|
--input-text: #ffffff;
|
|
--console-bg: rgba(0, 0, 0, 0.40);
|
|
--console-text: #c08bff;
|
|
--code-bg: rgba(0, 0, 0, 0.35);
|
|
--code-text: #e6dcff;
|
|
--tooltip-bg: rgba(26, 15, 58, 0.95);
|
|
--tooltip-text: #ffffff;
|
|
|
|
/* Chrome */
|
|
--topbar-bg: rgba(26, 15, 58, 0.40);
|
|
--topbar-text: #ffffff;
|
|
--topbar-border: rgba(255, 255, 255, 0.10);
|
|
--sidebar-bg: rgba(0, 0, 0, 0.15);
|
|
--sidebar-text: #ffffff;
|
|
--sidebar-border: rgba(255, 255, 255, 0.08);
|
|
|
|
/* Legacy aliases — keep these mapped so style.css's older var()
|
|
references resolve correctly. Don't change names here. */
|
|
--bg-primary: var(--topbar-bg);
|
|
--bg-secondary: var(--surface-elevated);
|
|
--bg-tertiary: var(--surface-hover);
|
|
--text-color: var(--text-primary);
|
|
--primary-color: var(--accent);
|
|
--primary-hover: var(--accent-hover);
|
|
--primary-color-rgb: var(--accent-rgb);
|
|
--border-color: var(--border);
|
|
--content-bg: var(--surface-bg);
|
|
--hover-bg: var(--surface-hover);
|
|
--error-color: var(--status-danger);
|
|
--danger-color: var(--status-danger);
|
|
}
|