feat(redesign): design-system tokens, 23 Vue components, game-aware shell + Fleet/Solo dashboard
All checks were successful
Test Asgard Runner / test (push) Successful in 4s
All checks were successful
Test Asgard Runner / test (push) Successful in 4s
Tokens ported 1:1 from the Claude Design bundle (colors/game-themes/type/spacing/elevation/motion/fonts) with the data-theme/data-game theming contract via useThemeGame (+ cc-skin-swap repaint guard). 23 design-system components reimplemented as Vue SFCs (core/forms/data/navigation/feedback/brand). DashboardLayout rebuilt as the game-aware shell (GameSwitcher, grouped nav with permission gating preserved, agent-health footer, topbar). DashboardView: Fleet + Solo with per-game GAME_FIELDS rows and the themed ECharts PlayersChart; Solo wired to the real server store, Fleet on representative data pending the multi-instance backend. All four game skins (Rust/Dune/Conan/Soulmask). vue-tsc + vite build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
15
frontend/src/styles/corrosion.css
Normal file
15
frontend/src/styles/corrosion.css
Normal file
@@ -0,0 +1,15 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Design System
|
||||
Root stylesheet. Consumers link THIS one file.
|
||||
Import order matters: fonts → primitives → colors → game themes
|
||||
→ base. (base.css references color/accent tokens.)
|
||||
============================================================ */
|
||||
|
||||
@import url("tokens/fonts.css");
|
||||
@import url("tokens/spacing.css");
|
||||
@import url("tokens/typography.css");
|
||||
@import url("tokens/motion.css");
|
||||
@import url("tokens/colors.css");
|
||||
@import url("tokens/game-themes.css");
|
||||
@import url("tokens/elevation.css");
|
||||
@import url("tokens/base.css");
|
||||
75
frontend/src/styles/tokens/base.css
Normal file
75
frontend/src/styles/tokens/base.css
Normal file
@@ -0,0 +1,75 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Base / Reset
|
||||
Minimal, opinionated. Applies the token system to bare HTML so
|
||||
specimen cards and kits inherit the look without boilerplate.
|
||||
============================================================ */
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
|
||||
html { -webkit-text-size-adjust: 100%; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-normal);
|
||||
color: var(--text-primary);
|
||||
background-color: var(--surface-canvas);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-feature-settings: "cv01", "ss01";
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, p, figure { margin: 0; }
|
||||
|
||||
a { color: inherit; text-decoration: none; }
|
||||
|
||||
::selection {
|
||||
background: var(--accent-soft-strong);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* Tabular numbers everywhere numbers matter */
|
||||
.tnum { font-variant-numeric: tabular-nums; }
|
||||
|
||||
/* Custom scrollbars — quiet, on-brand */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--border-strong) transparent;
|
||||
}
|
||||
*::-webkit-scrollbar { width: 10px; height: 10px; }
|
||||
*::-webkit-scrollbar-track { background: transparent; }
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: var(--border-strong);
|
||||
border-radius: var(--radius-pill);
|
||||
border: 2px solid transparent;
|
||||
background-clip: content-box;
|
||||
}
|
||||
*::-webkit-scrollbar-thumb:hover { background: var(--text-muted); background-clip: content-box; }
|
||||
|
||||
/* Focus-visible default */
|
||||
:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
|
||||
/* Reduced motion guard */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Skin-swap repaint guard ----
|
||||
When flipping data-game or data-theme on the root, add the .cc-skin-swap
|
||||
class for ONE frame. This suppresses transitions during the swap so every
|
||||
accent-consuming surface repaints immediately — works around a Chrome
|
||||
custom-property + transition staleness where elements that both read
|
||||
var(--accent)/var(--accent-text) AND have a color/background transition keep
|
||||
the old accent until the next reflow. See readme "Theming contract". */
|
||||
.cc-skin-swap *,
|
||||
.cc-skin-swap *::before,
|
||||
.cc-skin-swap *::after { transition: none !important; }
|
||||
136
frontend/src/styles/tokens/colors.css
Normal file
136
frontend/src/styles/tokens/colors.css
Normal file
@@ -0,0 +1,136 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Color System
|
||||
------------------------------------------------------------
|
||||
Three layers:
|
||||
1. Raw neutral ramp (absolute; identical in both themes)
|
||||
2. Semantic surface / text / border tokens (flip per theme)
|
||||
3. Status colors (online/offline/warn/info/...) — game-agnostic
|
||||
Game ACCENT colors live in game-themes.css.
|
||||
|
||||
Theme + game are set together on <html>:
|
||||
<html data-theme="dark" data-game="rust">
|
||||
Dark is primary. Light is full-parity.
|
||||
============================================================ */
|
||||
|
||||
:root {
|
||||
/* ---- Raw neutral ramp (warm-cool slate, absolute) ---- */
|
||||
--n-0: #ffffff;
|
||||
--n-25: #fafbfc;
|
||||
--n-50: #f3f5f7;
|
||||
--n-100: #e8ebef;
|
||||
--n-150: #dce0e6;
|
||||
--n-200: #ccd2da;
|
||||
--n-300: #aeb6c1;
|
||||
--n-400: #8a929e;
|
||||
--n-500: #6b7280;
|
||||
--n-600: #515862;
|
||||
--n-650: #444a53;
|
||||
--n-700: #363b43;
|
||||
--n-750: #2b2f36;
|
||||
--n-800: #1f2329;
|
||||
--n-850: #181b20;
|
||||
--n-900: #121419;
|
||||
--n-925: #0e0f13;
|
||||
--n-950: #0a0b0e;
|
||||
--n-975: #060709;
|
||||
|
||||
/* ---- Semantic: DARK (default) ---- */
|
||||
--surface-canvas: var(--n-950); /* app background */
|
||||
--surface-sunken: var(--n-975); /* wells, deep insets */
|
||||
--surface-base: var(--n-925); /* primary panels */
|
||||
--surface-raised: var(--n-850); /* cards, rows */
|
||||
--surface-raised-2:var(--n-800); /* nested cards, hover cards */
|
||||
--surface-overlay: var(--n-800); /* menus, popovers, dialogs */
|
||||
--surface-inset: #07080a; /* inputs, console, code */
|
||||
--surface-hover: rgba(255, 255, 255, 0.045);
|
||||
--surface-active: rgba(255, 255, 255, 0.075);
|
||||
--surface-selected:rgba(255, 255, 255, 0.06);
|
||||
|
||||
--border-subtle: rgba(255, 255, 255, 0.06);
|
||||
--border-default: rgba(255, 255, 255, 0.10);
|
||||
--border-strong: rgba(255, 255, 255, 0.16);
|
||||
|
||||
--text-primary: #f2f4f7;
|
||||
--text-secondary: #aeb4bf;
|
||||
--text-tertiary: #767d89;
|
||||
--text-muted: #565d68;
|
||||
--text-inverse: #0a0b0e;
|
||||
--text-on-accent: var(--accent-contrast);
|
||||
|
||||
/* Scrim for modals / image overlays */
|
||||
--scrim: rgba(4, 5, 7, 0.66);
|
||||
|
||||
/* ---- Status / semantic (consistent across themes) ---- */
|
||||
--status-online: #36c780;
|
||||
--status-online-soft: rgba(54, 199, 128, 0.14);
|
||||
--status-online-border: rgba(54, 199, 128, 0.38);
|
||||
|
||||
--status-offline: #e5484d;
|
||||
--status-offline-soft: rgba(229, 72, 77, 0.14);
|
||||
--status-offline-border: rgba(229, 72, 77, 0.40);
|
||||
|
||||
--status-warn: #e8a33c;
|
||||
--status-warn-soft: rgba(232, 163, 60, 0.15);
|
||||
--status-warn-border: rgba(232, 163, 60, 0.40);
|
||||
|
||||
--status-info: #4c8df0;
|
||||
--status-info-soft: rgba(76, 141, 240, 0.15);
|
||||
--status-info-border: rgba(76, 141, 240, 0.40);
|
||||
|
||||
--status-starting: #2bc2d4; /* booting / updating / restarting */
|
||||
--status-starting-soft: rgba(43, 194, 212, 0.15);
|
||||
--status-starting-border: rgba(43, 194, 212, 0.40);
|
||||
|
||||
--status-wiping: #9b7bf0; /* Rust map wipe / maintenance */
|
||||
--status-wiping-soft: rgba(155, 123, 240, 0.16);
|
||||
--status-wiping-border: rgba(155, 123, 240, 0.40);
|
||||
|
||||
/* Aliases used by components */
|
||||
--success: var(--status-online);
|
||||
--danger: var(--status-offline);
|
||||
--warning: var(--status-warn);
|
||||
--info: var(--status-info);
|
||||
|
||||
/* Data-viz categorical (ECharts-friendly) */
|
||||
--viz-1: var(--accent);
|
||||
--viz-2: #4c8df0;
|
||||
--viz-3: #36c780;
|
||||
--viz-4: #9b7bf0;
|
||||
--viz-5: #2bc2d4;
|
||||
--viz-6: #e8a33c;
|
||||
--viz-grid: var(--border-subtle);
|
||||
}
|
||||
|
||||
/* ---- Semantic: LIGHT (full parity) ---- */
|
||||
[data-theme="light"] {
|
||||
--surface-canvas: #f5f6f8;
|
||||
--surface-sunken: #eceef1;
|
||||
--surface-base: #ffffff;
|
||||
--surface-raised: #ffffff;
|
||||
--surface-raised-2:#fbfcfd;
|
||||
--surface-overlay: #ffffff;
|
||||
--surface-inset: #f1f3f5;
|
||||
--surface-hover: rgba(12, 16, 22, 0.04);
|
||||
--surface-active: rgba(12, 16, 22, 0.07);
|
||||
--surface-selected:rgba(12, 16, 22, 0.05);
|
||||
|
||||
--border-subtle: rgba(12, 16, 22, 0.07);
|
||||
--border-default: rgba(12, 16, 22, 0.12);
|
||||
--border-strong: rgba(12, 16, 22, 0.20);
|
||||
|
||||
--text-primary: #14171c;
|
||||
--text-secondary: #474e58;
|
||||
--text-tertiary: #6b727e;
|
||||
--text-muted: #969ca6;
|
||||
--text-inverse: #ffffff;
|
||||
|
||||
--scrim: rgba(16, 20, 28, 0.45);
|
||||
|
||||
/* Status soft fills need a touch more alpha on light */
|
||||
--status-online-soft: rgba(33, 160, 98, 0.12);
|
||||
--status-offline-soft: rgba(206, 44, 49, 0.10);
|
||||
--status-warn-soft: rgba(193, 124, 18, 0.13);
|
||||
--status-info-soft: rgba(43, 105, 214, 0.10);
|
||||
--status-starting-soft: rgba(18, 150, 168, 0.12);
|
||||
--status-wiping-soft: rgba(118, 86, 214, 0.12);
|
||||
}
|
||||
40
frontend/src/styles/tokens/elevation.css
Normal file
40
frontend/src/styles/tokens/elevation.css
Normal file
@@ -0,0 +1,40 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Elevation, Borders, Glows
|
||||
Shadows are quiet on dark surfaces; depth comes from layered
|
||||
fills + hairline borders. Accent "glow" is reserved for
|
||||
active/live states and game-themed focus.
|
||||
============================================================ */
|
||||
|
||||
:root {
|
||||
/* Hairline rings (use as box-shadow inset or border) */
|
||||
--ring-subtle: inset 0 0 0 1px var(--border-subtle);
|
||||
--ring-default: inset 0 0 0 1px var(--border-default);
|
||||
--ring-strong: inset 0 0 0 1px var(--border-strong);
|
||||
|
||||
/* Drop shadows — tuned for dark; subtle and tight */
|
||||
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.35);
|
||||
--shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.40);
|
||||
--shadow-md: 0 6px 18px -4px rgba(0, 0, 0, 0.50);
|
||||
--shadow-lg: 0 18px 40px -10px rgba(0, 0, 0, 0.60);
|
||||
--shadow-xl: 0 32px 70px -16px rgba(0, 0, 0, 0.70);
|
||||
|
||||
/* Popover / menu — combines ring + drop for crisp edges on dark */
|
||||
--shadow-pop: 0 0 0 1px var(--border-default), 0 12px 36px -8px rgba(0, 0, 0, 0.66);
|
||||
|
||||
/* Accent glow — game-themed; used on live/active controls & focus */
|
||||
--glow-accent: 0 0 0 1px var(--accent-border), 0 0 22px -2px var(--accent-glow);
|
||||
--glow-accent-sm: 0 0 14px -2px var(--accent-glow);
|
||||
--glow-online: 0 0 12px -1px rgba(54, 199, 128, 0.55);
|
||||
|
||||
/* Focus ring */
|
||||
--focus-ring: 0 0 0 2px var(--surface-canvas), 0 0 0 4px var(--accent);
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
--shadow-xs: 0 1px 2px rgba(16, 20, 28, 0.06);
|
||||
--shadow-sm: 0 2px 6px rgba(16, 20, 28, 0.08);
|
||||
--shadow-md: 0 8px 20px -6px rgba(16, 20, 28, 0.12);
|
||||
--shadow-lg: 0 20px 44px -12px rgba(16, 20, 28, 0.16);
|
||||
--shadow-xl: 0 32px 70px -18px rgba(16, 20, 28, 0.20);
|
||||
--shadow-pop: 0 0 0 1px var(--border-default), 0 14px 38px -10px rgba(16, 20, 28, 0.20);
|
||||
}
|
||||
21
frontend/src/styles/tokens/fonts.css
Normal file
21
frontend/src/styles/tokens/fonts.css
Normal file
@@ -0,0 +1,21 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Fonts
|
||||
Geist — UI / body / app headings
|
||||
JetBrains Mono — console, data, IDs, telemetry
|
||||
Oxanium — brand wordmark + marketing display (game-ops flavor)
|
||||
------------------------------------------------------------
|
||||
NOTE: Loaded from Google Fonts CDN. If you want these self-
|
||||
hosted (offline), send the woff2 files and these @imports
|
||||
become @font-face rules.
|
||||
============================================================ */
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700;800&family=JetBrains+Mono:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Oxanium:wght@500;600;700;800&display=swap');
|
||||
|
||||
:root {
|
||||
--font-sans: 'Geist', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, monospace;
|
||||
/* Brand wordmark + big marketing display — squared, technical, gamey */
|
||||
--font-brand: 'Oxanium', 'Geist', system-ui, sans-serif;
|
||||
/* App-level display headings stay on the neutral sans */
|
||||
--font-display: var(--font-sans);
|
||||
}
|
||||
150
frontend/src/styles/tokens/game-themes.css
Normal file
150
frontend/src/styles/tokens/game-themes.css
Normal file
@@ -0,0 +1,150 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Game Themes (the re-skin layer)
|
||||
------------------------------------------------------------
|
||||
The shell is neutral. Each game declares an ACCENT ramp + an
|
||||
ATMOSPHERE (backdrop hues for hero headers, login, glows).
|
||||
Set on <html data-game="rust"> (or dune / ark / valheim / ...).
|
||||
Default (no data-game) = Corrosion brand = Oxide Orange.
|
||||
|
||||
Accent contract every game must define:
|
||||
--accent base fill
|
||||
--accent-hover hover fill
|
||||
--accent-press pressed / darker
|
||||
--accent-contrast text/icon ON the accent fill
|
||||
--accent-text accent used AS text on dark surfaces (lightened for AA)
|
||||
--accent-soft low-alpha tint background
|
||||
--accent-soft-strong
|
||||
--accent-border accent hairline
|
||||
--accent-glow glow color (box-shadow)
|
||||
--game-label printable name
|
||||
--atmo-1 / --atmo-2 backdrop gradient stops
|
||||
--atmo-haze radial haze color
|
||||
============================================================ */
|
||||
|
||||
/* ---------- Default brand / RUST — Oxide Orange #F26622 ---------- */
|
||||
:root,
|
||||
[data-game="rust"] {
|
||||
--accent: #f26622;
|
||||
--accent-hover: #ff7a38;
|
||||
--accent-press: #d9550f;
|
||||
--accent-contrast: #190d05;
|
||||
--accent-text: #ff8a4c;
|
||||
--accent-soft: rgba(242, 102, 34, 0.13);
|
||||
--accent-soft-strong: rgba(242, 102, 34, 0.22);
|
||||
--accent-border: rgba(242, 102, 34, 0.42);
|
||||
--accent-glow: rgba(242, 102, 34, 0.50);
|
||||
--game-label: "Rust"; /* @kind other */
|
||||
--atmo-1: #2c1206;
|
||||
--atmo-2: #0a0b0e;
|
||||
--atmo-haze: rgba(242, 102, 34, 0.30);
|
||||
}
|
||||
|
||||
/* ---------- DUNE: AWAKENING — Spice Amber / desert gold ---------- */
|
||||
[data-game="dune"] {
|
||||
--accent: #e9a53a;
|
||||
--accent-hover: #f7b94f;
|
||||
--accent-press: #c9851f;
|
||||
--accent-contrast: #1c1303;
|
||||
--accent-text: #f0bc5e;
|
||||
--accent-soft: rgba(233, 165, 58, 0.14);
|
||||
--accent-soft-strong: rgba(233, 165, 58, 0.24);
|
||||
--accent-border: rgba(233, 165, 58, 0.44);
|
||||
--accent-glow: rgba(233, 165, 58, 0.46);
|
||||
--game-label: "Dune: Awakening"; /* @kind other */
|
||||
--atmo-1: #2c1e08;
|
||||
--atmo-2: #0a0b0e;
|
||||
--atmo-haze: rgba(233, 165, 58, 0.30);
|
||||
}
|
||||
|
||||
/* ---------- SOULMASK: Ritual Jade ---------- */
|
||||
[data-game="soulmask"] {
|
||||
--accent: #43c47e;
|
||||
--accent-hover: #59d792;
|
||||
--accent-press: #2c9c5f;
|
||||
--accent-contrast: #04140c;
|
||||
--accent-text: #63d894;
|
||||
--accent-soft: rgba(67, 196, 126, 0.14);
|
||||
--accent-soft-strong: rgba(67, 196, 126, 0.24);
|
||||
--accent-border: rgba(67, 196, 126, 0.42);
|
||||
--accent-glow: rgba(67, 196, 126, 0.46);
|
||||
--game-label: "Soulmask"; /* @kind other */
|
||||
--atmo-1: #08231a;
|
||||
--atmo-2: #0a0b0e;
|
||||
--atmo-haze: rgba(67, 196, 126, 0.26);
|
||||
}
|
||||
|
||||
/* ---------- CONAN EXILES: Hyborian Bronze ---------- */
|
||||
[data-game="conan"] {
|
||||
--accent: #bb7637;
|
||||
--accent-hover: #d28d4b;
|
||||
--accent-press: #985c24;
|
||||
--accent-contrast: #160d03;
|
||||
--accent-text: #d59a5e;
|
||||
--accent-soft: rgba(187, 118, 55, 0.15);
|
||||
--accent-soft-strong: rgba(187, 118, 55, 0.26);
|
||||
--accent-border: rgba(187, 118, 55, 0.44);
|
||||
--accent-glow: rgba(187, 118, 55, 0.46);
|
||||
--game-label: "Conan Exiles"; /* @kind other */
|
||||
--atmo-1: #2a1b0b;
|
||||
--atmo-2: #0a0b0e;
|
||||
--atmo-haze: rgba(187, 118, 55, 0.30);
|
||||
}
|
||||
|
||||
/* ---------- Room to add more (stubs, ready to ship) ---------- */
|
||||
[data-game="ark"] {
|
||||
--accent: #36c2a8;
|
||||
--accent-hover: #4ad7bd;
|
||||
--accent-press: #1f9c86;
|
||||
--accent-contrast: #04140f;
|
||||
--accent-text: #54dcc2;
|
||||
--accent-soft: rgba(54, 194, 168, 0.14);
|
||||
--accent-soft-strong: rgba(54, 194, 168, 0.24);
|
||||
--accent-border: rgba(54, 194, 168, 0.42);
|
||||
--accent-glow: rgba(54, 194, 168, 0.46);
|
||||
--game-label: "ARK"; /* @kind other */
|
||||
--atmo-1: #07241f;
|
||||
--atmo-2: #0a0b0e;
|
||||
--atmo-haze: rgba(54, 194, 168, 0.26);
|
||||
}
|
||||
|
||||
[data-game="valheim"] {
|
||||
--accent: #5b9bf0;
|
||||
--accent-hover: #74afff;
|
||||
--accent-press: #3c7ad4;
|
||||
--accent-contrast: #050d1a;
|
||||
--accent-text: #7fb2ff;
|
||||
--accent-soft: rgba(91, 155, 240, 0.14);
|
||||
--accent-soft-strong: rgba(91, 155, 240, 0.24);
|
||||
--accent-border: rgba(91, 155, 240, 0.42);
|
||||
--accent-glow: rgba(91, 155, 240, 0.46);
|
||||
--game-label: "Valheim"; /* @kind other */
|
||||
--atmo-1: #0a1c2e;
|
||||
--atmo-2: #0a0b0e;
|
||||
--atmo-haze: rgba(91, 155, 240, 0.26);
|
||||
}
|
||||
|
||||
[data-game="palworld"] {
|
||||
--accent: #58b6e8;
|
||||
--accent-hover: #71c8f6;
|
||||
--accent-press: #3a92c4;
|
||||
--accent-contrast: #04121b;
|
||||
--accent-text: #7fcaf2;
|
||||
--accent-soft: rgba(88, 182, 232, 0.14);
|
||||
--accent-soft-strong: rgba(88, 182, 232, 0.24);
|
||||
--accent-border: rgba(88, 182, 232, 0.42);
|
||||
--accent-glow: rgba(88, 182, 232, 0.46);
|
||||
--game-label: "Palworld"; /* @kind other */
|
||||
--atmo-1: #08222e;
|
||||
--atmo-2: #0a0b0e;
|
||||
--atmo-haze: rgba(88, 182, 232, 0.26);
|
||||
}
|
||||
|
||||
/* ---------- Light-theme accent legibility ----------
|
||||
On light surfaces, accent-as-text reads better at the pressed
|
||||
(darker) value. Placed last so it wins for --accent-text when
|
||||
data-theme="light" and data-game=* are both on <html>. */
|
||||
[data-theme="light"] {
|
||||
--accent-text: var(--accent-press);
|
||||
--accent-soft: color-mix(in srgb, var(--accent) 12%, transparent);
|
||||
--accent-soft-strong: color-mix(in srgb, var(--accent) 20%, transparent);
|
||||
}
|
||||
27
frontend/src/styles/tokens/motion.css
Normal file
27
frontend/src/styles/tokens/motion.css
Normal file
@@ -0,0 +1,27 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Motion
|
||||
Fast, mechanical, precise. No bounce on chrome. Subtle spring
|
||||
reserved for "live" telemetry (pulses, meters). Respect
|
||||
prefers-reduced-motion in components.
|
||||
============================================================ */
|
||||
|
||||
:root {
|
||||
--dur-instant: 80ms; /* @kind other */
|
||||
--dur-fast: 120ms; /* @kind other */
|
||||
--dur-base: 170ms; /* @kind other */
|
||||
--dur-slow: 240ms; /* @kind other */
|
||||
--dur-slower: 360ms; /* @kind other */
|
||||
|
||||
/* Easings */
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1); /* @kind other */
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* @kind other */
|
||||
--ease-in: cubic-bezier(0.5, 0, 0.84, 0); /* @kind other */
|
||||
--ease-emphasized: cubic-bezier(0.34, 1.4, 0.5, 1); /* @kind other */
|
||||
|
||||
/* Common transition bundles */
|
||||
--transition-colors: color var(--dur-fast) var(--ease-standard),
|
||||
background-color var(--dur-fast) var(--ease-standard),
|
||||
border-color var(--dur-fast) var(--ease-standard),
|
||||
box-shadow var(--dur-fast) var(--ease-standard);
|
||||
--transition-transform: transform var(--dur-base) var(--ease-out);
|
||||
}
|
||||
50
frontend/src/styles/tokens/spacing.css
Normal file
50
frontend/src/styles/tokens/spacing.css
Normal file
@@ -0,0 +1,50 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Spacing, Radius, Sizing
|
||||
Dense ops-cockpit scale. 4px base grid, tightened.
|
||||
============================================================ */
|
||||
|
||||
:root {
|
||||
/* Space scale (px) — used for padding, gap, margins */
|
||||
--space-0: 0;
|
||||
--space-px: 1px;
|
||||
--space-0-5: 2px;
|
||||
--space-1: 4px;
|
||||
--space-1-5: 6px;
|
||||
--space-2: 8px;
|
||||
--space-2-5: 10px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-7: 28px;
|
||||
--space-8: 32px;
|
||||
--space-10: 40px;
|
||||
--space-12: 48px;
|
||||
--space-14: 56px;
|
||||
--space-16: 64px;
|
||||
--space-20: 80px;
|
||||
--space-24: 96px;
|
||||
--space-32: 128px;
|
||||
|
||||
/* Radius — small & technical; cards stay crisp, not rounded-blobby */
|
||||
--radius-xs: 3px;
|
||||
--radius-sm: 5px;
|
||||
--radius-md: 7px;
|
||||
--radius-lg: 10px;
|
||||
--radius-xl: 14px;
|
||||
--radius-2xl: 20px;
|
||||
--radius-pill: 999px;
|
||||
|
||||
/* Control heights — compact rows for data-dense UI */
|
||||
--control-h-xs: 24px;
|
||||
--control-h-sm: 30px;
|
||||
--control-h-md: 36px;
|
||||
--control-h-lg: 44px;
|
||||
|
||||
/* Layout primitives */
|
||||
--sidebar-w: 248px;
|
||||
--sidebar-w-collapsed: 64px;
|
||||
--topbar-h: 56px;
|
||||
--content-max: 1440px;
|
||||
--container-pad: var(--space-6);
|
||||
}
|
||||
75
frontend/src/styles/tokens/typography.css
Normal file
75
frontend/src/styles/tokens/typography.css
Normal file
@@ -0,0 +1,75 @@
|
||||
/* ============================================================
|
||||
Corrosion Control — Typography
|
||||
Geist for UI & display; JetBrains Mono for telemetry, IDs,
|
||||
console, and any numeric/code data. Dense reading sizes.
|
||||
============================================================ */
|
||||
|
||||
:root {
|
||||
/* Font sizes (px) — base UI is 14 (dense) */
|
||||
--text-2xs: 11px;
|
||||
--text-xs: 12px;
|
||||
--text-sm: 13px;
|
||||
--text-base: 14px;
|
||||
--text-md: 15px;
|
||||
--text-lg: 17px;
|
||||
--text-xl: 20px;
|
||||
--text-2xl: 24px;
|
||||
--text-3xl: 30px;
|
||||
--text-4xl: 38px;
|
||||
--text-5xl: 50px;
|
||||
--text-6xl: 66px;
|
||||
--text-7xl: 88px;
|
||||
|
||||
/* Line heights */
|
||||
--leading-none: 1;
|
||||
--leading-tight: 1.15;
|
||||
--leading-snug: 1.3;
|
||||
--leading-normal: 1.5;
|
||||
--leading-relaxed: 1.65;
|
||||
|
||||
/* Weights */
|
||||
--weight-light: 300;
|
||||
--weight-regular: 400;
|
||||
--weight-medium: 500;
|
||||
--weight-semibold: 600;
|
||||
--weight-bold: 700;
|
||||
--weight-black: 800;
|
||||
|
||||
/* Letter spacing */
|
||||
--tracking-tighter: -0.03em;
|
||||
--tracking-tight: -0.015em;
|
||||
--tracking-normal: 0;
|
||||
--tracking-wide: 0.02em;
|
||||
--tracking-wider: 0.06em;
|
||||
--tracking-caps: 0.10em; /* eyebrows / overlines / labels */
|
||||
|
||||
/* ---- Semantic roles (font shorthands via custom props) ---- */
|
||||
--font-display: var(--font-sans);
|
||||
}
|
||||
|
||||
/* ---- Optional helper classes (cards/kits can use these) ---- */
|
||||
.t-display {
|
||||
font-family: var(--font-display);
|
||||
font-weight: var(--weight-bold);
|
||||
letter-spacing: var(--tracking-tight);
|
||||
line-height: var(--leading-tight);
|
||||
}
|
||||
.t-eyebrow {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--weight-medium);
|
||||
letter-spacing: var(--tracking-caps);
|
||||
text-transform: uppercase;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.t-mono {
|
||||
font-family: var(--font-mono);
|
||||
font-variant-numeric: tabular-nums;
|
||||
letter-spacing: var(--tracking-normal);
|
||||
}
|
||||
.t-metric {
|
||||
font-family: var(--font-mono);
|
||||
font-weight: var(--weight-semibold);
|
||||
font-variant-numeric: tabular-nums;
|
||||
letter-spacing: var(--tracking-tight);
|
||||
}
|
||||
Reference in New Issue
Block a user