@uncinq/design-tokens 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,7 +49,8 @@ Scoped to a specific component. Generic component tokens are provided by [@uncin
49
49
 
50
50
  ```css
51
51
  --alert-border-radius: var(--radius-none);
52
- --btn-padding: var(--spacing-control);
52
+ --btn-padding-x: var(--spacing-control);
53
+ --btn-padding-y: var(--spacing-control);
53
54
  ```
54
55
 
55
56
  ---
@@ -114,7 +115,6 @@ All tokens follow the pattern: `--{category}-{subcategory?}-{variant}-{state?}`
114
115
  | `easing` | Timing functions | `--easing-bounce` |
115
116
  | `transition` | Shorthand transitions | `--transition-normal`, `--transition-color` |
116
117
  | `ratio` | Aspect ratios | `--ratio-16-9` |
117
- | `flex` | Flex-basis fractions | `--flex-half`, `--flex-third` |
118
118
  | `fluid-text` | Responsive fluid type scale (Utopia) | `--fluid-text-sm`, `--fluid-text-xl` |
119
119
  | `fluid-spacing` | Responsive fluid spacing scale (Utopia) | `--fluid-spacing-sm`, `--fluid-spacing-lg` |
120
120
  | `focus` | Focus ring tokens | `--focus-color`, `--focus-outline-width` |
@@ -125,6 +125,188 @@ All tokens follow the pattern: `--{category}-{subcategory?}-{variant}-{state?}`
125
125
 
126
126
  ---
127
127
 
128
+ ## Colors
129
+
130
+ ### Color space — OKLCH
131
+
132
+ All primitive color values are defined in **OKLCH** (`oklch(L C H)`):
133
+
134
+ | Channel | Range | Meaning |
135
+ |---------|-------|---------|
136
+ | `L` | `0 → 1` | Perceptual lightness (0 = black, 1 = white) |
137
+ | `C` | `0 → ~0.4` | Chroma / colorfulness (0 = gray) |
138
+ | `H` | `0° → 360°` | Hue angle |
139
+
140
+ **Why OKLCH over hex/HSL?**
141
+
142
+ - **Perceptually uniform** — equal steps in L produce equal perceived brightness differences, regardless of hue. HSL does not guarantee this (`hsl(60, 100%, 50%)` yellow looks far brighter than `hsl(240, 100%, 50%)` blue at the same L).
143
+ - **Predictable contrast** — you can reason about WCAG contrast by comparing L values without converting to relative luminance.
144
+ - **Better interpolation** — gradients and animations between two OKLCH colors don't pass through muddy grays.
145
+ - **Future-proof** — native in all modern browsers, the color space used by Tailwind v4, Radix, and the W3C Design Tokens spec.
146
+
147
+ > Browser support: Chrome 111+, Firefox 113+, Safari 15.4+. Legacy browsers receive the nearest sRGB fallback automatically.
148
+
149
+ ### Primitive palette
150
+
151
+ The primitive palette provides **11 steps per hue** (50 → 950), named numerically. These are raw values with no opinion about usage.
152
+
153
+ | Hue | H angle | Character |
154
+ |-----|---------|-----------|
155
+ | `amber` | ≈ 70° | Golden yellow-orange |
156
+ | `blue` | ≈ 260° | Classic blue |
157
+ | `cyan` | ≈ 215° | Bright cyan |
158
+ | `gray` | neutral | Cool neutral |
159
+ | `green` | ≈ 150° | Lush green |
160
+ | `indigo` | ≈ 277° | Blue-violet |
161
+ | `lime` | ≈ 131° | Electric yellow-green |
162
+ | `orange` | ≈ 48° | Vivid orange |
163
+ | `pink` | ≈ 354° | Bright pink |
164
+ | `purple` | ≈ 304° | Rich purple |
165
+ | `red` | ≈ 25° | Classic red |
166
+ | `rose` | ≈ 16° | Pink-red |
167
+ | `sienna` | ≈ 23° | Brick-red (crimson × terracotta) |
168
+ | `sky` | ≈ 237° | Soft sky blue |
169
+ | `teal` | ≈ 183° | Blue-green |
170
+ | `violet` | ≈ 293° | Modern violet |
171
+ | `yellow` | ≈ 86° | Pure yellow |
172
+
173
+ Plus `--color-black` and `--color-white` (with `*-rgb` variants for `rgb()` opacity usage).
174
+
175
+ **Step guide:**
176
+
177
+ | Step | L (avg) | L amber/yellow/lime | Typical use |
178
+ |------|---------|---------------------|-------------|
179
+ | 50 | ≈ 0.97 | ≈ 0.98 | Page tinted backgrounds, hover states on white |
180
+ | 100 | ≈ 0.94 | ≈ 0.96 | Muted backgrounds, badges, tags |
181
+ | 200 | ≈ 0.90 | ≈ 0.93 | Borders, dividers |
182
+ | 300 | ≈ 0.83 | ≈ 0.88 | Disabled elements, placeholder text |
183
+ | 400 | ≈ 0.72 | ≈ 0.83 | Secondary icons, decorative |
184
+ | 500 | ≈ 0.63 | ≈ 0.77 | Mid-tone — use with dark text for UI |
185
+ | 600 | ≈ 0.53 | ≈ 0.67 | **Default brand/status bg** — white text passes WCAG AA (UI) |
186
+ | 700 | ≈ 0.46 | ≈ 0.55 | Hover state, colored text on white background |
187
+ | 800 | ≈ 0.39 | ≈ 0.47 | Deep accents, high-contrast text |
188
+ | 900 | ≈ 0.33 | ≈ 0.41 | Near-dark, very high contrast |
189
+ | 950 | ≈ 0.22 | ≈ 0.28 | Darkest tint, almost black |
190
+
191
+ > **Note OKLCH** — L est perceptuellement uniforme, mais les hues intrinsèquement brillantes (amber, yellow, lime) ont des valeurs L naturellement plus élevées aux steps 400–700. C'est un comportement attendu, pas une erreur de calibration. Gray va dans l'autre sens (chroma ≈ 0, pas de boost de brillance, L légèrement plus bas). La colonne "L avg" est représentative des hues chromatiques froides (blue, red, green, violet…).
192
+
193
+ ### Semantic color tokens
194
+
195
+ Semantic tokens are named by **purpose**, not by value. They reference primitives via `var()`.
196
+
197
+ #### Brand & accent
198
+
199
+ ```css
200
+ --color-brand: /* primary brand color (button bg, active states…) */
201
+ --color-brand-muted: /* tinted background for brand areas */
202
+ --color-brand-hover: /* hover state of brand */
203
+ --color-brand-strong: /* darkest brand shade */
204
+
205
+ --color-accent: /* = brand by default; override independently if needed */
206
+ ```
207
+
208
+ The default brand is **sienna** — a warm brick-red. Override it in your project:
209
+
210
+ ```css
211
+ @layer config {
212
+ :root {
213
+ --color-brand: var(--color-violet-600);
214
+ --color-brand-muted: var(--color-violet-100);
215
+ --color-brand-hover: var(--color-violet-700);
216
+ --color-brand-strong: var(--color-violet-900);
217
+ }
218
+ }
219
+ ```
220
+
221
+ #### Backgrounds
222
+
223
+ | Token | Default | Usage |
224
+ |-------|---------|-------|
225
+ | `--color-bg` | white | Page background |
226
+ | `--color-bg-muted` | gray-100 | Subtle section backgrounds |
227
+ | `--color-bg-surface` | = `--color-bg` | Card / panel backgrounds |
228
+ | `--color-bg-media` | gray-200 | Image placeholders, skeleton loaders |
229
+ | `--color-bg-accent` | = `--color-accent` | Highlighted sections |
230
+
231
+ #### Text
232
+
233
+ | Token | Default | Usage |
234
+ |-------|---------|-------|
235
+ | `--color-text` | gray-900 | Body text |
236
+ | `--color-text-muted` | gray-500 | Secondary, captions |
237
+ | `--color-text-disabled` | gray-300 | Disabled UI |
238
+ | `--color-heading` | black | Headings |
239
+ | `--color-link` | = `--color-text` | Default link color |
240
+ | `--color-link-hover` | = `--color-accent` | Link hover |
241
+ | `--color-active` | = `--color-accent` | Active nav item |
242
+ | `--color-credit` | = `--color-text-muted` | Bylines, captions |
243
+
244
+ #### Text on colored backgrounds
245
+
246
+ Used to ensure contrast when a color is the background:
247
+
248
+ ```css
249
+ --color-text-on-brand /* white */
250
+ --color-text-on-accent /* white */
251
+ --color-text-on-dark /* white */
252
+ --color-text-on-light /* gray-900 */
253
+ --color-text-on-surface /* = --color-text */
254
+ --color-text-on-danger /* white */
255
+ --color-text-on-info /* white */
256
+ --color-text-on-success /* white */
257
+ --color-text-on-warning /* gray-900 — amber is bright, dark text required */
258
+ ```
259
+
260
+ #### Status / semantic variants
261
+
262
+ | Token | Primitive | Notes |
263
+ |-------|-----------|-------|
264
+ | `--color-danger` | red-600 | Errors, destructive actions |
265
+ | `--color-success` | green-600 | Confirmations |
266
+ | `--color-warning` | amber-500 | Warnings — use with `--color-text-on-warning` |
267
+ | `--color-info` | blue-600 | Informational |
268
+ | `--color-secondary` | gray-500 | De-emphasized UI |
269
+ | `--color-dark` | gray-900 | Dark surfaces |
270
+ | `--color-light` | gray-200 | Light surfaces |
271
+
272
+ Each variant has `-muted` (tinted bg) and `-strong` (hover / emphasis) companions:
273
+
274
+ ```css
275
+ --color-danger-muted: var(--color-red-100);
276
+ --color-danger-strong: var(--color-red-800); /* used for hover */
277
+ ```
278
+
279
+ ### Accessibility (WCAG)
280
+
281
+ | Ratio | Requirement |
282
+ |-------|-------------|
283
+ | **4.5 : 1** | Normal text (< 18px / non-bold < 14px) — WCAG AA |
284
+ | **3 : 1** | Large text, UI components (buttons, inputs, icons) — WCAG AA |
285
+ | **7 : 1** | Any text — WCAG AAA |
286
+
287
+ **Rules of thumb for this palette:**
288
+
289
+ - **White text on a colored background** — use step **600 or darker**. Steps 500 and below are typically too light (3–3.5 : 1 ratio).
290
+ - **Colored text on white** — use step **700 or darker** for normal text.
291
+ - **Warning (amber-500)** — always pair with `--color-text-on-warning` (gray-900). Never white text on amber-500.
292
+ - **Decorative only** — any step is fine when color carries no information (icons, borders, illustrations).
293
+
294
+ ### Adding a custom hue
295
+
296
+ Add a new primitive scale in `tokens/primitive/color.css` following the existing pattern:
297
+
298
+ ```css
299
+ /* ── Coral — H ≈ 35° ──────────────────────────────────────────────── */
300
+ --color-coral-50: oklch(0.975 0.014 35.0);
301
+ --color-coral-100: oklch(0.948 0.032 35.0);
302
+ /* … 11 steps … */
303
+ --color-coral-950: oklch(0.225 0.078 35.0);
304
+ ```
305
+
306
+ Then reference it in `tokens/semantic/color.css` or your project's `@layer config` override.
307
+
308
+ ---
309
+
128
310
  ## CSS cascade layers
129
311
 
130
312
  All tokens are declared inside `@layer config`, the lowest-priority layer in the stack:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uncinq/design-tokens",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Framework-agnostic CSS design tokens — primitive and semantic layers.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,130 +1,263 @@
1
1
  /* primitive/color.css */
2
+ /*
3
+ * Primitive color palette in OKLCH.
4
+ * 11 steps per hue: 50 → 950.
5
+ * Values align with Tailwind v4 hue angles.
6
+ *
7
+ * DO NOT reference these directly in components — use semantic tokens instead.
8
+ */
2
9
  @layer config {
3
10
  :root {
4
- --color-black: #000000;
11
+ --color-black: oklch(0 0 0);
5
12
  --color-black-rgb: 0 0 0;
6
-
7
- --color-amber-100: #fef3c7;
8
- --color-amber-200: #fde68a;
9
- --color-amber-300: #fcd34d;
10
- --color-amber-400: #fbbf24;
11
- --color-amber-500: #f59e0b;
12
- --color-amber-600: #d97706;
13
- --color-amber-700: #b45309;
14
- --color-amber-800: #92400e;
15
- --color-amber-900: #78350f;
16
-
17
- --color-blue-100: #dbeafe;
18
- --color-blue-200: #bfdbfe;
19
- --color-blue-300: #93c5fd;
20
- --color-blue-400: #60a5fa;
21
- --color-blue-500: #3b82f6;
22
- --color-blue-600: #2563eb;
23
- --color-blue-700: #1d4ed8;
24
- --color-blue-800: #1e40af;
25
- --color-blue-900: #1e3a8a;
26
-
27
- --color-gray-100: #f3f4f6;
28
- --color-gray-200: #e5e7eb;
29
- --color-gray-300: #d1d5db;
30
- --color-gray-400: #9ca3af;
31
- --color-gray-500: #6b7280;
32
- --color-gray-600: #4b5563;
33
- --color-gray-700: #374151;
34
- --color-gray-800: #1f2937;
35
- --color-gray-900: #111827;
36
-
37
- --color-green-100: #dcfce7;
38
- --color-green-200: #bbf7d0;
39
- --color-green-300: #86efac;
40
- --color-green-400: #4ade80;
41
- --color-green-500: #22c55e;
42
- --color-green-600: #16a34a;
43
- --color-green-700: #15803d;
44
- --color-green-800: #166534;
45
- --color-green-900: #14532d;
46
-
47
- --color-cyan-100: #cffafe;
48
- --color-cyan-200: #a5f3fc;
49
- --color-cyan-300: #67e8f9;
50
- --color-cyan-400: #22d3ee;
51
- --color-cyan-500: #06b6d4;
52
- --color-cyan-600: #0891b2;
53
- --color-cyan-700: #0e7490;
54
- --color-cyan-800: #155e75;
55
- --color-cyan-900: #164e63;
56
-
57
- --color-indigo-100: #e0e7ff;
58
- --color-indigo-200: #c7d2fe;
59
- --color-indigo-300: #a5b4fc;
60
- --color-indigo-400: #818cf8;
61
- --color-indigo-500: #4f46e5;
62
- --color-indigo-600: #4338ca;
63
- --color-indigo-700: #3730a3;
64
- --color-indigo-800: #312e81;
65
- --color-indigo-900: #2e1065;
66
-
67
- --color-orange-100: #ffedd5;
68
- --color-orange-200: #fed7aa;
69
- --color-orange-300: #fdba74;
70
- --color-orange-400: #fb923c;
71
- --color-orange-500: #f97316;
72
- --color-orange-600: #ea580c;
73
- --color-orange-700: #c2410c;
74
- --color-orange-800: #9a3412;
75
- --color-orange-900: #431407;
76
-
77
- --color-pink-100: #fce7f3;
78
- --color-pink-200: #fbcfe8;
79
- --color-pink-300: #f9a8d4;
80
- --color-pink-400: #f472b6;
81
- --color-pink-500: #ec4899;
82
- --color-pink-600: #db2777;
83
- --color-pink-700: #be185d;
84
- --color-pink-800: #9d174d;
85
- --color-pink-900: #831843;
86
-
87
- --color-purple-100: #f3e8ff;
88
- --color-purple-200: #e9d5ff;
89
- --color-purple-300: #d8b4fe;
90
- --color-purple-400: #c084fc;
91
- --color-purple-500: #a855f7;
92
- --color-purple-600: #9333ea;
93
- --color-purple-700: #7e22ce;
94
- --color-purple-800: #6b21a8;
95
- --color-purple-900: #581c87;
96
-
97
- --color-red-100: #fee2e2;
98
- --color-red-200: #fecaca;
99
- --color-red-300: #fca5a5;
100
- --color-red-400: #f87171;
101
- --color-red-500: #ef4444;
102
- --color-red-600: #dc2626;
103
- --color-red-700: #b91c1c;
104
- --color-red-800: #991b1b;
105
- --color-red-900: #7f1d1d;
106
-
107
- --color-teal-100: #ccfbf1;
108
- --color-teal-200: #99f6e4;
109
- --color-teal-300: #5eead4;
110
- --color-teal-400: #2dd4bf;
111
- --color-teal-500: #14b8a6;
112
- --color-teal-600: #0d9488;
113
- --color-teal-700: #0f766e;
114
- --color-teal-800: #115e59;
115
- --color-teal-900: #134e4a;
116
-
117
- --color-white: #ffffff;
13
+ --color-white: oklch(1 0 0);
118
14
  --color-white-rgb: 255 255 255;
119
15
 
120
- --color-yellow-100: #fef9c3;
121
- --color-yellow-200: #fef08a;
122
- --color-yellow-300: #fde047;
123
- --color-yellow-400: #facc15;
124
- --color-yellow-500: #eab308;
125
- --color-yellow-600: #ca8a04;
126
- --color-yellow-700: #a16207;
127
- --color-yellow-800: #854d0e;
128
- --color-yellow-900: #713f12;
16
+ /* ── Amber — H ≈ 70° ───────────────────────────────────────────────── */
17
+ --color-amber-50: oklch(0.987 0.022 95.277);
18
+ --color-amber-100: oklch(0.962 0.059 95.617);
19
+ --color-amber-200: oklch(0.924 0.120 95.746);
20
+ --color-amber-300: oklch(0.879 0.169 91.605);
21
+ --color-amber-400: oklch(0.828 0.189 84.429);
22
+ --color-amber-500: oklch(0.769 0.188 70.080);
23
+ --color-amber-600: oklch(0.666 0.179 58.318);
24
+ --color-amber-700: oklch(0.555 0.163 48.998);
25
+ --color-amber-800: oklch(0.473 0.137 46.201);
26
+ --color-amber-900: oklch(0.414 0.112 45.904);
27
+ --color-amber-950: oklch(0.279 0.077 45.635);
28
+
29
+ /* ── Blue — H ≈ 260° ───────────────────────────────────────────────── */
30
+ --color-blue-50: oklch(0.970 0.014 254.604);
31
+ --color-blue-100: oklch(0.932 0.032 255.585);
32
+ --color-blue-200: oklch(0.882 0.059 254.128);
33
+ --color-blue-300: oklch(0.809 0.105 251.813);
34
+ --color-blue-400: oklch(0.707 0.165 254.624);
35
+ --color-blue-500: oklch(0.623 0.214 259.815);
36
+ --color-blue-600: oklch(0.546 0.245 262.881);
37
+ --color-blue-700: oklch(0.488 0.243 264.376);
38
+ --color-blue-800: oklch(0.424 0.199 265.638);
39
+ --color-blue-900: oklch(0.379 0.146 265.522);
40
+ --color-blue-950: oklch(0.282 0.091 267.935);
41
+
42
+ /* ── Cyan — H ≈ 215° ───────────────────────────────────────────────── */
43
+ --color-cyan-50: oklch(0.984 0.019 200.873);
44
+ --color-cyan-100: oklch(0.956 0.045 203.388);
45
+ --color-cyan-200: oklch(0.917 0.080 205.041);
46
+ --color-cyan-300: oklch(0.865 0.127 207.078);
47
+ --color-cyan-400: oklch(0.789 0.154 211.530);
48
+ --color-cyan-500: oklch(0.715 0.143 215.221);
49
+ --color-cyan-600: oklch(0.609 0.126 221.723);
50
+ --color-cyan-700: oklch(0.520 0.105 223.128);
51
+ --color-cyan-800: oklch(0.450 0.085 224.283);
52
+ --color-cyan-900: oklch(0.398 0.070 227.392);
53
+ --color-cyan-950: oklch(0.302 0.056 229.695);
54
+
55
+ /* ── Gray — neutral ─────────────────────────────────────────────────── */
56
+ --color-gray-50: oklch(0.985 0.002 247.839);
57
+ --color-gray-100: oklch(0.967 0.003 264.542);
58
+ --color-gray-200: oklch(0.928 0.006 264.531);
59
+ --color-gray-300: oklch(0.872 0.010 258.338);
60
+ --color-gray-400: oklch(0.707 0.022 261.325);
61
+ --color-gray-500: oklch(0.556 0.022 264.364);
62
+ --color-gray-600: oklch(0.439 0.020 264.531);
63
+ --color-gray-700: oklch(0.373 0.014 264.542);
64
+ --color-gray-800: oklch(0.279 0.010 264.542);
65
+ --color-gray-900: oklch(0.208 0.006 264.542);
66
+ --color-gray-950: oklch(0.145 0.005 264.542);
67
+
68
+ /* ── Emerald — H ≈ 148° ─────────────────────────────────────────────── */
69
+ --color-emerald-50: oklch(0.979 0.021 166.113);
70
+ --color-emerald-100: oklch(0.950 0.052 163.051);
71
+ --color-emerald-200: oklch(0.905 0.093 164.150);
72
+ --color-emerald-300: oklch(0.845 0.143 164.978);
73
+ --color-emerald-400: oklch(0.765 0.177 163.223);
74
+ --color-emerald-500: oklch(0.696 0.170 162.480);
75
+ --color-emerald-600: oklch(0.596 0.145 163.225);
76
+ --color-emerald-700: oklch(0.508 0.118 165.612);
77
+ --color-emerald-800: oklch(0.432 0.095 166.913);
78
+ --color-emerald-900: oklch(0.378 0.077 168.940);
79
+ --color-emerald-950: oklch(0.262 0.051 172.552);
80
+
81
+ /* ── Green — H ≈ 150° ─────────────────────────────────────────────── */
82
+ --color-green-50: oklch(0.982 0.018 155.826);
83
+ --color-green-100: oklch(0.962 0.044 156.743);
84
+ --color-green-200: oklch(0.925 0.084 155.995);
85
+ --color-green-300: oklch(0.871 0.150 154.449);
86
+ --color-green-400: oklch(0.792 0.209 151.711);
87
+ --color-green-500: oklch(0.723 0.219 149.579);
88
+ --color-green-600: oklch(0.627 0.194 149.214);
89
+ --color-green-700: oklch(0.527 0.154 150.069);
90
+ --color-green-800: oklch(0.448 0.119 151.328);
91
+ --color-green-900: oklch(0.393 0.095 152.535);
92
+ --color-green-950: oklch(0.266 0.065 152.934);
93
+
94
+ /* ── Indigo — H ≈ 277° ────────────────────────────────────────────── */
95
+ --color-indigo-50: oklch(0.962 0.018 272.314);
96
+ --color-indigo-100: oklch(0.930 0.034 272.788);
97
+ --color-indigo-200: oklch(0.870 0.065 274.039);
98
+ --color-indigo-300: oklch(0.785 0.115 274.713);
99
+ --color-indigo-400: oklch(0.673 0.182 276.935);
100
+ --color-indigo-500: oklch(0.585 0.233 277.117);
101
+ --color-indigo-600: oklch(0.511 0.262 276.966);
102
+ --color-indigo-700: oklch(0.457 0.240 277.023);
103
+ --color-indigo-800: oklch(0.398 0.195 277.366);
104
+ --color-indigo-900: oklch(0.359 0.144 278.697);
105
+ --color-indigo-950: oklch(0.257 0.090 281.288);
106
+
107
+ /* ── Lime — H ≈ 131° ──────────────────────────────────────────────── */
108
+ --color-lime-50: oklch(0.986 0.031 120.757);
109
+ --color-lime-100: oklch(0.967 0.067 122.328);
110
+ --color-lime-200: oklch(0.938 0.127 124.321);
111
+ --color-lime-300: oklch(0.897 0.196 126.665);
112
+ --color-lime-400: oklch(0.841 0.238 128.850);
113
+ --color-lime-500: oklch(0.768 0.233 130.850);
114
+ --color-lime-600: oklch(0.648 0.200 131.684);
115
+ --color-lime-700: oklch(0.532 0.157 131.589);
116
+ --color-lime-800: oklch(0.453 0.124 130.933);
117
+ --color-lime-900: oklch(0.405 0.101 131.063);
118
+ --color-lime-950: oklch(0.274 0.072 132.109);
119
+
120
+ /* ── Orange — H ≈ 48° ─────────────────────────────────────────────── */
121
+ --color-orange-50: oklch(0.980 0.016 73.684);
122
+ --color-orange-100: oklch(0.954 0.038 75.164);
123
+ --color-orange-200: oklch(0.901 0.076 70.697);
124
+ --color-orange-300: oklch(0.837 0.128 66.290);
125
+ --color-orange-400: oklch(0.750 0.183 55.934);
126
+ --color-orange-500: oklch(0.705 0.213 47.604);
127
+ --color-orange-600: oklch(0.646 0.222 41.116);
128
+ --color-orange-700: oklch(0.553 0.195 38.402);
129
+ --color-orange-800: oklch(0.470 0.157 37.304);
130
+ --color-orange-900: oklch(0.408 0.123 38.172);
131
+ --color-orange-950: oklch(0.266 0.079 36.259);
132
+
133
+ /* ── Pink — H ≈ 354° ──────────────────────────────────────────────── */
134
+ --color-pink-50: oklch(0.971 0.014 343.198);
135
+ --color-pink-100: oklch(0.948 0.028 342.258);
136
+ --color-pink-200: oklch(0.899 0.061 343.231);
137
+ --color-pink-300: oklch(0.823 0.120 346.018);
138
+ --color-pink-400: oklch(0.718 0.202 349.761);
139
+ --color-pink-500: oklch(0.656 0.241 354.308);
140
+ --color-pink-600: oklch(0.592 0.249 0.584);
141
+ --color-pink-700: oklch(0.525 0.223 3.958);
142
+ --color-pink-800: oklch(0.459 0.187 3.815);
143
+ --color-pink-900: oklch(0.408 0.153 2.432);
144
+ --color-pink-950: oklch(0.284 0.109 3.907);
145
+
146
+ /* ── Fuchsia — H ≈ 316° ─────────────────────────────────────────────── */
147
+ --color-fuchsia-50: oklch(0.977 0.017 320.058);
148
+ --color-fuchsia-100: oklch(0.952 0.037 318.852);
149
+ --color-fuchsia-200: oklch(0.903 0.076 319.062);
150
+ --color-fuchsia-300: oklch(0.833 0.145 321.434);
151
+ --color-fuchsia-400: oklch(0.740 0.238 322.160);
152
+ --color-fuchsia-500: oklch(0.667 0.295 322.150);
153
+ --color-fuchsia-600: oklch(0.591 0.293 322.896);
154
+ --color-fuchsia-700: oklch(0.518 0.253 323.949);
155
+ --color-fuchsia-800: oklch(0.452 0.211 324.591);
156
+ --color-fuchsia-900: oklch(0.401 0.170 325.612);
157
+ --color-fuchsia-950: oklch(0.293 0.136 325.661);
158
+
159
+ /* ── Purple — H ≈ 304° ────────────────────────────────────────────── */
160
+ --color-purple-50: oklch(0.977 0.014 308.299);
161
+ --color-purple-100: oklch(0.946 0.033 307.174);
162
+ --color-purple-200: oklch(0.902 0.063 306.703);
163
+ --color-purple-300: oklch(0.827 0.119 306.383);
164
+ --color-purple-400: oklch(0.714 0.203 305.504);
165
+ --color-purple-500: oklch(0.627 0.265 303.900);
166
+ --color-purple-600: oklch(0.558 0.288 302.321);
167
+ --color-purple-700: oklch(0.496 0.265 301.924);
168
+ --color-purple-800: oklch(0.438 0.218 303.724);
169
+ --color-purple-900: oklch(0.381 0.176 304.987);
170
+ --color-purple-950: oklch(0.291 0.149 302.717);
171
+
172
+ /* ── Red — H ≈ 25° ────────────────────────────────────────────────── */
173
+ --color-red-50: oklch(0.971 0.013 17.380);
174
+ --color-red-100: oklch(0.936 0.032 17.717);
175
+ --color-red-200: oklch(0.885 0.062 18.334);
176
+ --color-red-300: oklch(0.808 0.114 19.571);
177
+ --color-red-400: oklch(0.704 0.191 22.216);
178
+ --color-red-500: oklch(0.637 0.237 25.331);
179
+ --color-red-600: oklch(0.577 0.245 27.325);
180
+ --color-red-700: oklch(0.505 0.213 27.518);
181
+ --color-red-800: oklch(0.444 0.177 26.899);
182
+ --color-red-900: oklch(0.396 0.141 25.723);
183
+ --color-red-950: oklch(0.258 0.092 26.042);
184
+
185
+ /* ── Rose — H ≈ 16° ───────────────────────────────────────────────── */
186
+ --color-rose-50: oklch(0.969 0.015 12.422);
187
+ --color-rose-100: oklch(0.941 0.030 12.580);
188
+ --color-rose-200: oklch(0.892 0.058 10.001);
189
+ --color-rose-300: oklch(0.810 0.101 2.432);
190
+ --color-rose-400: oklch(0.712 0.194 13.428);
191
+ --color-rose-500: oklch(0.645 0.246 16.439);
192
+ --color-rose-600: oklch(0.586 0.253 17.585);
193
+ --color-rose-700: oklch(0.514 0.222 16.935);
194
+ --color-rose-800: oklch(0.455 0.188 13.697);
195
+ --color-rose-900: oklch(0.410 0.159 10.272);
196
+ --color-rose-950: oklch(0.271 0.105 12.094);
197
+
198
+ /* ── Sky — H ≈ 237° ───────────────────────────────────────────────── */
199
+ --color-sky-50: oklch(0.977 0.013 236.620);
200
+ --color-sky-100: oklch(0.951 0.026 236.824);
201
+ --color-sky-200: oklch(0.901 0.058 230.902);
202
+ --color-sky-300: oklch(0.828 0.111 230.318);
203
+ --color-sky-400: oklch(0.746 0.160 232.661);
204
+ --color-sky-500: oklch(0.685 0.169 237.323);
205
+ --color-sky-600: oklch(0.588 0.158 241.966);
206
+ --color-sky-700: oklch(0.500 0.134 242.749);
207
+ --color-sky-800: oklch(0.443 0.110 240.790);
208
+ --color-sky-900: oklch(0.391 0.090 240.876);
209
+ --color-sky-950: oklch(0.293 0.066 243.157);
210
+
211
+ /* ── Sienna — H ≈ 23° (crimson #a90940 × terracotta) ─────────────── */
212
+ --color-sienna-50: oklch(0.973 0.012 22.0);
213
+ --color-sienna-100: oklch(0.945 0.028 22.5);
214
+ --color-sienna-200: oklch(0.900 0.060 23.5);
215
+ --color-sienna-300: oklch(0.832 0.108 25.0);
216
+ --color-sienna-400: oklch(0.727 0.160 25.5);
217
+ --color-sienna-500: oklch(0.630 0.198 24.0);
218
+ --color-sienna-600: oklch(0.530 0.195 22.0);
219
+ --color-sienna-700: oklch(0.450 0.170 20.0);
220
+ --color-sienna-800: oklch(0.380 0.136 18.0);
221
+ --color-sienna-900: oklch(0.322 0.106 16.0);
222
+ --color-sienna-950: oklch(0.218 0.072 15.0);
223
+
224
+ /* ── Teal — H ≈ 183° ──────────────────────────────────────────────── */
225
+ --color-teal-50: oklch(0.984 0.014 180.720);
226
+ --color-teal-100: oklch(0.953 0.051 180.801);
227
+ --color-teal-200: oklch(0.910 0.096 180.426);
228
+ --color-teal-300: oklch(0.855 0.138 181.071);
229
+ --color-teal-400: oklch(0.777 0.152 181.912);
230
+ --color-teal-500: oklch(0.704 0.140 182.503);
231
+ --color-teal-600: oklch(0.600 0.118 184.704);
232
+ --color-teal-700: oklch(0.511 0.096 186.391);
233
+ --color-teal-800: oklch(0.437 0.078 188.216);
234
+ --color-teal-900: oklch(0.386 0.063 188.416);
235
+ --color-teal-950: oklch(0.277 0.046 192.524);
236
+
237
+ /* ── Violet — H ≈ 293° ────────────────────────────────────────────── */
238
+ --color-violet-50: oklch(0.969 0.016 293.756);
239
+ --color-violet-100: oklch(0.943 0.029 294.588);
240
+ --color-violet-200: oklch(0.894 0.057 293.283);
241
+ --color-violet-300: oklch(0.811 0.111 293.571);
242
+ --color-violet-400: oklch(0.702 0.183 293.541);
243
+ --color-violet-500: oklch(0.606 0.250 292.717);
244
+ --color-violet-600: oklch(0.541 0.281 293.009);
245
+ --color-violet-700: oklch(0.491 0.270 292.581);
246
+ --color-violet-800: oklch(0.432 0.232 292.222);
247
+ --color-violet-900: oklch(0.380 0.189 293.745);
248
+ --color-violet-950: oklch(0.283 0.141 291.089);
249
+
250
+ /* ── Yellow — H ≈ 86° ─────────────────────────────────────────────── */
251
+ --color-yellow-50: oklch(0.987 0.026 102.212);
252
+ --color-yellow-100: oklch(0.973 0.071 103.193);
253
+ --color-yellow-200: oklch(0.945 0.129 101.540);
254
+ --color-yellow-300: oklch(0.905 0.182 98.111);
255
+ --color-yellow-400: oklch(0.852 0.199 91.936);
256
+ --color-yellow-500: oklch(0.795 0.184 86.047);
257
+ --color-yellow-600: oklch(0.681 0.162 75.834);
258
+ --color-yellow-700: oklch(0.554 0.135 66.442);
259
+ --color-yellow-800: oklch(0.476 0.114 61.907);
260
+ --color-yellow-900: oklch(0.421 0.095 57.708);
261
+ --color-yellow-950: oklch(0.286 0.066 53.813);
129
262
  }
130
263
  }
@@ -16,10 +16,12 @@
16
16
  --font-weight-black: 900;
17
17
 
18
18
  /* Line heights */
19
+ --line-height-none: 1;
19
20
  --line-height-tight: 1.1;
20
21
  --line-height-snug: 1.25;
21
22
  --line-height-normal: 1.5;
22
23
  --line-height-relaxed: 1.75;
24
+ --line-height-loose: 2;
23
25
 
24
26
  /* Text decoration */
25
27
  --text-decoration-none: none;
@@ -4,16 +4,13 @@
4
4
  --shadow-none: none;
5
5
 
6
6
  /* Directional (top-left light source) */
7
- --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
8
- --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
9
- --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
7
+ --shadow-sm: 0 1px 2px 0 var(--color-shadow-light);
8
+ --shadow-md: 0 4px 6px -1px var(--color-shadow-normal), 0 2px 4px -2px var(--color-shadow-normal);
9
+ --shadow-lg: 0 10px 15px -3px var(--color-shadow-normal), 0 4px 6px -4px var(--color-shadow-normal);
10
10
 
11
11
  /* Centered (ambient glow) */
12
- --shadow-center-sm: 0 0 2px 2px rgb(0 0 0 / 0.05);
13
- --shadow-center-md: 0 0 5px 5px rgb(0 0 0 / 0.05);
14
- --shadow-center-lg: 0 0 10px 10px rgb(0 0 0 / 0.05);
15
-
16
- /* Surface */
17
- --shadow-surface: var(--shadow-sm);
12
+ --shadow-center-sm: 0 0 2px 2px var(--color-shadow-light);
13
+ --shadow-center-md: 0 0 5px 5px var(--color-shadow-light);
14
+ --shadow-center-lg: 0 0 10px 10px var(--color-shadow-light);
18
15
  }
