@mindlogic-ai/logician-ui 3.1.0-alpha.10 → 3.1.0-alpha.11

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.
@@ -33,32 +33,6 @@
33
33
  * @see https://www.w3.org/TR/WCAG21/#contrast-minimum
34
34
  * @version 3.0.0
35
35
  */
36
- /**
37
- * Semantic color tokens that map primitive colors to UI intent.
38
- *
39
- * Use these tokens in components instead of raw color values:
40
- * - `primary.*`: Buttons, links, focus states
41
- * - `secondary.*`: Accent elements, highlights
42
- * - `success.*`: Success messages, confirmations
43
- * - `warning.*`: Warning messages, caution states
44
- * - `danger.*`: Error messages, destructive actions
45
- *
46
- * Each category includes:
47
- * - `lightest`: Lightest backgrounds (ghost states, very subtle fills)
48
- * - `extralight`: Extra-light backgrounds (badges, subtle fills)
49
- * - `lighter`: Light backgrounds (toast backgrounds, subtle fills)
50
- * - `light`: Medium backgrounds (hover states, medium fills)
51
- * - `main`: Primary color (buttons, text, icons)
52
- * - `dark`: Dark variant (text on light backgrounds)
53
- * - `darker`: Darkest variant (high-contrast text)
54
- *
55
- * @example
56
- * ```tsx
57
- * <Button bgColor="primary.main" />
58
- * <Alert bgColor="danger.lighter" color="danger.dark" />
59
- * <Badge bgColor="success.lightest" color="success.dark" />
60
- * ```
61
- */
62
36
  export declare const semanticTokens: {
63
37
  readonly colors: {
64
38
  /**
@@ -117,6 +91,18 @@ export declare const semanticTokens: {
117
91
  readonly _dark: "{colors.blue.100}";
118
92
  };
119
93
  };
94
+ readonly fill: {
95
+ readonly value: {
96
+ readonly base: "{colors.blue.500}";
97
+ readonly _dark: "{colors.blue.700}";
98
+ };
99
+ };
100
+ readonly fillStrong: {
101
+ readonly value: {
102
+ readonly base: "{colors.blue.700}";
103
+ readonly _dark: "{colors.blue.800}";
104
+ };
105
+ };
120
106
  };
121
107
  /**
122
108
  * Secondary colors (Violet-based)
@@ -329,6 +315,130 @@ export declare const semanticTokens: {
329
315
  };
330
316
  };
331
317
  };
318
+ /**
319
+ * Neutral tone ramp — a mode-aware companion to the raw `gray.*` primitives.
320
+ *
321
+ * Each `slate.N` resolves to `gray.N` in light and to the desaturated
322
+ * counterpart of the *mirrored* step in dark, so a single token carries the
323
+ * same visual role in both modes (e.g. `slate.300` is a light divider in
324
+ * light and the equivalent dark divider in dark — no `_dark={{…}}` needed at
325
+ * the call site).
326
+ *
327
+ * @deprecated **Migration shim, not a blessed vocabulary.** `slate.*` exists
328
+ * to give code currently styling neutrals with a raw mode-aware ramp a
329
+ * lossless landing spot, and to be codemodded onto the `fg`/`bg`/`border`
330
+ * role tokens (e.g. `slate.200`→`border.subtle`, `slate.900`→`fg.muted`,
331
+ * `slate.800`→`fg.default`). **Do not reach for `slate.*` in new code** —
332
+ * use a role token. This ramp is slated for removal once consumers migrate.
333
+ *
334
+ * `600`/`700` are lifted off the straight mirror (#8E939F/#7C818D) so the
335
+ * secondary/muted text they most often carry clears WCAG AA 4.5:1 on the
336
+ * dark canvas/surface — the straight mirrors measured ~3.0–3.9 there.
337
+ */
338
+ readonly slate: {
339
+ readonly 0: {
340
+ readonly value: {
341
+ readonly base: "{colors.gray.0}";
342
+ readonly _dark: "#0E1014";
343
+ };
344
+ };
345
+ readonly 50: {
346
+ readonly value: {
347
+ readonly base: "{colors.gray.50}";
348
+ readonly _dark: "#181A20";
349
+ };
350
+ };
351
+ readonly 100: {
352
+ readonly value: {
353
+ readonly base: "{colors.gray.100}";
354
+ readonly _dark: "#23262E";
355
+ };
356
+ };
357
+ readonly 200: {
358
+ readonly value: {
359
+ readonly base: "{colors.gray.200}";
360
+ readonly _dark: "#30343C";
361
+ };
362
+ };
363
+ readonly 300: {
364
+ readonly value: {
365
+ readonly base: "{colors.gray.300}";
366
+ readonly _dark: "#3C404B";
367
+ };
368
+ };
369
+ readonly 400: {
370
+ readonly value: {
371
+ readonly base: "{colors.gray.400}";
372
+ readonly _dark: "#4A4E5A";
373
+ };
374
+ };
375
+ readonly 500: {
376
+ readonly value: {
377
+ readonly base: "{colors.gray.500}";
378
+ readonly _dark: "#595E6B";
379
+ };
380
+ };
381
+ readonly 600: {
382
+ readonly value: {
383
+ readonly base: "{colors.gray.600}";
384
+ readonly _dark: "#898E99";
385
+ };
386
+ };
387
+ readonly 700: {
388
+ readonly value: {
389
+ readonly base: "{colors.gray.700}";
390
+ readonly _dark: "#8D919D";
391
+ };
392
+ };
393
+ readonly 800: {
394
+ readonly value: {
395
+ readonly base: "{colors.gray.800}";
396
+ readonly _dark: "#8E939F";
397
+ };
398
+ };
399
+ readonly 900: {
400
+ readonly value: {
401
+ readonly base: "{colors.gray.900}";
402
+ readonly _dark: "#A2A6B1";
403
+ };
404
+ };
405
+ readonly 1000: {
406
+ readonly value: {
407
+ readonly base: "{colors.gray.1000}";
408
+ readonly _dark: "#B6BAC3";
409
+ };
410
+ };
411
+ readonly 1100: {
412
+ readonly value: {
413
+ readonly base: "{colors.gray.1100}";
414
+ readonly _dark: "#D2D5DB";
415
+ };
416
+ };
417
+ readonly 1200: {
418
+ readonly value: {
419
+ readonly base: "{colors.gray.1200}";
420
+ readonly _dark: "#E5E8EC";
421
+ };
422
+ };
423
+ readonly 1300: {
424
+ readonly value: {
425
+ readonly base: "{colors.gray.1300}";
426
+ readonly _dark: "#F2F4F7";
427
+ };
428
+ };
429
+ readonly 1400: {
430
+ readonly value: {
431
+ readonly base: "{colors.gray.1400}";
432
+ readonly _dark: "#F8F9FB";
433
+ };
434
+ };
435
+ readonly 1500: {
436
+ readonly value: {
437
+ readonly base: "{colors.gray.1500}";
438
+ readonly _dark: "#FEFEFF";
439
+ };
440
+ };
441
+ };
332
442
  /**
333
443
  * Neutral background tokens — map onto the gray.0–1500 scale.
334
444
  * Use for: page/canvas, raised surfaces (cards, menus), subtle/muted fills,
@@ -341,46 +451,58 @@ export declare const semanticTokens: {
341
451
  * - inverse: high-contrast surface (flips to light in dark mode)
342
452
  */
343
453
  readonly bg: {
454
+ readonly DEFAULT: {
455
+ readonly value: {
456
+ readonly _light: "{colors.white}";
457
+ readonly _dark: "#0E1014";
458
+ };
459
+ };
344
460
  readonly canvas: {
345
461
  readonly value: {
346
462
  readonly base: "{colors.gray.0}";
347
- readonly _dark: "{colors.gray.1500}";
463
+ readonly _dark: "#0E1014";
348
464
  };
349
465
  };
350
466
  readonly surface: {
351
467
  readonly value: {
352
468
  readonly base: "{colors.white}";
353
- readonly _dark: "{colors.gray.1400}";
469
+ readonly _dark: "#181A20";
354
470
  };
355
471
  };
356
472
  readonly raised: {
357
473
  readonly value: {
358
474
  readonly base: "{colors.white}";
359
- readonly _dark: "{colors.gray.1100}";
475
+ readonly _dark: "#3C404B";
360
476
  };
361
477
  };
362
478
  readonly subtle: {
363
479
  readonly value: {
364
480
  readonly base: "{colors.gray.50}";
365
- readonly _dark: "{colors.gray.1300}";
481
+ readonly _dark: "#23262E";
366
482
  };
367
483
  };
368
484
  readonly muted: {
369
485
  readonly value: {
370
486
  readonly base: "{colors.gray.100}";
371
- readonly _dark: "{colors.gray.1200}";
487
+ readonly _dark: "#30343C";
372
488
  };
373
489
  };
374
490
  readonly inverse: {
375
491
  readonly value: {
376
492
  readonly base: "{colors.gray.1300}";
377
- readonly _dark: "{colors.gray.50}";
493
+ readonly _dark: "#F8F9FB";
494
+ };
495
+ };
496
+ readonly sunken: {
497
+ readonly value: {
498
+ readonly base: "{colors.gray.50}";
499
+ readonly _dark: "#0E1014";
378
500
  };
379
501
  };
380
502
  readonly panel: {
381
503
  readonly value: {
382
504
  readonly base: "{colors.white}";
383
- readonly _dark: "{colors.gray.1400}";
505
+ readonly _dark: "#181A20";
384
506
  };
385
507
  };
386
508
  /**
@@ -423,28 +545,40 @@ export declare const semanticTokens: {
423
545
  * - inverse: text on inverse surfaces (flips with mode)
424
546
  */
425
547
  readonly fg: {
426
- readonly default: {
548
+ readonly DEFAULT: {
549
+ readonly value: {
550
+ readonly _light: "{colors.black}";
551
+ readonly _dark: "#F8F9FB";
552
+ };
553
+ };
554
+ readonly emphasized: {
427
555
  readonly value: {
428
556
  readonly base: "{colors.gray.1300}";
429
- readonly _dark: "{colors.gray.200}";
557
+ readonly _dark: "#E5E8EC";
558
+ };
559
+ };
560
+ readonly default: {
561
+ readonly value: {
562
+ readonly base: "{colors.gray.1000}";
563
+ readonly _dark: "#D2D5DB";
430
564
  };
431
565
  };
432
566
  readonly muted: {
433
567
  readonly value: {
434
568
  readonly base: "{colors.gray.900}";
435
- readonly _dark: "{colors.gray.300}";
569
+ readonly _dark: "#B6BAC3";
436
570
  };
437
571
  };
438
572
  readonly subtle: {
439
573
  readonly value: {
440
574
  readonly base: "{colors.gray.700}";
441
- readonly _dark: "{colors.gray.600}";
575
+ readonly _dark: "#989DA9";
442
576
  };
443
577
  };
444
578
  readonly inverse: {
445
579
  readonly value: {
446
580
  readonly base: "{colors.gray.0}";
447
- readonly _dark: "{colors.gray.1400}";
581
+ readonly _dark: "#181A20";
448
582
  };
449
583
  };
450
584
  };
@@ -456,22 +590,28 @@ export declare const semanticTokens: {
456
590
  * - strong: high-emphasis borders, focus outlines on neutral
457
591
  */
458
592
  readonly border: {
593
+ readonly DEFAULT: {
594
+ readonly value: {
595
+ readonly _light: "{colors.gray.200}";
596
+ readonly _dark: "#6A6F7C";
597
+ };
598
+ };
459
599
  readonly default: {
460
600
  readonly value: {
461
601
  readonly base: "{colors.gray.300}";
462
- readonly _dark: "{colors.gray.1100}";
602
+ readonly _dark: "#3C404B";
463
603
  };
464
604
  };
465
605
  readonly subtle: {
466
606
  readonly value: {
467
607
  readonly base: "{colors.gray.200}";
468
- readonly _dark: "{colors.gray.1300}";
608
+ readonly _dark: "#23262E";
469
609
  };
470
610
  };
471
611
  readonly strong: {
472
612
  readonly value: {
473
613
  readonly base: "{colors.gray.500}";
474
- readonly _dark: "{colors.gray.900}";
614
+ readonly _dark: "#595E6B";
475
615
  };
476
616
  };
477
617
  };
@@ -485,11 +625,12 @@ export declare const semanticTokens: {
485
625
  * by reviewers. It is intentionally hand-maintained alongside `semanticTokens`
486
626
  * so a rename here is a visible, reviewable diff.
487
627
  *
488
- * Note: `bg.panel` is deliberately omitted it is an internal realignment of a
489
- * Chakra default (for overlay surfaces), not part of the public migration
490
- * contract. App code should use `bg.surface`/`bg.canvas`.
628
+ * Note: `bg.panel` and the bare `bg`/`fg`/`border` DEFAULT tokens are
629
+ * deliberately omitted they are internal realignments of Chakra defaults
630
+ * (overlay surfaces and html-level globals), not part of the public migration
631
+ * contract. App code should use `bg.surface`/`bg.canvas`, `fg.default`, etc.
491
632
  */
492
- export type SemanticColorToken = `bg.${'canvas' | 'surface' | 'raised' | 'subtle' | 'muted' | 'inverse' | 'selected' | 'highlighted'}` | 'bg.invalid.subtle' | `fg.${'default' | 'muted' | 'subtle' | 'inverse'}` | `border.${'default' | 'subtle' | 'strong'}` | `${'primary' | 'secondary' | 'danger' | 'success' | 'warning'}.${'lightest' | 'extralight' | 'lighter' | 'light' | 'main' | 'dark' | 'darker'}`;
633
+ export type SemanticColorToken = `bg.${'canvas' | 'surface' | 'raised' | 'subtle' | 'muted' | 'sunken' | 'inverse' | 'selected' | 'highlighted'}` | 'bg.invalid.subtle' | `fg.${'emphasized' | 'default' | 'muted' | 'subtle' | 'inverse'}` | `border.${'default' | 'subtle' | 'strong'}` | `slate.${0 | 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 1000 | 1100 | 1200 | 1300 | 1400 | 1500}` | `primary.${'fill' | 'fillStrong'}` | `${'primary' | 'secondary' | 'danger' | 'success' | 'warning'}.${'lightest' | 'extralight' | 'lighter' | 'light' | 'main' | 'dark' | 'darker'}`;
493
634
  /**
494
635
  * Primitive color palette following the Golden Ratio system.
495
636
  *
@@ -1 +1 @@
1
- {"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../../src/theme/colors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,cAAc;;QAEvB;;;;;;;;;;;;WAYG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyBH;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA6BH;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyBH;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyBH;;;;;;;;;;WAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyBH;;;;;;;;;;WAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAoCD;;;;;;;;;eASG;;;;;;;;;;;;;;;;;;;;;;QAcL;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyBH;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;CAaG,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,GAC1B,MACI,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,SAAS,GACT,UAAU,GACV,aAAa,EAAE,GACnB,mBAAmB,GACnB,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,EAAE,GAClD,UAAU,SAAS,GAAG,QAAQ,GAAG,QAAQ,EAAE,GAC3C,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,IACzD,UAAU,GACV,YAAY,GACZ,SAAS,GACT,OAAO,GACP,MAAM,GACN,MAAM,GACN,QAAQ,EAAE,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,MAAM;IACjB;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;;;;;;;;OAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqBH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAaH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAaH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBJ,CAAC"}
1
+ {"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../../src/theme/colors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AA2DH,eAAO,MAAM,cAAc;;QAEvB;;;;;;;;;;;;WAYG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqCH;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA6BH;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyBH;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyBH;;;;;;;;;;WAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyBH;;;;;;;;;;;;;;;;;;;WAmBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA+CH;;;;;;;;;;WAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAoDD;;;;;;;;;eASG;;;;;;;;;;;;;;;;;;;;;;QAcL;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyCH;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoBG,CAAC;AAEX;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,kBAAkB,GAC1B,MACI,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,UAAU,GACV,aAAa,EAAE,GACnB,mBAAmB,GACnB,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,EAAE,GACjE,UAAU,SAAS,GAAG,QAAQ,GAAG,QAAQ,EAAE,GAI3C,SACI,CAAC,GACD,EAAE,GACF,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,EAAE,GACV,WAAW,MAAM,GAAG,YAAY,EAAE,GAClC,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,IACzD,UAAU,GACV,YAAY,GACZ,SAAS,GACT,OAAO,GACP,MAAM,GACN,MAAM,GACN,QAAQ,EAAE,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,MAAM;IACjB;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcH;;;;;;;;;;OAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqBH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAaH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAaH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBJ,CAAC"}
@@ -62,6 +62,35 @@
62
62
  * <Badge bgColor="success.lightest" color="success.dark" />
63
63
  * ```
64
64
  */
65
+ /**
66
+ * Halved-saturation counterpart of each primitive `gray.N` — same hue and
67
+ * lightness, HSL saturation cut by ~50% (e.g. `gray.1300` #1E2433 @ 26% →
68
+ * #23262E @ 13%). The blue-tinted `gray` ramp reads as the right neutral in
69
+ * light mode but turns muddy/over-chromatic as a dark surface, so every
70
+ * dark-mode neutral below (`slate.*`, and the `_dark` of `bg`/`fg`/`border`)
71
+ * resolves to this desaturated mirror instead of the raw `gray` step. Light
72
+ * mode is untouched — it keeps referencing `{colors.gray.*}` verbatim.
73
+ *
74
+ * Single source of truth: change a dark neutral here, not at each token.
75
+ */
76
+ const desaturatedGray = {
77
+ 0: '#FEFEFF',
78
+ 50: '#F8F9FB',
79
+ 100: '#F2F4F7',
80
+ 200: '#E5E8EC',
81
+ 300: '#D2D5DB',
82
+ 400: '#B6BAC3',
83
+ 500: '#A2A6B1',
84
+ 600: '#8E939F',
85
+ 800: '#6A6F7C',
86
+ 900: '#595E6B',
87
+ 1000: '#4A4E5A',
88
+ 1100: '#3C404B',
89
+ 1200: '#30343C',
90
+ 1300: '#23262E',
91
+ 1400: '#181A20',
92
+ 1500: '#0E1014',
93
+ };
65
94
  const semanticTokens = {
66
95
  colors: {
67
96
  /**
@@ -99,6 +128,18 @@ const semanticTokens = {
99
128
  darker: {
100
129
  value: { base: '{colors.blue.900}', _dark: '{colors.blue.100}' },
101
130
  }, // high-contrast text
131
+ // Solid brand-blue *fills* for surfaces with white text/icons on top
132
+ // (modal headers, hero/banner gradients, brand badges). `primary.main`/
133
+ // `primary.dark` lighten ~2 stops in dark — right for foreground, too
134
+ // light as a fill — so these stay a deep blue in dark instead. `base`
135
+ // repeats the old main/dark values, so light is unchanged. Bare accents
136
+ // (dots, progress bars) keep `primary.main`.
137
+ fill: {
138
+ value: { base: '{colors.blue.500}', _dark: '{colors.blue.700}' },
139
+ },
140
+ fillStrong: {
141
+ value: { base: '{colors.blue.700}', _dark: '{colors.blue.800}' },
142
+ },
102
143
  },
103
144
  /**
104
145
  * Secondary colors (Violet-based)
@@ -231,6 +272,71 @@ const semanticTokens = {
231
272
  value: { base: '{colors.gold.900}', _dark: '{colors.gold.100}' },
232
273
  },
233
274
  },
275
+ /**
276
+ * Neutral tone ramp — a mode-aware companion to the raw `gray.*` primitives.
277
+ *
278
+ * Each `slate.N` resolves to `gray.N` in light and to the desaturated
279
+ * counterpart of the *mirrored* step in dark, so a single token carries the
280
+ * same visual role in both modes (e.g. `slate.300` is a light divider in
281
+ * light and the equivalent dark divider in dark — no `_dark={{…}}` needed at
282
+ * the call site).
283
+ *
284
+ * @deprecated **Migration shim, not a blessed vocabulary.** `slate.*` exists
285
+ * to give code currently styling neutrals with a raw mode-aware ramp a
286
+ * lossless landing spot, and to be codemodded onto the `fg`/`bg`/`border`
287
+ * role tokens (e.g. `slate.200`→`border.subtle`, `slate.900`→`fg.muted`,
288
+ * `slate.800`→`fg.default`). **Do not reach for `slate.*` in new code** —
289
+ * use a role token. This ramp is slated for removal once consumers migrate.
290
+ *
291
+ * `600`/`700` are lifted off the straight mirror (#8E939F/#7C818D) so the
292
+ * secondary/muted text they most often carry clears WCAG AA 4.5:1 on the
293
+ * dark canvas/surface — the straight mirrors measured ~3.0–3.9 there.
294
+ */
295
+ slate: {
296
+ 0: { value: { base: '{colors.gray.0}', _dark: desaturatedGray[1500] } },
297
+ 50: { value: { base: '{colors.gray.50}', _dark: desaturatedGray[1400] } },
298
+ 100: {
299
+ value: { base: '{colors.gray.100}', _dark: desaturatedGray[1300] },
300
+ },
301
+ 200: {
302
+ value: { base: '{colors.gray.200}', _dark: desaturatedGray[1200] },
303
+ },
304
+ 300: {
305
+ value: { base: '{colors.gray.300}', _dark: desaturatedGray[1100] },
306
+ },
307
+ 400: {
308
+ value: { base: '{colors.gray.400}', _dark: desaturatedGray[1000] },
309
+ },
310
+ 500: {
311
+ value: { base: '{colors.gray.500}', _dark: desaturatedGray[900] },
312
+ },
313
+ 600: { value: { base: '{colors.gray.600}', _dark: '#898E99' } },
314
+ 700: { value: { base: '{colors.gray.700}', _dark: '#8D919D' } },
315
+ 800: {
316
+ value: { base: '{colors.gray.800}', _dark: desaturatedGray[600] },
317
+ },
318
+ 900: {
319
+ value: { base: '{colors.gray.900}', _dark: desaturatedGray[500] },
320
+ },
321
+ 1000: {
322
+ value: { base: '{colors.gray.1000}', _dark: desaturatedGray[400] },
323
+ },
324
+ 1100: {
325
+ value: { base: '{colors.gray.1100}', _dark: desaturatedGray[300] },
326
+ },
327
+ 1200: {
328
+ value: { base: '{colors.gray.1200}', _dark: desaturatedGray[200] },
329
+ },
330
+ 1300: {
331
+ value: { base: '{colors.gray.1300}', _dark: desaturatedGray[100] },
332
+ },
333
+ 1400: {
334
+ value: { base: '{colors.gray.1400}', _dark: desaturatedGray[50] },
335
+ },
336
+ 1500: {
337
+ value: { base: '{colors.gray.1500}', _dark: desaturatedGray[0] },
338
+ },
339
+ },
234
340
  /**
235
341
  * Neutral background tokens — map onto the gray.0–1500 scale.
236
342
  * Use for: page/canvas, raised surfaces (cards, menus), subtle/muted fills,
@@ -243,11 +349,19 @@ const semanticTokens = {
243
349
  * - inverse: high-contrast surface (flips to light in dark mode)
244
350
  */
245
351
  bg: {
352
+ // Chakra's own global css paints `html { background: bg }` — the *plain*
353
+ // `bg` token, not `bg.canvas` — so this is the actual page background
354
+ // wherever no component paints over it. `_light` is pure white (Chakra's
355
+ // value, so light is untouched); `_dark` rejoins our neutral floor instead
356
+ // of Chakra's off-palette black.
357
+ DEFAULT: {
358
+ value: { _light: '{colors.white}', _dark: desaturatedGray[1500] },
359
+ },
246
360
  canvas: {
247
- value: { base: '{colors.gray.0}', _dark: '{colors.gray.1500}' },
361
+ value: { base: '{colors.gray.0}', _dark: desaturatedGray[1500] },
248
362
  },
249
363
  surface: {
250
- value: { base: '{colors.white}', _dark: '{colors.gray.1400}' },
364
+ value: { base: '{colors.white}', _dark: desaturatedGray[1400] },
251
365
  },
252
366
  // Strongly-raised neutral surface — one level above `surface` (e.g. the
253
367
  // selected thumb of a SegmentedControl). In dark this is the *lightest*
@@ -259,23 +373,31 @@ const semanticTokens = {
259
373
  // cannot be overridden via semanticTokens in this setup (it keeps
260
374
  // resolving to Chakra's own gray.200), whereas a fresh name is honoured.
261
375
  raised: {
262
- value: { base: '{colors.white}', _dark: '{colors.gray.1100}' },
376
+ value: { base: '{colors.white}', _dark: desaturatedGray[1100] },
263
377
  },
264
378
  subtle: {
265
- value: { base: '{colors.gray.50}', _dark: '{colors.gray.1300}' },
379
+ value: { base: '{colors.gray.50}', _dark: desaturatedGray[1300] },
266
380
  },
267
381
  muted: {
268
- value: { base: '{colors.gray.100}', _dark: '{colors.gray.1200}' },
382
+ value: { base: '{colors.gray.100}', _dark: desaturatedGray[1200] },
269
383
  },
270
384
  inverse: {
271
- value: { base: '{colors.gray.1300}', _dark: '{colors.gray.50}' },
385
+ value: { base: '{colors.gray.1300}', _dark: desaturatedGray[50] },
386
+ },
387
+ // Sunken page wash for list/overview surfaces: a gray floor in light so
388
+ // `bg.surface` cards read as raised above it. In dark the `bg.*` ramp is
389
+ // compressed (`subtle` sits *lighter* than `surface`), which would invert
390
+ // that elevation — so the dark value drops to the canvas floor instead.
391
+ // Component-level fills (hover, chips, inner blocks) keep using `bg.subtle`.
392
+ sunken: {
393
+ value: { base: '{colors.gray.50}', _dark: desaturatedGray[1500] },
272
394
  },
273
395
  // Override Chakra's default `bg.panel` (whose `_dark` resolves to Chakra's
274
396
  // own gray.950 = #111111, off our slate palette). Light value is white —
275
397
  // identical to Chakra's default — so this only realigns dark overlay
276
398
  // surfaces (Menu / Modal / Popover / Toast) onto our gray scale.
277
399
  panel: {
278
- value: { base: '{colors.white}', _dark: '{colors.gray.1400}' },
400
+ value: { base: '{colors.white}', _dark: desaturatedGray[1400] },
279
401
  },
280
402
  /**
281
403
  * Row/selection state tints. Use these for selected rows,
@@ -308,26 +430,42 @@ const semanticTokens = {
308
430
  * - inverse: text on inverse surfaces (flips with mode)
309
431
  */
310
432
  fg: {
433
+ // Plain `fg` is Chakra's html-level text color (`html { color: fg }`).
434
+ // `_light` repeats Chakra's value (black); `_dark` rejoins our desaturated
435
+ // neutral so legacy html-level text tracks `fg.default`.
436
+ DEFAULT: {
437
+ value: { _light: '{colors.black}', _dark: desaturatedGray[50] },
438
+ },
439
+ // Strongest text — headings, titles, key figures, emphasis. This is the
440
+ // near-black step that `fg.default` used to be; `default` is now re-pegged
441
+ // to a lighter body weight (see below), so reach for `emphasized` when you
442
+ // specifically want maximum contrast.
443
+ emphasized: {
444
+ value: { base: '{colors.gray.1300}', _dark: desaturatedGray[200] },
445
+ },
311
446
  default: {
312
- // _dark is gray.200 (not gray.50): near-white text on the dark canvas
313
- // ran ~18:1 brighter than the light baseline (~15:1) and close to pure
314
- // white, which causes glare/halation. gray.200 matches the light
315
- // contrast (~15.4:1) while staying AAA.
316
- value: { base: '{colors.gray.1300}', _dark: '{colors.gray.200}' },
447
+ // Primary *body* text. Re-pegged from gray.1300 gray.1000: near-black
448
+ // (gray.1300, ~14:1 on white) is unusually heavy for running copy, and
449
+ // real product usage clustered well below it. gray.1000 (~9:1) is a
450
+ // comfortable AAA body weight; the old near-black step lives on as
451
+ // `fg.emphasized`. _dark drops one step from emphasized for hierarchy.
452
+ value: { base: '{colors.gray.1000}', _dark: desaturatedGray[300] },
317
453
  },
318
454
  muted: {
319
- // _dark lifts gray.400 gray.300: secondary text read as too dim on the
320
- // dark canvas next to fg.default (gray.200). gray.300 sits one step under
321
- // default — restoring the light-mode hierarchy gap — while staying well
322
- // clear of AA (~12.8:1 on bg.canvas, ~11.7:1 on bg.surface). Light value
323
- // (gray.900) is unchanged.
324
- value: { base: '{colors.gray.900}', _dark: '{colors.gray.300}' },
455
+ // Secondary text. _dark sits one step below `default` (~9.5:1 on the dark
456
+ // canvas) to keep the default→muted hierarchy gap. Light value (gray.900)
457
+ // is unchanged.
458
+ value: { base: '{colors.gray.900}', _dark: desaturatedGray[400] },
325
459
  },
326
460
  subtle: {
327
- value: { base: '{colors.gray.700}', _dark: '{colors.gray.600}' },
461
+ // Tertiary / placeholder / icon text. _dark a11y-bumped from the straight
462
+ // mirror (desaturatedGray[600] #8E939F, ~4.06:1 on bg.muted) to #989DA9
463
+ // (~4.6:1) so it clears AA while staying below fg.muted. Light value
464
+ // (gray.700) is unchanged.
465
+ value: { base: '{colors.gray.700}', _dark: '#989DA9' },
328
466
  },
329
467
  inverse: {
330
- value: { base: '{colors.gray.0}', _dark: '{colors.gray.1400}' },
468
+ value: { base: '{colors.gray.0}', _dark: desaturatedGray[1400] },
331
469
  },
332
470
  },
333
471
  /**
@@ -338,14 +476,21 @@ const semanticTokens = {
338
476
  * - strong: high-emphasis borders, focus outlines on neutral
339
477
  */
340
478
  border: {
479
+ // Plain `border` feeds Chakra's `--global-color-border` (the implicit
480
+ // default border color). Not a text color, so its `_dark` takes the
481
+ // straight halved-saturation mirror (no a11y bump). `_light` repeats
482
+ // Chakra's value so light is untouched.
483
+ DEFAULT: {
484
+ value: { _light: '{colors.gray.200}', _dark: desaturatedGray[800] },
485
+ },
341
486
  default: {
342
- value: { base: '{colors.gray.300}', _dark: '{colors.gray.1100}' },
487
+ value: { base: '{colors.gray.300}', _dark: desaturatedGray[1100] },
343
488
  },
344
489
  subtle: {
345
- value: { base: '{colors.gray.200}', _dark: '{colors.gray.1300}' },
490
+ value: { base: '{colors.gray.200}', _dark: desaturatedGray[1300] },
346
491
  },
347
492
  strong: {
348
- value: { base: '{colors.gray.500}', _dark: '{colors.gray.900}' },
493
+ value: { base: '{colors.gray.500}', _dark: desaturatedGray[900] },
349
494
  },
350
495
  },
351
496
  },