Skip to content

Commit 83bac61

Browse files
itspradeclaude
andcommitted
feat(theme): merge light/dark CSS and add brand-token tiers
Merge light.css and dark.css into a single default.css holding both the light :root block and the .dark override. Organize every theme block (default, cream, bloom) into tiers: BRAND (primary/secondary + foregrounds, shell-gradient — the only re-skin knobs), DERIVED (accent/ring/sidebar-* via color-mix on var(--primary)), SYSTEM (neutral surfaces, accessibility- locked), and STATUS (semantic, fixed). Give cream and bloom dark variants that inherit default's status colors. Decouple the shell gradient from --background via a dedicated --shell-gradient-base token. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 21f5a73 commit 83bac61

6 files changed

Lines changed: 309 additions & 179 deletions

File tree

packages/core/src/assets/theme.css

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
@import "./themes/light.css";
2-
@import "./themes/dark.css";
1+
@import "./themes/default.css";
32
@import "./themes/cream.css";
43
@import "./themes/bloom.css";
54

packages/core/src/assets/themes/bloom.css

Lines changed: 101 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,138 @@
11
/**
2-
* Bloom — light lavender app shell; cream secondary/accent surfaces (inverse of Tailor light).
2+
* Bloom — lavender shell + indigo brand (light + dark).
3+
*
4+
* Token tiers (see default.css for the full explanation):
5+
* BRAND — re-skin knobs: primary/secondary (+foregrounds) + shell gradient.
6+
* DERIVED — computed from BRAND; declared once and re-resolves in dark.
7+
* SYSTEM — neutral surfaces/text; accessibility-locked.
8+
* STATUS — semantic status, charts, radius, shadows; fixed.
9+
*
10+
* Mode = `.dark` class; palette = `data-theme="bloom"`.
311
*/
412
html[data-theme="bloom"] {
513
color-scheme: light;
6-
--background: rgba(239, 232, 255, 1);
7-
/* Shell gradient stops (globals.css): light lavender tint at top → white at bottom. */
8-
--shell-gradient-start: color-mix(in srgb, var(--background) 55%, rgb(255, 255, 255));
9-
--shell-gradient-end: rgb(255, 255, 255);
14+
15+
/* ───── BRAND — override to re-skin ───── */
16+
--primary: rgba(83, 90, 232, 1);
17+
--primary-foreground: rgba(255, 255, 255, 1);
18+
--secondary: rgba(245, 245, 245, 1);
19+
--secondary-foreground: rgba(23, 23, 23, 1);
20+
--shell-gradient-base: rgba(239, 232, 255, 1);
21+
--shell-gradient-tint: rgb(255, 255, 255);
22+
23+
/* ───── DERIVED from brand (do not edit; re-resolves in dark) ───── */
24+
--accent: color-mix(in srgb, var(--primary) 15%, var(--card));
25+
--accent-foreground: var(--foreground);
26+
--ring: color-mix(in srgb, var(--primary) 45%, transparent);
27+
--sidebar-primary: var(--primary);
28+
--sidebar-primary-foreground: var(--primary-foreground);
29+
--sidebar-accent: var(--accent);
30+
--sidebar-accent-foreground: var(--accent-foreground);
31+
--sidebar-ring: var(--ring);
32+
--shell-gradient-start: color-mix(
33+
in srgb,
34+
var(--shell-gradient-base) 55%,
35+
var(--shell-gradient-tint)
36+
);
37+
--shell-gradient-end: var(--shell-gradient-tint);
38+
39+
/* ───── SYSTEM — neutral surfaces/text (accessibility-locked) ───── */
40+
--background: rgba(250, 250, 250, 1);
1041
--foreground: rgba(16, 18, 43, 1);
1142
--card: rgba(255, 255, 255, 1);
1243
--card-foreground: rgba(16, 18, 43, 1);
1344
--popover: rgba(255, 255, 255, 1);
1445
--popover-foreground: rgba(16, 18, 43, 1);
15-
--primary: rgba(83, 90, 232, 1);
16-
--primary-foreground: rgba(255, 255, 255, 1);
17-
/* Match light theme — neutral pale grey reads as a soft pill on the lavender shell. */
18-
--secondary: rgba(245, 245, 245, 1);
19-
--secondary-foreground: rgba(23, 23, 23, 1);
20-
/* Row hovers / `bg-muted`: subtle neutral lift (same alpha family as `--border`). */
21-
--muted: rgba(0, 0, 0, 0.08);
46+
/* Lighter lavender (gradient top) so muted surfaces read on-theme on white cards. */
47+
--muted: rgba(246, 242, 255, 1);
2248
--muted-foreground: rgba(16, 18, 43, 0.72);
23-
--accent: rgba(248, 243, 228, 1);
24-
--accent-foreground: rgba(16, 18, 43, 1);
25-
/* Destructive matches default light theme so the brand red stays consistent across light/cream/bloom. */
26-
--destructive: rgba(220, 38, 38, 1);
27-
--destructive-foreground: rgba(254, 242, 242, 1);
2849
--border: rgba(0, 0, 0, 0.08);
2950
--input: rgba(0, 0, 0, 0.08);
30-
--ring: rgba(83, 90, 232, 0.45);
51+
--sidebar: rgba(250, 250, 250, 1);
52+
--sidebar-foreground: rgba(16, 18, 43, 1);
53+
--sidebar-border: rgba(0, 0, 0, 0.08);
54+
55+
/* ───── STATUS / STRUCTURAL — semantic, fixed ───── */
56+
--destructive: rgba(220, 38, 38, 1);
57+
--destructive-foreground: rgba(254, 242, 242, 1);
58+
--radius: 1rem;
3159
--chart-1: rgba(83, 90, 232, 1);
3260
--chart-2: rgba(0, 151, 156, 1);
3361
--chart-3: rgba(1, 55, 66, 1);
3462
--chart-4: rgba(110, 95, 195, 1);
3563
--chart-5: rgba(217, 119, 6, 1);
36-
--radius: 1rem;
37-
--sidebar: rgba(239, 232, 255, 1);
38-
--sidebar-foreground: rgba(16, 18, 43, 1);
39-
--sidebar-primary: rgba(83, 90, 232, 1);
40-
--sidebar-primary-foreground: rgba(255, 255, 255, 1);
41-
/* White elevated row on lavender shell (readable vs lavender-on-lavender) */
42-
--sidebar-accent: rgba(255, 255, 255, 1);
43-
--sidebar-accent-foreground: rgba(16, 18, 43, 1);
44-
--sidebar-border: rgba(0, 0, 0, 0.08);
45-
--sidebar-ring: rgba(83, 90, 232, 0.45);
46-
--status-default: rgba(16, 18, 43, 0.55);
47-
/* Bloom: teal + violet-tint foregrounds; amber + dusty rose harmonize with shell */
48-
--status-neutral: #0b8c9a;
49-
--status-completed: #0d7668;
50-
--status-attention: #ae6f12;
51-
--status-danger: #ae2438;
64+
/* --status-* inherited from the default palette (semantic, theme-independent). */
5265
--semantic-shadow-xs: 0 1px 2px 0 rgb(16 18 43 / 0.07);
5366
--semantic-shadow-sm: 0 1px 3px 0 rgb(16 18 43 / 0.08), 0 1px 2px -1px rgb(16 18 43 / 0.06);
5467
--semantic-shadow-md: 0 4px 6px -1px rgb(16 18 43 / 0.1), 0 2px 4px -2px rgb(16 18 43 / 0.08);
5568
--semantic-shadow-lg: 0 10px 15px -3px rgb(16 18 43 / 0.12), 0 4px 6px -4px rgb(83 90 232 / 0.1);
5669
}
5770