19
16
  }
@@ -3,21 +3,29 @@
3
3
  * Purposeful color aliases — reference primitives, never raw values.
4
4
  * Override --color-brand (and optionally --color-*) in your project to rebrand.
5
5
  *
6
- * Default brand: indigo.
6
+ * Default brand: sienna (mix crimson #a90940 × terracotta, H ≈ 23°).
7
+ *
8
+ * A11y notes:
9
+ * - Status colors (danger, success, info) use 600-level primitives so white
10
+ * text meets WCAG AA (4.5:1) when used as button/badge backgrounds.
11
+ * - Warning uses amber-500 (inherently bright); --color-text-on-warning is
12
+ * dark (gray-900) to maintain contrast.
7
13
  */
8
14
  @layer config {
9
15
  :root {
16
+ color-scheme: light;
17
+
10
18
  /* ── Accent ─────────────────────────────────────────────────────────── */
11
- --color-accent: var(--color-indigo-600);
12
- --color-accent-muted: var(--color-indigo-100);
13
- --color-accent-hover: var(--color-indigo-700);
14
- --color-accent-strong: var(--color-indigo-900);
15
-
19
+ --color-accent: var(--color-sienna-600);
20
+ --color-accent-muted: var(--color-sienna-100);
21
+ --color-accent-hover: var(--color-sienna-700);
22
+ --color-accent-strong: var(--color-sienna-900);
23
+
16
24
  /* ── Brand ─────────────────────────────────────────────────────────── */
17
- --color-brand: var(--color-indigo-600);
18
- --color-brand-muted: var(--color-indigo-100);
19
- --color-brand-hover: var(--color-indigo-700);
20
- --color-brand-strong: var(--color-indigo-900);
25
+ --color-brand: var(--color-sienna-600);
26
+ --color-brand-muted: var(--color-sienna-100);
27
+ --color-brand-hover: var(--color-sienna-700);
28
+ --color-brand-strong: var(--color-sienna-900);
21
29
 
22
30
  /* ── Overlay ───────────────────────────────────────────────────────── */
23
31
  --color-backdrop: rgb(var(--color-black-rgb) / var(--opacity-backdrop));
@@ -27,11 +35,20 @@
27
35
  --color-bg-accent: var(--color-accent);
28
36
  --color-bg-media: var(--color-gray-200);
29
37
  --color-bg-muted: var(--color-gray-100);
38
+ --color-bg-muted-hover: var(--color-gray-200);
30
39
  --color-bg-surface: var(--color-bg);
31
40
 
32
41
  /* ── Borders & focus ───────────────────────────────────────────────── */
33
42
  --color-border: var(--color-gray-200);
34
- --color-focus: var(--color-accent);
43
+ --color-border-hover: var(--color-gray-500);
44
+ --color-focus: var(--color-text);
45
+
46
+ /* ── Shadows ───────────────────────────────────────────────────────── */
47
+ /* --color-shadow holds raw RGB channels so rgb(var(--color-shadow) / α) works. */
48
+ /* In dark mode, flip to 255 255 255 → all shadows become a white glow. */
49
+ --color-shadow: var(--color-black-rgb);
50
+ --color-shadow-light: rgb(var(--color-shadow) / var(--opacity-shadow)); /* sm, center-* */
51
+ --color-shadow-normal: rgb(var(--color-shadow) / var(--opacity-shadow)); /* md, lg */
35
52
 
36
53
  /* ── Text ──────────────────────────────────────────────────────────── */
37
54
  --color-active: var(--color-accent);
@@ -41,6 +58,7 @@
41
58
  --color-link-active: var(--color-active);
42
59
  --color-link-hover: var(--color-accent);
43
60
  --color-text: var(--color-gray-900);
61
+ --color-text-hover: var(--color-gray-700);
44
62
  --color-text-muted: var(--color-gray-500);
45
63
  --color-text-disabled: var(--color-gray-300);
46
64
  --color-text-on-accent: var(--color-white);
@@ -53,49 +71,49 @@
53
71
  --color-text-on-secondary: var(--color-white);
54
72
  --color-text-on-surface: var(--color-text);
55
73
  --color-text-on-success: var(--color-white);
56
- --color-text-on-warning: var(--color-gray-900);
74
+ --color-text-on-warning: var(--color-gray-900); /* amber is bright — dark text */
57
75
 
58
76
  /* ── Semantic variants ─────────────────────────────────────────────── */
59
77
 
60
- /* Primary (alias of accent) */
78
+ /* Primary (alias of brand) */
61
79
  --color-primary: var(--color-brand);
62
80
  --color-primary-muted: var(--color-brand-muted);
63
81
  --color-primary-hover: var(--color-brand-hover);
64
82
  --color-primary-strong: var(--color-brand-strong);
65
83
 
66
84
  /* Secondary */
67
- --color-secondary: var(--color-gray-500);
85
+ --color-secondary: var(--color-gray-600);
68
86
  --color-secondary-muted: var(--color-gray-100);
69
87
  --color-secondary-strong: var(--color-gray-800);
70
88
 
71
- /* Danger */
72
- --color-danger: var(--color-red-500);
89
+ /* Danger — red-600 ensures white text meets WCAG AA */
90
+ --color-danger: var(--color-red-600);
73
91
  --color-danger-muted: var(--color-red-100);
74
- --color-danger-strong: var(--color-red-900);
92
+ --color-danger-strong: var(--color-red-800);
75
93
 
76
94
  /* Dark */
77
95
  --color-dark: var(--color-gray-900);
78
96
  --color-dark-muted: var(--color-gray-100);
79
97
  --color-dark-strong: var(--color-black);
80
98
 
81
- /* Info */
82
- --color-info: var(--color-blue-500);
99
+ /* Info — blue-600 ensures white text meets WCAG AA */
100
+ --color-info: var(--color-blue-600);
83
101
  --color-info-muted: var(--color-blue-100);
84
- --color-info-strong: var(--color-blue-900);
102
+ --color-info-strong: var(--color-blue-800);
85
103
 
86
104
  /* Light */
87
105
  --color-light: var(--color-gray-200);
88
106
  --color-light-muted: var(--color-gray-100);
89
107
  --color-light-strong: var(--color-gray-700);
90
108
 
91
- /* Success */
92
- --color-success: var(--color-green-500);
109
+ /* Success — green-600 ensures white text meets WCAG AA */
110
+ --color-success: var(--color-green-600);
93
111
  --color-success-muted: var(--color-green-100);
94
- --color-success-strong: var(--color-green-900);
112
+ --color-success-strong: var(--color-green-800);
95
113
 
96
- /* Warning */
97
- --color-warning: var(--color-yellow-500);
98
- --color-warning-muted: var(--color-yellow-100);
99
- --color-warning-strong: var(--color-yellow-900);
114
+ /* Warning — amber-500 is bright; pair with dark text (see text-on-warning above) */
115
+ --color-warning: var(--color-amber-500);
116
+ --color-warning-muted: var(--color-amber-100);
117
+ --color-warning-strong: var(--color-amber-700);
100
118
  }
101
119
  }
@@ -0,0 +1,48 @@
1
+ /* semantic/dark.css */
2
+ /*
3
+ * Dark mode token overrides — activated by OS preference.
4
+ * Projects without dark mode: add `color-scheme: only light` in @layer config.
5
+ * Manual toggle ([data-theme]): handled at project level.
6
+ *
7
+ * Tokens that adapt automatically (reference semantic tokens that change here):
8
+ * --color-bg-surface → var(--color-bg)
9
+ * --color-link → var(--color-text)
10
+ * --form-color-border → var(--color-border)
11
+ * --form-color-text → var(--color-text)
12
+ * --input-color-bg → var(--form-color-bg)
13
+ *
14
+ * Not changed: brand, status (danger/success/info/warning), secondary, dark,
15
+ * light — functional colors that stay consistent in dark mode.
16
+ * Override at project level if needed.
17
+ */
18
+ @layer config {
19
+ @media (prefers-color-scheme: dark) {
20
+ :root:not([data-color-scheme="light"]) {
21
+ color-scheme: dark;
22
+
23
+ /* ── Backgrounds ─────────────────────────────────────────────────── */
24
+ --color-bg: var(--color-gray-950);
25
+ --color-bg-muted: var(--color-gray-900);
26
+ --color-bg-muted-hover: var(--color-gray-800);
27
+ --color-bg-media: var(--color-gray-800);
28
+
29
+ /* ── Borders ─────────────────────────────────────────────────────── */
30
+ --color-border: var(--color-gray-800);
31
+
32
+ /* ── Text ────────────────────────────────────────────────────────── */
33
+ --color-heading: var(--color-white);
34
+ --color-text: var(--color-gray-200);
35
+ --color-text-muted: var(--color-gray-400);
36
+ --color-text-disabled: var(--color-gray-600);
37
+ --color-text-hover: var(--color-gray-300);
38
+
39
+ /* ── Forms ───────────────────────────────────────────────────────── */
40
+ /* --form-color-bg references --color-white directly — must be explicit */
41
+ --form-color-bg: var(--color-gray-900);
42
+
43
+ /* ── Shadows ─────────────────────────────────────────────────────── */
44
+ /* Flip to white → all shadows become a subtle white glow */
45
+ --color-shadow: var(--color-white-rgb);
46
+ }
47
+ }
48
+ }
@@ -1,9 +1,10 @@
1
1
  /* semantic/focus.css */
2
2
  @layer config {
3
3
  :root {
4
+ --focus: var(--focus-outline-width) var(--focus-outline-style) var(--focus-color);
4
5
  --focus-color: var(--color-focus);
5
6
  --focus-outline-style: solid;
6
- --focus-outline-width: 2px;
7
+ --focus-outline-width: 1px;
7
8
  --focus-outline-offset: 2px;
8
9
  }
9
10
  }
@@ -7,9 +7,11 @@
7
7
  --form-color-accent: var(--color-black);
8
8
  --form-color-bg: var(--color-white);
9
9
  --form-color-border: var(--color-border);
10
- --form-color-border-hover: var(--form-color-accent);
10
+ --form-color-border-hover: var(--color-border-hover);
11
11
  --form-color-text: var(--color-text);
12
12
  --form-padding: var(--spacing-control);
13
+ --form-shadow: var(--shadow-control);
14
+ --form-shadow-hover: var(--shadow-control-hover);
13
15
  --form-transition: var(--transition-normal);
14
16
 
15
17
  /* ── Input ─────────────────────────────────────────────────────────── */
@@ -95,11 +97,11 @@
95
97
  --radio-scale-checked: 0.5;
96
98
 
97
99
  /* ── Range ─────────────────────────────────────────────────────────── */
98
- --range-color-accent: var(--form-color-accent);
99
- --range-color-track: var(--form-color-border);
100
+ --range-thumb-color: var(--form-color-accent);
100
101
  --range-thumb-color-border: var(--color-white);
101
102
  --range-thumb-border-width: var(--size-4);
102
103
  --range-thumb-size: var(--size-24);
104
+ --range-track-color: var(--form-color-border);
103
105
  --range-track-height: calc(var(--border-width-normal) + 2px);
104
106
  }
