kaze-design-system 0.8.0 → 0.9.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.
Files changed (66) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/README.md +46 -4
  3. package/components.css +243 -164
  4. package/core.css +9 -0
  5. package/dist/components/Avatar/Avatar.js +2 -2
  6. package/dist/components/BarChart/BarChart.js +27 -19
  7. package/dist/components/BarList/BarList.js +10 -2
  8. package/dist/components/Checkbox/Checkbox.js +12 -2
  9. package/dist/components/ColumnChart/ColumnChart.js +5 -17
  10. package/dist/components/CommandPalette/CommandPalette.js +89 -45
  11. package/dist/components/Dialog/Dialog.js +47 -27
  12. package/dist/components/Disclosure/Disclosure.js +7 -6
  13. package/dist/components/DonutChart/DonutChart.js +69 -53
  14. package/dist/components/Dropdown/Dropdown.js +141 -125
  15. package/dist/components/FAQ/FAQ.js +11 -5
  16. package/dist/components/FormField/FormField.js +32 -14
  17. package/dist/components/Heatmap/Heatmap.js +11 -1
  18. package/dist/components/Icon/Icon.js +2 -12
  19. package/dist/components/Input/Input.js +5 -3
  20. package/dist/components/LineChart/LineChart.js +6 -17
  21. package/dist/components/NumberField/NumberField.js +62 -31
  22. package/dist/components/Pagination/Pagination.js +6 -3
  23. package/dist/components/Radio/Radio.js +24 -6
  24. package/dist/components/Search/Search.js +54 -38
  25. package/dist/components/Select/Select.js +5 -3
  26. package/dist/components/Sidebar/Sidebar.js +10 -4
  27. package/dist/components/Sparkline/Sparkline.js +6 -1
  28. package/dist/components/Stepper/Stepper.js +38 -24
  29. package/dist/components/Table/Table.js +1 -10
  30. package/dist/components/Tabs/Tabs.js +30 -5
  31. package/dist/components/Textarea/Textarea.js +5 -3
  32. package/dist/components/Toast/Toast.js +189 -111
  33. package/dist/components/Tooltip/Tooltip.js +109 -60
  34. package/dist/components/Tracker/Tracker.js +33 -17
  35. package/dist/components/_internal/aria.js +11 -0
  36. package/dist/hooks/ThemeScript.js +8 -0
  37. package/dist/hooks/useFocusTrap.js +25 -23
  38. package/dist/hooks.js +2 -0
  39. package/dist/lib/composeEventHandlers.js +9 -0
  40. package/dist/lib/jaText.js +21 -0
  41. package/dist/lib/useChartWidth.js +28 -0
  42. package/dist/types/components/Checkbox/Checkbox.d.ts +2 -0
  43. package/dist/types/components/CommandPalette/CommandPalette.d.ts +4 -0
  44. package/dist/types/components/Dropdown/Dropdown.d.ts +7 -1
  45. package/dist/types/components/FAQ/FAQ.d.ts +3 -0
  46. package/dist/types/components/FormField/FormField.d.ts +1 -1
  47. package/dist/types/components/NumberField/NumberField.d.ts +9 -2
  48. package/dist/types/components/Pagination/Pagination.d.ts +2 -0
  49. package/dist/types/components/Search/Search.d.ts +4 -1
  50. package/dist/types/components/Sidebar/Sidebar.d.ts +4 -1
  51. package/dist/types/components/Sparkline/Sparkline.d.ts +5 -0
  52. package/dist/types/components/Toast/Toast.d.ts +6 -1
  53. package/dist/types/components/Tooltip/Tooltip.d.ts +5 -1
  54. package/dist/types/components/Tracker/Tracker.d.ts +1 -1
  55. package/dist/types/components/_internal/aria.d.ts +9 -0
  56. package/dist/types/hooks/ThemeScript.d.ts +15 -0
  57. package/dist/types/hooks/index.d.ts +2 -0
  58. package/dist/types/lib/composeEventHandlers.d.ts +8 -0
  59. package/dist/types/lib/jaText.d.ts +22 -0
  60. package/dist/types/lib/useChartWidth.d.ts +14 -0
  61. package/dist/utils/scrollLock.js +9 -0
  62. package/kaze.css +13 -10
  63. package/package.json +10 -3
  64. package/reset.css +13 -1
  65. package/tokens.css +43 -20
  66. package/utilities.css +6 -0