71+
/*
72+
* Dark variant — overrides BRAND + SYSTEM (+ differing STATUS); the DERIVED tier
73+
* re-resolves against the dark `--primary` / `--card` / `--shell-gradient-base`.
74+
* Surfaces reuse the default-dark neutrals so cards sit clearly above the canvas.
75+
*/
76+
html[data-theme="bloom"].dark {
77+
color-scheme: dark;
78+
79+
/* ───── BRAND ───── */
80+
--primary: rgba(131, 138, 247, 1);
81+
--primary-foreground: rgba(16, 18, 43, 1);
82+
--secondary: rgba(40, 43, 62, 1);
83+
--secondary-foreground: rgba(248, 249, 252, 1);
84+
--shell-gradient-base: rgba(9, 10, 17, 1);
85+
--shell-gradient-tint: rgb(16, 17, 26);
86+
87+
/* ───── SYSTEM ───── */
88+
--background: rgba(10, 10, 10, 1);
89+
--foreground: rgba(248, 249, 252, 1);
90+
--card: rgba(26, 28, 42, 1);
91+
--card-foreground: rgba(248, 249, 252, 1);
92+
--popover: rgba(34, 37, 54, 1);
93+
--popover-foreground: rgba(248, 249, 252, 1);
94+
--muted: rgba(36, 39, 58, 1);
95+
--muted-foreground: rgba(180, 183, 200, 1);
96+
--border: rgba(255, 255, 255, 0.08);
97+
--input: rgba(255, 255, 255, 0.12);
98+
--sidebar: rgba(10, 10, 10, 1);
99+
--sidebar-foreground: rgba(248, 249, 252, 1);
100+
--sidebar-border: rgba(255, 255, 255, 0.08);
101+
102+
/* ───── STATUS / STRUCTURAL (dark) ───── */
103+
--destructive: rgba(248, 113, 113, 1);
104+
--destructive-foreground: rgba(254, 242, 242, 1);
105+
--chart-1: rgba(131, 138, 247, 1);
106+
--chart-2: rgba(45, 191, 196, 1);
107+
--chart-3: rgba(94, 234, 212, 1);
108+
--chart-4: rgba(167, 139, 250, 1);
109+
--chart-5: rgba(251, 191, 36, 1);
110+
/* --status-* inherited from the default palette (semantic, theme-independent). */
111+
--semantic-shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.35);
112+
--semantic-shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.38), 0 1px 2px -1px rgb(0 0 0 / 0.32);
113+
--semantic-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.35), 0 2px 4px -2px rgb(0 0 0 / 0.28);
114+
--semantic-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.42), 0 4px 6px -4px rgb(0 0 0 / 0.35);
115+
}
116+
58117
/*
59118
* Structural overrides — shell gradient, transparent chrome, squircle corners,
60-
* tighter heading rhythm. These rules give Bloom its distinctive branded look.
119+
* tighter heading rhythm. Apply in both modes (gradient reads `--shell-gradient-base`
120+
* + the per-mode `--shell-gradient-tint`).
61121
*/
62122