105
107
  }
@@ -5,20 +5,6 @@
5
5
  --columns: 12;
6
6
  --gap: var(--spacing-md);
7
7
 
8
- /* ── Flex fractions ─────────────────────────────────────────────────── */
9
- --flex-full: 100%;
10
- --flex-eleven-twelfths: 91.6666666667%;
11
- --flex-five-sixths: 83.3333333333%;
12
- --flex-four-fifths: 80%;
13
- --flex-three-quarters: 75%;
14
- --flex-two-thirds: 66.6666666667%;
15
- --flex-half: 50%;
16
- --flex-third: 33.3333333333%;
17
- --flex-quarter: 25%;
18
- --flex-fifth: 20%;
19
- --flex-sixth: 16.6666666667%;
20
- --flex-twelfth: 8.3333333333%;
21
-
22
8
  /* ── Grid column spans ──────────────────────────────────────────────── */
23
9
  /* Integer spans — grid-agnostic. Comments show col-12 / col-24 fractions. */
24
10
  --span-full: span var(--columns);
@@ -1,12 +1,19 @@
1
1
  /* semantic/icon.css */
2
2
  @layer config {
3
3
  :root {
4
- --icon-size: var(--size-16);
4
+ --icon-size: var(--size-16);
5
5
 
6
+ /* Icons */
7
+ --icon-arrow: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><line x1="2" y1="8" x2="12" y2="8"/><polyline points="8 4 12 8 8 12"/></svg>');
8
+ --icon-arrow-skip: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><line x1="2" y1="8" x2="10" y2="8"/><polyline points="6 4 10 8 6 12"/><line x1="14" y1="3" x2="14" y2="13"/></svg>');
6
9
  --icon-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><polyline points="2 5 8 11 14 5"/></svg>');
7
- --icon-close: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round"><line x1="3" y1="3" x2="13" y2="13"/><line x1="13" y1="3" x2="3" y2="13"/></svg>');
8
- --icon-dash: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M431 256c0 17.7-14.3 32-32 32H49c-17.7 0-32-14.3-32-32s14.3-32 32-32h350c17.7 0 32 14.3 32 32z"/></svg>');
9
- --icon-plus: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round"><line x1="8" y1="3" x2="8" y2="13"/><line x1="3" y1="8" x2="13" y2="8"/></svg>');
10
- --icon-tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>');
10
+ --icon-close: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round"><line x1="3" y1="3" x2="13" y2="13"/><line x1="13" y1="3" x2="3" y2="13"/></svg>');
11
+ --icon-dash: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M431 256c0 17.7-14.3 32-32 32H49c-17.7 0-32-14.3-32-32s14.3-32 32-32h350c17.7 0 32 14.3 32 32z"/></svg>');
12
+ --icon-filter: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><path d="M1.3 3.3h13.4"/><path d="M4 8h8"/><path d="M6 12.7h4"/></svg>');
13
+ --icon-menu: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round"><line x1="2" y1="4" x2="14" y2="4"/><line x1="2" y1="8" x2="14" y2="8"/><line x1="2" y1="12" x2="14" y2="12"/></svg>');
14
+ --icon-plus: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round"><line x1="8" y1="3" x2="8" y2="13"/><line x1="3" y1="8" x2="13" y2="8"/></svg>');
15
+ --icon-share: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><path d="M8 1.3v8.7"/><path d="m10.7 4-2.7-2.7-2.7 2.7"/><path d="M2.7 8v5.3a1.3 1.3 0 0 0 1.3 1.3h8a1.3 1.3 0 0 0 1.3-1.3v-5.3"/></svg>');
16
+ --icon-tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>');
17
+ --icon-toc: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="%23000000" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><path d="M10.7 3.3H2"/><path d="M10.7 8H2"/><path d="M10.7 12.7H2"/><path d="M14 3.3h.01"/><path d="M14 8h.01"/><path d="M14 12.7h.01"/></svg>');
11
18
  }
12
19
  }
