feat(ui): Velocity redesign — foundations (tokens, theme, chrome)

Re-skin the app into the "Velocity" neo-brutalist direction: acid-lime
accent, hard offset shadows, slammed uppercase headlines, rounded
brutalist blocks. Light "paper" chassis + a warm-charcoal dark mode, both
keeping the lime accent and a constant black appbar; the light/dark toggle
is preserved.

- Type is Cyrillic-complete (the mockup's Anton/DM Sans/Space Mono are not,
  and this product is Russian-first): Oswald (display) + Manrope (body) +
  JetBrains Mono (numerals), loaded via the existing Google Fonts CDN.
- app.css: Velocity token palette (light+dark) + brutalist shared
  components (cards, kicker chips, stat blocks, nav, segmented, sections,
  anomaly badge); diagonal-hatch texture; electric-blue focus rings.
- MarathonTheme + Tokens.cs: Mud palette / typography / radius retargeted
  so every Mud component follows; appbar black, drawer flipped to paper.
- MainLayout + NavBody chrome: black appbar, lime capture chip, paper
  drawer with brutalist nav blocks (fixes the old white-on-paper brand).
- OddsTimeline + SportIcon recoloured to the Velocity palette (chart lines
  now read on both themes; dropped the off-brand purple sport hue).

Foundations only — build clean, all 568 tests green. Page-level polish
(Results winner colours, bespoke page styles) rolls out next.
This commit is contained in:
2026-05-29 14:47:42 +03:00
parent 0683e348ba
commit 5d79911c12
9 changed files with 325 additions and 278 deletions
@@ -8,17 +8,17 @@
<!-- Prevent flash of unthemed content --> <!-- Prevent flash of unthemed content -->
<style> <style>
html, body { background: #f5f4ef; margin: 0; } html, body { background: #f3f1e9; margin: 0; }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html, body { background: #0c0a09; } html, body { background: #141310; }
} }
</style> </style>
<!-- Fonts: IBM Plex Sans / Serif / Mono + JetBrains Mono. Full Cyrillic coverage. --> <!-- Fonts: Oswald (display) + Manrope (body) + JetBrains Mono (numerals). Full Cyrillic coverage. -->
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link <link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=IBM+Plex+Serif:wght@300;400;500;600&family=IBM+Plex+Mono:wght@400;500&family=JetBrains+Mono:wght@400;500;600&display=swap" href="https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;600;700&family=Manrope:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700;800&display=swap"
rel="stylesheet" /> rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" /> <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
@@ -26,13 +26,13 @@
</head> </head>
<body> <body>
<div id="app"> <div id="app">
<div style="padding: 64px; font-family: 'IBM Plex Serif', Georgia, serif; color: #475569;"> <div style="padding: 64px; font-family: 'Manrope', system-ui, sans-serif; color: #6b6757;">
<span style="font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: #d97706;">Booting</span> <span style="font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: #0a0a0a; background: #c6f400; border: 2px solid #0a0a0a; border-radius: 8px; padding: 4px 9px;">Booting</span>
<div style="font-size: 32px; font-weight: 300; margin-top: 8px;">Marathon Odds Lab</div> <div style="font-family: 'Oswald', sans-serif; font-size: 42px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.01em; margin-top: 14px; color: #0a0a0a;">Marathon Odds Lab</div>
</div> </div>
</div> </div>
<div id="blazor-error-ui" style="display:none; position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000; padding: 12px 24px; background: #dc2626; color: #fafaf7; font-family: 'IBM Plex Sans', sans-serif;"> <div id="blazor-error-ui" style="display:none; position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000; padding: 12px 24px; background: #ff3b30; color: #fffef8; font-family: 'Manrope', system-ui, sans-serif;">
<span>An unhandled error has occurred.</span> <span>An unhandled error has occurred.</span>
<a href="" class="reload" style="color: #fff; text-decoration: underline; margin-left: 12px;">Reload</a> <a href="" class="reload" style="color: #fff; text-decoration: underline; margin-left: 12px;">Reload</a>
<a class="dismiss" style="float: right; cursor: pointer; padding: 0 8px;">×</a> <a class="dismiss" style="float: right; cursor: pointer; padding: 0 8px;">×</a>
+11 -9
View File
@@ -3,11 +3,11 @@
@inject AnomalyBrowsingState AnomalyState @inject AnomalyBrowsingState AnomalyState
<nav class="m-nav" aria-label="primary"> <nav class="m-nav" aria-label="primary">
<div style="padding: var(--m-space-5) var(--m-space-4) var(--m-space-3); border-bottom: 1px solid rgba(231,229,228,0.10);"> <div style="padding: var(--m-space-5) var(--m-space-4) var(--m-space-4); border-bottom: 2px solid var(--m-c-ink);">
<div style="font-family: var(--m-font-display); font-size: 1.25rem; color: #fafaf7;"> <div style="font-family: var(--m-font-display); font-weight: 700; font-size: 1.5rem; text-transform: uppercase; letter-spacing: 0.01em; color: var(--m-c-ink);">
<span style="color: var(--m-c-accent);">M</span>arathon <span style="background: var(--m-c-accent); color: var(--m-c-on-accent); padding: 0 5px; border-radius: 5px;">M</span>arathon
</div> </div>
<div style="font-family: var(--m-font-mono); font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase; color: rgba(231,229,228,0.55); margin-top: 4px;"> <div style="font-family: var(--m-font-mono); font-size: 0.625rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--m-c-ink-soft); margin-top: 4px;">
Odds Lab · v0.1 Odds Lab · v0.1
</div> </div>
</div> </div>
@@ -78,18 +78,20 @@
<style> <style>
.m-nav__badge { .m-nav__badge {
margin-left: auto; margin-left: auto;
min-width: 18px; box-sizing: border-box;
min-width: 20px;
padding: 0 6px; padding: 0 6px;
background: var(--m-c-anomaly); background: var(--m-c-anomaly);
color: #ffffff; color: #ffffff;
font-family: var(--m-font-mono); font-family: var(--m-font-mono);
font-size: 0.625rem; font-size: 0.625rem;
font-weight: 600; font-weight: 700;
letter-spacing: 0.05em; letter-spacing: 0.05em;
line-height: 18px; line-height: 16px;
height: 18px; height: 20px;
text-align: center; text-align: center;
border-radius: var(--m-radius-xs); border: 2px solid var(--m-c-ink);
border-radius: var(--m-radius-sm);
animation: m-pulse 1.6s ease-in-out infinite; animation: m-pulse 1.6s ease-in-out infinite;
} }
@@media (prefers-reduced-motion: reduce) { @@media (prefers-reduced-motion: reduce) {
+13 -13
View File
@@ -152,9 +152,9 @@
var times = points.Select(p => (object)p.At.UtcDateTime).ToList(); var times = points.Select(p => (object)p.At.UtcDateTime).ToList();
return new List<ITrace> return new List<ITrace>
{ {
BuildSeries("Win 1", "#0f172a", points.Select(p => (object?)p.Win1Rate).ToList(), times), BuildSeries("Win 1", "#244bff", points.Select(p => (object?)p.Win1Rate).ToList(), times),
BuildSeries("Draw", "#d97706", points.Select(p => (object?)p.DrawRate).ToList(), times), BuildSeries("Draw", "#ff8a00", points.Select(p => (object?)p.DrawRate).ToList(), times),
BuildSeries("Win 2", "#dc2626", points.Select(p => (object?)p.Win2Rate).ToList(), times), BuildSeries("Win 2", "#ff3b30", points.Select(p => (object?)p.Win2Rate).ToList(), times),
}; };
} }
@@ -178,13 +178,13 @@
{ {
AutoSize = true, AutoSize = true,
Margin = new Plotly.Blazor.LayoutLib.Margin { L = 56, R = 24, T = 24, B = 48 }, Margin = new Plotly.Blazor.LayoutLib.Margin { L = 56, R = 24, T = 24, B = 48 },
PaperBgColor = dark ? "#1c1917" : "#fafaf7", PaperBgColor = dark ? "#1e1c15" : "#fffef8",
PlotBgColor = dark ? "#0c0a09" : "#fafaf7", PlotBgColor = dark ? "#141310" : "#fffef8",
Font = new Plotly.Blazor.LayoutLib.Font Font = new Plotly.Blazor.LayoutLib.Font
{ {
Family = "JetBrains Mono, IBM Plex Mono, Consolas, monospace", Family = "JetBrains Mono, IBM Plex Mono, Consolas, monospace",
Size = 11, Size = 11,
Color = dark ? "#f5f5f4" : "#0f172a", Color = dark ? "#f5f3ea" : "#0a0a0a",
}, },
XAxis = new List<XAxis> XAxis = new List<XAxis>
{ {
@@ -192,14 +192,14 @@
{ {
Title = new Plotly.Blazor.LayoutLib.XAxisLib.Title { Text = string.Empty }, Title = new Plotly.Blazor.LayoutLib.XAxisLib.Title { Text = string.Empty },
ShowGrid = true, ShowGrid = true,
GridColor = dark ? "#292524" : "#e7e5e4", GridColor = dark ? "#2a2820" : "#e7e3d6",
ZeroLine = false, ZeroLine = false,
LineColor = dark ? "#292524" : "#e7e5e4", LineColor = dark ? "#2a2820" : "#e7e3d6",
TickFont = new Plotly.Blazor.LayoutLib.XAxisLib.TickFont TickFont = new Plotly.Blazor.LayoutLib.XAxisLib.TickFont
{ {
Family = "JetBrains Mono, IBM Plex Mono, Consolas, monospace", Family = "JetBrains Mono, IBM Plex Mono, Consolas, monospace",
Size = 10, Size = 10,
Color = dark ? "#a8a29e" : "#475569", Color = dark ? "#9c9784" : "#6b6757",
}, },
}, },
}, },
@@ -209,14 +209,14 @@
{ {
Title = new Plotly.Blazor.LayoutLib.YAxisLib.Title { Text = string.Empty }, Title = new Plotly.Blazor.LayoutLib.YAxisLib.Title { Text = string.Empty },
ShowGrid = true, ShowGrid = true,
GridColor = dark ? "#292524" : "#e7e5e4", GridColor = dark ? "#2a2820" : "#e7e3d6",
ZeroLine = false, ZeroLine = false,
LineColor = dark ? "#292524" : "#e7e5e4", LineColor = dark ? "#2a2820" : "#e7e3d6",
TickFont = new Plotly.Blazor.LayoutLib.YAxisLib.TickFont TickFont = new Plotly.Blazor.LayoutLib.YAxisLib.TickFont
{ {
Family = "JetBrains Mono, IBM Plex Mono, Consolas, monospace", Family = "JetBrains Mono, IBM Plex Mono, Consolas, monospace",
Size = 10, Size = 10,
Color = dark ? "#a8a29e" : "#475569", Color = dark ? "#9c9784" : "#6b6757",
}, },
}, },
}, },
@@ -232,7 +232,7 @@
{ {
Family = "JetBrains Mono, IBM Plex Mono, Consolas, monospace", Family = "JetBrains Mono, IBM Plex Mono, Consolas, monospace",
Size = 11, Size = 11,
Color = dark ? "#e7e5e4" : "#1e293b", Color = dark ? "#d8d4c6" : "#26241e",
}, },
}, },
}, },
+4 -4
View File
@@ -20,10 +20,10 @@
flex: 0 0 auto; flex: 0 0 auto;
} }
.m-sport svg { width: 100%; height: 100%; display: block; } .m-sport svg { width: 100%; height: 100%; display: block; }
.m-sport[data-sport="6"] { color: #d97706; } .m-sport[data-sport="6"] { color: #ff8a00; } /* basketball — amber */
.m-sport[data-sport="11"] { color: #15803d; } .m-sport[data-sport="11"] { color: #1f9e3d; } /* football — green */
.m-sport[data-sport="22723"] { color: #0369a1; } .m-sport[data-sport="22723"] { color: #0d9488; } /* tennis — teal */
.m-sport[data-sport="43658"] { color: #6d28d9; } .m-sport[data-sport="43658"] { color: #244bff; } /* hockey — electric blue */
[data-theme="dark"] .m-sport { filter: brightness(1.1); } [data-theme="dark"] .m-sport { filter: brightness(1.1); }
</style> </style>
+10 -12
View File
@@ -27,8 +27,8 @@
<div class="m-appbar__tools m-rise m-rise-2"> <div class="m-appbar__tools m-rise m-rise-2">
<span class="m-capture-pill" data-test="capture-pill" <span class="m-capture-pill" data-test="capture-pill"
aria-label="@L["Scraping.Aria"]" title="@L["Scraping.Aria"]" aria-label="@L["Scraping.Aria"]" title="@L["Scraping.Aria"]"
style="display:inline-flex; align-items:center; gap:7px; font-family:var(--m-font-mono); font-size:0.6875rem; text-transform:uppercase; letter-spacing:0.12em; color:@(Capturing ? "var(--m-c-positive)" : "var(--m-c-ink-soft)");"> style="display:inline-flex; align-items:center; gap:7px; font-family:var(--m-font-mono); font-size:0.6875rem; font-weight:700; text-transform:uppercase; letter-spacing:0.1em; padding:6px 10px; border-radius:8px; border:2px solid @(Capturing ? "#0a0a0a" : "rgba(255,254,248,0.4)"); background:@(Capturing ? "var(--m-c-accent)" : "transparent"); color:@(Capturing ? "var(--m-c-on-accent)" : "rgba(255,254,248,0.72)");">
<span style="width:8px; height:8px; border-radius:50%; background:@(Capturing ? "var(--m-c-positive)" : "var(--m-c-ink-soft)");"></span> <span style="width:8px; height:8px; border-radius:50%; background:@(Capturing ? "#0a0a0a" : "rgba(255,254,248,0.72)");"></span>
@(Capturing ? L["Scraping.On"] : L["Scraping.Off"]) @(Capturing ? L["Scraping.On"] : L["Scraping.Off"])
</span> </span>
<LocaleSwitcher /> <LocaleSwitcher />
@@ -43,7 +43,7 @@
ClipMode="DrawerClipMode.Always" ClipMode="DrawerClipMode.Always"
Elevation="0" Elevation="0"
Width="248px" Width="248px"
Color="Color.Dark"> Color="Color.Surface">
<NavBody /> <NavBody />
</MudDrawer> </MudDrawer>
@@ -58,7 +58,7 @@
<footer class="m-footer"> <footer class="m-footer">
<span class="m-kicker">Marathon Odds Lab</span> <span class="m-kicker">Marathon Odds Lab</span>
<span style="font-family: var(--m-font-mono); font-size: 0.6875rem; color: var(--m-c-ink-soft); letter-spacing: 0.16em; text-transform: uppercase;"> <span style="font-family: var(--m-font-mono); font-size: 0.6875rem; color: var(--m-c-ink-soft); letter-spacing: 0.16em; text-transform: uppercase;">
Phase 5 · Editorial-Quant · v0.1 Velocity · v0.1
</span> </span>
</footer> </footer>
</div> </div>
@@ -76,8 +76,9 @@
align-items: center; align-items: center;
gap: var(--m-space-3); gap: var(--m-space-3);
padding: 0 clamp(var(--m-space-3), 2vw, var(--m-space-5)); padding: 0 clamp(var(--m-space-3), 2vw, var(--m-space-5));
border-bottom: 1px solid var(--m-c-rule); border-bottom: 2px solid var(--m-c-accent);
background: var(--m-c-paper); background: #0a0a0a;
color: #fffef8;
z-index: 10; z-index: 10;
} }
@@ -116,15 +117,12 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 0 clamp(var(--m-space-3), 2vw, var(--m-space-5)); padding: 0 clamp(var(--m-space-3), 2vw, var(--m-space-5));
border-top: 1px solid var(--m-c-rule); border-top: 2px solid var(--m-c-ink);
background: var(--m-c-paper); background: var(--m-c-paper);
} }
[data-theme="dark"] .m-appbar, /* The appbar is a constant black bar in both themes (set above); only the
[data-theme="dark"] .m-footer { footer follows the paper/charcoal surface token. */
background: var(--m-c-paper-2);
border-color: var(--m-c-rule);
}
</style> </style>
@code { @code {
+103 -97
View File
@@ -6,12 +6,14 @@ namespace Marathon.UI.Theme;
/// <summary> /// <summary>
/// The Marathon design system, expressed as a MudBlazor theme. /// The Marathon design system, expressed as a MudBlazor theme.
/// ///
/// Aesthetic direction: editorial-quant. Inspired by Bloomberg terminals, /// Aesthetic direction: "Velocity" — neo-brutalist sportsbook. Acid lime
/// FT.com long-reads, and Quartz dashboards. Confident, information-dense, /// accent, hard offset shadows, slammed uppercase headlines. Pairs Oswald
/// reveals patterns. Pairs IBM Plex Sans (Cyrillic-capable display + body) /// (Cyrillic-capable condensed display) and Manrope (body) with JetBrains
/// with JetBrains Mono for tabular numerals. Anomaly accent is a load-bearing /// Mono for tabular numerals — the mockup's Anton/DM Sans/Space Mono lack
/// signal red so Phase 7 can hang the entire anomaly visual language off /// Cyrillic, which this Russian-first product requires. Anomaly accent is a
/// <c>palette.Error</c> without coupling to a hard-coded hex. /// load-bearing signal red so the anomaly visual language hangs off
/// <c>palette.Error</c> without coupling to a hard-coded hex. Light "paper"
/// chassis with a warm-charcoal dark mode; the black appbar is constant.
/// </summary> /// </summary>
public static class MarathonTheme public static class MarathonTheme
{ {
@@ -27,103 +29,105 @@ public static class MarathonTheme
}; };
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// Palettes — single accent (amber #d97706), single signal (red #ef4444) // Palettes — acid lime accent + signal red on a "paper" chassis
// on a deep navy/parchment chassis. No purple gradients, no cliche. // (warm-charcoal in dark). Primary is the boldest structural colour
// per mode: ink in light, lime in dark. The appbar is black in both.
// ------------------------------------------------------------------ // ------------------------------------------------------------------
private static readonly PaletteLight LightPalette = new() private static readonly PaletteLight LightPalette = new()
{ {
Primary = "#0f172a", // deep navy / ink Primary = "#0a0a0a", // ink — brutalist black actions
PrimaryContrastText = "#fafaf7", PrimaryContrastText = "#fffef8",
Secondary = "#334155", // slate Secondary = "#26241e", // warm ink
SecondaryContrastText = "#fafaf7", SecondaryContrastText = "#fffef8",
Tertiary = "#d97706", // amber accent Tertiary = "#c6f400", // acid lime accent
TertiaryContrastText = "#1c1917", TertiaryContrastText = "#0a0a0a",
Info = "#0369a1", Info = "#244bff", // electric blue
Success = "#15803d", Success = "#1f9e3d",
Warning = "#b45309", Warning = "#ff8a00",
Error = "#dc2626", // anomaly signal Error = "#ff3b30", // anomaly signal
ErrorContrastText = "#fff7ed", ErrorContrastText = "#fffef8",
Black = "#1c1917", Black = "#0a0a0a",
White = "#fafaf7", White = "#fffef8",
Surface = "#fafaf7", // warm parchment Surface = "#fffef8", // card paper
Background = "#f5f4ef", // a half-step warmer than surface Background = "#f3f1e9", // page paper
BackgroundGray = "#ebe9e1", BackgroundGray = "#e7e3d6",
DrawerBackground = "#0f172a", // dark drawer on light app — editorial contrast DrawerBackground = "#fffef8", // paper drawer — brutalist light nav
DrawerText = "#e7e5e4", DrawerText = "#26241e",
DrawerIcon = "#d6d3d1", DrawerIcon = "#6b6757",
AppbarBackground = "#fafaf7", AppbarBackground = "#0a0a0a", // constant black bar
AppbarText = "#0f172a", AppbarText = "#fffef8",
TextPrimary = "#0f172a", TextPrimary = "#0a0a0a",
TextSecondary = "#475569", TextSecondary = "#6b6757",
TextDisabled = "#94a3b8", TextDisabled = "#a8a293",
ActionDefault = "#334155", ActionDefault = "#26241e",
ActionDisabled = "#cbd5e1", ActionDisabled = "#cbc7b8",
ActionDisabledBackground = "#e2e8f0", ActionDisabledBackground = "#e7e3d6",
LinesDefault = "#e7e5e4", LinesDefault = "#d8d4c4",
LinesInputs = "#cbd5e1", LinesInputs = "#0a0a0a", // bold black input borders
TableLines = "#e7e5e4", TableLines = "#e7e3d6",
TableStriped = "#f5f4ef", TableStriped = "#f3f1e9",
TableHover = "#ebe9e1", TableHover = "#e7e3d6",
Divider = "#e7e5e4", Divider = "#d8d4c4",
DividerLight = "#f1f5f9", DividerLight = "#ebe7da",
OverlayDark = new MudColor("#0f172a99").Value, OverlayDark = new MudColor("#0a0a0a99").Value,
OverlayLight = new MudColor("#fafaf7cc").Value, OverlayLight = new MudColor("#fffef8cc").Value,
}; };
private static readonly PaletteDark DarkPalette = new() private static readonly PaletteDark DarkPalette = new()
{ {
Primary = "#fbbf24", // amber, promoted in dark mode Primary = "#c6f400", // lime, promoted in dark mode
PrimaryContrastText = "#0c0a09", PrimaryContrastText = "#0a0a0a",
Secondary = "#94a3b8", Secondary = "#d8d4c6",
SecondaryContrastText = "#0c0a09", SecondaryContrastText = "#0a0a0a",
Tertiary = "#fbbf24", Tertiary = "#c6f400",
TertiaryContrastText = "#0c0a09", TertiaryContrastText = "#0a0a0a",
Info = "#38bdf8", Info = "#6f8bff",
Success = "#4ade80", Success = "#4ade80",
Warning = "#fbbf24", Warning = "#ffae42",
Error = "#f87171", // anomaly signal — softened for dark Error = "#ff5a4f", // anomaly signal — softened for dark
ErrorContrastText = "#0c0a09", ErrorContrastText = "#0a0a0a",
Black = "#0c0a09", Black = "#0a0a0a",
White = "#fafaf7", White = "#fffef8",
Surface = "#1c1917", // ink-stained paper Surface = "#1e1c15", // warm charcoal card
Background = "#0c0a09", // near-black Background = "#141310", // near-black warm
BackgroundGray = "#1c1917", BackgroundGray = "#2a2820",
DrawerBackground = "#0c0a09", DrawerBackground = "#1e1c15",
DrawerText = "#e7e5e4", DrawerText = "#d8d4c6",
DrawerIcon = "#a8a29e", DrawerIcon = "#9c9784",
AppbarBackground = "#0c0a09", AppbarBackground = "#0a0a0a", // constant black bar
AppbarText = "#fafaf7", AppbarText = "#f5f3ea",
TextPrimary = "#f5f5f4", TextPrimary = "#f5f3ea",
TextSecondary = "#a8a29e", TextSecondary = "#9c9784",
TextDisabled = "#57534e", TextDisabled = "#57534e",
ActionDefault = "#a8a29e", ActionDefault = "#d8d4c6",
ActionDisabled = "#44403c", ActionDisabled = "#57534e",
ActionDisabledBackground = "#1c1917", ActionDisabledBackground = "#2a2820",
LinesDefault = "#292524", LinesDefault = "#3a3730",
LinesInputs = "#44403c", LinesInputs = "#f5f3ea", // light input borders on charcoal
TableLines = "#292524", TableLines = "#2a2820",
TableStriped = "#1c1917", TableStriped = "#1e1c15",
TableHover = "#292524", TableHover = "#2a2820",
Divider = "#292524", Divider = "#3a3730",
DividerLight = "#1c1917", DividerLight = "#2a2820",
OverlayDark = new MudColor("#0c0a09cc").Value, OverlayDark = new MudColor("#141310cc").Value,
OverlayLight = new MudColor("#fafaf722").Value, OverlayLight = new MudColor("#f5f3ea22").Value,
}; };
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// Typography — IBM Plex Sans / JetBrains Mono / IBM Plex Serif (display) // Typography — Oswald (condensed display) / Manrope (body) /
// All have full Cyrillic coverage. Numerals are tabular. // JetBrains Mono (numerals). All have full Cyrillic coverage, which
// the Velocity mockup's Anton/DM Sans/Space Mono do not. Numerals tabular.
// ------------------------------------------------------------------ // ------------------------------------------------------------------
private static readonly string[] DisplayStack = { "IBM Plex Serif", "PT Serif", "Georgia", "serif" }; private static readonly string[] DisplayStack = { "Oswald", "PT Sans Narrow", "Arial Narrow", "sans-serif" };
private static readonly string[] BodyStack = { "IBM Plex Sans", "PT Sans", "system-ui", "sans-serif" }; private static readonly string[] BodyStack = { "Manrope", "Segoe UI", "system-ui", "sans-serif" };
private static readonly string[] MonoStack = { "JetBrains Mono", "IBM Plex Mono", "Fira Code", "Consolas", "monospace" }; private static readonly string[] MonoStack = { "JetBrains Mono", "IBM Plex Mono", "Fira Code", "Consolas", "monospace" };
private static readonly Typography MarathonTypography = new() private static readonly Typography MarathonTypography = new()
@@ -139,26 +143,29 @@ public static class MarathonTheme
H1 = new H1 H1 = new H1
{ {
FontFamily = DisplayStack, FontFamily = DisplayStack,
FontWeight = 300, FontWeight = 700,
FontSize = "clamp(2.25rem, 4vw, 3.5rem)", FontSize = "clamp(2.5rem, 5vw, 4rem)",
LineHeight = 1.05, LineHeight = 0.98,
LetterSpacing = "-0.022em", LetterSpacing = "0.005em",
TextTransform = "uppercase",
}, },
H2 = new H2 H2 = new H2
{ {
FontFamily = DisplayStack, FontFamily = DisplayStack,
FontWeight = 400, FontWeight = 700,
FontSize = "clamp(1.75rem, 2.5vw, 2.25rem)", FontSize = "clamp(1.875rem, 3vw, 2.5rem)",
LineHeight = 1.15, LineHeight = 1.02,
LetterSpacing = "-0.018em", LetterSpacing = "0.005em",
TextTransform = "uppercase",
}, },
H3 = new H3 H3 = new H3
{ {
FontFamily = DisplayStack, FontFamily = DisplayStack,
FontWeight = 500, FontWeight = 600,
FontSize = "1.5rem", FontSize = "1.625rem",
LineHeight = 1.25, LineHeight = 1.1,
LetterSpacing = "-0.012em", LetterSpacing = "0.01em",
TextTransform = "uppercase",
}, },
H4 = new H4 H4 = new H4
{ {
@@ -242,12 +249,11 @@ public static class MarathonTheme
}; };
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// Layout — sharp corners, narrow drawer. The aesthetic earns its // Layout — rounded brutalist blocks, narrow drawer.
// authority through restraint.
// ------------------------------------------------------------------ // ------------------------------------------------------------------
private static readonly LayoutProperties LayoutProps = new() private static readonly LayoutProperties LayoutProps = new()
{ {
DefaultBorderRadius = "2px", DefaultBorderRadius = "10px",
AppbarHeight = "60px", AppbarHeight = "60px",
DrawerWidthLeft = "248px", DrawerWidthLeft = "248px",
DrawerWidthRight = "248px", DrawerWidthRight = "248px",
+10 -10
View File
@@ -9,14 +9,14 @@ public static class Tokens
{ {
public static class Colors public static class Colors
{ {
public const string AnomalySignal = "#dc2626"; public const string AnomalySignal = "#ff3b30";
public const string AnomalySignalDark = "#f87171"; public const string AnomalySignalDark = "#ff5a4f";
public const string Accent = "#d97706"; public const string Accent = "#c6f400"; // acid lime
public const string AccentDark = "#fbbf24"; public const string AccentDark = "#c6f400";
public const string InkPrimary = "#0f172a"; public const string InkPrimary = "#0a0a0a";
public const string Parchment = "#fafaf7"; public const string Parchment = "#fffef8";
public const string ParchmentDeep = "#f5f4ef"; public const string ParchmentDeep = "#f3f1e9";
public const string InkDeep = "#0c0a09"; public const string InkDeep = "#141310";
} }
public static class Spacing public static class Spacing
@@ -31,8 +31,8 @@ public static class Tokens
public static class Typography public static class Typography
{ {
public const string DisplayStack = "\"IBM Plex Serif\", \"PT Serif\", Georgia, serif"; public const string DisplayStack = "\"Oswald\", \"PT Sans Narrow\", \"Arial Narrow\", sans-serif";
public const string BodyStack = "\"IBM Plex Sans\", \"PT Sans\", system-ui, sans-serif"; public const string BodyStack = "\"Manrope\", \"Segoe UI\", system-ui, sans-serif";
public const string MonoStack = "\"JetBrains Mono\", \"IBM Plex Mono\", \"Fira Code\", Consolas, monospace"; public const string MonoStack = "\"JetBrains Mono\", \"IBM Plex Mono\", \"Fira Code\", Consolas, monospace";
} }
} }
+158 -117
View File
@@ -1,9 +1,13 @@
/* =================================================================== /* ===================================================================
Marathon — Editorial-Quant design system Marathon — "Velocity" design system
------------------------------------------------------------------ ------------------------------------------------------------------
Inspiration: long-form data journalism (FT, Quartz), terminal Neo-brutalist sportsbook. Acid lime, hard offset shadows, slammed
instruments (Bloomberg), and Belarusian / Soviet print typography. uppercase headlines. Cyrillic-complete type: Oswald (display) +
The aesthetic is confident, dense, and serif-led on display surfaces. Manrope (body) + JetBrains Mono (numerals / labels) — the Velocity
mockup's Anton/DM Sans/Space Mono have no Cyrillic, which this
Russian-first product needs.
Light "paper" chassis + a warm-charcoal dark mode; both keep the
lime accent and the hard ink/black shadow signature.
=================================================================== */ =================================================================== */
:root { :root {
@@ -18,50 +22,63 @@
--m-space-8: 64px; --m-space-8: 64px;
--m-space-9: 96px; --m-space-9: 96px;
/* ----- Radius — sharp by default, soft variants for inputs ----- */ /* ----- Radius — rounded brutalist blocks ----- */
--m-radius-sharp: 0; --m-radius-sharp: 0;
--m-radius-xs: 2px; --m-radius-xs: 6px;
--m-radius-sm: 4px; --m-radius-sm: 8px;
--m-radius-md: 6px; --m-radius-md: 10px;
--m-radius-lg: 10px; --m-radius-lg: 14px;
/* ----- Typography ----- */ /* ----- Brutalist borders + hard offset shadows ----- */
--m-font-display: "IBM Plex Serif", "PT Serif", Georgia, serif; --m-border-w: 2px;
--m-font-body: "IBM Plex Sans", "PT Sans", system-ui, sans-serif; --m-border-w-bold: 3px;
--m-shadow-hard: 5px 5px 0 var(--m-c-ink);
--m-shadow-hard-sm: 3px 3px 0 var(--m-c-ink);
--m-shadow-hard-accent: 5px 5px 0 var(--m-c-accent);
--m-shadow-hard-anomaly: 5px 5px 0 var(--m-c-anomaly);
/* ----- Typography (all Cyrillic-complete) ----- */
--m-font-display: "Oswald", "PT Sans Narrow", "Arial Narrow", sans-serif;
--m-font-body: "Manrope", "Segoe UI", system-ui, sans-serif;
--m-font-mono: "JetBrains Mono", "IBM Plex Mono", "Fira Code", Consolas, monospace; --m-font-mono: "JetBrains Mono", "IBM Plex Mono", "Fira Code", Consolas, monospace;
/* ----- Colors — light (parchment) chassis ----- */ /* ----- Colors — light "paper" chassis ----- */
--m-c-ink: #0f172a; --m-c-ink: #0a0a0a;
--m-c-ink-2: #1e293b; --m-c-ink-2: #26241e;
--m-c-ink-soft: #475569; --m-c-ink-soft: #6b6757;
--m-c-paper: #fafaf7; --m-c-paper: #fffef8;
--m-c-paper-2: #f5f4ef; --m-c-paper-2: #f3f1e9;
--m-c-paper-3: #ebe9e1; --m-c-paper-3: #e7e3d6;
--m-c-rule: #e7e5e4; --m-c-rule: #0a0a0a;
--m-c-accent: #d97706; --m-c-accent: #c6f400; /* acid lime */
--m-c-accent-soft: #f59e0b; --m-c-accent-soft: #b3dd00;
--m-c-anomaly: #dc2626; --m-c-on-accent: #0a0a0a; /* ink on lime — lime is a light hue */
--m-c-positive: #15803d; --m-c-anomaly: #ff3b30;
--m-c-info: #0369a1; --m-c-positive: #1f9e3d;
--m-c-info: #244bff; /* electric blue */
/* Tabular numerals for everywhere odds/scores appear */ /* Tabular numerals for everywhere odds/scores appear */
--m-num-feature: "tnum" 1, "lnum" 1, "ss01" 1; --m-num-feature: "tnum" 1, "lnum" 1;
} }
/* Dark theme overrides (applied via class on <html> or via MudThemeProvider) */ /* Dark theme overrides — warm charcoal, lime retained */
.mud-theme-dark, [data-theme="dark"] { .mud-theme-dark, [data-theme="dark"] {
--m-c-ink: #f5f5f4; --m-c-ink: #f5f3ea;
--m-c-ink-2: #e7e5e4; --m-c-ink-2: #d8d4c6;
--m-c-ink-soft: #a8a29e; --m-c-ink-soft: #9c9784;
--m-c-paper: #1c1917; --m-c-paper: #1e1c15;
--m-c-paper-2: #0c0a09; --m-c-paper-2: #141310;
--m-c-paper-3: #292524; --m-c-paper-3: #2a2820;
--m-c-rule: #292524; --m-c-rule: #f5f3ea;
--m-c-accent: #fbbf24; --m-c-accent: #c6f400;
--m-c-accent-soft: #fcd34d; --m-c-accent-soft: #aacc00;
--m-c-anomaly: #f87171; --m-c-on-accent: #0a0a0a;
--m-c-anomaly: #ff5a4f;
--m-c-positive: #4ade80; --m-c-positive: #4ade80;
--m-c-info: #38bdf8; --m-c-info: #6f8bff;
/* 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;
} }
/* =================================================================== /* ===================================================================
@@ -81,19 +98,13 @@ html, body {
} }
body { body {
/* Subtle paper grain — 1px mottled noise, rendered cheaply via SVG. */ /* Subtle diagonal hatch — the Velocity texture. */
background-image: background-image: repeating-linear-gradient(135deg, transparent 0 22px, rgba(10, 10, 10, 0.025) 22px 24px);
radial-gradient(circle at 25% 12%, rgba(217, 119, 6, 0.035), transparent 45%),
radial-gradient(circle at 88% 78%, rgba(15, 23, 42, 0.040), transparent 50%),
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.045 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
background-attachment: fixed; background-attachment: fixed;
} }
.mud-theme-dark body, [data-theme="dark"] body { .mud-theme-dark body, [data-theme="dark"] body {
background-image: background-image: repeating-linear-gradient(135deg, transparent 0 22px, rgba(255, 255, 255, 0.022) 22px 24px);
radial-gradient(circle at 25% 12%, rgba(251, 191, 36, 0.045), transparent 45%),
radial-gradient(circle at 88% 78%, rgba(56, 189, 248, 0.030), transparent 50%),
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.025 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
} }
#app { #app {
@@ -120,61 +131,71 @@ body {
} }
/* =================================================================== /* ===================================================================
Editorial markers — kicker label + serif display lockup Editorial markers — lime kicker chip + slammed display lockup
=================================================================== */ =================================================================== */
.m-kicker { .m-kicker {
font-family: var(--m-font-mono); font-family: var(--m-font-mono);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.18em; letter-spacing: 0.14em;
font-size: 0.6875rem; font-size: 0.6875rem;
color: var(--m-c-accent); font-weight: 700;
font-weight: 500; color: var(--m-c-on-accent);
background: var(--m-c-accent);
border: var(--m-border-w) solid var(--m-c-ink);
border-radius: var(--m-radius-md);
padding: 5px 10px;
display: inline-block; display: inline-block;
padding-bottom: var(--m-space-1); }
border-bottom: 1px solid var(--m-c-accent);
/* A tilted variant for hero kickers — opt-in so it never skews chrome. */
.m-kicker--tilt {
transform: rotate(-1.5deg);
} }
.m-display { .m-display {
font-family: var(--m-font-display); font-family: var(--m-font-display);
font-weight: 300; font-weight: 700;
letter-spacing: -0.022em; letter-spacing: 0.005em;
line-height: 1.05; line-height: 0.98;
text-transform: uppercase;
color: var(--m-c-ink); color: var(--m-c-ink);
} }
.m-rule { .m-rule {
border: 0; border: 0;
border-top: 1px solid var(--m-c-rule); border-top: var(--m-border-w) solid var(--m-c-ink);
margin: var(--m-space-5) 0; margin: var(--m-space-5) 0;
} }
.m-rule--double { .m-rule--double {
border: 0; border: 0;
border-top: 3px double var(--m-c-rule); border-top: var(--m-border-w-bold) double var(--m-c-ink);
margin: var(--m-space-5) 0; margin: var(--m-space-5) 0;
} }
/* =================================================================== /* ===================================================================
Cards — paper-like, borders not shadows Cards — brutalist blocks: thick border + hard offset shadow
=================================================================== */ =================================================================== */
.m-card { .m-card {
background: var(--m-c-paper); background: var(--m-c-paper);
border: 1px solid var(--m-c-rule); border: var(--m-border-w-bold) solid var(--m-c-ink);
border-radius: var(--m-radius-xs); border-radius: var(--m-radius-lg);
box-shadow: var(--m-shadow-hard);
padding: var(--m-space-5); padding: var(--m-space-5);
position: relative; position: relative;
} }
/* Emphasis variants recolour the hard shadow rather than a hidden left rule. */
.m-card--accented { .m-card--accented {
border-left: 3px solid var(--m-c-accent); box-shadow: var(--m-shadow-hard-accent);
} }
.m-card--anomaly { .m-card--anomaly {
border-left: 3px solid var(--m-c-anomaly); box-shadow: var(--m-shadow-hard-anomaly);
} }
/* =================================================================== /* ===================================================================
Stat block — large number, mono, kicker on top Stat block — slammed Oswald number, lime tick, mono label
=================================================================== */ =================================================================== */
.m-stat { .m-stat {
display: flex; display: flex;
@@ -183,26 +204,37 @@ body {
} }
.m-stat__value { .m-stat__value {
font-family: var(--m-font-mono); font-family: var(--m-font-display);
font-feature-settings: var(--m-num-feature); font-feature-settings: var(--m-num-feature);
font-size: clamp(2rem, 4vw, 3rem); font-size: clamp(2.25rem, 4.5vw, 3.25rem);
font-weight: 500; font-weight: 700;
line-height: 1; line-height: 1;
color: var(--m-c-ink); color: var(--m-c-ink);
letter-spacing: -0.02em; letter-spacing: 0.01em;
}
.m-stat__value::after {
content: "";
display: block;
width: 42px;
height: 5px;
margin-top: var(--m-space-2);
background: var(--m-c-accent);
} }
.m-stat__label { .m-stat__label {
font-family: var(--m-font-body); font-family: var(--m-font-mono);
font-size: 0.8125rem; font-size: 0.6875rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--m-c-ink-soft); color: var(--m-c-ink-soft);
text-transform: none;
letter-spacing: 0;
} }
.m-stat__delta { .m-stat__delta {
font-family: var(--m-font-mono); font-family: var(--m-font-mono);
font-size: 0.75rem; font-size: 0.75rem;
font-weight: 700;
color: var(--m-c-positive); color: var(--m-c-positive);
} }
@@ -239,16 +271,16 @@ body {
} }
/* =================================================================== /* ===================================================================
Focus rings — deliberate, accent, never invisible Focus rings — electric blue for contrast on lime/paper and charcoal
=================================================================== */ =================================================================== */
:focus-visible { :focus-visible {
outline: 2px solid var(--m-c-accent); outline: var(--m-border-w) solid var(--m-c-info);
outline-offset: 2px; outline-offset: 2px;
} }
.mud-button:focus-visible, .mud-button:focus-visible,
.mud-icon-button:focus-visible { .mud-icon-button:focus-visible {
outline: 2px solid var(--m-c-accent); outline: var(--m-border-w) solid var(--m-c-info);
outline-offset: 2px; outline-offset: 2px;
} }
@@ -292,10 +324,12 @@ body {
.m-brand__mark { .m-brand__mark {
font-family: var(--m-font-display); font-family: var(--m-font-display);
font-weight: 500; font-weight: 700;
font-size: 1.375rem; font-size: 1.5rem;
letter-spacing: -0.02em; letter-spacing: 0.01em;
line-height: 1; line-height: 1;
text-transform: uppercase;
color: inherit;
} }
.m-brand__mark::first-letter { .m-brand__mark::first-letter {
@@ -304,47 +338,55 @@ body {
.m-brand__dateline { .m-brand__dateline {
font-family: var(--m-font-mono); font-family: var(--m-font-mono);
font-size: 0.6875rem; font-size: 0.625rem;
font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.16em; letter-spacing: 0.16em;
color: var(--m-c-ink-soft); color: var(--m-c-accent);
border-left: 1px solid var(--m-c-rule); border-left: var(--m-border-w) solid currentColor;
padding-left: var(--m-space-3); padding-left: var(--m-space-3);
} }
/* =================================================================== /* ===================================================================
Drawer — narrow, dark, mono labels Drawer — paper sidebar, brutalist nav blocks
=================================================================== */ =================================================================== */
.m-nav__group { .m-nav__group {
padding: var(--m-space-3) var(--m-space-4); padding: var(--m-space-4) var(--m-space-3) var(--m-space-2);
font-family: var(--m-font-mono); font-family: var(--m-font-mono);
font-size: 0.6875rem; font-size: 0.625rem;
font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.18em; letter-spacing: 0.18em;
color: rgba(231, 229, 228, 0.55); color: var(--m-c-ink-soft);
} }
.m-nav__link { .m-nav__link {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--m-space-3); gap: var(--m-space-3);
padding: var(--m-space-3) var(--m-space-4); padding: 10px 12px;
color: rgba(231, 229, 228, 0.85); color: var(--m-c-ink-2);
text-decoration: none; text-decoration: none;
font-size: 0.9375rem; font-family: var(--m-font-body);
border-left: 2px solid transparent; font-weight: 700;
transition: background 120ms ease, border-color 120ms ease, color 120ms ease; font-size: 0.875rem;
border: var(--m-border-w) solid transparent;
border-radius: var(--m-radius-md);
transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease, background 120ms ease, color 120ms ease;
} }
.m-nav__link:hover { .m-nav__link:hover {
background: rgba(217, 119, 6, 0.10); border-color: var(--m-c-ink);
color: #ffffff; transform: translate(-1px, -1px);
box-shadow: var(--m-shadow-hard-sm);
color: var(--m-c-ink);
} }
.m-nav__link.active { .m-nav__link.active {
color: #ffffff; background: var(--m-c-accent);
background: rgba(217, 119, 6, 0.14); color: var(--m-c-on-accent);
border-left-color: var(--m-c-accent); border-color: var(--m-c-ink);
box-shadow: var(--m-shadow-hard-sm);
} }
.m-nav__link .mud-icon-root { font-size: 1.1rem; } .m-nav__link .mud-icon-root { font-size: 1.1rem; }
@@ -354,8 +396,8 @@ body {
=================================================================== */ =================================================================== */
.m-segmented { .m-segmented {
display: inline-flex; display: inline-flex;
border: 1px solid var(--m-c-rule); border: var(--m-border-w) solid var(--m-c-ink);
border-radius: var(--m-radius-xs); border-radius: var(--m-radius-md);
overflow: hidden; overflow: hidden;
background: var(--m-c-paper); background: var(--m-c-paper);
} }
@@ -367,15 +409,16 @@ body {
padding: 6px 12px; padding: 6px 12px;
font-family: var(--m-font-mono); font-family: var(--m-font-mono);
font-size: 0.6875rem; font-size: 0.6875rem;
font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.14em; letter-spacing: 0.12em;
color: var(--m-c-ink-soft); color: var(--m-c-ink-soft);
cursor: pointer; cursor: pointer;
transition: background 120ms ease, color 120ms ease; transition: background 120ms ease, color 120ms ease;
} }
.m-segmented__btn + .m-segmented__btn { .m-segmented__btn + .m-segmented__btn {
border-left: 1px solid var(--m-c-rule); border-left: var(--m-border-w) solid var(--m-c-ink);
} }
.m-segmented__btn:hover { .m-segmented__btn:hover {
@@ -383,21 +426,17 @@ body {
} }
.m-segmented__btn.is-active { .m-segmented__btn.is-active {
background: var(--m-c-ink);
color: var(--m-c-paper);
}
.mud-theme-dark .m-segmented__btn.is-active,
[data-theme="dark"] .m-segmented__btn.is-active {
background: var(--m-c-accent); background: var(--m-c-accent);
color: var(--m-c-paper-2); color: var(--m-c-on-accent);
} }
/* =================================================================== /* ===================================================================
Settings page — section ledger Settings page — section ledger
=================================================================== */ =================================================================== */
.m-section { .m-section {
border: 1px solid var(--m-c-rule); border: var(--m-border-w-bold) solid var(--m-c-ink);
border-radius: var(--m-radius-lg);
box-shadow: var(--m-shadow-hard);
background: var(--m-c-paper); background: var(--m-c-paper);
margin-bottom: var(--m-space-5); margin-bottom: var(--m-space-5);
} }
@@ -407,16 +446,17 @@ body {
align-items: baseline; align-items: baseline;
justify-content: space-between; justify-content: space-between;
padding: var(--m-space-4) var(--m-space-5); padding: var(--m-space-4) var(--m-space-5);
border-bottom: 1px solid var(--m-c-rule); border-bottom: var(--m-border-w) solid var(--m-c-ink);
background: var(--m-c-paper-2); background: var(--m-c-paper-3);
} }
.m-section__head h2 { .m-section__head h2 {
margin: 0; margin: 0;
font-family: var(--m-font-display); font-family: var(--m-font-display);
font-weight: 400; font-weight: 700;
font-size: 1.25rem; font-size: 1.375rem;
letter-spacing: -0.012em; text-transform: uppercase;
letter-spacing: 0.01em;
} }
.m-section__body { .m-section__body {
@@ -450,15 +490,16 @@ body {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: var(--m-space-2); gap: var(--m-space-2);
padding: 2px 8px; padding: 3px 9px;
background: rgba(220, 38, 38, 0.10); background: var(--m-c-paper);
color: var(--m-c-anomaly); color: var(--m-c-anomaly);
border: 1px solid currentColor; border: var(--m-border-w) solid currentColor;
border-radius: var(--m-radius-xs); border-radius: var(--m-radius-sm);
font-family: var(--m-font-mono); font-family: var(--m-font-mono);
font-size: 0.6875rem; font-size: 0.6875rem;
font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.14em; letter-spacing: 0.12em;
} }
.m-anomaly__pulse { .m-anomaly__pulse {
+8 -8
View File
@@ -8,17 +8,17 @@
<!-- Prevent flash of unthemed content --> <!-- Prevent flash of unthemed content -->
<style> <style>
html, body { background: #f5f4ef; margin: 0; } html, body { background: #f3f1e9; margin: 0; }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html, body { background: #0c0a09; } html, body { background: #141310; }
} }
</style> </style>
<!-- Fonts: IBM Plex Sans / Serif / Mono + JetBrains Mono. Full Cyrillic coverage. --> <!-- Fonts: Oswald (display) + Manrope (body) + JetBrains Mono (numerals). Full Cyrillic coverage. -->
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link <link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=IBM+Plex+Serif:wght@300;400;500;600&family=IBM+Plex+Mono:wght@400;500&family=JetBrains+Mono:wght@400;500;600&display=swap" href="https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;600;700&family=Manrope:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700;800&display=swap"
rel="stylesheet" /> rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" /> <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
@@ -26,13 +26,13 @@
</head> </head>
<body> <body>
<div id="app"> <div id="app">
<div style="padding: 64px; font-family: 'IBM Plex Serif', Georgia, serif; color: #475569;"> <div style="padding: 64px; font-family: 'Manrope', system-ui, sans-serif; color: #6b6757;">
<span style="font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: #d97706;">Booting</span> <span style="font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: #0a0a0a; background: #c6f400; border: 2px solid #0a0a0a; border-radius: 8px; padding: 4px 9px;">Booting</span>
<div style="font-size: 32px; font-weight: 300; margin-top: 8px;">Marathon Odds Lab</div> <div style="font-family: 'Oswald', sans-serif; font-size: 42px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.01em; margin-top: 14px; color: #0a0a0a;">Marathon Odds Lab</div>
</div> </div>
</div> </div>
<div id="blazor-error-ui" style="display:none; position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000; padding: 12px 24px; background: #dc2626; color: #fafaf7; font-family: 'IBM Plex Sans', sans-serif;"> <div id="blazor-error-ui" style="display:none; position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000; padding: 12px 24px; background: #ff3b30; color: #fffef8; font-family: 'Manrope', system-ui, sans-serif;">
<span>An unhandled error has occurred.</span> <span>An unhandled error has occurred.</span>
<a href="" class="reload" style="color: #fff; text-decoration: underline; margin-left: 12px;">Reload</a> <a href="" class="reload" style="color: #fff; text-decoration: underline; margin-left: 12px;">Reload</a>
<a class="dismiss" style="float: right; cursor: pointer; padding: 0 8px;">×</a> <a class="dismiss" style="float: right; cursor: pointer; padding: 0 8px;">×</a>