fix(decnet_web/css): sweep rgba colour literals to tokens app-wide
Pre-this-commit, ~80 rgba() literals across 24 files were hardcoding alert-red, warn-amber, info-cyan, panel-dark, and white-text-with-alpha shades that bypassed the token cascade. Net effect in light mode: the .eml/SESSREC drawers, AttackerDetail verdict pills, MazeNET net-box headers, OPEN/REPLAY action buttons, threat-intel cards, and all the dim 'whitish' overlays stayed on their dark-mode hex values, producing the unreadable panels in the screenshots. Sweep maps each rgba colour family onto the existing token by alpha bucket — rgba(13,17,23,*) -> var(--panel), rgba(255,65,65,*) -> var(--alert)/-tint-10, rgba(255,170,0,*) and rgba(224,160,64,*) -> var(--warn)/-tint-10, rgba(0,200,255,*) -> var(--info)/-tint-10, rgba(255,255,255,*) -> var(--fg-N)/var(--matrix-tint-N) by alpha. VERDICT_TONE in AttackerDetail (MALICIOUS/SUSPICIOUS/BENIGN/ NO SIGNAL) was the worst offender — string literals '#ff4d4d'/'#ffae42'/'#5fd07a'/rgba(255,255,255,0.4) baked into inline JS styles. Now resolves at render time via var(--alert)/ var(--warn)/var(--ok)/var(--fg-4). New tokens in :root: - --bg-color (alias of --bg) — drawers used this name with #0d1117 fallback that fired in every browser because nothing defined --bg-color. Adding the alias makes drawers re-tone. - --info / --info-tint-10 / --info-tint-30 — REPLAY buttons and any future neutral-secondary use. - --ok — semantic alias for 'verified good' (matrix in dark, emerald in light) so BENIGN pills stay readable across themes. Login.css left intentionally — pre-auth surface, not themed.
This commit is contained in:
@@ -27,7 +27,7 @@ function decodeMeta(fields: Record<string, any>): Record<string, any> | null {
|
||||
}
|
||||
|
||||
const Row: React.FC<{ label: string; value: React.ReactNode }> = ({ label, value }) => (
|
||||
<div style={{ display: 'flex', gap: '12px', padding: '6px 0', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
|
||||
<div style={{ display: 'flex', gap: '12px', padding: '6px 0', borderBottom: '1px solid var(--matrix-tint-5)' }}>
|
||||
<div style={{ minWidth: '140px', color: 'var(--dim-color)', fontSize: '0.75rem', textTransform: 'uppercase' }}>{label}</div>
|
||||
<div style={{ flex: 1, fontSize: '0.85rem', wordBreak: 'break-all' }}>{value ?? <span style={{ opacity: 0.4 }}>—</span>}</div>
|
||||
</div>
|
||||
@@ -120,9 +120,9 @@ const ArtifactDrawer: React.FC<ArtifactDrawerProps> = ({ decky, storedAs, fields
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', gap: '8px',
|
||||
padding: '8px 12px', marginBottom: '16px',
|
||||
border: '1px solid rgba(255, 170, 0, 0.3)',
|
||||
backgroundColor: 'rgba(255, 170, 0, 0.05)',
|
||||
fontSize: '0.75rem', color: '#ffaa00',
|
||||
border: '1px solid var(--warn)',
|
||||
backgroundColor: 'var(--warn-tint-10)',
|
||||
fontSize: '0.75rem', color: 'var(--warn)',
|
||||
}}>
|
||||
<AlertTriangle size={14} />
|
||||
Attacker-controlled content. Download at your own risk.
|
||||
@@ -176,7 +176,7 @@ const ArtifactDrawer: React.FC<ArtifactDrawerProps> = ({ decky, storedAs, fields
|
||||
<h3 style={{ fontSize: '0.8rem', letterSpacing: '0.1em', color: 'var(--dim-color)', marginBottom: '8px' }}>
|
||||
CONCURRENT SESSIONS ({concurrent.length})
|
||||
</h3>
|
||||
<pre style={{ fontSize: '0.75rem', background: 'rgba(255,255,255,0.03)', padding: '8px', overflowX: 'auto' }}>
|
||||
<pre style={{ fontSize: '0.75rem', background: 'var(--matrix-tint-5)', padding: '8px', overflowX: 'auto' }}>
|
||||
{JSON.stringify(concurrent, null, 2)}
|
||||
</pre>
|
||||
</section>
|
||||
@@ -187,7 +187,7 @@ const ArtifactDrawer: React.FC<ArtifactDrawerProps> = ({ decky, storedAs, fields
|
||||
<h3 style={{ fontSize: '0.8rem', letterSpacing: '0.1em', color: 'var(--dim-color)', marginBottom: '8px' }}>
|
||||
SS SNAPSHOT ({ssSnapshot.length})
|
||||
</h3>
|
||||
<pre style={{ fontSize: '0.75rem', background: 'rgba(255,255,255,0.03)', padding: '8px', overflowX: 'auto' }}>
|
||||
<pre style={{ fontSize: '0.75rem', background: 'var(--matrix-tint-5)', padding: '8px', overflowX: 'auto' }}>
|
||||
{JSON.stringify(ssSnapshot, null, 2)}
|
||||
</pre>
|
||||
</section>
|
||||
|
||||
@@ -1292,10 +1292,10 @@ type IntelRow = {
|
||||
};
|
||||
|
||||
const VERDICT_TONE: Record<string, { color: string; label: string }> = {
|
||||
malicious: { color: '#ff4d4d', label: 'MALICIOUS' },
|
||||
suspicious: { color: '#ffae42', label: 'SUSPICIOUS' },
|
||||
benign: { color: '#5fd07a', label: 'BENIGN' },
|
||||
unknown: { color: 'rgba(255,255,255,0.4)', label: 'NO SIGNAL' },
|
||||
malicious: { color: 'var(--alert)', label: 'MALICIOUS' },
|
||||
suspicious: { color: 'var(--warn)', label: 'SUSPICIOUS' },
|
||||
benign: { color: 'var(--ok)', label: 'BENIGN' },
|
||||
unknown: { color: 'var(--fg-4)', label: 'NO SIGNAL' },
|
||||
};
|
||||
|
||||
const fmtTs = (iso?: string | null): string => {
|
||||
@@ -1317,7 +1317,7 @@ const ProviderRow: React.FC<{
|
||||
gridTemplateColumns: '160px 1fr auto',
|
||||
gap: '12px',
|
||||
padding: '10px 16px',
|
||||
borderTop: '1px solid rgba(255,255,255,0.05)',
|
||||
borderTop: '1px solid var(--matrix-tint-5)',
|
||||
alignItems: 'center',
|
||||
fontSize: '0.85rem',
|
||||
}}>
|
||||
@@ -1391,7 +1391,7 @@ const IntelPanel: React.FC<{ uuid: string }> = ({ uuid }) => {
|
||||
alignItems: 'center',
|
||||
gap: '12px',
|
||||
padding: '14px 16px',
|
||||
borderBottom: '1px solid rgba(255,255,255,0.05)',
|
||||
borderBottom: '1px solid var(--matrix-tint-5)',
|
||||
}}>
|
||||
<Shield size={16} style={{ color: tone.color }} />
|
||||
<span style={{
|
||||
@@ -2310,11 +2310,11 @@ const AttackerDetail: React.FC = () => {
|
||||
style={{
|
||||
display: 'flex', alignItems: 'center', gap: '6px',
|
||||
fontSize: '0.7rem',
|
||||
backgroundColor: 'rgba(255, 170, 0, 0.1)',
|
||||
backgroundColor: 'var(--warn-tint-10)',
|
||||
padding: '2px 8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid rgba(255, 170, 0, 0.5)',
|
||||
color: '#ffaa00',
|
||||
border: '1px solid var(--warn)',
|
||||
color: 'var(--warn)',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
@@ -2449,11 +2449,11 @@ const AttackerDetail: React.FC = () => {
|
||||
style={{
|
||||
display: 'flex', alignItems: 'center', gap: '6px',
|
||||
fontSize: '0.7rem',
|
||||
backgroundColor: 'rgba(255, 170, 0, 0.1)',
|
||||
backgroundColor: 'var(--warn-tint-10)',
|
||||
padding: '2px 8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid rgba(255, 170, 0, 0.5)',
|
||||
color: '#ffaa00',
|
||||
border: '1px solid var(--warn)',
|
||||
color: 'var(--warn)',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
@@ -2532,11 +2532,11 @@ const AttackerDetail: React.FC = () => {
|
||||
style={{
|
||||
display: 'flex', alignItems: 'center', gap: '6px',
|
||||
fontSize: '0.7rem',
|
||||
backgroundColor: 'rgba(0, 200, 255, 0.1)',
|
||||
backgroundColor: 'var(--info-tint-10)',
|
||||
padding: '2px 8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid rgba(0, 200, 255, 0.5)',
|
||||
color: '#00c8ff',
|
||||
border: '1px solid var(--info)',
|
||||
color: 'var(--info)',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -44,7 +44,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const Row: React.FC<{ label: string; value: React.ReactNode }> = ({ label, value }) => (
|
||||
<div style={{ display: 'flex', gap: '12px', padding: '6px 0', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
|
||||
<div style={{ display: 'flex', gap: '12px', padding: '6px 0', borderBottom: '1px solid var(--matrix-tint-5)' }}>
|
||||
<div style={{ minWidth: '140px', color: 'var(--dim-color)', fontSize: '0.75rem', textTransform: 'uppercase' }}>{label}</div>
|
||||
<div style={{ flex: 1, fontSize: '0.85rem', wordBreak: 'break-all' }}>{value ?? <span style={{ opacity: 0.4 }}>—</span>}</div>
|
||||
</div>
|
||||
@@ -291,8 +291,8 @@ const CanaryTokenDrawer: React.FC<Props> = ({ token, onClose, onRevoked }) => {
|
||||
key={t.uuid}
|
||||
style={{
|
||||
padding: '8px 12px',
|
||||
border: '1px solid rgba(255,255,255,0.08)',
|
||||
background: 'rgba(255,255,255,0.02)',
|
||||
border: '1px solid var(--matrix-tint-5)',
|
||||
background: 'var(--matrix-tint-5)',
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -458,9 +458,9 @@ const UploadModal: React.FC<UploadModalProps> = ({ onClose, onUploaded }) => {
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', gap: '8px',
|
||||
padding: '8px 12px', marginBottom: '16px',
|
||||
border: '1px solid rgba(255, 170, 0, 0.3)',
|
||||
backgroundColor: 'rgba(255, 170, 0, 0.05)',
|
||||
fontSize: '0.75rem', color: '#ffaa00',
|
||||
border: '1px solid var(--warn)',
|
||||
backgroundColor: 'var(--warn-tint-10)',
|
||||
fontSize: '0.75rem', color: 'var(--warn)',
|
||||
}}>
|
||||
<AlertTriangle size={14} />
|
||||
DECNET injects the callback server-side; the original bytes stay on the master.
|
||||
@@ -811,9 +811,9 @@ const FileDropModal: React.FC<FileDropModalProps> = ({ deckies, topologies, onCl
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', gap: '8px',
|
||||
padding: '8px 12px', marginBottom: '16px',
|
||||
border: '1px solid rgba(255, 170, 0, 0.3)',
|
||||
backgroundColor: 'rgba(255, 170, 0, 0.05)',
|
||||
fontSize: '0.7rem', color: '#ffaa00',
|
||||
border: '1px solid var(--warn)',
|
||||
backgroundColor: 'var(--warn-tint-10)',
|
||||
fontSize: '0.7rem', color: 'var(--warn)',
|
||||
}}>
|
||||
<AlertTriangle size={14} />
|
||||
File drops bypass canary instrumentation — bytes land verbatim. The list below is local only.
|
||||
@@ -1052,7 +1052,7 @@ const CanaryTokens: React.FC = () => {
|
||||
alignItems: 'center', gap: '12px',
|
||||
padding: '10px 14px',
|
||||
border: '1px solid var(--border-color, #30363d)',
|
||||
background: 'rgba(255,255,255,0.02)',
|
||||
background: 'var(--matrix-tint-5)',
|
||||
color: 'var(--text-color)',
|
||||
cursor: 'pointer',
|
||||
textAlign: 'left',
|
||||
@@ -1114,7 +1114,7 @@ const CanaryTokens: React.FC = () => {
|
||||
alignItems: 'center', gap: '12px',
|
||||
padding: '10px 14px',
|
||||
border: '1px solid var(--border-color, #30363d)',
|
||||
background: 'rgba(255,255,255,0.02)',
|
||||
background: 'var(--matrix-tint-5)',
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
@@ -1189,7 +1189,7 @@ const CanaryTokens: React.FC = () => {
|
||||
alignItems: 'center', gap: '12px',
|
||||
padding: '10px 14px',
|
||||
border: '1px solid var(--border-color, #30363d)',
|
||||
background: 'rgba(255,255,255,0.02)',
|
||||
background: 'var(--matrix-tint-5)',
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
@@ -1281,7 +1281,7 @@ const INPUT_STYLE: React.CSSProperties = {
|
||||
width: '100%',
|
||||
padding: '8px 10px',
|
||||
marginBottom: '12px',
|
||||
background: 'rgba(255,255,255,0.03)',
|
||||
background: 'var(--matrix-tint-5)',
|
||||
border: '1px solid var(--border-color, #30363d)',
|
||||
color: 'var(--text-color)',
|
||||
fontSize: '0.85rem',
|
||||
@@ -1324,7 +1324,7 @@ const Stat: React.FC<{ label: string; value: number | string; color: string }> =
|
||||
flex: '1 1 120px',
|
||||
padding: '12px 16px',
|
||||
border: '1px solid var(--border-color, #30363d)',
|
||||
background: 'rgba(255,255,255,0.02)',
|
||||
background: 'var(--matrix-tint-5)',
|
||||
}}>
|
||||
<div style={{ fontSize: '0.7rem', color: 'var(--dim-color)', letterSpacing: '0.1em' }}>{label}</div>
|
||||
<div style={{ fontSize: '1.4rem', fontWeight: 'bold', color, marginTop: '4px' }}>{value}</div>
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
.action-btn.danger:hover {
|
||||
background: #ff4141;
|
||||
color: var(--background-color);
|
||||
box-shadow: 0 0 10px rgba(255, 65, 65, 0.5);
|
||||
box-shadow: 0 0 10px var(--alert);
|
||||
}
|
||||
|
||||
/* Add User Form */
|
||||
@@ -260,7 +260,7 @@
|
||||
font-size: 0.75rem;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #ff4141;
|
||||
background: rgba(255, 65, 65, 0.1);
|
||||
background: var(--alert-tint-10);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
@@ -635,7 +635,7 @@ const RealismBadge: React.FC<{
|
||||
const breaker = realism.llm_breaker_state ?? 'closed';
|
||||
const breakerColor =
|
||||
breaker === 'open' ? '#ff5555'
|
||||
: breaker === 'half_open' ? '#ffaa00'
|
||||
: breaker === 'half_open' ? 'var(--warn)'
|
||||
: 'var(--matrix)';
|
||||
const tooltip = [
|
||||
`Backend: ${realism.llm_backend ?? '?'}`,
|
||||
@@ -793,8 +793,8 @@ const WorkersPanel: React.FC<WorkersPanelProps> = ({ pushToast }) => {
|
||||
margin: '16px 20px 0',
|
||||
padding: '10px 14px',
|
||||
border: '1px solid #ffaa00',
|
||||
background: 'rgba(255, 170, 0, 0.08)',
|
||||
color: '#ffaa00',
|
||||
background: 'var(--warn-tint-10)',
|
||||
color: 'var(--warn)',
|
||||
fontSize: '0.72rem',
|
||||
letterSpacing: 1,
|
||||
lineHeight: 1.5,
|
||||
@@ -906,8 +906,8 @@ const WorkersPanel: React.FC<WorkersPanelProps> = ({ pushToast }) => {
|
||||
</td>
|
||||
<td style={{
|
||||
color: w.status === 'ok' ? 'var(--matrix)'
|
||||
: w.status === 'stale' ? '#ffaa00'
|
||||
: 'rgba(255,255,255,0.4)',
|
||||
: w.status === 'stale' ? 'var(--warn)'
|
||||
: 'var(--fg-4)',
|
||||
letterSpacing: 1,
|
||||
}}>
|
||||
{w.status.toUpperCase()}
|
||||
@@ -927,8 +927,8 @@ const WorkersPanel: React.FC<WorkersPanelProps> = ({ pushToast }) => {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 4,
|
||||
color: canStop ? '#ff4d4d' : '#ff4d4d',
|
||||
borderColor: canStop ? '#ff4d4d' : 'rgba(255, 77, 77, 0.4)',
|
||||
color: canStop ? 'var(--alert)' : 'var(--alert)',
|
||||
borderColor: canStop ? 'var(--alert)' : 'rgba(255, 77, 77, 0.4)',
|
||||
opacity: canStop ? 1 : 0.3,
|
||||
cursor: canStop ? 'pointer' : 'not-allowed',
|
||||
}}
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
.chip.alert-chip {
|
||||
border-color: var(--alert);
|
||||
color: var(--alert);
|
||||
background: rgba(255, 65, 65, 0.1);
|
||||
background: var(--alert-tint-10);
|
||||
}
|
||||
|
||||
/* Key-value chips in the live-feed event column. Values are unbounded
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
/* Breach banner */
|
||||
.breach-banner {
|
||||
background: rgba(255, 65, 65, 0.1);
|
||||
background: var(--alert-tint-10);
|
||||
border: 1px solid var(--alert);
|
||||
padding: 12px 20px;
|
||||
display: flex;
|
||||
@@ -128,7 +128,7 @@
|
||||
}
|
||||
|
||||
.breach-banner button:hover {
|
||||
background: rgba(255, 65, 65, 0.15);
|
||||
background: var(--alert-tint-10);
|
||||
}
|
||||
|
||||
/* Stats */
|
||||
@@ -155,7 +155,7 @@
|
||||
}
|
||||
|
||||
.stat-card.alert {
|
||||
border-color: rgba(255, 65, 65, 0.4);
|
||||
border-color: var(--alert);
|
||||
}
|
||||
|
||||
.stat-card .row {
|
||||
@@ -370,7 +370,7 @@
|
||||
|
||||
.status-dot.warn {
|
||||
background: var(--warn);
|
||||
box-shadow: 0 0 6px rgba(255, 170, 0, 0.6);
|
||||
box-shadow: 0 0 6px var(--warn);
|
||||
}
|
||||
|
||||
.status-dot.hot {
|
||||
|
||||
@@ -399,11 +399,11 @@ const Dashboard: React.FC<DashboardProps> = ({ searchQuery }) => {
|
||||
style={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 4,
|
||||
fontSize: '0.62rem',
|
||||
backgroundColor: 'rgba(255, 170, 0, 0.1)',
|
||||
backgroundColor: 'var(--warn-tint-10)',
|
||||
padding: '2px 8px',
|
||||
borderRadius: 4,
|
||||
border: '1px solid rgba(255, 170, 0, 0.5)',
|
||||
color: '#ffaa00',
|
||||
border: '1px solid var(--warn)',
|
||||
color: 'var(--warn)',
|
||||
cursor: 'pointer',
|
||||
letterSpacing: 1,
|
||||
}}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
.fleet-root .btn.violet { border-color: var(--violet); color: var(--violet); }
|
||||
.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: var(--bg); 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 var(--alert); }
|
||||
.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; }
|
||||
@@ -137,7 +137,7 @@
|
||||
line-height: 1;
|
||||
padding: 2px 8px;
|
||||
border-color: var(--border);
|
||||
color: var(--text-dim, rgba(255,255,255,0.5));
|
||||
color: var(--text-dim, var(--fg-3));
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.tarpit-menu-btn:hover {
|
||||
@@ -173,14 +173,14 @@
|
||||
.tarpit-dropdown-item:last-child { border-bottom: none; }
|
||||
.tarpit-dropdown-item:hover { background: rgba(57,255,20,0.08); }
|
||||
.tarpit-dropdown-item.alert { color: var(--alert); }
|
||||
.tarpit-dropdown-item.alert:hover { background: rgba(255,65,65,0.08); }
|
||||
.tarpit-dropdown-item.alert:hover { background: var(--alert-tint-10); }
|
||||
|
||||
/* Tarpit enable form — rendered below the card footer */
|
||||
.tarpit-form {
|
||||
margin-top: 8px;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--alert);
|
||||
background: rgba(255,65,65,0.04);
|
||||
background: var(--alert-tint-10);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
@@ -194,7 +194,7 @@
|
||||
.tarpit-form input.input {
|
||||
font-size: 0.72rem;
|
||||
padding: 4px 6px;
|
||||
background: rgba(255,255,255,0.04);
|
||||
background: var(--matrix-tint-10);
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text-color);
|
||||
}
|
||||
@@ -204,7 +204,7 @@
|
||||
Modal portal; PersonaGeneration.css scopes its own copy under
|
||||
.persona-gen-root, which doesn't match the modal's DOM location. */
|
||||
.info-banner {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
background: var(--matrix-tint-5);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 3px solid var(--violet);
|
||||
padding: 10px 14px;
|
||||
@@ -222,7 +222,7 @@
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
background: var(--matrix-tint-5);
|
||||
border: none;
|
||||
color: inherit;
|
||||
font-family: var(--font-mono);
|
||||
@@ -232,7 +232,7 @@
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
.wizard-svc-toggle:hover { background: rgba(255, 255, 255, 0.05); }
|
||||
.wizard-svc-toggle:hover { background: var(--matrix-tint-10); }
|
||||
.wizard-svc-toggle.open { border-bottom: 1px solid var(--border); }
|
||||
.wizard-svc-caret { color: var(--violet); width: 10px; }
|
||||
.wizard-svc-name { color: var(--matrix); flex: 1; }
|
||||
|
||||
@@ -519,7 +519,7 @@ const DeckyCard: React.FC<DeckyCardProps> = ({
|
||||
onChange={(e) => setAddSlug(e.target.value)}
|
||||
style={{
|
||||
flex: 1, fontSize: '0.75rem', padding: '4px 6px',
|
||||
background: 'rgba(255,255,255,0.04)',
|
||||
background: 'var(--matrix-tint-10)',
|
||||
border: '1px solid var(--border-color, #30363d)',
|
||||
color: 'var(--text-color)',
|
||||
}}
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
color: var(--alert);
|
||||
border: 1px solid var(--alert);
|
||||
padding: 1px 5px;
|
||||
background: rgba(255, 65, 65, 0.1);
|
||||
background: var(--alert-tint-10);
|
||||
letter-spacing: 1px;
|
||||
margin-left: auto;
|
||||
}
|
||||
@@ -286,7 +286,7 @@
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--alert);
|
||||
color: var(--alert);
|
||||
background: rgba(255, 65, 65, 0.08);
|
||||
background: var(--alert-tint-10);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
|
||||
@@ -137,15 +137,15 @@
|
||||
font-size: 0.68rem;
|
||||
padding: 2px 8px;
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 170, 0, 0.1);
|
||||
border: 1px solid rgba(255, 170, 0, 0.5);
|
||||
background: var(--warn-tint-10);
|
||||
border: 1px solid var(--warn);
|
||||
color: var(--warn);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
}
|
||||
.logs-root .artifact-btn:hover {
|
||||
background: rgba(255, 170, 0, 0.2);
|
||||
box-shadow: 0 0 8px rgba(255, 170, 0, 0.4);
|
||||
background: var(--warn-tint-10);
|
||||
box-shadow: 0 0 8px var(--warn);
|
||||
}
|
||||
|
||||
/* Empty state */
|
||||
|
||||
@@ -31,7 +31,7 @@ function parseAttachments(fields: Record<string, any>): AttachmentManifest[] {
|
||||
}
|
||||
|
||||
const Row: React.FC<{ label: string; value: React.ReactNode }> = ({ label, value }) => (
|
||||
<div style={{ display: 'flex', gap: '12px', padding: '6px 0', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
|
||||
<div style={{ display: 'flex', gap: '12px', padding: '6px 0', borderBottom: '1px solid var(--matrix-tint-5)' }}>
|
||||
<div style={{ minWidth: '140px', color: 'var(--dim-color)', fontSize: '0.75rem', textTransform: 'uppercase' }}>{label}</div>
|
||||
<div style={{ flex: 1, fontSize: '0.85rem', wordBreak: 'break-all' }}>{value ?? <span style={{ opacity: 0.4 }}>—</span>}</div>
|
||||
</div>
|
||||
@@ -125,9 +125,9 @@ const MailDrawer: React.FC<MailDrawerProps> = ({ decky, storedAs, fields, onClos
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', gap: '8px',
|
||||
padding: '8px 12px', marginBottom: '16px',
|
||||
border: '1px solid rgba(255, 170, 0, 0.3)',
|
||||
backgroundColor: 'rgba(255, 170, 0, 0.05)',
|
||||
fontSize: '0.75rem', color: '#ffaa00',
|
||||
border: '1px solid var(--warn)',
|
||||
backgroundColor: 'var(--warn-tint-10)',
|
||||
fontSize: '0.75rem', color: 'var(--warn)',
|
||||
}}>
|
||||
<AlertTriangle size={14} />
|
||||
Attacker-controlled content. Phishing kits / malware likely.
|
||||
@@ -184,8 +184,8 @@ const MailDrawer: React.FC<MailDrawerProps> = ({ decky, storedAs, fields, onClos
|
||||
key={idx}
|
||||
style={{
|
||||
padding: '8px 12px',
|
||||
border: '1px solid rgba(255,255,255,0.08)',
|
||||
background: 'rgba(255,255,255,0.02)',
|
||||
border: '1px solid var(--matrix-tint-5)',
|
||||
background: 'var(--matrix-tint-5)',
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -211,7 +211,7 @@ const Inspector: React.FC<Props> = ({
|
||||
onChange={(e) => setAddSlug(e.target.value)}
|
||||
style={{
|
||||
flex: 1, fontSize: '0.75rem', padding: '4px 6px',
|
||||
background: 'rgba(255,255,255,0.04)',
|
||||
background: 'var(--matrix-tint-10)',
|
||||
border: '1px solid var(--border-color, #30363d)',
|
||||
color: 'var(--text-color)',
|
||||
}}
|
||||
|
||||
@@ -151,7 +151,7 @@ body.maze-fullscreen .maze-shell {
|
||||
.maze-net-box {
|
||||
position: absolute;
|
||||
border: 1px dashed var(--border);
|
||||
background: rgba(13, 17, 23, 0.6);
|
||||
background: var(--panel);
|
||||
padding: 32px 16px 16px;
|
||||
min-width: 220px; min-height: 140px;
|
||||
transition: border-color 0.2s;
|
||||
@@ -165,14 +165,14 @@ body.maze-fullscreen .maze-shell {
|
||||
border-color: var(--matrix); background: var(--matrix-tint-5);
|
||||
}
|
||||
.maze-net-box.internet {
|
||||
border-color: var(--alert); background: rgba(255, 65, 65, 0.04);
|
||||
border-color: var(--alert); background: var(--alert-tint-10);
|
||||
}
|
||||
.maze-net-box.dmz {
|
||||
border-color: var(--alert); background: rgba(255, 65, 65, 0.06);
|
||||
border-color: var(--alert); background: var(--alert-tint-10);
|
||||
border-style: dashed;
|
||||
}
|
||||
.maze-net-box.dmz .maze-net-box-head {
|
||||
color: var(--alert); border-bottom-color: rgba(255, 65, 65, 0.45);
|
||||
color: var(--alert); border-bottom-color: var(--alert);
|
||||
}
|
||||
/* Deployed: topology is active/degraded — make it visually unmistakable.
|
||||
* Subnet LANs glow matrix-green; DMZ stays hot red (and gets a stronger
|
||||
@@ -188,42 +188,42 @@ body.maze-fullscreen .maze-shell {
|
||||
}
|
||||
.maze-net-box.deployed.dmz {
|
||||
border-color: var(--alert);
|
||||
background: rgba(255, 65, 65, 0.09);
|
||||
box-shadow: 0 0 0 1px rgba(255, 65, 65, 0.35) inset,
|
||||
0 0 16px rgba(255, 65, 65, 0.5);
|
||||
background: var(--alert-tint-10);
|
||||
box-shadow: 0 0 0 1px var(--alert) inset,
|
||||
0 0 16px var(--alert);
|
||||
}
|
||||
.maze-net-box.deployed.dmz .maze-net-box-head {
|
||||
color: var(--alert); border-bottom-color: rgba(255, 65, 65, 0.55);
|
||||
color: var(--alert); border-bottom-color: var(--alert);
|
||||
}
|
||||
.maze-net-box.inactive {
|
||||
opacity: 0.42; filter: grayscale(0.7); border-style: dotted;
|
||||
}
|
||||
.maze-net-box.inactive .maze-net-box-head { color: rgba(255, 255, 255, 0.5); }
|
||||
.maze-net-box.inactive .maze-net-box-head { color: var(--fg-3); }
|
||||
/* Optimistic placeholder for an enqueued LAN-add. Amber tint matches
|
||||
* the REAP button voice — clearly "in-flight, not committed" without
|
||||
* collapsing into the dimmed-out 'inactive' style which means the
|
||||
* opposite (no traffic on a deployed LAN). */
|
||||
.maze-net-box.pending {
|
||||
border-color: var(--warn, #e0a040);
|
||||
background: rgba(224, 160, 64, 0.04);
|
||||
background: var(--warn-tint-10);
|
||||
border-style: dashed;
|
||||
filter: none; opacity: 1;
|
||||
}
|
||||
.maze-net-box.pending .maze-net-box-head {
|
||||
color: var(--warn, #e0a040);
|
||||
border-bottom-color: rgba(224, 160, 64, 0.45);
|
||||
border-bottom-color: var(--warn);
|
||||
}
|
||||
.maze-net-box.pending .cidr { color: rgba(224, 160, 64, 0.7); }
|
||||
.maze-net-box.pending .cidr { color: var(--warn); }
|
||||
.maze-net-box-head {
|
||||
position: absolute; top: 0; left: 0; right: 0;
|
||||
padding: 6px 12px; border-bottom: 1px dashed var(--border);
|
||||
display: flex; align-items: center; gap: 8px; justify-content: space-between;
|
||||
font-size: 0.65rem; letter-spacing: 1.5px; opacity: 0.8;
|
||||
background: rgba(13, 17, 23, 0.8); cursor: move;
|
||||
background: var(--panel); cursor: move;
|
||||
}
|
||||
.maze-net-box-head .cidr { opacity: 0.5; font-size: 0.6rem; letter-spacing: 1px; }
|
||||
.maze-net-box.internet .maze-net-box-head {
|
||||
color: var(--alert); border-bottom-color: rgba(255, 65, 65, 0.4);
|
||||
color: var(--alert); border-bottom-color: var(--alert);
|
||||
}
|
||||
|
||||
/* ── Network resize handles ─────────────────── */
|
||||
@@ -271,8 +271,8 @@ body.maze-fullscreen .maze-shell {
|
||||
.maze-node.deployed .mn-head { color: var(--matrix); }
|
||||
.maze-node.deployed.dmz-gateway {
|
||||
border-color: var(--alert);
|
||||
box-shadow: 0 0 12px rgba(255, 65, 65, 0.55);
|
||||
background: rgba(255, 65, 65, 0.06);
|
||||
box-shadow: 0 0 12px var(--alert);
|
||||
background: var(--alert-tint-10);
|
||||
}
|
||||
.maze-node.deployed.dmz-gateway .mn-head { color: var(--alert); }
|
||||
.maze-node .mn-head {
|
||||
@@ -322,7 +322,7 @@ body.maze-fullscreen .maze-shell {
|
||||
}
|
||||
.maze-legend {
|
||||
position: absolute; bottom: 12px; right: 12px; z-index: 5;
|
||||
background: rgba(13, 17, 23, 0.85); border: 1px solid var(--border);
|
||||
background: var(--panel); border: 1px solid var(--border);
|
||||
padding: 8px 10px; font-size: 0.6rem; letter-spacing: 1px;
|
||||
display: flex; flex-direction: column; gap: 4px;
|
||||
}
|
||||
@@ -425,7 +425,7 @@ body.maze-fullscreen .maze-shell {
|
||||
.ghost-edge.snap { stroke: var(--matrix); opacity: 0.9; }
|
||||
.ctx-item:hover { background: var(--violet-tint-10); color: var(--violet); }
|
||||
.ctx-item.danger { color: var(--alert); }
|
||||
.ctx-item.danger:hover { background: rgba(255, 65, 65, 0.12); }
|
||||
.ctx-item.danger:hover { background: var(--alert-tint-10); }
|
||||
.ctx-item.disabled { opacity: 0.35; cursor: not-allowed; }
|
||||
.ctx-item.disabled:hover { background: transparent; color: inherit; }
|
||||
.ctx-divider { height: 1px; background: var(--border); margin: 4px 0; }
|
||||
@@ -453,7 +453,7 @@ body.maze-fullscreen .maze-shell {
|
||||
.inspector-close-btn {
|
||||
background: transparent;
|
||||
border: 1px solid var(--border);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
color: var(--fg-3);
|
||||
padding: 3px 5px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
@@ -550,7 +550,7 @@ body.maze-fullscreen .maze-shell {
|
||||
padding: 1px 5px;
|
||||
border: 1px solid var(--border);
|
||||
letter-spacing: 1px;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
color: var(--fg-3);
|
||||
}
|
||||
|
||||
/* Inspector buttons */
|
||||
@@ -563,7 +563,7 @@ body.maze-fullscreen .maze-shell {
|
||||
.maze-btn.alert:hover {
|
||||
background: var(--alert);
|
||||
color: var(--bg);
|
||||
box-shadow: 0 0 10px rgba(255, 65, 65, 0.5);
|
||||
box-shadow: 0 0 10px var(--alert);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -606,8 +606,8 @@ body.maze-fullscreen .maze-shell {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
background: rgba(255, 65, 65, 0.04);
|
||||
border: 1px solid rgba(255, 65, 65, 0.3);
|
||||
background: var(--alert-tint-10);
|
||||
border: 1px solid var(--alert);
|
||||
}
|
||||
.inspector-tarpit-field {
|
||||
display: flex;
|
||||
@@ -617,7 +617,7 @@ body.maze-fullscreen .maze-shell {
|
||||
.maze-input {
|
||||
font-size: 0.72rem;
|
||||
padding: 4px 6px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
background: var(--matrix-tint-5);
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text-color, #e0e0e0);
|
||||
font-family: inherit;
|
||||
|
||||
@@ -56,7 +56,7 @@ const NetBox: React.FC<Props> = ({
|
||||
<span>{net.label}</span>
|
||||
{inactive && !net.pending && (
|
||||
<span className="chip-mini"
|
||||
style={{ marginLeft: 4, borderColor: 'var(--border)', color: 'rgba(255,255,255,0.45)' }}>
|
||||
style={{ marginLeft: 4, borderColor: 'var(--border)', color: 'var(--fg-4)' }}>
|
||||
INACTIVE
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
letter-spacing: 1.5px;
|
||||
border: 1px solid var(--alert);
|
||||
color: var(--alert);
|
||||
background: rgba(255, 65, 65, 0.06);
|
||||
background: var(--alert-tint-10);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@@ -192,9 +192,9 @@
|
||||
}
|
||||
.orchestrator-root .logs-table tr:hover td { background: var(--matrix-tint-5); }
|
||||
.orchestrator-root .logs-table tr.fail td {
|
||||
background: rgba(255, 65, 65, 0.05);
|
||||
background: var(--alert-tint-10);
|
||||
}
|
||||
.orchestrator-root .logs-table tr.fail:hover td { background: rgba(255, 65, 65, 0.08); }
|
||||
.orchestrator-root .logs-table tr.fail:hover td { background: var(--alert-tint-10); }
|
||||
|
||||
/* Live-prepended row tint — fades back to neutral after a moment via opacity. */
|
||||
.orchestrator-root .logs-table tr.fresh td {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/* Info banner explaining scope (non-MazeNET) + showing pool path. */
|
||||
.persona-gen-root .info-banner {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
background: var(--matrix-tint-5);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 3px solid var(--violet);
|
||||
padding: 10px 14px;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.realism-config-root .mono { font-family: var(--font-mono); }
|
||||
|
||||
.realism-config-root .info-banner {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
background: var(--matrix-tint-5);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 3px solid var(--violet);
|
||||
padding: 10px 14px;
|
||||
|
||||
@@ -29,7 +29,7 @@ interface TranscriptPage {
|
||||
const PAGE_SIZE = 500;
|
||||
|
||||
const Row: React.FC<{ label: string; value: React.ReactNode }> = ({ label, value }) => (
|
||||
<div style={{ display: 'flex', gap: '12px', padding: '6px 0', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
|
||||
<div style={{ display: 'flex', gap: '12px', padding: '6px 0', borderBottom: '1px solid var(--matrix-tint-5)' }}>
|
||||
<div style={{ minWidth: '140px', color: 'var(--dim-color)', fontSize: '0.75rem', textTransform: 'uppercase' }}>{label}</div>
|
||||
<div style={{ flex: 1, fontSize: '0.85rem', wordBreak: 'break-all' }}>{value ?? <span style={{ opacity: 0.4 }}>—</span>}</div>
|
||||
</div>
|
||||
@@ -204,9 +204,9 @@ const SessionDrawer: React.FC<SessionDrawerProps> = ({ decky, sid, fields, onClo
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', gap: '8px',
|
||||
padding: '8px 12px', marginBottom: '16px',
|
||||
border: '1px solid rgba(255, 170, 0, 0.3)',
|
||||
backgroundColor: 'rgba(255, 170, 0, 0.05)',
|
||||
fontSize: '0.75rem', color: '#ffaa00',
|
||||
border: '1px solid var(--warn)',
|
||||
backgroundColor: 'var(--warn-tint-10)',
|
||||
fontSize: '0.75rem', color: 'var(--warn)',
|
||||
}}>
|
||||
<AlertTriangle size={14} />
|
||||
Session exceeded 10 MB cap — playback is truncated.
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 4px 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||||
border-bottom: 1px solid var(--matrix-tint-10);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
font-size: 0.7rem;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 2px 6px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid var(--matrix-tint-10);
|
||||
background: var(--matrix-tint-10);
|
||||
color: var(--text-color);
|
||||
border-radius: 3px;
|
||||
min-width: 20px;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.synthetic-files-root .mono { font-family: var(--font-mono); }
|
||||
|
||||
.synthetic-files-root .info-banner {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
background: var(--matrix-tint-5);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 3px solid var(--violet);
|
||||
padding: 10px 14px;
|
||||
@@ -69,7 +69,7 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.synthetic-files-root .files-table tbody tr {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||||
border-bottom: 1px solid var(--matrix-tint-5);
|
||||
cursor: pointer;
|
||||
transition: background 0.1s;
|
||||
}
|
||||
@@ -194,7 +194,7 @@
|
||||
font-family: var(--font-mono);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
background: var(--matrix-tint-5);
|
||||
border: 1px solid var(--border);
|
||||
padding: 12px;
|
||||
font-size: 0.78rem;
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
background: rgba(255, 255, 255, 0.015);
|
||||
background: var(--matrix-tint-5);
|
||||
}
|
||||
|
||||
.ttp-tag-card .ttp-card-head {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
.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: var(--bg); 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 var(--warn); }
|
||||
.tlist-btn.warn.armed { background: var(--warn, #e0a040); color: #000; }
|
||||
|
||||
.tlist-create-row {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
.webhooks-root .btn.alert { border-color: var(--alert, #ff4d4d); color: var(--alert, #ff4d4d); }
|
||||
.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: var(--bg); 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 var(--warn); }
|
||||
.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; }
|
||||
@@ -67,7 +67,7 @@
|
||||
}
|
||||
|
||||
.webhooks-root .webhooks-warning-banner {
|
||||
background: rgba(224, 160, 64, 0.08);
|
||||
background: var(--warn-tint-10);
|
||||
border: 1px solid var(--warn, #e0a040);
|
||||
color: var(--warn, #e0a040);
|
||||
padding: 10px 14px;
|
||||
@@ -167,7 +167,7 @@
|
||||
|
||||
.webhooks-root .wh-chip.status-warn {
|
||||
border-color: var(--warn, #e0a040);
|
||||
background: rgba(224, 160, 64, 0.1);
|
||||
background: var(--warn-tint-10);
|
||||
color: var(--warn, #e0a040);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,24 @@
|
||||
|
||||
/* Back-compat names used across the codebase */
|
||||
--background-color: var(--bg);
|
||||
--bg-color: var(--bg); /* used by drawers and other inline styles */
|
||||
--text-color: var(--matrix);
|
||||
--accent-color: var(--violet);
|
||||
--secondary-color: var(--panel);
|
||||
--border-color: var(--border);
|
||||
|
||||
/* Cyan/info — REPLAY buttons, neutral status that's neither
|
||||
* "good/active" (matrix) nor "stop" (alert). */
|
||||
--info: #22d3ee;
|
||||
--info-tint-10: rgba(34, 211, 238, 0.10);
|
||||
--info-tint-30: rgba(34, 211, 238, 0.30);
|
||||
|
||||
/* Benign/healthy — semantic alias for "verified good". Stays
|
||||
* matrix in dark, picks up a darker emerald in light so a
|
||||
* BENIGN pill still reads as "green check" without the dark-mode
|
||||
* neon. */
|
||||
--ok: var(--matrix);
|
||||
|
||||
/* ── Foreground opacities ──────────────────────── */
|
||||
--fg-1: var(--matrix);
|
||||
--fg-2: rgba(0, 255, 65, 0.80);
|
||||
@@ -151,6 +164,16 @@ html[data-theme="light"] {
|
||||
--warn-tint-10: rgba(180, 83, 9, 0.12);
|
||||
--crit-tint-10: rgba(185, 28, 28, 0.10);
|
||||
|
||||
/* Cyan/info dims to slate in light mode so REPLAY buttons read
|
||||
* as a calm secondary against cream rather than an electric pop. */
|
||||
--info: #155e75;
|
||||
--info-tint-10: rgba(21, 94, 117, 0.10);
|
||||
--info-tint-30: rgba(21, 94, 117, 0.20);
|
||||
|
||||
/* Benign in light mode — emerald, the one "happy green" we keep,
|
||||
* tuned dark enough to read on cream. */
|
||||
--ok: #047857;
|
||||
|
||||
/* Glows no-op'd — kept defined so .btn:hover etc. don't
|
||||
* break, just produce no halo. */
|
||||
--matrix-glow: none;
|
||||
|
||||
Reference in New Issue
Block a user