@@ -0,0 +1,17 @@
1
+ /* semantic/mediaqueries.css */
2
+ /* https://www.npmjs.com/package/postcss-custom-media */
3
+ @layer config {
4
+ /* ── UP ──────────────────────────────────────────────── */
5
+
6
+ /* 768px */
7
+ @custom-media --tablet (width >= 48rem);
8
+
9
+ /* 1024px */
10
+ @custom-media --tablet-wide (width >= 64rem);
11
+
12
+ /* 1440px */
13
+ @custom-media --laptop (width >= 90rem);
14
+
15
+ /* 1600px */
16
+ @custom-media --desktop (width >= 100rem);
17
+ }
@@ -40,7 +40,7 @@
40
40
  --transition-opacity: opacity var(--duration-normal) var(--easing-default);
41
41
  --transition-transform: transform var(--duration-normal) var(--easing-default);
42
42
  /* Targeted color transitions */
43
- --transition-property-color: color, background-color, border-color, outline-color, fill, stroke;
43
+ --transition-property-color: color, background-color, border-color, outline-color, fill, stroke, text-decoration;
44
44
  --transition-color: var(--transition-property-color) var(--duration-normal) var(--easing-default);
45
45
  }
46
46
  }
@@ -2,8 +2,9 @@
2
2
  @layer config {
3
3
  :root {
4
4
  --opacity-backdrop: var(--opacity-50);
5
- --opacity-disabled: var(--opacity-25);
5
+ --opacity-disabled: var(--opacity-50);
6
6
  --opacity-overlay: var(--opacity-75);
7
- --opacity-subtle: var(--opacity-10);
7
+ --opacity-shadow: var(--opacity-10);
8
+ --opacity-subtle: var(--opacity-25);
8
9
  }
9
10
  }