package/components.css CHANGED
@@ -1,3 +1,8 @@
1
+ /* Wrapped in @layer kaze.components so the file stays layered when imported on
2
+ its own (e.g. `import "kaze-design-system/css/components"`). The `kaze` parent
3
+ layer keeps these rules out of Tailwind's `components` / `utilities` layers.
4
+ Unlayered author styles always win over these rules. */
5
+ @layer kaze.components {
1
6
  /* ============================================================
2
7
  Kaze (風) Design System — Components
3
8
  Minimal, composable UI components
@@ -303,19 +308,33 @@
303
308
  }
304
309
 
305
310
  .input::placeholder {
306
- color: var(--color-fg-tertiary);
311
+ color: var(--color-fg-placeholder);
307
312
  }
308
313
 
309
- .input:focus {
314
+ .input:focus-visible {
310
315
  border-color: var(--color-border-strong);
311
- box-shadow: 0 0 0 var(--ring-width) var(--ring-color);
316
+ outline: var(--ring-width) solid var(--ring-color);
317
+ outline-offset: var(--ring-offset);
318
+ }
319
+
320
+ /* FormField injects aria-invalid (not `error`), so style from the attribute too */
321
+ .input[aria-invalid="true"],
322
+ .select[aria-invalid="true"],
323
+ .textarea[aria-invalid="true"] {
324
+ border-color: var(--color-negative);
325
+ }
326
+
327
+ .input[aria-invalid="true"]:focus-visible,
328
+ .select[aria-invalid="true"]:focus-visible,
329
+ .textarea[aria-invalid="true"]:focus-visible {
330
+ outline-color: var(--color-negative);
312
331
  }
313
332
 
314
333
  .input--error {
315
334
  border-color: var(--color-negative);
316
335
  }
317
- .input--error:focus {
318
- box-shadow: 0 0 0 var(--ring-width) var(--color-error-ring);
336
+ .input--error:focus-visible {
337
+ outline-color: var(--color-negative);
319
338
  }
320
339
 
321
340
  /* ── Select ──────────────────────────────────────────────── */
@@ -340,9 +359,10 @@
340
359
  box-shadow var(--duration-normal) var(--ease-default);
341
360
  }
342
361
 
343
- .select:focus {
362
+ .select:focus-visible {
344
363
  border-color: var(--color-border-strong);
345
- box-shadow: 0 0 0 var(--ring-width) var(--ring-color);
364
+ outline: var(--ring-width) solid var(--ring-color);
365
+ outline-offset: var(--ring-offset);
346
366
  }
347
367
 
348
368
  [data-theme="dark"] .select {
@@ -372,9 +392,10 @@
372
392
  box-shadow var(--duration-normal) var(--ease-default);
373
393
  }
374
394
 
375
- .textarea:focus {
395
+ .textarea:focus-visible {
376
396
  border-color: var(--color-border-strong);
377
- box-shadow: 0 0 0 var(--ring-width) var(--ring-color);
397
+ outline: var(--ring-width) solid var(--ring-color);
398
+ outline-offset: var(--ring-offset);
378
399
  }
379
400
 
380
401
  /* ── Label ───────────────────────────────────────────────── */
@@ -439,6 +460,10 @@
439
460
  inset: -10px;
440
461
  }
441
462
 
463
+ .checkbox__input[aria-invalid="true"] {
464
+ border-color: var(--color-negative);
465
+ }
466
+
442
467
  .checkbox__input:checked {
443
468
  background-color: var(--color-primary);
444
469
  border-color: var(--color-primary);
@@ -503,6 +528,10 @@
503
528
  transition: border-color var(--duration-normal) var(--ease-default);
504
529
  }
505
530
 
531
+ .radio__input[aria-invalid="true"] + .radio__circle {
532
+ border-color: var(--color-negative);
533
+ }
534
+
506
535
  .radio__input:checked + .radio__circle {
507
536
  border-color: var(--color-primary);
508
537
  background: radial-gradient(circle, var(--color-primary) 40%, transparent 40%);
@@ -571,22 +600,22 @@
571
600
 
572
601
  .badge--positive {
573
602
  background-color: var(--color-positive-light);
574
- color: var(--color-positive-fg);
603
+ color: var(--color-positive-strong);
575
604
  }
576
605
 
577
606
  .badge--negative {
578
607
  background-color: var(--color-negative-light);
579
- color: var(--color-negative-fg);
608
+ color: var(--color-negative-strong);
580
609
  }
581
610
 
582
611
  .badge--warning {
583
612
  background-color: var(--color-warning-light);
584
- color: var(--color-warning-fg);
613
+ color: var(--color-warning-strong);
585
614
  }
586
615
 
587
616
  .badge--info {
588
617
  background-color: var(--color-info-light);
589
- color: var(--color-info-fg);
618
+ color: var(--color-info-strong);
590
619
  }
591
620
 
592
621
  /* Solid (inverted) badges */
@@ -595,20 +624,20 @@
595
624
  color: var(--color-bg);
596
625
  }
597
626
  .badge--solid.badge--positive {
598
- background-color: var(--color-positive);
599
- color: var(--color-fg-inverse);
627
+ background-color: var(--color-positive-strong);
628
+ color: var(--color-primary-fg);
600
629
  }
601
630
  .badge--solid.badge--negative {
602
- background-color: var(--color-negative);
603
- color: var(--color-fg-inverse);
631
+ background-color: var(--color-negative-strong);
632
+ color: var(--color-primary-fg);
604
633
  }
605
634
  .badge--solid.badge--warning {
606
- background-color: var(--color-warning);
607
- color: var(--color-fg-inverse);
635
+ background-color: var(--color-warning-strong);
636
+ color: var(--color-primary-fg);
608
637
  }
609
638
  .badge--solid.badge--info {
610
- background-color: var(--color-info);
611
- color: var(--color-fg-inverse);
639
+ background-color: var(--color-info-strong);
640
+ color: var(--color-primary-fg);
612
641
  }
613
642
 
614
643
  /* Badge with dot indicator */
@@ -843,6 +872,8 @@
843
872
  }
844
873
 
845
874
  .metric__value {
875
+ font-family: var(--font-display);
876
+ font-feature-settings: var(--font-feature-display);
846
877
  font-size: var(--font-size-2xl);
847
878
  font-weight: var(--font-weight-semibold);
848
879
  color: var(--color-fg);
@@ -875,9 +906,19 @@
875
906
  color: var(--color-fg-inverse);
876
907
  font-size: var(--font-size-xs);
877
908
  border-radius: var(--radius-md);
878
- pointer-events: none;
909
+ pointer-events: auto; /* hoverable (WCAG 1.4.13) */
910
+ white-space: normal;
911
+ max-width: 20em;
912
+ overflow-wrap: anywhere;
913
+ }
914
+
915
+ .tooltip[data-state="open"] {
879
916
  animation: kaze-fade-in var(--duration-fast) var(--ease-out);
880
- white-space: nowrap;
917
+ }
918
+
919
+ /* Kept in the DOM so aria-describedby resolves before the tooltip opens */
920
+ .tooltip[hidden] {
921
+ display: none;
881
922
  }
882
923
 
883
924
  /* ── Search Bar ──────────────────────────────────────────── */
@@ -912,12 +953,19 @@
912
953
  border: none;
913
954
  background: none;
914
955
  outline: none;
956
+ appearance: none;
915
957
  font-size: inherit;
916
958
  color: var(--color-fg);
917
959
  }
