@bubble-design-system/ui 0.2.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.
@@ -0,0 +1,750 @@
1
+ /* ─────────────────────────────────────────────────────────
2
+ bubble · design tokens
3
+ Layer 1: primitives (raw values)
4
+ Layer 2: semantics (purpose-bound)
5
+ Layer 3: component (only when semantics don't fit)
6
+
7
+ Tone axis (`[data-tone]`, default `soft`):
8
+ · soft — signature look: gray page, white floating pills,
9
+ layered shadows w/ inset highlight, pill controls
10
+ · vivid — flat shadcn-like: white surfaces, single-layer shadows
11
+ · pastel — warm desaturated, off-white surfaces
12
+ ───────────────────────────────────────────────────────── */
13
+
14
+ :root {
15
+ /* ── neutrals: cool slate (default) ─────────────────── */
16
+ --slate-50: #F8FAFC;
17
+ --slate-100: #F1F5F9;
18
+ --slate-200: #E2E8F0;
19
+ --slate-300: #CBD5E1;
20
+ --slate-400: #94A3B8;
21
+ --slate-500: #64748B;
22
+ --slate-600: #475569;
23
+ --slate-700: #334155;
24
+ --slate-800: #1E293B;
25
+ --slate-900: #0F172A;
26
+ --slate-950: #020617;
27
+
28
+ /* ── neutrals: true neutral ─────────────────────────── */
29
+ --neutral-50: #FAFAFA;
30
+ --neutral-100: #F5F5F5;
31
+ --neutral-200: #E5E5E5;
32
+ --neutral-300: #D4D4D4;
33
+ --neutral-400: #A3A3A3;
34
+ --neutral-500: #737373;
35
+ --neutral-600: #525252;
36
+ --neutral-700: #404040;
37
+ --neutral-800: #262626;
38
+ --neutral-900: #171717;
39
+ --neutral-950: #0A0A0A;
40
+
41
+ /* ── neutrals: warm stone ───────────────────────────── */
42
+ --stone-50: #FAFAF9;
43
+ --stone-100: #F5F5F4;
44
+ --stone-200: #E7E5E4;
45
+ --stone-300: #D6D3D1;
46
+ --stone-400: #A8A29E;
47
+ --stone-500: #78716C;
48
+ --stone-600: #57534E;
49
+ --stone-700: #44403C;
50
+ --stone-800: #292524;
51
+ --stone-900: #1C1917;
52
+ --stone-950: #0C0A09;
53
+
54
+ /* ── brand: blue (default, anchored on #1D4ED8) ─────── */
55
+ --blue-50: #EFF6FF;
56
+ --blue-100: #DBEAFE;
57
+ --blue-200: #BFDBFE;
58
+ --blue-300: #93C5FD;
59
+ --blue-400: #60A5FA;
60
+ --blue-500: #3B82F6;
61
+ --blue-600: #1D4ED8;
62
+ --blue-700: #1E40AF;
63
+ --blue-800: #1E3A8A;
64
+ --blue-900: #172554;
65
+ --blue-950: #0B1336;
66
+
67
+ /* ── brand: violet ──────────────────────────────────── */
68
+ --violet-50: #F5F3FF;
69
+ --violet-100: #EDE9FE;
70
+ --violet-200: #DDD6FE;
71
+ --violet-300: #C4B5FD;
72
+ --violet-400: #A78BFA;
73
+ --violet-500: #8B5CF6;
74
+ --violet-600: #6D28D9;
75
+ --violet-700: #5B21B6;
76
+ --violet-800: #4C1D95;
77
+ --violet-900: #3B0764;
78
+ --violet-950: #2A0556;
79
+
80
+ /* ── brand: emerald ─────────────────────────────────── */
81
+ --emerald-50: #ECFDF5;
82
+ --emerald-100: #D1FAE5;
83
+ --emerald-200: #A7F3D0;
84
+ --emerald-300: #6EE7B7;
85
+ --emerald-400: #34D399;
86
+ --emerald-500: #10B981;
87
+ --emerald-600: #047857;
88
+ --emerald-700: #065F46;
89
+ --emerald-800: #064E3B;
90
+ --emerald-900: #022C22;
91
+ --emerald-950: #011D18;
92
+
93
+ /* ── brand: orange ──────────────────────────────────── */
94
+ --orange-50: #FFF7ED;
95
+ --orange-100: #FFEDD5;
96
+ --orange-200: #FED7AA;
97
+ --orange-300: #FDBA74;
98
+ --orange-400: #FB923C;
99
+ --orange-500: #F97316;
100
+ --orange-600: #C2410C;
101
+ --orange-700: #9A3412;
102
+ --orange-800: #7C2D12;
103
+ --orange-900: #431407;
104
+ --orange-950: #2A0D04;
105
+
106
+ /* ── brand: mono (uses neutrals) ────────────────────── */
107
+ /* mono-* are aliased per gray family below */
108
+
109
+ /* ── semantic palette: green ────────────────────────── */
110
+ --green-50: #F0FDF4;
111
+ --green-100: #DCFCE7;
112
+ --green-200: #BBF7D0;
113
+ --green-300: #86EFAC;
114
+ --green-400: #4ADE80;
115
+ --green-500: #22C55E;
116
+ --green-600: #16A34A;
117
+ --green-700: #15803D;
118
+ --green-800: #166534;
119
+ --green-900: #14532D;
120
+ --green-950: #052E16;
121
+
122
+ /* ── semantic palette: amber ────────────────────────── */
123
+ --amber-50: #FFFBEB;
124
+ --amber-100: #FEF3C7;
125
+ --amber-200: #FDE68A;
126
+ --amber-300: #FCD34D;
127
+ --amber-400: #FBBF24;
128
+ --amber-500: #F59E0B;
129
+ --amber-600: #D97706;
130
+ --amber-700: #B45309;
131
+ --amber-800: #92400E;
132
+ --amber-900: #78350F;
133
+ --amber-950: #451A03;
134
+
135
+ /* ── semantic palette: red ──────────────────────────── */
136
+ --red-50: #FEF2F2;
137
+ --red-100: #FEE2E2;
138
+ --red-200: #FECACA;
139
+ --red-300: #FCA5A5;
140
+ --red-400: #F87171;
141
+ --red-500: #EF4444;
142
+ --red-600: #DC2626;
143
+ --red-700: #B91C1C;
144
+ --red-800: #991B1B;
145
+ --red-900: #7F1D1D;
146
+ --red-950: #450A0A;
147
+
148
+ /* ── pure ───────────────────────────────────────────── */
149
+ --white: #FFFFFF;
150
+ --black: #000000;
151
+ }
152
+
153
+ /* ─────────────────────────────────────────────────────────
154
+ gray-family aliases — selected via [data-gray]
155
+ ───────────────────────────────────────────────────────── */
156
+ :root,
157
+ [data-gray="slate"] {
158
+ --gray-50: var(--slate-50);
159
+ --gray-100: var(--slate-100);
160
+ --gray-200: var(--slate-200);
161
+ --gray-300: var(--slate-300);
162
+ --gray-400: var(--slate-400);
163
+ --gray-500: var(--slate-500);
164
+ --gray-600: var(--slate-600);
165
+ --gray-700: var(--slate-700);
166
+ --gray-800: var(--slate-800);
167
+ --gray-900: var(--slate-900);
168
+ --gray-950: var(--slate-950);
169
+ }
170
+ [data-gray="neutral"] {
171
+ --gray-50: var(--neutral-50);
172
+ --gray-100: var(--neutral-100);
173
+ --gray-200: var(--neutral-200);
174
+ --gray-300: var(--neutral-300);
175
+ --gray-400: var(--neutral-400);
176
+ --gray-500: var(--neutral-500);
177
+ --gray-600: var(--neutral-600);
178
+ --gray-700: var(--neutral-700);
179
+ --gray-800: var(--neutral-800);
180
+ --gray-900: var(--neutral-900);
181
+ --gray-950: var(--neutral-950);
182
+ }
183
+ [data-gray="stone"] {
184
+ --gray-50: var(--stone-50);
185
+ --gray-100: var(--stone-100);
186
+ --gray-200: var(--stone-200);
187
+ --gray-300: var(--stone-300);
188
+ --gray-400: var(--stone-400);
189
+ --gray-500: var(--stone-500);
190
+ --gray-600: var(--stone-600);
191
+ --gray-700: var(--stone-700);
192
+ --gray-800: var(--stone-800);
193
+ --gray-900: var(--stone-900);
194
+ --gray-950: var(--stone-950);
195
+ }
196
+
197
+ /* ─────────────────────────────────────────────────────────
198
+ brand aliases — selected via [data-brand]
199
+ ───────────────────────────────────────────────────────── */
200
+ :root,
201
+ [data-brand="blue"] {
202
+ --brand-50: var(--blue-50);
203
+ --brand-100: var(--blue-100);
204
+ --brand-200: var(--blue-200);
205
+ --brand-300: var(--blue-300);
206
+ --brand-400: var(--blue-400);
207
+ --brand-500: var(--blue-500);
208
+ --brand-600: var(--blue-600);
209
+ --brand-700: var(--blue-700);
210
+ --brand-800: var(--blue-800);
211
+ --brand-900: var(--blue-900);
212
+ --brand-950: var(--blue-950);
213
+ }
214
+ [data-brand="violet"] {
215
+ --brand-50: var(--violet-50);
216
+ --brand-100: var(--violet-100);
217
+ --brand-200: var(--violet-200);
218
+ --brand-300: var(--violet-300);
219
+ --brand-400: var(--violet-400);
220
+ --brand-500: var(--violet-500);
221
+ --brand-600: var(--violet-600);
222
+ --brand-700: var(--violet-700);
223
+ --brand-800: var(--violet-800);
224
+ --brand-900: var(--violet-900);
225
+ --brand-950: var(--violet-950);
226
+ }
227
+ [data-brand="emerald"] {
228
+ --brand-50: var(--emerald-50);
229
+ --brand-100: var(--emerald-100);
230
+ --brand-200: var(--emerald-200);
231
+ --brand-300: var(--emerald-300);
232
+ --brand-400: var(--emerald-400);
233
+ --brand-500: var(--emerald-500);
234
+ --brand-600: var(--emerald-600);
235
+ --brand-700: var(--emerald-700);
236
+ --brand-800: var(--emerald-800);
237
+ --brand-900: var(--emerald-900);
238
+ --brand-950: var(--emerald-950);
239
+ }
240
+ [data-brand="orange"] {
241
+ --brand-50: var(--orange-50);
242
+ --brand-100: var(--orange-100);
243
+ --brand-200: var(--orange-200);
244
+ --brand-300: var(--orange-300);
245
+ --brand-400: var(--orange-400);
246
+ --brand-500: var(--orange-500);
247
+ --brand-600: var(--orange-600);
248
+ --brand-700: var(--orange-700);
249
+ --brand-800: var(--orange-800);
250
+ --brand-900: var(--orange-900);
251
+ --brand-950: var(--orange-950);
252
+ }
253
+ [data-brand="mono"] {
254
+ --brand-50: var(--gray-50);
255
+ --brand-100: var(--gray-100);
256
+ --brand-200: var(--gray-200);
257
+ --brand-300: var(--gray-300);
258
+ --brand-400: var(--gray-400);
259
+ --brand-500: var(--gray-500);
260
+ --brand-600: var(--gray-900);
261
+ --brand-700: var(--gray-950);
262
+ --brand-800: var(--black);
263
+ --brand-900: var(--black);
264
+ --brand-950: var(--black);
265
+ }
266
+ [data-brand="teal"] {
267
+ --brand-50: #E2FBFA;
268
+ --brand-100: #B8F4F1;
269
+ --brand-200: #8AECE7;
270
+ --brand-300: #4DDFD9;
271
+ --brand-400: #14D2CB;
272
+ --brand-500: #00CEC8;
273
+ --brand-600: #00CEC8;
274
+ --brand-700: #009E99;
275
+ --brand-800: #007570;
276
+ --brand-900: #004B48;
277
+ --brand-950: #002523;
278
+ }
279
+
280
+ /* ─────────────────────────────────────────────────────────
281
+ Semantic tokens — LIGHT (default)
282
+ ───────────────────────────────────────────────────────── */
283
+ :root {
284
+ /* background */
285
+ --color-bg-page: var(--color-bg-primary);
286
+ --color-bg-primary: var(--white);
287
+ --color-bg-secondary: var(--gray-50);
288
+ --color-bg-tertiary: var(--gray-100);
289
+ --color-bg-inverse: var(--gray-900);
290
+
291
+ --color-bg-brand: var(--brand-600);
292
+ --color-bg-brand-hover: var(--brand-700);
293
+ --color-bg-brand-active: var(--brand-800);
294
+ --color-bg-brand-subtle: var(--brand-50);
295
+
296
+ --color-bg-success: var(--green-50);
297
+ --color-bg-success-strong: var(--green-600);
298
+ --color-bg-warning: var(--amber-50);
299
+ --color-bg-warning-strong: var(--amber-500);
300
+ --color-bg-danger: var(--red-50);
301
+ --color-bg-danger-strong: var(--red-600);
302
+ --color-bg-danger-hover: var(--red-700);
303
+ --color-bg-info: var(--brand-50);
304
+
305
+ --color-bg-hover: var(--gray-100);
306
+ --color-bg-pressed: var(--gray-200);
307
+ --color-bg-disabled: var(--gray-100);
308
+
309
+ /* text */
310
+ --color-text-primary: var(--gray-900);
311
+ --color-text-secondary: var(--gray-600);
312
+ --color-text-tertiary: var(--gray-400);
313
+ --color-text-disabled: var(--gray-300);
314
+ --color-text-inverse: var(--white);
315
+
316
+ --color-text-brand: var(--brand-700);
317
+ --color-text-success: var(--green-700);
318
+ --color-text-warning: var(--amber-700);
319
+ --color-text-danger: var(--red-700);
320
+
321
+ --color-text-on-brand: var(--white);
322
+ --color-text-on-danger: var(--white);
323
+ --color-text-on-success: var(--white);
324
+
325
+ /* border */
326
+ --color-border-primary: var(--gray-300);
327
+ --color-border-secondary: var(--gray-200);
328
+ --color-border-tertiary: var(--gray-100);
329
+ --color-border-brand: var(--brand-600);
330
+ --color-border-success: var(--green-200);
331
+ --color-border-warning: var(--amber-200);
332
+ --color-border-danger: var(--red-200);
333
+ --color-border-focus: var(--brand-600);
334
+
335
+ /* shadow */
336
+ --shadow-xs: 0 1px 2px 0 rgba(15, 23, 42, 0.04);
337
+ --shadow-sm: 0 1px 2px 0 rgba(15, 23, 42, 0.05), 0 1px 1px -1px rgba(15, 23, 42, 0.04);
338
+ --shadow-md: 0 4px 6px -1px rgba(15, 23, 42, 0.06), 0 2px 4px -2px rgba(15, 23, 42, 0.04);
339
+ --shadow-lg: 0 10px 15px -3px rgba(15, 23, 42, 0.08), 0 4px 6px -4px rgba(15, 23, 42, 0.04);
340
+ --shadow-xl: 0 20px 25px -5px rgba(15, 23, 42, 0.10), 0 8px 10px -6px rgba(15, 23, 42, 0.04);
341
+ --shadow-focus: 0 0 0 3px var(--brand-100);
342
+
343
+ /* code surface */
344
+ --color-code-bg: var(--gray-50);
345
+ --color-code-border: var(--gray-200);
346
+ --color-code-text: var(--gray-800);
347
+
348
+ /* signature gradient — used for the brand blob + AI/featured accents.
349
+ Always present regardless of tone; soft tone leans on it most. */
350
+ --gradient-accent: linear-gradient(135deg,
351
+ #FF8A9E 0%,
352
+ #FF6BA5 25%,
353
+ #C760D9 55%,
354
+ #8B6BE8 100%);
355
+ --gradient-accent-soft: linear-gradient(135deg,
356
+ rgba(255, 138, 158, 0.18) 0%,
357
+ rgba(199, 96, 217, 0.16) 50%,
358
+ rgba(139, 107, 232, 0.18) 100%);
359
+
360
+ /* control radius — pill-first in soft, default otherwise */
361
+ --ctrl-radius: var(--radius-md);
362
+ }
363
+
364
+ /* ─────────────────────────────────────────────────────────
365
+ Semantic tokens — DARK
366
+ ───────────────────────────────────────────────────────── */
367
+ [data-theme="dark"] {
368
+ --color-bg-primary: var(--gray-950);
369
+ --color-bg-secondary: var(--gray-900);
370
+ --color-bg-tertiary: var(--gray-800);
371
+ --color-bg-inverse: var(--gray-50);
372
+
373
+ --color-bg-brand: var(--brand-500);
374
+ --color-bg-brand-hover: var(--brand-400);
375
+ --color-bg-brand-active: var(--brand-300);
376
+ --color-bg-brand-subtle: color-mix(in srgb, var(--brand-500) 14%, transparent);
377
+
378
+ --color-bg-success: color-mix(in srgb, var(--green-500) 14%, transparent);
379
+ --color-bg-success-strong: var(--green-500);
380
+ --color-bg-warning: color-mix(in srgb, var(--amber-500) 14%, transparent);
381
+ --color-bg-warning-strong: var(--amber-400);
382
+ --color-bg-danger: color-mix(in srgb, var(--red-500) 14%, transparent);
383
+ --color-bg-danger-strong: var(--red-500);
384
+ --color-bg-danger-hover: var(--red-400);
385
+ --color-bg-info: color-mix(in srgb, var(--brand-500) 14%, transparent);
386
+
387
+ --color-bg-hover: var(--gray-800);
388
+ --color-bg-pressed: var(--gray-700);
389
+ --color-bg-disabled: var(--gray-800);
390
+
391
+ --color-text-primary: var(--gray-50);
392
+ --color-text-secondary: var(--gray-400);
393
+ --color-text-tertiary: var(--gray-500);
394
+ --color-text-disabled: var(--gray-700);
395
+ --color-text-inverse: var(--gray-950);
396
+
397
+ --color-text-brand: var(--brand-400);
398
+ --color-text-success: var(--green-400);
399
+ --color-text-warning: var(--amber-400);
400
+ --color-text-danger: var(--red-400);
401
+
402
+ --color-text-on-brand: var(--gray-950);
403
+ --color-text-on-danger: var(--white);
404
+ --color-text-on-success: var(--gray-950);
405
+
406
+ --color-border-primary: var(--gray-700);
407
+ --color-border-secondary: var(--gray-800);
408
+ --color-border-tertiary: var(--gray-800);
409
+ --color-border-brand: var(--brand-400);
410
+ --color-border-success: color-mix(in srgb, var(--green-500) 30%, transparent);
411
+ --color-border-warning: color-mix(in srgb, var(--amber-500) 30%, transparent);
412
+ --color-border-danger: color-mix(in srgb, var(--red-500) 30%, transparent);
413
+ --color-border-focus: var(--brand-400);
414
+
415
+ --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.5);
416
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.6), 0 1px 1px -1px rgba(0, 0, 0, 0.5);
417
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -2px rgba(0, 0, 0, 0.4);
418
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.6), 0 4px 6px -4px rgba(0, 0, 0, 0.4);
419
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.7), 0 8px 10px -6px rgba(0, 0, 0, 0.4);
420
+ --shadow-focus: 0 0 0 3px color-mix(in srgb, var(--brand-400) 35%, transparent);
421
+
422
+ --color-code-bg: var(--gray-900);
423
+ --color-code-border: var(--gray-800);
424
+ --color-code-text: var(--gray-200);
425
+ }
426
+
427
+ /* "mono" brand needs special treatment in dark so it stays visible */
428
+ [data-theme="dark"][data-brand="mono"] {
429
+ --color-bg-brand: var(--gray-50);
430
+ --color-bg-brand-hover: var(--gray-100);
431
+ --color-bg-brand-active: var(--gray-200);
432
+ --color-text-on-brand: var(--gray-950);
433
+ --color-text-brand: var(--gray-50);
434
+ --color-border-brand: var(--gray-50);
435
+ }
436
+
437
+ /* "teal" anchor (#00CEC8) is too light for white text — force dark text on brand */
438
+ :root[data-brand="teal"] {
439
+ --color-text-on-brand: var(--gray-950);
440
+ }
441
+ [data-theme="dark"][data-brand="teal"] {
442
+ --color-bg-brand: var(--brand-500);
443
+ --color-bg-brand-hover: var(--brand-400);
444
+ --color-bg-brand-active: var(--brand-300);
445
+ --color-text-on-brand: var(--gray-950);
446
+ --color-text-brand: var(--brand-400);
447
+ --color-border-brand: var(--brand-500);
448
+ }
449
+
450
+ /* ═════════════════════════════════════════════════════════
451
+ Tone axis — vivid (flat) · pastel (dusty) · soft (signature)
452
+ `vivid` is the implicit default produced by the primitives
453
+ above. `pastel` and `soft` retune the slate/neutral/stone +
454
+ semantic palettes; `soft` additionally swaps surface model
455
+ (gray page, white floating pills) and shadow stack (layered
456
+ with inset white highlight).
457
+ ═════════════════════════════════════════════════════════ */
458
+
459
+ /* ─── pastel ─────────────────────────────────────────────── */
460
+ [data-tone="pastel"] {
461
+ --slate-50: #F6F7F9; --slate-100: #EBEEF3; --slate-200: #DDE1E9;
462
+ --slate-300: #C1C7D3; --slate-400: #8E96A7; --slate-500: #686F82;
463
+ --slate-600: #4E5667; --slate-700: #3C4250; --slate-800: #272C38;
464
+ --slate-900: #161A24; --slate-950: #0A0D14;
465
+
466
+ --neutral-50: #F8F7F5; --neutral-100: #EFEDEA; --neutral-200: #E0DDD9;
467
+ --neutral-300: #C8C5BF; --neutral-400: #9D9A93; --neutral-500: #757269;
468
+ --neutral-600: #56544D; --neutral-700: #41403A; --neutral-800: #2A2926;
469
+ --neutral-900: #1A1A18; --neutral-950: #0D0D0B;
470
+
471
+ --stone-50: #F8F6F2; --stone-100: #EFECE5; --stone-200: #E1DBD0;
472
+ --stone-300: #CAC2B3; --stone-400: #A19888; --stone-500: #7A7263;
473
+ --stone-600: #5A5447; --stone-700: #443F35; --stone-800: #2B2822;
474
+ --stone-900: #1A1814; --stone-950: #0D0B09;
475
+
476
+ --green-50: #EEF6EF; --green-500: #66A26F; --green-600: #568D5E; --green-700: #45724B;
477
+ --amber-50: #FBF4E1; --amber-400: #D5A741; --amber-500: #C19234; --amber-700: #855F23;
478
+ --red-50: #FAEBEA; --red-500: #BE584F; --red-600: #A8463F; --red-700: #883831;
479
+ }
480
+
481
+ /* pastel · light — warm off-white surfaces, softer shadows */
482
+ [data-tone="pastel"]:not([data-theme="dark"]) {
483
+ --color-bg-primary: #FBFAF7;
484
+ --color-bg-secondary: #F4F2EC;
485
+ --color-bg-tertiary: #EBE8DF;
486
+ --color-bg-page: var(--color-bg-primary);
487
+
488
+ --shadow-xs: 0 1px 2px 0 rgba(50, 47, 38, 0.04);
489
+ --shadow-sm: 0 1px 2px 0 rgba(50, 47, 38, 0.05), 0 1px 1px -1px rgba(50, 47, 38, 0.04);
490
+ --shadow-md: 0 4px 8px -2px rgba(50, 47, 38, 0.06), 0 2px 4px -2px rgba(50, 47, 38, 0.04);
491
+ --shadow-lg: 0 10px 18px -4px rgba(50, 47, 38, 0.08), 0 4px 6px -4px rgba(50, 47, 38, 0.04);
492
+ --shadow-xl: 0 20px 28px -6px rgba(50, 47, 38, 0.10), 0 8px 10px -6px rgba(50, 47, 38, 0.04);
493
+ }
494
+ [data-tone="pastel"][data-gray="stone"]:not([data-theme="dark"]) {
495
+ --color-bg-primary: #FBF9F4;
496
+ --color-bg-secondary: #F3EFE5;
497
+ --color-bg-tertiary: #E9E3D4;
498
+ }
499
+
500
+ /* ─── soft (signature look) ──────────────────────────────── */
501
+ [data-tone="soft"] {
502
+ --slate-50: #F6F7F8; --slate-100: #ECEDF0; --slate-200: #DCDEE3;
503
+ --slate-300: #BCC0C9; --slate-400: #8C92A0; --slate-500: #666C7B;
504
+ --slate-600: #4C5263; --slate-700: #3A3F4D; --slate-800: #262A35;
505
+ --slate-900: #181B23; --slate-950: #0C0E13;
506
+
507
+ --neutral-50: #F7F7F6; --neutral-100: #EDEDEB; --neutral-200: #DEDDDA;
508
+ --neutral-300: #C5C4BF; --neutral-400: #99988F; --neutral-500: #71706A;
509
+ --neutral-600: #555450; --neutral-700: #41403D; --neutral-800: #2A2A28;
510
+ --neutral-900: #1A1A18; --neutral-950: #0D0D0C;
511
+
512
+ --stone-50: #F8F6F2; --stone-100: #F0EDE6; --stone-200: #E2DDD2;
513
+ --stone-300: #CDC5B4; --stone-400: #A09683; --stone-500: #777060;
514
+ --stone-600: #595348; --stone-700: #443F37; --stone-800: #2B2823;
515
+ --stone-900: #1A1815; --stone-950: #0E0C0A;
516
+
517
+ /* soft status ramps — vivid but warm */
518
+ --green-50: #E8F8EF; --green-500: #46B47C; --green-600: #38A06A; --green-700: #2A8054;
519
+ --amber-50: #FFF8E0; --amber-400: #F5BC2E; --amber-500: #E8A716; --amber-700: #9C6E0E;
520
+ --red-50: #FFEDEC; --red-500: #ED5E5B; --red-600: #D6443F; --red-700: #AB3531;
521
+
522
+ /* pill controls */
523
+ --ctrl-radius: 9999px;
524
+ }
525
+
526
+ /* soft · light — gray page, white floating pills, layered shadow w/ inset highlight */
527
+ [data-tone="soft"]:not([data-theme="dark"]) {
528
+ --color-bg-primary: #FFFFFF;
529
+ --color-bg-secondary: #ECEDEF;
530
+ --color-bg-tertiary: #E1E2E6;
531
+ --color-bg-page: #ECEDEF;
532
+
533
+ --color-bg-brand-subtle: color-mix(in srgb, var(--brand-500) 14%, white);
534
+ --color-bg-success: #E8F6EE;
535
+ --color-bg-warning: #FFF6DC;
536
+ --color-bg-danger: #FFE8E6;
537
+ --color-bg-info: #ECF1FF;
538
+
539
+ --color-border-primary: #DCDEE3;
540
+ --color-border-secondary: #E6E8EB;
541
+ --color-border-tertiary: #EFF0F2;
542
+
543
+ /* the signature layered shadows — md/lg/xl carry an inset white top-highlight */
544
+ --shadow-xs: 0 1px 2px 0 rgba(20, 24, 34, 0.04);
545
+ --shadow-sm: 0 1px 2px 0 rgba(20, 24, 34, 0.05),
546
+ 0 1px 3px 0 rgba(20, 24, 34, 0.04);
547
+ --shadow-md: 0 2px 4px -1px rgba(20, 24, 34, 0.05),
548
+ 0 6px 16px -4px rgba(20, 24, 34, 0.08),
549
+ 0 1px 1px 0 rgba(255, 255, 255, 0.65) inset;
550
+ --shadow-lg: 0 4px 6px -2px rgba(20, 24, 34, 0.06),
551
+ 0 12px 24px -8px rgba(20, 24, 34, 0.10),
552
+ 0 1px 1px 0 rgba(255, 255, 255, 0.70) inset;
553
+ --shadow-xl: 0 6px 10px -2px rgba(20, 24, 34, 0.07),
554
+ 0 20px 40px -12px rgba(20, 24, 34, 0.14),
555
+ 0 1px 1px 0 rgba(255, 255, 255, 0.70) inset;
556
+ --shadow-focus: 0 0 0 4px color-mix(in srgb, var(--brand-500) 18%, transparent);
557
+ }
558
+
559
+ [data-tone="soft"][data-theme="dark"] {
560
+ --color-bg-primary: var(--gray-900);
561
+ --color-bg-secondary: var(--gray-950);
562
+ --color-bg-tertiary: var(--gray-800);
563
+ --color-bg-page: var(--gray-950);
564
+
565
+ --shadow-md: 0 2px 4px -1px rgba(0, 0, 0, 0.40),
566
+ 0 6px 16px -4px rgba(0, 0, 0, 0.50),
567
+ 0 1px 0 0 rgba(255, 255, 255, 0.04) inset;
568
+ --shadow-lg: 0 4px 6px -2px rgba(0, 0, 0, 0.45),
569
+ 0 12px 24px -8px rgba(0, 0, 0, 0.60),
570
+ 0 1px 0 0 rgba(255, 255, 255, 0.05) inset;
571
+ }
572
+
573
+ /* ─────────────────────────────────────────────────────────
574
+ Typography scale (rem-based, root = 16px)
575
+ ───────────────────────────────────────────────────────── */
576
+ :root {
577
+ --font-size-xs: 0.75rem; /* 12 */
578
+ --font-size-sm: 0.875rem; /* 14 */
579
+ --font-size-md: 1rem; /* 16 */
580
+ --font-size-lg: 1.125rem; /* 18 */
581
+ --font-size-xl: 1.25rem; /* 20 */
582
+ --font-size-2xl: 1.5rem; /* 24 */
583
+ --font-size-3xl: 1.875rem; /* 30 */
584
+ --font-size-4xl: 2.25rem; /* 36 */
585
+ --font-size-5xl: 3rem; /* 48 */
586
+ --font-size-6xl: 3.75rem; /* 60 */
587
+
588
+ --line-height-tight: 1.15;
589
+ --line-height-snug: 1.3;
590
+ --line-height-normal: 1.5;
591
+ --line-height-relaxed: 1.65;
592
+
593
+ --font-weight-regular: 400;
594
+ --font-weight-medium: 500;
595
+ --font-weight-semibold: 600;
596
+ --font-weight-bold: 700;
597
+
598
+ --letter-tight: -0.022em;
599
+ --letter-snug: -0.012em;
600
+ --letter-normal: 0;
601
+ --letter-wide: 0.04em;
602
+ }
603
+
604
+ /* font pairs — selected via [data-font] */
605
+ :root,
606
+ [data-font="geist"] {
607
+ --font-sans: 'Geist', 'Anuphan', ui-sans-serif, system-ui, -apple-system, sans-serif;
608
+ --font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
609
+ }
610
+ [data-font="plex"] {
611
+ --font-sans: 'IBM Plex Sans', 'IBM Plex Sans Thai Looped', ui-sans-serif, system-ui, sans-serif;
612
+ --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;
613
+ }
614
+ [data-font="system"] {
615
+ --font-sans: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
616
+ --font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
617
+ }
618
+
619
+ /* ─────────────────────────────────────────────────────────
620
+ Spacing scale — base 4px (8px after 4)
621
+ ───────────────────────────────────────────────────────── */
622
+ :root {
623
+ --space-0: 0;
624
+ --space-1: 0.25rem; /* 4 */
625
+ --space-2: 0.5rem; /* 8 */
626
+ --space-3: 0.75rem; /* 12 */
627
+ --space-4: 1rem; /* 16 */
628
+ --space-5: 1.25rem; /* 20 */
629
+ --space-6: 1.5rem; /* 24 */
630
+ --space-8: 2rem; /* 32 */
631
+ --space-10: 2.5rem; /* 40 */
632
+ --space-12: 3rem; /* 48 */
633
+ --space-16: 4rem; /* 64 */
634
+ --space-20: 5rem; /* 80 */
635
+ --space-24: 6rem; /* 96 */
636
+ }
637
+
638
+ /* ─────────────────────────────────────────────────────────
639
+ Radius scale — selected via [data-radius]
640
+ ───────────────────────────────────────────────────────── */
641
+ :root,
642
+ [data-radius="default"] {
643
+ --radius-xs: 2px;
644
+ --radius-sm: 4px;
645
+ --radius-md: 6px;
646
+ --radius-lg: 8px;
647
+ --radius-xl: 12px;
648
+ --radius-2xl: 16px;
649
+ --radius-full: 9999px;
650
+ }
651
+ [data-radius="sharp"] {
652
+ --radius-xs: 0px;
653
+ --radius-sm: 1px;
654
+ --radius-md: 2px;
655
+ --radius-lg: 3px;
656
+ --radius-xl: 4px;
657
+ --radius-2xl: 6px;
658
+ --radius-full: 9999px;
659
+ }
660
+ [data-radius="soft"] {
661
+ --radius-xs: 4px;
662
+ --radius-sm: 8px;
663
+ --radius-md: 12px;
664
+ --radius-lg: 14px;
665
+ --radius-xl: 18px;
666
+ --radius-2xl: 24px;
667
+ --radius-full: 9999px;
668
+ }
669
+ [data-radius="pill"] {
670
+ --radius-xs: 4px;
671
+ --radius-sm: 9999px;
672
+ --radius-md: 9999px;
673
+ --radius-lg: 9999px;
674
+ --radius-xl: 18px;
675
+ --radius-2xl: 22px;
676
+ --radius-full: 9999px;
677
+ }
678
+
679
+ /* ─────────────────────────────────────────────────────────
680
+ Density — affects control sizes, not the spacing scale
681
+ ───────────────────────────────────────────────────────── */
682
+ :root,
683
+ [data-density="default"] {
684
+ --control-h-sm: 28px;
685
+ --control-h-md: 36px;
686
+ --control-h-lg: 44px;
687
+ --control-px-sm: 10px;
688
+ --control-px-md: 14px;
689
+ --control-px-lg: 18px;
690
+ --card-p: 24px;
691
+ --row-gap: 16px;
692
+ }
693
+ [data-density="compact"] {
694
+ --control-h-sm: 24px;
695
+ --control-h-md: 30px;
696
+ --control-h-lg: 38px;
697
+ --control-px-sm: 8px;
698
+ --control-px-md: 12px;
699
+ --control-px-lg: 16px;
700
+ --card-p: 16px;
701
+ --row-gap: 12px;
702
+ }
703
+ [data-density="comfortable"] {
704
+ --control-h-sm: 32px;
705
+ --control-h-md: 42px;
706
+ --control-h-lg: 52px;
707
+ --control-px-sm: 12px;
708
+ --control-px-md: 18px;
709
+ --control-px-lg: 22px;
710
+ --card-p: 32px;
711
+ --row-gap: 20px;
712
+ }
713
+
714
+ /* ─────────────────────────────────────────────────────────
715
+ Layout — 12-column grid, breakpoints, container widths
716
+ ───────────────────────────────────────────────────────── */
717
+ :root {
718
+ --grid-columns: 12;
719
+ --grid-gutter: var(--space-6); /* 24 */
720
+ --grid-gutter-tight: var(--space-4); /* 16 — used below sm */
721
+ --grid-margin: var(--space-6); /* 24 */
722
+ --grid-margin-lg: var(--space-10); /* 40 */
723
+
724
+ --breakpoint-sm: 640px;
725
+ --breakpoint-md: 768px;
726
+ --breakpoint-lg: 1024px;
727
+ --breakpoint-xl: 1280px;
728
+
729
+ --container-sm: 640px;
730
+ --container-md: 768px;
731
+ --container-lg: 1024px;
732
+ --container-xl: 1140px;
733
+ --container-prose: 1080px;
734
+ }
735
+
736
+ /* ─────────────────────────────────────────────────────────
737
+ Motion
738
+ ───────────────────────────────────────────────────────── */
739
+ :root {
740
+ --duration-instant: 50ms;
741
+ --duration-fast: 120ms;
742
+ --duration-normal: 200ms;
743
+ --duration-slow: 320ms;
744
+ --duration-slower: 500ms;
745
+
746
+ --ease-linear: linear;
747
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
748
+ --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
749
+ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
750
+ }