63123
@layer base {
64-
/* Vertical shell gradient: light lavender tint at top -> white at bottom. */
124+
/* Vertical shell gradient: tinted lift at top -> base surface at bottom. */
65125
html[data-theme="bloom"] {
66126
min-height: 100vh;
67127
min-height: 100dvh;
68-
background-color: var(--background);
128+
background-color: var(--shell-gradient-base);
69129
background-image: linear-gradient(
70130
to bottom,
71131
var(--shell-gradient-start) 0%,
72-
color-mix(in srgb, var(--background) 45%, white) 20%,
73-
color-mix(in srgb, var(--background) 30%, white) 40%,
74-
color-mix(in srgb, var(--background) 15%, white) 55%,
75-
color-mix(in srgb, var(--background) 6%, white) 65%,
132+
color-mix(in srgb, var(--shell-gradient-base) 45%, var(--shell-gradient-tint)) 20%,
133+
color-mix(in srgb, var(--shell-gradient-base) 30%, var(--shell-gradient-tint)) 40%,
134+
color-mix(in srgb, var(--shell-gradient-base) 15%, var(--shell-gradient-tint)) 55%,
135+
color-mix(in srgb, var(--shell-gradient-base) 6%, var(--shell-gradient-tint)) 65%,
76136
var(--shell-gradient-end) 70%,
77137
var(--shell-gradient-end) 100%
78138
);

packages/core/src/assets/themes/cream.css

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,131 @@
11
/**
2-
* Cream — Tailor brand light palette.
3-
* Primary: #535AE8 · Text: #10122B · White: #FFFFFF
4-
* Secondary: Deep Cyan #00979C · Dark Green #013742 · Off-White #F8F3E4 · Neutral #EEEEEE · Light Violet #E2D4FE
2+
* Cream — Tailor brand palette (light + dark).
3+
*
4+
* Token tiers (see default.css for the full explanation):
5+
* BRAND — re-skin knobs: primary/secondary (+foregrounds) + shell gradient.
6+
* DERIVED — computed from BRAND; declared once and re-resolves in dark.
7+
* SYSTEM — neutral surfaces/text; accessibility-locked.
8+
* STATUS — semantic status, charts, radius, shadows; fixed.
9+
*
10+
* Mode = `.dark` class; palette = `data-theme="cream"`.
511
*/
6-
html[data-theme="cream"] {
12+
[data-theme="cream"] {
713
color-scheme: light;
8-
/* Off-white app shell; white cards for elevation */
9-
--background: rgba(248, 243, 228, 1);
10-
/* Shell gradient stops (globals.css): light cream tint at top → white at bottom. */
11-
--shell-gradient-start: color-mix(in srgb, var(--background) 55%, rgb(255, 255, 255));
12-
--shell-gradient-end: rgb(255, 255, 255);
14+
/* ───── BRAND — override to re-skin ───── */
15+
--primary: rgba(83, 90, 232, 1);
16+
--primary-foreground: rgba(255, 255, 255, 1);
17+
--secondary: rgba(226, 212, 254, 1);
18+
--secondary-foreground: rgba(16, 18, 43, 1);
19+
--shell-gradient-base: #fef6e3;
20+
--shell-gradient-tint: #fffdfa;
21+
/* ───── DERIVED from brand (do not edit; re-resolves in dark) ───── */
22+
--accent: color-mix(in srgb, var(--primary) 25%, var(--card));
23+
--accent-foreground: var(--foreground);
24+
--ring: color-mix(in srgb, var(--primary) 45%, transparent);
25+
--sidebar-primary: var(--primary);
26+
--sidebar-primary-foreground: var(--primary-foreground);
27+
--sidebar-accent: var(--accent);
28+
--sidebar-accent-foreground: var(--accent-foreground);
29+
--sidebar-ring: var(--ring);
30+
--shell-gradient-start: color-mix(
31+
in srgb,
32+
var(--shell-gradient-base) 55%,
33+
var(--shell-gradient-tint)
34+
);
35+
--shell-gradient-end: var(--shell-gradient-tint);
36+
/* ───── SYSTEM — neutral surfaces/text (accessibility-locked) ───── */
37+
--background: rgba(250, 250, 250, 1);
1338
--foreground: rgba(16, 18, 43, 1);
1439
--card: rgba(255, 255, 255, 1);
1540
--card-foreground: rgba(16, 18, 43, 1);
1641
--popover: rgba(255, 255, 255, 1);
1742
--popover-foreground: rgba(16, 18, 43, 1);
18-
--primary: rgba(83, 90, 232, 1);
19-
--primary-foreground: rgba(255, 255, 255, 1);
20-
/* Light violet surfaces; near-black text (match bloom; drop the brand dark-green pairing). */
21-
--secondary: rgba(226, 212, 254, 1);
22-
--secondary-foreground: rgba(16, 18, 43, 1);
23-
/* Row hovers / `bg-muted`: subtle neutral lift (same alpha family as `--border`), not a second brand tint. */
24-
--muted: rgba(0, 0, 0, 0.08);
43+
/* Lighter cream (gradient top) so muted surfaces read on-theme on white cards. */
44+
--muted: rgba(251, 248, 240, 1);
2545
--muted-foreground: rgba(16, 18, 43, 0.72);
26-
--accent: rgba(226, 212, 254, 1);
27-
--accent-foreground: rgba(16, 18, 43, 1);
28-
/* Destructive matches default light theme so the brand red stays consistent across light/cream/bloom. */
29-
--destructive: rgba(220, 38, 38, 1);
30-
--destructive-foreground: rgba(254, 242, 242, 1);
3146
--border: rgba(0, 0, 0, 0.08);
3247
--input: rgba(0, 0, 0, 0.08);
33-
--ring: rgba(83, 90, 232, 0.45);
48+
--sidebar: rgba(250, 250, 250, 1);
49+
--sidebar-foreground: rgba(16, 18, 43, 1);
50+
--sidebar-border: rgba(0, 0, 0, 0.08);
51+
52+
/* ───── STATUS / STRUCTURAL — semantic, fixed ───── */
53+
--destructive: rgba(220, 38, 38, 1);
54+
--destructive-foreground: rgba(254, 242, 242, 1);
55+
--radius: 1rem;
3456
--chart-1: rgba(83, 90, 232, 1);
3557
--chart-2: rgba(0, 151, 156, 1);
3658
--chart-3: rgba(1, 55, 66, 1);
3759
--chart-4: rgba(110, 95, 195, 1);
3860
--chart-5: rgba(217, 119, 6, 1);
39-
/* Larger corner scale; squircle overlays via globals.css where supported */
40-
--radius: 1rem;
41-
--sidebar: rgba(248, 243, 228, 1);
42-
--sidebar-foreground: rgba(16, 18, 43, 1);
43-
--sidebar-primary: rgba(83, 90, 232, 1);
44-
--sidebar-primary-foreground: rgba(255, 255, 255, 1);
45-
--sidebar-accent: rgba(226, 212, 254, 1);
46-
--sidebar-accent-foreground: rgba(16, 18, 43, 1);
47-
--sidebar-border: rgba(0, 0, 0, 0.08);
48-
--sidebar-ring: rgba(83, 90, 232, 0.45);
49-
--status-default: rgba(16, 18, 43, 0.55);
50-
--status-neutral: #00979c;
51-
--status-completed: #00979c;
52-
--status-attention: #d97706;
53-
--status-danger: #dc2626;
61+
/* --status-* inherited from the default palette (semantic, theme-independent). */
5462
--semantic-shadow-xs: 0 1px 2px 0 rgb(16 18 43 / 0.07);
5563
--semantic-shadow-sm: 0 1px 3px 0 rgb(16 18 43 / 0.08), 0 1px 2px -1px rgb(16 18 43 / 0.06);
5664
--semantic-shadow-md: 0 4px 6px -1px rgb(16 18 43 / 0.1), 0 2px 4px -2px rgb(16 18 43 / 0.08);
5765
--semantic-shadow-lg: 0 10px 15px -3px rgb(16 18 43 / 0.12), 0 4px 6px -4px rgb(83 90 232 / 0.1);
5866
}
5967

68+
/*
69+
* Dark variant — overrides BRAND+SYSTEM (+ differing STATUS);
70+
the DERIVED tier * re-resolves against the dark `--primary` / `--card` / `--shell-gradient-base`. * Surfaces reuse the default-dark neutrals so cards sit clearly above the canvas.
71+
*/
72+
[data-theme="cream"].dark {
73+
color-scheme: dark;
74+
/* ───── BRAND ───── */
75+
--primary: rgba(131, 138, 247, 1);
76+
--primary-foreground: rgba(16, 18, 43, 1);
77+
--secondary: rgba(48, 42, 36, 1);
78+
--secondary-foreground: rgba(247, 244, 238, 1);
79+
--shell-gradient-base: rgb(8, 6, 5);
80+
--shell-gradient-tint: rgb(17, 14, 10);
81+
/* ───── SYSTEM ───── */
82+
--background: rgba(10, 10, 10, 1);
83+
--foreground: rgba(247, 244, 238, 1);
84+
--card: rgb(22, 19, 17);
85+
--card-foreground: rgba(247, 244, 238, 1);
86+
--popover: rgb(37, 33, 28);
87+
--popover-foreground: rgba(247, 244, 238, 1);
88+
--muted: rgba(42, 37, 31, 1);
89+
--muted-foreground: rgba(186, 180, 170, 1);
90+
--border: rgba(255, 255, 255, 0.08);
91+
--input: rgba(255, 255, 255, 0.12);
92+
--sidebar: rgba(10, 10, 10, 1);
93+
--sidebar-foreground: rgba(247, 244, 238, 1);
94+
--sidebar-border: rgba(255, 255, 255, 0.08);
95+
96+
/* ───── STATUS / STRUCTURAL (dark) ───── */
97+
--destructive: rgba(248, 113, 113, 1);
98+
--destructive-foreground: rgba(254, 242, 242, 1);
99+
--chart-1: rgba(131, 138, 247, 1);
100+
--chart-2: rgba(45, 191, 196, 1);
101+
--chart-3: rgba(94, 234, 212, 1);
102+
--chart-4: rgba(167, 139, 250, 1);
103+
--chart-5: rgba(251, 191, 36, 1);
104+
/* --status-* inherited from the default palette (semantic, theme-independent). */
105+
--semantic-shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.35);
106+
--semantic-shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.38), 0 1px 2px -1px rgb(0 0 0 / 0.32);
107+
--semantic-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.35), 0 2px 4px -2px rgb(0 0 0 / 0.28);
108+
--semantic-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.42), 0 4px 6px -4px rgb(0 0 0 / 0.35);
109+
}
110+
60111
/*
61112
* Structural overrides — shell gradient, transparent chrome, squircle corners,
62-
* tighter heading rhythm. These rules give Cream its distinctive branded look.
113+
* tighter heading rhythm. Apply in both modes (gradient reads `--shell-gradient-base` * + the per-mode `--shell-gradient-tint`).
63114
*/
64115