@@ -0,0 +1,14 @@
1
+ /* semantic/shadow.css */
2
+ /*
3
+ * Semantic shadow aliases — map primitive shadows to purposeful roles.
4
+ * Override in @layer config to restyle elevation system-wide.
5
+ * In dark mode (semantic/dark.css), --shadow-sm/md/lg are overridden with
6
+ * higher opacity — these aliases adapt automatically.
7
+ */
8
+ @layer config {
9
+ :root {
10
+ --shadow-control: none;
11
+ --shadow-control-hover: none;
12
+ --shadow-surface: var(--shadow-sm);
13
+ }
14
+ }
@@ -2,10 +2,11 @@
2
2
  @layer config {
3
3
  :root {
4
4
  /* ── Breakpoints ────────────────────────────────────────────────────── */
5
- --size-tablet: var(--size-768); /* 48rem — 768px */
6
- --size-tablet-wide: var(--size-1024); /* 64rem — 1024px */
7
- --size-laptop: var(--size-1440); /* 90rem — 1440px */
8
- --size-desktop: var(--size-1920); /* 120rem1920px */
5
+ --size-tablet: var(--size-768); /* 48rem — 768px */
6
+ --size-tablet-wide: var(--size-1024); /* 64rem — 1024px */
7
+ --size-laptop: var(--size-1440); /* 90rem — 1440px */
8
+ --size-desktop: var(--size-1600); /* 100rem1600px */
9
+ --size-desktop-wide: var(--size-1920); /* 120rem — 1920px */
9
10
 
10
11
  /* ── T-shirt scale ──────────────────────────────────────────────────── */
11
12
  --size-2xs: var(--size-5);
@@ -32,10 +32,11 @@
32
32
  --spacing-fluid-2xl: clamp(3.75rem, 2.5rem + 5.5556vw, 7.5rem); /* 60 → 120px */
33
33
 
34
34
  /* ── Purposeful aliases ─────────────────────────────────────────────── */
35
+ --spacing-card: var(--spacing-sm); /* padding inside surfaces (card) */
35
36
  --spacing-control: var(--spacing-xs); /* padding inside interactive controls */
36
37
  --spacing-heading: var(--spacing-fluid-sm); /* gap below headings */
37
38
  --spacing-section: var(--spacing-fluid-2xl); /* vertical rhythm between sections */
38
- --spacing-surface: var(--spacing-fluid-sm); /* padding inside surfaces (card, panel) */
39
+ --spacing-surface: var(--spacing-fluid-sm); /* padding inside surfaces (panel) */
39
40
  --spacing-typography: var(--spacing-fluid-xs); /* gap between typographic elements */
40
41
  }
41
42
  }
