fix(decnet_web/css): light-mode contrast across wizards, code blocks, hovers
Sweeps four invariant violations that were leaking dark surfaces
into light mode and producing the unreadable / inverted areas:
1. Hardcoded `color: #000` in 14 :hover rules across 11 CSS
files swapped to `color: var(--bg)` — collapses to #000 in
dark mode (no-op), becomes cream in light. Fixes DEPLOY
DECKIES (button hover was rendering charcoal-purple text on
charcoal-purple background).
2. Hardcoded `background: #000` (3 sites) and `#0d1117`
(3 sites) replaced with `var(--bg)` / `var(--panel)`. Fixes
code blocks and modal panels staying dark on cream — the
deploy-wizard preview, topology-creation NAME input, and the
MazeNET canvas backdrop now follow the active theme.
3. `rgba(0,0,0,0.35)` and `rgba(0,0,0,0.5)` input/card
backgrounds (ServiceConfigForm, DeckyFleet .input)
swapped to `var(--panel)`. Fixes per-service config rows
in the deploy wizard rendering as dark slabs.
4. SVG arrow markers in MazeNET Canvas.tsx hardcoded
`fill="#00ff41"` / "#ee82ee" — replaced with currentColor +
style hook so they re-resolve on theme change.
New behaviour: light-mode hovers tint instead of inverting. The
dark-mode rules fully fill bg with --matrix/--violet/--alert and
flip text to --bg; that lands cream-on-near-ink in light mode
and reads as a jarring colour inversion every cursor move. Light
mode now layers a *-tint-10 background and keeps text in its
base colour. Single override block in index.css targets every
scoped `.X-btn`/`.btn`/`button:hover` via :is() + [class*="-btn"]
so we don't have to chase every component file.
This commit is contained in:
@@ -19,9 +19,9 @@
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.bounty-root .btn:hover { background: var(--matrix); color: #000; box-shadow: var(--matrix-glow); }
|
||||
.bounty-root .btn:hover { background: var(--matrix); color: var(--bg); box-shadow: var(--matrix-glow); }
|
||||
.bounty-root .btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.bounty-root .btn.violet:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.bounty-root .btn.violet:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.bounty-root .btn.ghost { border-color: var(--border); color: var(--matrix); opacity: 0.7; }
|
||||
.bounty-root .btn.ghost:hover { opacity: 1; border-color: var(--matrix); background: transparent; box-shadow: var(--matrix-glow); }
|
||||
.bounty-root .btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
}
|
||||
|
||||
.add-user-form select {
|
||||
background: #0d1117;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--text-color);
|
||||
padding: 8px 12px;
|
||||
@@ -213,7 +213,7 @@
|
||||
}
|
||||
|
||||
.role-select {
|
||||
background: #0d1117;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--text-color);
|
||||
padding: 4px 8px;
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.credentials-root .btn:hover { background: var(--matrix); color: #000; box-shadow: var(--matrix-glow); }
|
||||
.credentials-root .btn:hover { background: var(--matrix); color: var(--bg); box-shadow: var(--matrix-glow); }
|
||||
.credentials-root .btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.credentials-root .btn.violet:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.credentials-root .btn.violet:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.credentials-root .btn.ghost { border-color: var(--border); color: var(--matrix); opacity: 0.7; }
|
||||
.credentials-root .btn.ghost:hover { opacity: 1; border-color: var(--matrix); background: transparent; box-shadow: var(--matrix-glow); }
|
||||
.credentials-root .btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
|
||||
@@ -52,11 +52,11 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.fleet-root .btn:hover { background: var(--matrix); color: #000; box-shadow: var(--matrix-glow); }
|
||||
.fleet-root .btn:hover { background: var(--matrix); color: var(--bg); box-shadow: var(--matrix-glow); }
|
||||
.fleet-root .btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.fleet-root .btn.violet:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.fleet-root .btn.violet:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.fleet-root .btn.alert { border-color: var(--alert); color: var(--alert); }
|
||||
.fleet-root .btn.alert:hover { background: var(--alert); color: #000; box-shadow: 0 0 10px rgba(255, 65, 65, 0.5); }
|
||||
.fleet-root .btn.alert:hover { background: var(--alert); color: var(--bg); box-shadow: 0 0 10px rgba(255, 65, 65, 0.5); }
|
||||
.fleet-root .btn.ghost { border-color: var(--border); color: var(--matrix); opacity: 0.7; }
|
||||
.fleet-root .btn.ghost:hover { color: var(--matrix); opacity: 1; border-color: var(--matrix); box-shadow: var(--matrix-glow); background: transparent; }
|
||||
.fleet-root .btn.small { padding: 4px 10px; font-size: 0.68rem; }
|
||||
@@ -409,7 +409,7 @@
|
||||
.tweak-group label { font-size: 0.62rem; opacity: 0.55; letter-spacing: 1.5px; }
|
||||
.input {
|
||||
width: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
color: var(--matrix);
|
||||
padding: 8px 12px;
|
||||
@@ -422,7 +422,7 @@
|
||||
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||
|
||||
.code-block {
|
||||
background: #000;
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
padding: 14px 16px;
|
||||
font-size: 0.75rem;
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
}
|
||||
.logs-root .btn:hover {
|
||||
background: var(--matrix);
|
||||
color: #000;
|
||||
color: var(--bg);
|
||||
box-shadow: var(--matrix-glow);
|
||||
}
|
||||
.logs-root .btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.logs-root .btn.violet:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.logs-root .btn.violet:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.logs-root .btn.ghost { border-color: var(--border); color: var(--matrix); opacity: 0.7; }
|
||||
.logs-root .btn.ghost:hover { opacity: 1; border-color: var(--matrix); background: transparent; box-shadow: var(--matrix-glow); }
|
||||
.logs-root .btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
|
||||
@@ -142,10 +142,10 @@ const Canvas = forwardRef<HTMLDivElement, Props>(function Canvas(
|
||||
<svg className="maze-svg" overflow="visible">
|
||||
<defs>
|
||||
<marker id="arrow-matrix" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="#00ff41" />
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="currentColor" style={{ color: 'var(--matrix)' }} />
|
||||
</marker>
|
||||
<marker id="arrow-violet" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="#ee82ee" />
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="currentColor" style={{ color: 'var(--violet)' }} />
|
||||
</marker>
|
||||
<marker id="arrow-alert" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="#ff4141" />
|
||||
|
||||
@@ -46,7 +46,7 @@ body.maze-fullscreen .maze-shell {
|
||||
gap: 8px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.maze-btn:hover { background: var(--matrix); color: #000; box-shadow: var(--matrix-glow); }
|
||||
.maze-btn:hover { background: var(--matrix); color: var(--bg); box-shadow: var(--matrix-glow); }
|
||||
.maze-btn.ghost { border-color: var(--border); color: var(--matrix); opacity: 0.7; }
|
||||
.maze-btn.ghost:hover {
|
||||
background: transparent; color: var(--matrix); opacity: 1;
|
||||
@@ -127,14 +127,14 @@ body.maze-fullscreen .maze-shell {
|
||||
|
||||
/* ── Canvas ─────────────────────────────────── */
|
||||
.maze-canvas-wrap {
|
||||
position: relative; background: #000;
|
||||
position: relative; background: var(--bg);
|
||||
overflow: hidden; user-select: none;
|
||||
height: 100%; min-height: 0;
|
||||
}
|
||||
.maze-pan-layer { position: absolute; inset: 0; will-change: transform; }
|
||||
.maze-grid-bg {
|
||||
position: absolute; inset: 0;
|
||||
pointer-events: none; opacity: 0.6; overflow: hidden; background: #000;
|
||||
pointer-events: none; opacity: 0.6; overflow: hidden; background: var(--bg);
|
||||
}
|
||||
.maze-grid-bg svg { display: block; width: 100%; height: 100%; }
|
||||
.maze-svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
|
||||
@@ -372,7 +372,7 @@ body.maze-fullscreen .maze-shell {
|
||||
padding: 30px 10px; font-size: 0.7rem; letter-spacing: 1px;
|
||||
}
|
||||
.maze-diff {
|
||||
background: #000; border: 1px solid var(--border);
|
||||
background: var(--bg); border: 1px solid var(--border);
|
||||
padding: 10px 12px; font-size: 0.68rem; line-height: 1.6;
|
||||
white-space: pre; overflow-x: auto;
|
||||
}
|
||||
@@ -562,7 +562,7 @@ body.maze-fullscreen .maze-shell {
|
||||
}
|
||||
.maze-btn.alert:hover {
|
||||
background: var(--alert);
|
||||
color: #000;
|
||||
color: var(--bg);
|
||||
box-shadow: 0 0 10px rgba(255, 65, 65, 0.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ select.svc-cfg-input {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.72rem;
|
||||
padding: 4px 6px;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 0;
|
||||
color: var(--matrix);
|
||||
@@ -146,10 +146,10 @@ select.svc-cfg-input {
|
||||
}
|
||||
.svc-cfg-btn:hover:not(:disabled) {
|
||||
background: var(--matrix);
|
||||
color: #000;
|
||||
color: var(--bg);
|
||||
}
|
||||
.svc-cfg-btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.svc-cfg-btn.violet:hover:not(:disabled) { background: var(--violet); color: #000; }
|
||||
.svc-cfg-btn.violet:hover:not(:disabled) { background: var(--violet); color: var(--bg); }
|
||||
.svc-cfg-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
|
||||
.svc-cfg-pw-toggle {
|
||||
|
||||
@@ -89,14 +89,14 @@
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.control-btn:hover { background: var(--matrix); color: #000; box-shadow: var(--matrix-glow); }
|
||||
.control-btn:hover { background: var(--matrix); color: var(--bg); box-shadow: var(--matrix-glow); }
|
||||
.control-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
|
||||
.control-btn.primary {
|
||||
border-color: var(--violet);
|
||||
color: var(--violet);
|
||||
}
|
||||
.control-btn.primary:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.control-btn.primary:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
|
||||
.control-btn.danger {
|
||||
border-color: var(--alert, var(--alert));
|
||||
@@ -104,7 +104,7 @@
|
||||
}
|
||||
.control-btn.danger:hover {
|
||||
background: var(--alert, var(--alert));
|
||||
color: #000;
|
||||
color: var(--bg);
|
||||
box-shadow: 0 0 10px rgba(255, 77, 77, 0.5);
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
}
|
||||
.ctw-field input[type='text'] {
|
||||
padding: 8px 10px;
|
||||
background: #000;
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border, var(--panel-border));
|
||||
color: var(--text-color);
|
||||
font-family: var(--font-mono);
|
||||
@@ -191,7 +191,7 @@
|
||||
margin-right: 6px;
|
||||
}
|
||||
.ctw-note code {
|
||||
background: #000;
|
||||
background: var(--bg);
|
||||
padding: 1px 5px;
|
||||
font-family: var(--font-mono);
|
||||
color: var(--matrix, #33ff66);
|
||||
@@ -232,7 +232,7 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.ctw-btn:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.ctw-btn:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.ctw-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
.ctw-btn.ghost { border-color: var(--border); color: var(--matrix); opacity: 0.7; }
|
||||
.ctw-btn.ghost:hover {
|
||||
|
||||
@@ -48,16 +48,16 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.tlist-btn:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.tlist-btn:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.tlist-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
.tlist-btn.ghost { border-color: var(--matrix); color: var(--matrix); }
|
||||
.tlist-btn.ghost:hover { background: var(--matrix); color: #000; box-shadow: var(--matrix-glow); }
|
||||
.tlist-btn.ghost:hover { background: var(--matrix); color: var(--bg); box-shadow: var(--matrix-glow); }
|
||||
.tlist-btn.small { padding: 4px 10px; font-size: 0.68rem; }
|
||||
.tlist-btn.danger { border-color: var(--alert, #e74c3c); color: var(--alert, #e74c3c); }
|
||||
.tlist-btn.danger:hover { background: var(--alert, #e74c3c); color: #000; box-shadow: 0 0 10px rgba(231, 76, 60, 0.5); }
|
||||
.tlist-btn.danger:hover { background: var(--alert, #e74c3c); color: var(--bg); box-shadow: 0 0 10px rgba(231, 76, 60, 0.5); }
|
||||
.tlist-btn.danger.armed { background: var(--alert, #e74c3c); color: #000; }
|
||||
.tlist-btn.warn { border-color: var(--warn, #e0a040); color: var(--warn, #e0a040); }
|
||||
.tlist-btn.warn:hover { background: var(--warn, #e0a040); color: #000; box-shadow: 0 0 10px rgba(224, 160, 64, 0.5); }
|
||||
.tlist-btn.warn:hover { background: var(--warn, #e0a040); color: var(--bg); box-shadow: 0 0 10px rgba(224, 160, 64, 0.5); }
|
||||
.tlist-btn.warn.armed { background: var(--warn, #e0a040); color: #000; }
|
||||
|
||||
.tlist-create-row {
|
||||
|
||||
@@ -49,15 +49,15 @@
|
||||
}
|
||||
.webhooks-root .btn:hover {
|
||||
background: var(--matrix);
|
||||
color: #000;
|
||||
color: var(--bg);
|
||||
box-shadow: var(--matrix-glow);
|
||||
}
|
||||
.webhooks-root .btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.webhooks-root .btn.violet:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.webhooks-root .btn.violet:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.webhooks-root .btn.alert { border-color: var(--alert, #ff4d4d); color: var(--alert, #ff4d4d); }
|
||||
.webhooks-root .btn.alert:hover { background: var(--alert, #ff4d4d); color: #000; box-shadow: 0 0 10px rgba(255, 77, 77, 0.5); }
|
||||
.webhooks-root .btn.alert:hover { background: var(--alert, #ff4d4d); color: var(--bg); box-shadow: 0 0 10px rgba(255, 77, 77, 0.5); }
|
||||
.webhooks-root .btn.warn { border-color: var(--warn, #e0a040); color: var(--warn, #e0a040); }
|
||||
.webhooks-root .btn.warn:hover { background: var(--warn, #e0a040); color: #000; box-shadow: 0 0 10px rgba(224, 160, 64, 0.5); }
|
||||
.webhooks-root .btn.warn:hover { background: var(--warn, #e0a040); color: var(--bg); box-shadow: 0 0 10px rgba(224, 160, 64, 0.5); }
|
||||
.webhooks-root .btn.ghost { border-color: var(--border-color); color: var(--matrix); opacity: 0.7; }
|
||||
.webhooks-root .btn.ghost:hover { opacity: 1; border-color: var(--matrix); background: transparent; box-shadow: var(--matrix-glow); }
|
||||
.webhooks-root .btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
@@ -126,7 +126,7 @@
|
||||
}
|
||||
.webhooks-root .action-btn.fire:hover {
|
||||
background: var(--violet);
|
||||
color: #000;
|
||||
color: var(--bg);
|
||||
box-shadow: var(--violet-glow);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
.webhooks-root .wh-form-grid input[type="url"],
|
||||
.webhooks-root .wh-form-grid input[type="password"],
|
||||
.webhooks-root .wh-form-grid textarea {
|
||||
background: #0d1117;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--text-color);
|
||||
padding: 8px 12px;
|
||||
@@ -307,7 +307,7 @@
|
||||
}
|
||||
|
||||
.wh-secret-modal .wh-secret-value {
|
||||
background: #0d1117;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 10px 12px;
|
||||
font-size: 0.85rem;
|
||||
@@ -336,6 +336,6 @@
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.wh-secret-modal .btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.wh-secret-modal .btn.violet:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.wh-secret-modal .btn.violet:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.wh-secret-modal .btn.ghost { border-color: var(--border-color); color: var(--matrix); opacity: 0.7; }
|
||||
.wh-secret-modal .btn.ghost:hover { opacity: 1; border-color: var(--matrix); background: transparent; box-shadow: var(--matrix-glow); }
|
||||
|
||||
@@ -172,6 +172,44 @@ html[data-theme="light"] {
|
||||
--accent-glow: none;
|
||||
}
|
||||
|
||||
/* Hover behaviour in light mode.
|
||||
*
|
||||
* Dark mode hovers fully invert: bg fills with --matrix/--violet/
|
||||
* --alert and text becomes --bg. That works on black-cream because
|
||||
* neon-on-ink has obvious contrast. In light mode that same flip
|
||||
* lands cream text on near-ink and reads as a jarring colour
|
||||
* inversion every time the cursor moves.
|
||||
*
|
||||
* Light mode therefore tints instead of inverting — hover backgrounds
|
||||
* use the matching --*-tint-10, text stays in its base colour.
|
||||
* Targets every common scoped button class via [class*="-btn"] plus
|
||||
* the unprefixed .btn/button selectors. */
|
||||
html[data-theme="light"]
|
||||
:is(button, .btn, [class*="-btn"]):hover:not(:disabled) {
|
||||
background: var(--matrix-tint-10);
|
||||
color: var(--matrix);
|
||||
box-shadow: none;
|
||||
}
|
||||
html[data-theme="light"]
|
||||
:is(button, .btn, [class*="-btn"]).violet:hover:not(:disabled),
|
||||
html[data-theme="light"]
|
||||
:is(button, .btn, [class*="-btn"]).primary:hover:not(:disabled) {
|
||||
background: var(--violet-tint-10);
|
||||
color: var(--violet);
|
||||
}
|
||||
html[data-theme="light"]
|
||||
:is(button, .btn, [class*="-btn"]).alert:hover:not(:disabled),
|
||||
html[data-theme="light"]
|
||||
:is(button, .btn, [class*="-btn"]).danger:hover:not(:disabled) {
|
||||
background: var(--alert-tint-10);
|
||||
color: var(--alert);
|
||||
}
|
||||
html[data-theme="light"]
|
||||
:is(button, .btn, [class*="-btn"]).warn:hover:not(:disabled) {
|
||||
background: var(--warn-tint-10);
|
||||
color: var(--warn);
|
||||
}
|
||||
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
@@ -220,9 +258,9 @@ button:disabled {
|
||||
|
||||
/* Shared .btn variants (unscoped) */
|
||||
.btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.btn.violet:hover { background: var(--violet); color: #000; box-shadow: var(--violet-glow); }
|
||||
.btn.violet:hover { background: var(--violet); color: var(--bg); box-shadow: var(--violet-glow); }
|
||||
.btn.alert { border-color: var(--alert); color: var(--alert); }
|
||||
.btn.alert:hover { background: var(--alert); color: #000; box-shadow: 0 0 10px rgba(255, 65, 65, 0.5); }
|
||||
.btn.alert:hover { background: var(--alert); color: var(--bg); box-shadow: 0 0 10px rgba(255, 65, 65, 0.5); }
|
||||
.btn.ghost { border-color: var(--border); color: var(--matrix); opacity: 0.7; }
|
||||
.btn.ghost:hover {
|
||||
background: transparent; color: var(--matrix); opacity: 1;
|
||||
|
||||
Reference in New Issue
Block a user