918
960
 
961
+ /* type="search": hide the UA clear button, Search renders its own affordances */
962
+ .search__input::-webkit-search-decoration,
963
+ .search__input::-webkit-search-cancel-button {
964
+ appearance: none;
965
+ }
966
+
919
967
  .search__input::placeholder {
920
- color: var(--color-fg-tertiary);
968
+ color: var(--color-fg-placeholder);
921
969
  }
922
970
 
923
971
  .search__kbd {
@@ -998,6 +1046,11 @@
998
1046
  }
999
1047
  }
1000
1048
 
1049
+ /* The dialog itself receives focus when it has no focusable children */
1050
+ .dialog:focus {
1051
+ outline: none;
1052
+ }
1053
+
1001
1054
  .dialog {
1002
1055
  background-color: var(--color-surface);
1003
1056
  border: 1px solid var(--color-border);
@@ -1104,7 +1157,7 @@
1104
1157
  }
1105
1158
 
1106
1159
  .form-field__label--required::after {
1107
- content: " *";
1160
+ content: " *" / ""; /* decorative: the control carries required / aria-required */
1108
1161
  color: var(--color-negative-fg);
1109
1162
  }
1110
1163
 
@@ -1372,10 +1425,13 @@
1372
1425
  }
1373
1426
 
1374
1427
  .hero__title {
1428
+ font-family: var(--font-display);
1429
+ font-feature-settings: var(--font-feature-display);
1375
1430
  font-size: var(--font-size-3xl);
1376
1431
  font-weight: var(--font-weight-bold);
1377
- letter-spacing: var(--letter-spacing-tight);
1378
- line-height: var(--line-height-tight);
1432
+ letter-spacing: 0;
1433
+ line-height: 1.35;
1434
+ text-wrap: balance;
1379
1435
  margin: 0 0 var(--space-4);
1380
1436
  }