@@ -28,7 +28,7 @@
28
28
  --font-size-lg: var(--size-24);
29
29
  --font-size-xl: var(--size-48);
30
30
  --font-size-2xl: var(--size-64);
31
- --font-size-display: var(--size-96); /* hero / marketing */
31
+ --font-size-display: var(--size-96);
32
32
 
33
33
  /* ── Fluid font sizes ───────────────────────────────────────────────── */
34
34
  /*
@@ -56,6 +56,7 @@
56
56
 
57
57
  /* ── Body ───────────────────────────────────────────────────────────── */
58
58
  --font-size-text: var(--font-size-fluid-md);
59
+ --font-size-small: var(--font-size-fluid-sm);
59
60
 
60
61
  /* ── Headings ───────────────────────────────────────────────────────── */
61
62
  --font-size-heading-01: var(--font-size-fluid-xl);
@@ -8,11 +8,15 @@
8
8
  @import 'semantic/form.css';
9
9
  @import 'semantic/grid.css';
10
10
  @import 'semantic/icon.css';
11
+ @import 'semantic/mediaqueries.css';
11
12
  @import 'semantic/motion.css';
12
13
  @import 'semantic/opacity.css';
13
14
  @import 'semantic/radius.css';
14
15
  @import 'semantic/ratio.css';
16
+ @import 'semantic/shadow.css';
15
17
  @import 'semantic/size.css';
16
18
  @import 'semantic/spacing.css';
17
19
  @import 'semantic/typography.css';
18
20
  @import 'semantic/z-index.css';
21
+
22
+ @import 'semantic/dark.css';