feat(ui): Velocity rollout — page polish + lime-as-text contrast fixes

Roll the re-skin across the remaining surfaces and fix the readability
regressions the lime accent introduced (lime works as a fill/border but is
unreadable as text on light):

- --m-c-rule is now a soft divider, so page panels/tables get tidy outlines
  instead of a mess of black hairlines; the brutalist weight stays on cards,
  nav, sections and inputs (which reference ink directly).
- New --m-c-warning (amber) for medium severity, keeping the low→medium→high
  gradient legible; applied to SeverityBadge, AnomalyCard, feed stat.
- Interactive/link/highlight text (Home CTA + links, Journal/Backtest/Compare
  buttons, KPI + evidence values) moved off lime to the readable --m-c-info
  blue; Home first-run CTA is now a filled-lime brutalist button; odds-up
  delta → positive green; rate arrow → neutral.
- Results winner colours → tokens (positive / info) + Velocity-aligned tints.

CSS-only — build clean, all 568 tests green.
This commit is contained in:
2026-05-29 15:04:15 +03:00
parent 5d79911c12
commit 1e4dddbbad
15 changed files with 33 additions and 31 deletions
+2 -2
View File
@@ -77,7 +77,7 @@
outline-offset: 2px;
}
.m-anomaly-card--high { border-left-color: var(--m-c-anomaly); }
.m-anomaly-card--medium { border-left-color: var(--m-c-accent); }
.m-anomaly-card--medium { border-left-color: var(--m-c-warning); }
.m-anomaly-card--low { border-left-color: var(--m-c-ink-soft); }
.m-anomaly-card__head {
@@ -132,7 +132,7 @@
color: var(--m-c-ink-soft);
font-size: 0.875rem;
}
.m-anomaly-card__rate-arrow { color: var(--m-c-accent); font-size: 0.875rem; }
.m-anomaly-card__rate-arrow { color: var(--m-c-ink-soft); font-size: 0.875rem; }
.m-anomaly-card__rate-post {
color: var(--m-c-ink);
font-weight: 600;
@@ -143,7 +143,7 @@
justify-content: center;
font-family: var(--m-font-display);
font-size: 1.75rem;
color: var(--m-c-accent);
color: var(--m-c-info);
}
.m-evidence__row {
display: grid;
+1 -1
View File
@@ -60,7 +60,7 @@
color: var(--m-c-ink-soft);
transition: color 220ms ease;
}
.m-odds.is-up .m-odds__delta { color: var(--m-c-accent); }
.m-odds.is-up .m-odds__delta { color: var(--m-c-positive); }
.m-odds.is-down .m-odds__delta { color: var(--m-c-anomaly); }
.m-odds.is-flat .m-odds__delta { color: var(--m-c-ink-soft); }
@@ -2,7 +2,7 @@
SeverityBadge — small uppercase pill encoding an anomaly's severity bucket.
The High variant is signal-red (`--m-c-anomaly`) and pulses to draw the eye
on the feed page. Medium uses the editorial amber accent. Low is a muted
on the feed page. Medium uses an amber warning tone. Low is a muted
neutral so it does not compete with higher severities.
The component is presentational only — callers compute the severity (via
@@ -56,8 +56,8 @@
background: color-mix(in srgb, var(--m-c-ink-soft) 8%, transparent);
}
.m-severity--medium {
color: var(--m-c-accent);
background: color-mix(in srgb, var(--m-c-accent) 12%, transparent);
color: var(--m-c-warning);
background: color-mix(in srgb, var(--m-c-warning) 12%, transparent);
}
.m-severity--high {
color: var(--m-c-anomaly);
@@ -200,7 +200,7 @@
font-feature-settings: var(--m-num-feature);
}
.m-anomaly-feed__stat--high dd { color: var(--m-c-anomaly); }
.m-anomaly-feed__stat--medium dd { color: var(--m-c-accent); }
.m-anomaly-feed__stat--medium dd { color: var(--m-c-warning); }
.m-anomaly-feed__list {
display: grid;
@@ -452,8 +452,8 @@
.m-backtest__submit {
gap: var(--m-space-2);
padding: 8px 16px;
border-color: var(--m-c-accent);
color: var(--m-c-accent);
border-color: var(--m-c-info);
color: var(--m-c-info);
font-family: var(--m-font-mono);
font-size: 0.75rem;
text-transform: uppercase;
@@ -553,7 +553,7 @@
letter-spacing: 0.14em;
padding: 8px 16px;
}
.m-backtest__preset-save-btn:not(:disabled):hover { border-color: var(--m-c-accent); color: var(--m-c-accent); }
.m-backtest__preset-save-btn:not(:disabled):hover { border-color: var(--m-c-info); color: var(--m-c-info); }
.m-backtest__preset-save-btn:disabled { opacity: 0.6; cursor: progress; }
@@media (prefers-reduced-motion: reduce) {
.m-backtest__preset, .m-backtest__preset-del, .m-backtest__preset-save-btn { transition: none; }
@@ -748,7 +748,7 @@
transition: color 120ms ease, border-color 120ms ease;
}
.m-backtest__open:hover {
color: var(--m-c-accent);
color: var(--m-c-info);
border-bottom-color: var(--m-c-ink);
}
@@ -617,7 +617,7 @@
transition: color 120ms ease, border-color 120ms ease;
}
.m-insights__open:hover {
color: var(--m-c-accent);
color: var(--m-c-info);
border-bottom-color: var(--m-c-ink);
}
@@ -220,7 +220,7 @@
color: var(--m-c-ink); border-bottom: 1px solid var(--m-c-accent); padding-bottom: 1px;
transition: color 120ms ease, border-color 120ms ease;
}
.m-paper__open:hover { color: var(--m-c-accent); border-bottom-color: var(--m-c-ink); }
.m-paper__open:hover { color: var(--m-c-info); border-bottom-color: var(--m-c-ink); }
.m-list-empty {
display: grid; place-content: center; gap: var(--m-space-3); padding: var(--m-space-7);
@@ -139,7 +139,7 @@
.m-cmp__form-hint { font-size: 0.75rem; color: var(--m-c-ink-soft); }
.m-cmp__form-actions { display: flex; align-items: end; }
.m-cmp__run {
gap: var(--m-space-2); padding: 8px 16px; border-color: var(--m-c-accent); color: var(--m-c-accent);
gap: var(--m-space-2); padding: 8px 16px; border-color: var(--m-c-info); color: var(--m-c-info);
font-family: var(--m-font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.14em;
}
.m-cmp__run:not(:disabled):hover { background: var(--m-c-accent); color: var(--m-c-paper); }
+4 -4
View File
@@ -43,7 +43,7 @@
{
@* First-run: nothing captured yet. Make the next step unmissable. *@
<div data-test="home-empty" style="display: grid; gap: var(--m-space-4); padding: var(--m-space-4) 0;">
<span class="m-mono" style="font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.16em; color: var(--m-c-accent);">
<span class="m-mono" style="font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.16em; color: var(--m-c-info);">
@L["Home.Empty.Heading"]
</span>
<p style="color: var(--m-c-ink-soft); max-width: 48ch; margin: 0;">
@@ -51,7 +51,7 @@
</p>
<div>
<a href="/settings" data-test="home-empty-cta"
style="display: inline-flex; align-items: center; gap: 8px; padding: 10px 18px; border: 1px solid var(--m-c-accent); color: var(--m-c-accent); font-family: var(--m-font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.12em; text-decoration: none;">
style="display: inline-flex; align-items: center; gap: 8px; padding: 10px 18px; background: var(--m-c-accent); color: var(--m-c-on-accent); border: 2px solid var(--m-c-ink); border-radius: var(--m-radius-md); box-shadow: var(--m-shadow-hard-sm); font-family: var(--m-font-mono); font-weight: 700; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.12em; text-decoration: none;">
@L["Home.Empty.Cta"] →
</a>
</div>
@@ -62,7 +62,7 @@
@* Capturing, but the detector hasn't flagged anything yet. *@
<div data-test="home-no-signals" style="display: grid; gap: var(--m-space-3); padding: var(--m-space-3) 0; border-top: 1px solid var(--m-c-rule);">
<p style="color: var(--m-c-ink-soft); margin: 0;">@L["Home.NoSignals"]</p>
<a href="/anomalies" style="font-family: var(--m-font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--m-c-accent); text-decoration: none;">
<a href="/anomalies" style="font-family: var(--m-font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--m-c-info); text-decoration: none;">
@L["Home.ViewAll"] →
</a>
</div>
@@ -92,7 +92,7 @@
</div>
<div style="margin-top: var(--m-space-5); padding-top: var(--m-space-3); border-top: 1px solid var(--m-c-rule);">
<a href="/anomalies" style="font-family: var(--m-font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--m-c-accent); text-decoration: none;">
<a href="/anomalies" style="font-family: var(--m-font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--m-c-info); text-decoration: none;">
@L["Home.ViewAll"] →
</a>
</div>
+2 -2
View File
@@ -579,8 +579,8 @@
gap: var(--m-space-3);
}
.m-journal__submit {
border-color: var(--m-c-accent);
color: var(--m-c-accent);
border-color: var(--m-c-info);
color: var(--m-c-info);
}
.m-journal__submit:not(:disabled):hover {
background: var(--m-c-accent);
@@ -156,11 +156,11 @@
border-radius: var(--m-radius-xs);
border: 1px solid var(--m-c-rule);
}
.m-result-winner--side1 { background: rgba(34,197,94,0.10); color: #15803d; border-color: rgba(34,197,94,0.30); }
.m-result-winner--side2 { background: rgba(59,130,246,0.10); color: #1d4ed8; border-color: rgba(59,130,246,0.30); }
.m-result-winner--side1 { background: rgba(31,158,61,0.10); color: var(--m-c-positive); border-color: rgba(31,158,61,0.32); }
.m-result-winner--side2 { background: rgba(36,75,255,0.10); color: var(--m-c-info); border-color: rgba(36,75,255,0.32); }
.m-result-winner--draw { background: rgba(120,113,108,0.10); color: var(--m-c-ink-soft); }
[data-theme="dark"] .m-result-winner--side1 { color: #4ade80; background: rgba(34,197,94,0.15); }
[data-theme="dark"] .m-result-winner--side2 { color: #93c5fd; background: rgba(59,130,246,0.15); }
[data-theme="dark"] .m-result-winner--side1 { background: rgba(74,222,128,0.16); }
[data-theme="dark"] .m-result-winner--side2 { background: rgba(111,139,255,0.16); }
</style>
@code {
@@ -198,8 +198,8 @@
border-radius: var(--m-radius-xs);
border: 1px solid var(--m-c-rule);
}
.m-result-winner--side1 { background: rgba(34,197,94,0.10); color: #15803d; border-color: rgba(34,197,94,0.30); }
.m-result-winner--side2 { background: rgba(59,130,246,0.10); color: #1d4ed8; border-color: rgba(59,130,246,0.30); }
.m-result-winner--side1 { background: rgba(31,158,61,0.10); color: var(--m-c-positive); border-color: rgba(31,158,61,0.32); }
.m-result-winner--side2 { background: rgba(36,75,255,0.10); color: var(--m-c-info); border-color: rgba(36,75,255,0.32); }
.m-result-winner--draw { background: rgba(120,113,108,0.10); color: var(--m-c-ink-soft); }
</style>
@@ -516,7 +516,7 @@
{
if (_filter.SortKey != key) return;
builder.OpenElement(0, "span");
builder.AddAttribute(1, "style", "margin-left: 6px; color: var(--m-c-accent);");
builder.AddAttribute(1, "style", "margin-left: 6px; color: var(--m-c-info);");
builder.AddContent(2, _filter.SortDescending ? "▼" : "▲");
builder.CloseElement();
};
+5 -3
View File
@@ -49,13 +49,14 @@
--m-c-paper: #fffef8;
--m-c-paper-2: #f3f1e9;
--m-c-paper-3: #e7e3d6;
--m-c-rule: #0a0a0a;
--m-c-rule: #d8d4c4; /* soft divider — brutalist weight lives on cards/inputs, not page hairlines */
--m-c-accent: #c6f400; /* acid lime */
--m-c-accent-soft: #b3dd00;
--m-c-on-accent: #0a0a0a; /* ink on lime — lime is a light hue */
--m-c-anomaly: #ff3b30;
--m-c-positive: #1f9e3d;
--m-c-info: #244bff; /* electric blue */
--m-c-info: #244bff; /* electric blue — interactive / highlight / link text */
--m-c-warning: #c2680a; /* amber — medium severity + warnings (lime is unreadable as text) */
/* Tabular numerals for everywhere odds/scores appear */
--m-num-feature: "tnum" 1, "lnum" 1;
@@ -69,13 +70,14 @@
--m-c-paper: #1e1c15;
--m-c-paper-2: #141310;
--m-c-paper-3: #2a2820;
--m-c-rule: #f5f3ea;
--m-c-rule: #3a3730;
--m-c-accent: #c6f400;
--m-c-accent-soft: #aacc00;
--m-c-on-accent: #0a0a0a;
--m-c-anomaly: #ff5a4f;
--m-c-positive: #4ade80;
--m-c-info: #6f8bff;
--m-c-warning: #ffb24d;
/* Hard shadow goes pure-black on dark; the light border defines the block. */
--m-shadow-hard: 5px 5px 0 #000000;
--m-shadow-hard-sm: 3px 3px 0 #000000;