1381
1437
 
@@ -1451,10 +1507,12 @@
1451
1507
  }
1452
1508
 
1453
1509
  .stat__value {
1510
+ font-family: var(--font-display);
1511
+ font-feature-settings: var(--font-feature-display);
1454
1512
  font-size: var(--font-size-4xl);
1455
1513
  font-weight: var(--font-weight-bold);
1456
1514
  letter-spacing: var(--letter-spacing-tight);
1457
- line-height: 1;
1515
+ line-height: 1.2;
1458
1516
  }
1459
1517
 
1460
1518
  .stat__label {
@@ -1526,10 +1584,12 @@
1526
1584
  }
1527
1585
 
1528
1586
  .pricing-card__amount {
1587
+ font-family: var(--font-display);
1588
+ font-feature-settings: var(--font-feature-display);
1529
1589
  font-size: var(--font-size-4xl);
1530
1590
  font-weight: var(--font-weight-bold);
1531
1591
  letter-spacing: var(--letter-spacing-tight);
1532
- line-height: 1;
1592
+ line-height: 1.2;
1533
1593
  }
1534
1594
 
1535
1595
  .pricing-card__period {
@@ -1631,6 +1691,12 @@
1631
1691
  border-bottom: 1px solid var(--color-border);
1632
1692
  }
1633
1693
 
1694
+ /* The question button is wrapped in a heading for document structure */
1695
+ .faq__heading {
1696
+ margin: 0;
1697
+ font: inherit;
1698
+ }
1699
+
1634
1700
  .faq__trigger {
1635
1701
  width: 100%;
1636
1702
  display: flex;
@@ -1697,9 +1763,11 @@
1697
1763
  }
1698
1764
 
1699
1765
  .cta-banner__title {
1766
+ font-family: var(--font-display);
1767
+ font-feature-settings: var(--font-feature-display);
1700
1768
  font-size: var(--font-size-xl);
1701
1769
  font-weight: var(--font-weight-bold);
1702
- letter-spacing: var(--letter-spacing-tight);
1770
+ letter-spacing: 0;
1703
1771
  margin: 0 0 var(--space-3);
1704
1772
  }
1705
1773
 
@@ -1856,109 +1924,9 @@
1856
1924
  .donut-chart__svg { margin: 0; }
1857
1925
  }
1858
1926
 