65116
@layer base {
66-
/* Vertical shell gradient: light cream tint at top -> white at bottom. */
117+
/* Vertical shell gradient: tinted lift at top -> base surface at bottom. */
67118
html[data-theme="cream"] {
68119
min-height: 100vh;
69120
min-height: 100dvh;
70-
background-color: var(--background);
121+
background-color: var(--shell-gradient-base);
71122
background-image: linear-gradient(
72123
to bottom,
73124
var(--shell-gradient-start) 0%,
74-
color-mix(in srgb, var(--background) 45%, white) 20%,
75-
color-mix(in srgb, var(--background) 30%, white) 40%,
76-
color-mix(in srgb, var(--background) 15%, white) 55%,
77-
color-mix(in srgb, var(--background) 6%, white) 65%,
125+
color-mix(in srgb, var(--shell-gradient-base) 45%, var(--shell-gradient-tint)) 20%,
126+
color-mix(in srgb, var(--shell-gradient-base) 30%, var(--shell-gradient-tint)) 40%,
127+
color-mix(in srgb, var(--shell-gradient-base) 15%, var(--shell-gradient-tint)) 55%,
128+
color-mix(in srgb, var(--shell-gradient-base) 6%, var(--shell-gradient-tint)) 65%,
78129
var(--shell-gradient-end) 70%,
79130
var(--shell-gradient-end) 100%
80131
);

0 commit comments

Comments
 (0)