v3: design tokens — shared radius, type, elevation, motion and layer scales; single light-dark() palette for smooth
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
818
src/App.css
818
src/App.css
File diff suppressed because it is too large
Load Diff
@@ -36,7 +36,7 @@ h1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
border-radius: 8px;
|
border-radius: var(--radius-lg);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
padding: 0.6em 1.2em;
|
padding: 0.6em 1.2em;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
@@ -44,7 +44,7 @@ button {
|
|||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
background-color: var(--color-surface);
|
background-color: var(--color-surface);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.25s, background-color 0.2s;
|
transition: border-color 0.25s, background-color var(--dur-slow);
|
||||||
}
|
}
|
||||||
button:hover {
|
button:hover {
|
||||||
border-color: var(--color-accent);
|
border-color: var(--color-accent);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { I18nProvider } from "@lingui/react";
|
|||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
import { i18n, loadCatalog } from "./i18n.ts";
|
import { i18n, loadCatalog } from "./i18n.ts";
|
||||||
|
|
||||||
|
import "./tokens.css";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import "./themes/smooth.css";
|
import "./themes/smooth.css";
|
||||||
import "./themes/brutalist.css";
|
import "./themes/brutalist.css";
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
/* ══════════════════════════════════════════════════════════════════════
|
/* ══════════════════════════════════════════════════════════════════════
|
||||||
Smooth theme — clean, modern, Saira typeface
|
Smooth theme — clean, modern, Saira typeface
|
||||||
Palette: Prussian Blue · Deep Teal · Jasmine · Brick Ember · Blood Red
|
Dark: Prussian Blue · Deep Teal · Jasmine · Brick Ember · Blood Red
|
||||||
Applied when data-style is absent or "smooth".
|
Light: Cream · Deep Teal · Terracotta
|
||||||
|
Applied when data-style is absent or "smooth". Also the base every other
|
||||||
|
theme builds on: anything a theme leaves unset falls back to these.
|
||||||
|
|
||||||
|
Every colour is `light-dark(<light>, <dark>)`, resolved against the
|
||||||
|
root `color-scheme` (see tokens.css), so auto / light / dark share this
|
||||||
|
one block.
|
||||||
══════════════════════════════════════════════════════════════════════ */
|
══════════════════════════════════════════════════════════════════════ */
|
||||||
|
|
||||||
/* ── Dark variant (default) ───────────────────────────────────────── */
|
|
||||||
:root,
|
:root,
|
||||||
:root[data-style="smooth"] {
|
:root[data-style="smooth"] {
|
||||||
/* Global font defaults — other themes override --font-body; App.css styles
|
|
||||||
consume these variables rather than hard-coding font names. */
|
|
||||||
--font-body: "Saira", sans-serif;
|
--font-body: "Saira", sans-serif;
|
||||||
--font-mono: monospace;
|
--font-mono: monospace;
|
||||||
|
|
||||||
@@ -18,48 +21,55 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
|
|
||||||
color-scheme: light dark;
|
|
||||||
|
|
||||||
/* Text */
|
/* Text */
|
||||||
--color-text: #eef0f3;
|
--color-text: light-dark(#0e3a42, #eef0f3);
|
||||||
--color-text-secondary: #8aaabb;
|
--color-text-secondary: light-dark(#2c6671, #8aaabb);
|
||||||
--color-text-muted: #506878;
|
--color-text-muted: light-dark(#5c8a91, #506878);
|
||||||
--color-on-accent: #001427; /* Prussian Blue on Jasmine */
|
--color-on-accent: light-dark(#fef8e6, #001427);
|
||||||
|
|
||||||
/* Surfaces */
|
/* Surfaces */
|
||||||
--color-bg: #001427; /* Prussian Blue */
|
--color-bg: light-dark(#fef8e6, #001427);
|
||||||
--color-surface: #0a1f35;
|
--color-surface: light-dark(#fffdf6, #0a1f35);
|
||||||
|
|
||||||
/* Borders */
|
/* Borders */
|
||||||
--color-border: transparent;
|
--color-border: transparent;
|
||||||
--color-border-subtle: rgba(112, 141, 129, 0.2); /* Deep Teal tint */
|
--color-border-subtle: light-dark(
|
||||||
|
rgba(48, 144, 161, 0.18),
|
||||||
|
rgba(112, 141, 129, 0.2)
|
||||||
|
);
|
||||||
|
|
||||||
/* Accent */
|
/* Accent */
|
||||||
--color-accent: #f4d58d; /* Jasmine */
|
--color-accent: light-dark(#bc5148, #f4d58d);
|
||||||
--color-accent-hover: #d4aa5a;
|
--color-accent-hover: light-dark(#97392f, #d4aa5a);
|
||||||
|
|
||||||
/* Links */
|
/* Links */
|
||||||
--color-link: #f4d58d;
|
--color-link: light-dark(#bc5148, #f4d58d);
|
||||||
--color-link-hover: #d4aa5a;
|
--color-link-hover: light-dark(#97392f, #d4aa5a);
|
||||||
|
|
||||||
/* Danger */
|
/* Danger */
|
||||||
--color-danger: #bf0603; /* Brick Ember */
|
--color-danger: light-dark(#bc5148, #bf0603);
|
||||||
--color-danger-bg: #220404;
|
--color-danger-bg: light-dark(#f8e3e0, #220404);
|
||||||
--color-danger-hover: #8d0801; /* Blood Red */
|
--color-danger-hover: light-dark(#97392f, #8d0801);
|
||||||
|
|
||||||
/* Success */
|
/* Success */
|
||||||
--color-success: #708d81; /* Deep Teal */
|
--color-success: light-dark(#2e8a86, #708d81);
|
||||||
--color-success-bg: #0d2820;
|
--color-success-bg: light-dark(#ddf2f1, #0d2820);
|
||||||
--color-success-hover: #8aaa9a;
|
--color-success-hover: light-dark(#1f6b67, #8aaa9a);
|
||||||
|
|
||||||
/* Overlays */
|
/* Overlays */
|
||||||
--color-overlay: rgba(0, 10, 20, 0.55);
|
--color-overlay: light-dark(rgba(14, 58, 66, 0.35), rgba(0, 10, 20, 0.55));
|
||||||
--color-header-user-bg: rgba(244, 213, 141, 0.06);
|
--color-header-user-bg: light-dark(
|
||||||
--color-header-user-bg-hover: rgba(244, 213, 141, 0.12);
|
rgba(188, 81, 72, 0.08),
|
||||||
|
rgba(244, 213, 141, 0.06)
|
||||||
|
);
|
||||||
|
--color-header-user-bg-hover: light-dark(
|
||||||
|
rgba(188, 81, 72, 0.15),
|
||||||
|
rgba(244, 213, 141, 0.12)
|
||||||
|
);
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
--color-option-bg: #0d2340;
|
--color-option-bg: light-dark(#fff9ec, #0d2340);
|
||||||
--color-option-border: #001427;
|
--color-option-border: light-dark(#ece4cc, #001427);
|
||||||
|
|
||||||
/* Service brand colors (fixed, not theme-dependent). `on-brand` is the
|
/* Service brand colors (fixed, not theme-dependent). `on-brand` is the
|
||||||
foreground for text sitting on any of these — also fixed, so the contrast
|
foreground for text sitting on any of these — also fixed, so the contrast
|
||||||
@@ -73,102 +83,6 @@
|
|||||||
--color-on-brand: #fff;
|
--color-on-brand: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Light via system preference (auto color-scheme) ──────────────── */
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
:root:not([data-style]),
|
|
||||||
:root[data-style="smooth"]:not([data-color-scheme]) {
|
|
||||||
--color-text: #0e3a42; /* darkened deep teal */
|
|
||||||
--color-text-secondary: #2c6671;
|
|
||||||
--color-text-muted: #5c8a91;
|
|
||||||
--color-on-accent: #fef8e6; /* cream on teal */
|
|
||||||
|
|
||||||
--color-bg: #fef8e6; /* cream */
|
|
||||||
--color-surface: #fffdf6;
|
|
||||||
|
|
||||||
--color-border: transparent;
|
|
||||||
--color-border-subtle: rgba(48, 144, 161, 0.18);
|
|
||||||
|
|
||||||
--color-accent: #bc5148; /* terracotta — pops on cream bg */
|
|
||||||
--color-accent-hover: #97392f;
|
|
||||||
|
|
||||||
--color-link: #bc5148;
|
|
||||||
--color-link-hover: #97392f;
|
|
||||||
|
|
||||||
--color-danger: #bc5148; /* terracotta */
|
|
||||||
--color-danger-bg: #f8e3e0;
|
|
||||||
--color-danger-hover: #97392f;
|
|
||||||
|
|
||||||
--color-success: #2e8a86; /* darkened light teal */
|
|
||||||
--color-success-bg: #ddf2f1;
|
|
||||||
--color-success-hover: #1f6b67;
|
|
||||||
|
|
||||||
--color-overlay: rgba(14, 58, 66, 0.35);
|
|
||||||
--color-header-user-bg: rgba(188, 81, 72, 0.08);
|
|
||||||
--color-header-user-bg-hover: rgba(188, 81, 72, 0.15);
|
|
||||||
|
|
||||||
--color-option-bg: #fff9ec;
|
|
||||||
--color-option-border: #ece4cc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Manual dark override ─────────────────────────────────────────── */
|
|
||||||
:root:not([data-style])[data-color-scheme="dark"],
|
|
||||||
:root[data-style="smooth"][data-color-scheme="dark"] {
|
|
||||||
color-scheme: dark;
|
|
||||||
--color-text: #eef0f3;
|
|
||||||
--color-text-secondary: #8aaabb;
|
|
||||||
--color-text-muted: #506878;
|
|
||||||
--color-on-accent: #001427;
|
|
||||||
--color-bg: #001427;
|
|
||||||
--color-surface: #0a1f35;
|
|
||||||
--color-border: transparent;
|
|
||||||
--color-border-subtle: rgba(112, 141, 129, 0.2);
|
|
||||||
--color-accent: #f4d58d;
|
|
||||||
--color-accent-hover: #d4aa5a;
|
|
||||||
--color-link: #f4d58d;
|
|
||||||
--color-link-hover: #d4aa5a;
|
|
||||||
--color-danger: #bf0603;
|
|
||||||
--color-danger-bg: #220404;
|
|
||||||
--color-danger-hover: #8d0801;
|
|
||||||
--color-success: #708d81;
|
|
||||||
--color-success-bg: #0d2820;
|
|
||||||
--color-success-hover: #8aaa9a;
|
|
||||||
--color-overlay: rgba(0, 10, 20, 0.55);
|
|
||||||
--color-header-user-bg: rgba(244, 213, 141, 0.06);
|
|
||||||
--color-header-user-bg-hover: rgba(244, 213, 141, 0.12);
|
|
||||||
--color-option-bg: #0d2340;
|
|
||||||
--color-option-border: #001427;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Manual light override ────────────────────────────────────────── */
|
|
||||||
:root:not([data-style])[data-color-scheme="light"],
|
|
||||||
:root[data-style="smooth"][data-color-scheme="light"] {
|
|
||||||
color-scheme: light;
|
|
||||||
--color-text: #0e3a42;
|
|
||||||
--color-text-secondary: #2c6671;
|
|
||||||
--color-text-muted: #5c8a91;
|
|
||||||
--color-on-accent: #fef8e6;
|
|
||||||
--color-bg: #fef8e6;
|
|
||||||
--color-surface: #fffdf6;
|
|
||||||
--color-border: transparent;
|
|
||||||
--color-border-subtle: rgba(48, 144, 161, 0.18);
|
|
||||||
--color-accent: #bc5148;
|
|
||||||
--color-accent-hover: #97392f;
|
|
||||||
--color-link: #bc5148;
|
|
||||||
--color-link-hover: #97392f;
|
|
||||||
--color-danger: #bc5148;
|
|
||||||
--color-danger-bg: #f8e3e0;
|
|
||||||
--color-danger-hover: #97392f;
|
|
||||||
--color-success: #2e8a86;
|
|
||||||
--color-success-bg: #ddf2f1;
|
|
||||||
--color-success-hover: #1f6b67;
|
|
||||||
--color-overlay: rgba(14, 58, 66, 0.35);
|
|
||||||
--color-header-user-bg: rgba(188, 81, 72, 0.08);
|
|
||||||
--color-header-user-bg-hover: rgba(188, 81, 72, 0.15);
|
|
||||||
--color-option-bg: #fff9ec;
|
|
||||||
--color-option-border: #ece4cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ══════════════════════════════════════════════════════════════════════
|
/* ══════════════════════════════════════════════════════════════════════
|
||||||
Structural overrides
|
Structural overrides
|
||||||
══════════════════════════════════════════════════════════════════════ */
|
══════════════════════════════════════════════════════════════════════ */
|
||||||
|
|||||||
112
src/tokens.css
Normal file
112
src/tokens.css
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/* ══════════════════════════════════════════════════════════════════════
|
||||||
|
Design tokens — shared by every theme.
|
||||||
|
Themes (src/themes/*.css) set the palette (`--color-*`) and may override
|
||||||
|
any of the shape/type/depth tokens below; App.css only consumes tokens.
|
||||||
|
══════════════════════════════════════════════════════════════════════ */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* ── Color scheme ──
|
||||||
|
`light-dark()` in the theme palettes resolves against this, so a single
|
||||||
|
palette block covers auto, forced-light and forced-dark. */
|
||||||
|
color-scheme: light dark;
|
||||||
|
|
||||||
|
/* ── Space (4px grid) ── */
|
||||||
|
--space-1: 0.25rem;
|
||||||
|
--space-2: 0.5rem;
|
||||||
|
--space-3: 0.75rem;
|
||||||
|
--space-4: 1rem;
|
||||||
|
--space-5: 1.25rem;
|
||||||
|
--space-6: 1.5rem;
|
||||||
|
--space-7: 2rem;
|
||||||
|
--space-8: 3rem;
|
||||||
|
|
||||||
|
/* ── Radius ── */
|
||||||
|
--radius-xs: 3px;
|
||||||
|
--radius-sm: 4px;
|
||||||
|
--radius-md: 6px;
|
||||||
|
--radius-lg: 8px;
|
||||||
|
--radius-xl: 12px;
|
||||||
|
--radius-full: 999px;
|
||||||
|
|
||||||
|
/* ── Type scale ── */
|
||||||
|
--text-2xs: 0.7rem;
|
||||||
|
--text-xs: 0.78rem;
|
||||||
|
--text-sm: 0.85rem;
|
||||||
|
--text-md: 0.92rem;
|
||||||
|
--text-base: 1rem;
|
||||||
|
--text-lg: 1.15rem;
|
||||||
|
--text-xl: 1.25rem;
|
||||||
|
--text-2xl: 1.5rem;
|
||||||
|
--text-3xl: 2rem;
|
||||||
|
--text-display: 3rem;
|
||||||
|
|
||||||
|
--leading-tight: 1.2;
|
||||||
|
--leading-snug: 1.35;
|
||||||
|
--leading-normal: 1.5;
|
||||||
|
|
||||||
|
--weight-regular: 400;
|
||||||
|
--weight-medium: 500;
|
||||||
|
--weight-semibold: 600;
|
||||||
|
--weight-bold: 700;
|
||||||
|
|
||||||
|
--tracking-caps: 0.06em;
|
||||||
|
|
||||||
|
/* ── Fonts ── */
|
||||||
|
--font-body: system-ui, sans-serif;
|
||||||
|
--font-display: var(--font-body);
|
||||||
|
--font-mono: ui-monospace, "SFMono-Regular", Menlo, monospace;
|
||||||
|
|
||||||
|
/* ── Elevation ── */
|
||||||
|
--shadow-1: 0 1px 2px rgb(0 0 0 / 0.12);
|
||||||
|
--shadow-2: 0 4px 16px rgb(0 0 0 / 0.2);
|
||||||
|
--shadow-3: 0 8px 32px rgb(0 0 0 / 0.45), 0 2px 8px rgb(0 0 0 / 0.3);
|
||||||
|
--shadow-focus: 0 0 0 3px var(--color-focus-ring);
|
||||||
|
|
||||||
|
/* ── Motion ── */
|
||||||
|
--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
||||||
|
--dur-fast: 0.12s;
|
||||||
|
--dur-base: 0.15s;
|
||||||
|
--dur-slow: 0.2s;
|
||||||
|
|
||||||
|
/* ── Layers ── */
|
||||||
|
--z-raised: 1;
|
||||||
|
--z-sticky: 100;
|
||||||
|
--z-dropdown: 200;
|
||||||
|
--z-fab: 900;
|
||||||
|
--z-modal: 1000;
|
||||||
|
--z-popover: 1100;
|
||||||
|
--z-toast: 9999;
|
||||||
|
|
||||||
|
/* ── Derived colors ──
|
||||||
|
Defaults computed from each theme's base palette, so every theme gets
|
||||||
|
the full semantic set; a theme overrides any of these when the derived
|
||||||
|
value isn't right for it. */
|
||||||
|
--color-surface-raised: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--color-surface) 94%,
|
||||||
|
var(--color-text)
|
||||||
|
);
|
||||||
|
--color-surface-sunken: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--color-bg) 96%,
|
||||||
|
var(--color-text)
|
||||||
|
);
|
||||||
|
--color-accent-soft: color-mix(in srgb, var(--color-accent) 14%, transparent);
|
||||||
|
--color-focus-ring: color-mix(in srgb, var(--color-accent) 45%, transparent);
|
||||||
|
--color-warning: #d4a017;
|
||||||
|
--color-on-danger: #fff;
|
||||||
|
|
||||||
|
/* Legacy names still referenced by a few rules. */
|
||||||
|
--color-muted: var(--color-text-muted);
|
||||||
|
--color-error: var(--color-danger);
|
||||||
|
--color-surface-alt: var(--color-surface-raised);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-color-scheme="light"] {
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-color-scheme="dark"] {
|
||||||
|
color-scheme: dark;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user