1859
- /* ── Sample Pages Responsive ─────────────────────────────── */
1860
-
1861
- .blog-layout {
1862
- display: grid;
1863
- grid-template-columns: 1fr;
1864
- gap: var(--space-10);
1865
- }
1866
-
1867
- .showcase-hero {
1868
- padding: var(--space-12) var(--space-4) var(--space-8);
1869
- }
1870
-
1871
- @media (min-width: 768px) {
1872
- .showcase-hero { padding: var(--space-24) var(--space-6) var(--space-16); }
1873
- }
1874
-
1875
- @media (min-width: 1024px) {
1876
- .blog-layout { grid-template-columns: 1fr 20rem; }
1877
- }
1878
-
1879
- .settings-profile {
1880
- display: flex;
1881
- flex-direction: column;
1882
- align-items: center;
1883
- gap: var(--space-6);
1884
- }
1885
-
1886
- .settings-plan-row {
1887
- display: flex;
1888
- flex-direction: column;
1889
- align-items: flex-start;
1890
- padding: var(--space-4);
1891
- border-radius: var(--radius-lg);
1892
- background: var(--color-bg-secondary);
1893
- margin-bottom: var(--space-6);
1894
- gap: var(--space-4);
1895
- flex-wrap: wrap;
1896
- }
1897
-
1898
- .settings-danger-row {
1899
- display: flex;
1900
- flex-direction: column;
1901
- align-items: flex-start;
1902
- padding: var(--space-4);
1903
- border-radius: var(--radius-lg);
1904
- border: 1px solid var(--color-border);
1905
- gap: var(--space-4);
1906
- flex-wrap: wrap;
1907
- }
1908
-
1909
- .settings-danger-row .btn {
1910
- align-self: flex-start;
1911
- margin-left: 0;
1912
- }
1913
-
1914
- @media (min-width: 640px) {
1915
- .settings-profile { flex-direction: row; align-items: flex-start; }
1916
-
1917
- .settings-plan-row {
1918
- flex-direction: row;
1919
- align-items: center;
1920
- justify-content: space-between;
1921
- gap: var(--space-3);
1922
- }
1923
-
1924
- .settings-danger-row {
1925
- flex-direction: row;
1926
- align-items: center;
1927
- justify-content: space-between;
1928
- }
1929
-
1930
- .settings-danger-row .btn {
1931
- align-self: auto;
1932
- margin-left: auto;
1933
- }
1934
- }
1935
-
1936
- @media (min-width: 640px) {
1937
- .feature-grid--cols-4 { grid-template-columns: repeat(2, 1fr); }
1938
- .stats { grid-template-columns: repeat(2, 1fr); }
1939
- .lp-footer__nav { grid-template-columns: repeat(2, 1fr); }
1940
- .testimonial-grid { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
1941
- }
1942
-
1943
- @media (min-width: 1024px) {
1944
- .stats { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
1945
- }
1946
-
1947
- @media (min-width: 768px) {
1948
- .lp-footer__nav { grid-template-columns: repeat(3, 1fr); }
1949
- }
1950
-
1951
- @media (min-width: 1024px) {
1952
- .feature-grid--cols-4 { grid-template-columns: repeat(4, 1fr); }
1953
- }
1954
-
1955
- /* ================================================================
1956
- Article / Prose
1957
- ================================================================ */
1958
-
1959
1927
  /* ── Article Layout ──────────────────────────────────────── */
1960
1928
  .article {
1961
- max-width: 720px;
1929
+ max-width: var(--measure-ja);
1962
1930
  margin: 0 auto;
1963
1931
  padding: 0 var(--space-6);
1964
1932
  }
@@ -1988,10 +1956,12 @@
1988
1956
  }
1989
1957
 
1990
1958
  .article__title {
1959
+ font-family: var(--font-display);
1960
+ font-feature-settings: var(--font-feature-display);
1991
1961
  font-size: var(--font-size-2xl);
1992
1962
  font-weight: var(--font-weight-bold);
1993
- letter-spacing: -0.03em;
1994
- line-height: var(--line-height-tight);
1963
+ letter-spacing: 0;
1964
+ line-height: 1.4;
1995
1965
  margin: 0 0 var(--space-5);
1996
1966
  }
1997
1967
 
@@ -2094,7 +2064,7 @@
2094
2064
  }
2095
2065
 
2096
2066
  .prose li::marker {
2097
- color: var(--color-fg-tertiary);
2067
+ color: var(--color-fg-decorative);
2098
2068
  }
2099
2069
 
2100
2070
  .prose code {
@@ -2449,18 +2419,18 @@
2449
2419
  ================================================================ */
2450
2420
 
2451
2421
  .heading {
2452
- font-family: var(--font-sans);
2422
+ font-family: var(--font-display);
2423
+ font-feature-settings: var(--font-feature-display);
2453
2424
  font-weight: var(--font-weight-bold);
2454
2425
  color: var(--color-fg);
2455
2426
  line-height: 1.5; /* CJK headings need ≥1.5 for proper readability */
2456
- letter-spacing: var(--letter-spacing-tight);
2427
+ letter-spacing: 0; /* negative tracking collides kana; palt already tightens */
2457
2428
  margin: 0;
2458
2429
  }
2459
2430
 
2460
2431
  .heading--1 {
2461
2432
  font-size: var(--font-size-2xl);
2462
- letter-spacing: -0.03em;
2463
- line-height: 1.3;
2433
+ line-height: 1.4;
2464
2434
  }
2465
2435
 
2466
2436
  .heading--2 {
@@ -2902,6 +2872,7 @@
2902
2872
  .chart-legend__item {
2903
2873
  display: inline-flex;
2904
2874
  align-items: center;
2875
+ min-height: 24px;
2905
2876
  gap: var(--space-1-5);
2906
2877
  padding: 0;
2907
2878
  background: none;
@@ -2922,7 +2893,8 @@ button.chart-legend__item:hover {
2922
2893
 
2923
2894
  button.chart-legend__item:focus-visible {
2924
2895
  outline: none;
2925
- box-shadow: 0 0 0 var(--ring-width) var(--ring-color);
2896
+ outline: var(--ring-width) solid var(--ring-color);
2897
+ outline-offset: var(--ring-offset);
2926
2898
  }
2927
2899
 
2928
2900
  .chart-legend__item--hidden {
@@ -3080,7 +3052,8 @@ button.chart-legend__item:focus-visible {
3080
3052
 
3081
3053
  .column-chart__figure:focus-visible {
3082
3054
  outline: none;
3083
- box-shadow: 0 0 0 var(--ring-width) var(--ring-color);
3055
+ outline: var(--ring-width) solid var(--ring-color);
3056
+ outline-offset: var(--ring-offset);
3084
3057
  }
3085
3058
 
3086
3059
  .column-chart__plot {
@@ -3478,7 +3451,7 @@ button.chart-legend__item:focus-visible {
3478
3451
 
3479
3452
  .breadcrumb__item + .breadcrumb__item::before {
3480
3453
  content: "/";
3481
- color: var(--color-fg-tertiary);
3454
+ color: var(--color-fg-decorative);
3482
3455
  margin: 0 var(--space-1);
3483
3456
  }
3484
3457
 
@@ -3596,10 +3569,10 @@ button.chart-legend__item:focus-visible {
3596
3569
  transition: width var(--duration-slower) var(--ease-out);
3597
3570
  }
3598
3571
 
3599
- .progress__fill--positive { background: var(--color-positive); }
3600
- .progress__fill--negative { background: var(--color-negative); }
3601
- .progress__fill--warning { background: var(--color-warning); }
3602
- .progress__fill--info { background: var(--color-info); }
3572
+ .progress__fill--positive { background: var(--color-positive-fg); }
3573
+ .progress__fill--negative { background: var(--color-negative-fg); }
3574
+ .progress__fill--warning { background: var(--color-warning-fg); }
3575
+ .progress__fill--info { background: var(--color-info-fg); }
3603
3576
 
3604
3577
  /* ================================================================
3605
3578
  Switch
@@ -3616,6 +3589,8 @@ button.chart-legend__item:focus-visible {
3616
3589
  position: relative;
3617
3590
  width: 36px;
3618
3591
  height: 20px;
3592
+ /* 24px minimum target (WCAG 2.5.8) without changing the drawn size */
3593
+ --switch-hit: 2px;
3619
3594
  border-radius: var(--radius-full);
3620
3595
  background: var(--color-bg-tertiary);
3621
3596
  border: 1px solid var(--color-border);
@@ -3623,6 +3598,12 @@ button.chart-legend__item:focus-visible {
3623
3598
  flex-shrink: 0;
3624
3599
  }
3625
3600
 
3601
+ .switch__track::before {
3602
+ content: "";
3603
+ position: absolute;
3604
+ inset: calc(-1 * var(--switch-hit)) calc(-2 * var(--switch-hit));
3605
+ }
3606
+
3626
3607
  .switch__thumb {
3627
3608
  position: absolute;
3628
3609
  top: 2px;
@@ -3643,6 +3624,10 @@ button.chart-legend__item:focus-visible {
3643
3624
  clip: rect(0, 0, 0, 0);
3644
3625
  }
3645
3626
 
3627
+ .switch__input[aria-invalid="true"] + .switch__track {
3628
+ border-color: var(--color-negative);
3629
+ }
3630
+
3646
3631
  .switch__input:checked + .switch__track {
3647
3632
  background: var(--color-primary);
3648
3633
  border-color: var(--color-primary);
@@ -3819,6 +3804,23 @@ button.chart-legend__item:focus-visible {
3819
3804
  gap: var(--space-0);
3820
3805
  }
3821
3806
 
3807
+ /* <ol>/<li> carry list semantics; lay them out exactly like the old flat div */
3808
+ .stepper__list {
3809
+ display: flex;
3810
+ flex-direction: column;
3811
+ align-items: flex-start;
3812
+ gap: var(--space-0);
3813
+ list-style: none;
3814
+ margin: 0;
3815
+ padding: 0;
3816
+ }
3817
+
3818
+ .stepper__item {
3819
+ display: flex;
3820
+ flex-direction: column;
3821
+ align-items: flex-start;
3822
+ }
3823
+
3822
3824
  .stepper__step {
3823
3825
  display: flex;
3824
3826
  align-items: center;
@@ -3848,8 +3850,8 @@ button.chart-legend__item:focus-visible {
3848
3850
  }
3849
3851
 
3850
3852
  .stepper__circle--completed {
3851
- border-color: var(--color-positive);
3852
- background: var(--color-positive);
3853
+ border-color: var(--color-positive-strong);
3854
+ background: var(--color-positive-strong);
3853
3855
  color: var(--color-fg-inverse);
3854
3856
  }
3855
3857
 
@@ -3934,10 +3936,10 @@ button.chart-legend__item:focus-visible {
3934
3936
  background-color var(--duration-normal) var(--ease-default);
3935
3937
  }
3936
3938
 
3937
- .meter__fill--positive { background: var(--color-positive); }
3938
- .meter__fill--negative { background: var(--color-negative); }
3939
- .meter__fill--warning { background: var(--color-warning); }
3940
- .meter__fill--info { background: var(--color-info); }
3939
+ .meter__fill--positive { background: var(--color-positive-fg); }
3940
+ .meter__fill--negative { background: var(--color-negative-fg); }
3941
+ .meter__fill--warning { background: var(--color-warning-fg); }
3942
+ .meter__fill--info { background: var(--color-info-fg); }
3941
3943
 
3942
3944
  .meter__marker {
3943
3945
  position: absolute;
@@ -3958,6 +3960,16 @@ button.chart-legend__item:focus-visible {
3958
3960
  align-items: stretch;
3959
3961
  }
3960
3962
 
3963
+ .tracker__list {
3964
+ display: flex;
3965
+ flex: 1;
3966
+ min-width: 0;
3967
+ gap: 2px;
3968
+ list-style: none;
3969
+ margin: 0;
3970
+ padding: 0;
3971
+ }
3972
+
3961
3973
  .tracker__segment {
3962
3974
  flex: 1;
3963
3975
  border-radius: 2px;
@@ -3974,10 +3986,10 @@ button.chart-legend__item:focus-visible {
3974
3986
  border-radius: 2px var(--radius-sm) var(--radius-sm) 2px;
3975
3987
  }
3976
3988
 
3977
- .tracker__segment--positive { background: var(--color-positive); }
3978
- .tracker__segment--negative { background: var(--color-negative); }
3979
- .tracker__segment--warning { background: var(--color-warning); }
3980
- .tracker__segment--info { background: var(--color-info); }
3989
+ .tracker__segment--positive { background: var(--color-positive-fg); }
3990
+ .tracker__segment--negative { background: var(--color-negative-fg); }
3991
+ .tracker__segment--warning { background: var(--color-warning-fg); }
3992
+ .tracker__segment--info { background: var(--color-info-fg); }
3981
3993
  .tracker__segment--default { background: var(--color-bg-tertiary); }
3982
3994
 
3983
3995
  /* ── BarList ─────────────────────────────────────────────── */
@@ -4066,7 +4078,17 @@ button.chart-legend__item:focus-visible {
4066
4078
 
4067
4079
  .number-field__wrapper:focus-within {
4068
4080
  border-color: var(--color-primary);
4069
- box-shadow: 0 0 0 var(--ring-width) var(--ring-color);
4081
+ outline: var(--ring-width) solid var(--ring-color);
4082
+ outline-offset: var(--ring-offset);
4083
+ }
4084
+
4085
+ .number-field__wrapper:has(.number-field__input[aria-invalid="true"]) {
4086
+ border-color: var(--color-negative);
4087
+ }
4088
+
4089
+ .number-field__wrapper:has(.number-field__input[aria-invalid="true"]):focus-within {
4090
+ outline: var(--ring-width) solid var(--color-negative);
4091
+ outline-offset: var(--ring-offset);
4070
4092
  }
4071
4093
 
4072
4094
  .number-field--error .number-field__wrapper {
@@ -4074,7 +4096,8 @@ button.chart-legend__item:focus-visible {
4074
4096
  }
4075
4097
 
4076
4098
  .number-field--error .number-field__wrapper:focus-within {
4077
- box-shadow: 0 0 0 var(--ring-width) var(--color-error-ring);
4099
+ outline: var(--ring-width) solid var(--color-negative);
4100
+ outline-offset: var(--ring-offset);
4078
4101
  }
4079
4102
 
4080
4103
  .number-field__input {
@@ -4093,7 +4116,7 @@ button.chart-legend__item:focus-visible {
4093
4116
  }
4094
4117
 
4095
4118
  .number-field__input::placeholder {
4096
- color: var(--color-fg-tertiary);
4119
+ color: var(--color-fg-placeholder);
4097
4120
  }
4098
4121
 
4099
4122
  .number-field__input:disabled {
@@ -4426,10 +4449,23 @@ button.chart-legend__item:focus-visible {
4426
4449
  }
4427
4450
 
4428
4451
  .dropdown__item:hover,
4452
+ .dropdown__item:focus,
4429
4453
  .dropdown__item[data-highlighted="true"] {
4430
4454
  background: var(--color-surface-hover);
4431
4455
  }
4432
4456
 
4457
+ /* Focus is shown by the background; keep a visible ring in forced-colors mode */
4458
+ .dropdown__item:focus {
4459
+ outline: none;
4460
+ }
4461
+
4462
+ @media (forced-colors: active) {
4463
+ .dropdown__item:focus {
4464
+ outline: 2px solid Highlight;
4465
+ outline-offset: -2px;
4466
+ }
4467
+ }
4468
+
4433
4469
  .dropdown__item[data-disabled="true"] {
4434
4470
  opacity: 0.5;
4435
4471
  pointer-events: none;
@@ -4512,14 +4548,14 @@ button.chart-legend__item:focus-visible {
4512
4548
  display: inline-flex;
4513
4549
  align-items: center;
4514
4550
  justify-content: center;
4515
- width: 18px;
4516
- height: 18px;
4551
+ width: 24px;
4552
+ height: 24px;
4517
4553
  padding: 0;
4518
4554
  border: 1px solid var(--color-border);
4519
4555
  border-radius: var(--radius-full);
4520
4556
  background: var(--color-bg);
4521
4557
  color: var(--color-fg-tertiary);
4522
- font-size: 11px;
4558
+ font-size: var(--font-size-2xs);
4523
4559
  font-weight: var(--font-weight-medium);
4524
4560
  line-height: 1;
4525
4561
  cursor: pointer;
@@ -4536,13 +4572,13 @@ button.chart-legend__item:focus-visible {
4536
4572
  }
4537
4573
 
4538
4574
  .help-button:focus-visible {
4539
- outline: 2px solid var(--color-focus, var(--color-primary));
4540
- outline-offset: 2px;
4575
+ outline: var(--ring-width) solid var(--ring-color);
4576
+ outline-offset: var(--ring-offset);
4541
4577
  }
4542
4578
 
4543
4579
  .help-popover {
4544
4580
  position: absolute;
4545
- z-index: 1000;
4581
+ z-index: var(--z-tooltip);
4546
4582
  background: var(--color-surface, var(--color-bg));
4547
4583
  border: 1px solid var(--color-border);
4548
4584
  border-radius: var(--radius-md);
@@ -4709,3 +4745,46 @@ button.chart-legend__item:focus-visible {
4709
4745
  .disclosure__content-inner {
4710
4746
  color: inherit;
4711
4747
  }
4748
+
4749
+ /* ── Reduced motion ─────────────────────────────────────────
4750
+ Shipped in the components layer so it applies even when utilities.css is
4751
+ not loaded. Covers every animated component above. */
4752
+ @media (prefers-reduced-motion: reduce) {
4753
+ .btn[disabled]:active,
4754
+ .tooltip,
4755
+ .skeleton,
4756
+ .overlay,
4757
+ .overlay--closing,
4758
+ .overlay--closing .dialog,
4759
+ .dialog,
4760
+ .command-palette,
4761
+ .toast,
4762
+ .toast[data-removing="true"],
4763
+ .dropdown__menu {
4764
+ animation: none;
4765
+ }
4766
+
4767
+ .dialog,
4768
+ .faq__answer,
4769
+ .disclosure__content,
4770
+ .segmented-control__indicator,
4771
+ .switch__thumb,
4772
+ .switch__track {
4773
+ transition: none;
4774
+ }
4775
+ }
4776
+
4777
+ /* Visually hidden text for assistive technology (duplicated from utilities.css
4778
+ so components that rely on it work when only components.css is loaded). */
4779
+ .sr-only {
4780
+ position: absolute;
4781
+ width: 1px;
4782
+ height: 1px;
4783
+ padding: 0;
4784
+ margin: -1px;
4785
+ overflow: hidden;
4786
+ clip: rect(0, 0, 0, 0);
4787
+ white-space: nowrap;
4788
+ border: 0;
4789
+ }
4790
+ }