@databricks/design-system 2.0.1 → 2.0.3

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 (91) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/{WizardStepContentWrapper-CFCTOSm8.js → WizardStepContentWrapper-DsAS2ZAT.js} +1356 -686
  3. package/dist/WizardStepContentWrapper-DsAS2ZAT.js.map +1 -0
  4. package/dist/dubois-colors.less +2 -0
  5. package/dist/fonts/dm-mono/DMMono-Regular.woff2 +0 -0
  6. package/dist/fonts/dm-mono/dm-mono.css +11 -0
  7. package/dist/index-dark.css +305 -516
  8. package/dist/index-dark.mitigated.css +305 -516
  9. package/dist/index.css +438 -544
  10. package/dist/index.js +1971 -244
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mitigated.css +447 -553
  13. package/dist/patterns.js +12 -2
  14. package/dist/patterns.js.map +1 -1
  15. package/dist-types/design-system/Button/Button.d.ts +2 -2
  16. package/dist-types/design-system/ContextMenu/ContextMenu.d.ts +2 -2
  17. package/dist-types/design-system/DesignSystemProvider/DesignSystemProvider.d.ts +44 -0
  18. package/dist-types/design-system/Drawer/DrawerContext.d.ts +9 -0
  19. package/dist-types/design-system/FormV2/RHFAdapters.d.ts +8 -8
  20. package/dist-types/design-system/Grid/Col.d.ts +1 -3
  21. package/dist-types/design-system/Grid/NativeCol.d.ts +10 -0
  22. package/dist-types/design-system/Grid/NativeGridContext.d.ts +11 -0
  23. package/dist-types/design-system/Grid/NativeRow.d.ts +13 -0
  24. package/dist-types/design-system/Grid/Row.d.ts +3 -4
  25. package/dist-types/design-system/Grid/grid-styling.d.ts +22 -0
  26. package/dist-types/design-system/Grid/gridConstants.d.ts +2 -0
  27. package/dist-types/design-system/Grid/index.d.ts +1 -0
  28. package/dist-types/design-system/Grid/rowConstants.d.ts +7 -0
  29. package/dist-types/design-system/Grid/types.d.ts +49 -0
  30. package/dist-types/design-system/Hooks/index.d.ts +1 -1
  31. package/dist-types/design-system/Hooks/useDesignSystemTheme.d.ts +7 -7
  32. package/dist-types/design-system/Icon/LegacyAntDIcon.d.ts +21 -0
  33. package/dist-types/design-system/Icon/__generated/icons/FlowsIcon.d.ts +4 -0
  34. package/dist-types/design-system/Icon/__generated/icons/LakewatchAlertIcon.d.ts +4 -0
  35. package/dist-types/design-system/Icon/__generated/icons/LakewatchDatasourceIcon.d.ts +4 -0
  36. package/dist-types/design-system/Icon/__generated/icons/LakewatchDetectionRuleIcon.d.ts +4 -0
  37. package/dist-types/design-system/Icon/__generated/icons/LakewatchParserIcon.d.ts +4 -0
  38. package/dist-types/design-system/Icon/__generated/icons/index.d.ts +5 -0
  39. package/dist-types/design-system/Icon/index.d.ts +0 -1
  40. package/dist-types/design-system/LegacyTooltip/index.d.ts +0 -1
  41. package/dist-types/design-system/Skeleton/TitleSkeleton.d.ts +9 -3
  42. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxAddButton.d.ts +4 -0
  43. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxCheckboxItem.d.ts +8 -0
  44. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxControls.d.ts +2 -0
  45. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxFooter.d.ts +12 -0
  46. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxInput.d.ts +8 -0
  47. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxMenu.d.ts +8 -0
  48. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxMenuItem.d.ts +8 -0
  49. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxMultiSelectInput.d.ts +17 -0
  50. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxRoot.d.ts +8 -0
  51. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxSectionHeader.d.ts +4 -0
  52. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxSelectedItem.d.ts +8 -0
  53. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxSeparator.d.ts +4 -0
  54. package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxToggleButton.d.ts +8 -0
  55. package/dist-types/design-system/TypeaheadCombobox/hooks/downshiftHookWrappers.d.ts +8 -0
  56. package/dist-types/design-system/TypeaheadComboboxV2/CountBadge.d.ts +6 -0
  57. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxAddButton.d.ts +3 -0
  58. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxCheckboxItem.d.ts +10 -0
  59. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxControls.d.ts +11 -0
  60. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxFooter.d.ts +2 -0
  61. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxInput.d.ts +9 -0
  62. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxMenu.d.ts +17 -0
  63. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxMenuItem.d.ts +16 -0
  64. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxMultiSelectInput.d.ts +18 -0
  65. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxRoot.d.ts +17 -0
  66. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxSectionHeader.d.ts +1 -0
  67. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxSelectedItem.d.ts +11 -0
  68. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxSeparator.d.ts +1 -0
  69. package/dist-types/design-system/TypeaheadComboboxV2/TypeaheadComboboxToggleButton.d.ts +4 -0
  70. package/dist-types/design-system/TypeaheadComboboxV2/hooks/footerFocus.d.ts +13 -0
  71. package/dist-types/design-system/TypeaheadComboboxV2/hooks/index.d.ts +4 -0
  72. package/dist-types/design-system/TypeaheadComboboxV2/hooks/useComboboxItems.d.ts +32 -0
  73. package/dist-types/design-system/TypeaheadComboboxV2/hooks/useComboboxState.d.ts +81 -0
  74. package/dist-types/design-system/TypeaheadComboboxV2/hooks/useComboboxStateProps.d.ts +36 -0
  75. package/dist-types/design-system/TypeaheadComboboxV2/hooks/useMultipleSelectionState.d.ts +25 -0
  76. package/dist-types/design-system/TypeaheadComboboxV2/hooks/useRestoreHighlightedOption.d.ts +18 -0
  77. package/dist-types/design-system/TypeaheadComboboxV2/hooks/useScrollOptionIntoView.d.ts +11 -0
  78. package/dist-types/design-system/TypeaheadComboboxV2/hooks/useTypeaheadComboboxContext.d.ts +2 -0
  79. package/dist-types/design-system/TypeaheadComboboxV2/hooks/useVirtualizedComboboxScroll.d.ts +36 -0
  80. package/dist-types/design-system/TypeaheadComboboxV2/index.d.ts +13 -0
  81. package/dist-types/design-system/TypeaheadComboboxV2/providers/TypeaheadComboboxContext.d.ts +47 -0
  82. package/dist-types/design-system/Typography/titleLevel.d.ts +11 -0
  83. package/dist-types/design-system/_shared_/Menu/index.d.ts +1 -1
  84. package/dist-types/design-system/fonts.d.ts +1 -0
  85. package/dist-types/design-system/index.d.ts +1 -0
  86. package/dist-types/design-system/utils/useMediaQuery.d.ts +4 -1
  87. package/dist-types/theme/_generated/ValidSemanticColors.d.ts +2 -1
  88. package/package.json +14 -3
  89. package/dist/WizardStepContentWrapper-CFCTOSm8.js.map +0 -1
  90. package/dist-types/design-system/Icon/AntdIcon.d.ts +0 -114
  91. package/dist-types/design-system/LegacyTooltip/LegacyInfoTooltip.d.ts +0 -16
package/dist/index.css CHANGED
@@ -10858,220 +10858,6 @@ textarea.du-bois-light-input {
10858
10858
  background: rgba(255, 255, 255, 0.35) !important;
10859
10859
  }
10860
10860
 
10861
- /* stylelint-disable at-rule-empty-line-before,at-rule-name-space-after,at-rule-no-unknown */
10862
- /* stylelint-disable no-duplicate-selectors */
10863
- /* stylelint-disable */
10864
- /* stylelint-disable declaration-bang-space-before,no-duplicate-selectors,string-no-newline */
10865
- .du-bois-light-modal {
10866
- box-sizing: border-box;
10867
- margin: 0;
10868
- padding: 0;
10869
- color: #161616;
10870
- font-size: 13px;
10871
- font-variant: tabular-nums;
10872
- line-height: 20px;
10873
- list-style: none;
10874
- font-feature-settings: 'tnum';
10875
- pointer-events: none;
10876
- position: relative;
10877
- top: 100px;
10878
- width: auto;
10879
- max-width: calc(100vw - 32px);
10880
- margin: 0 auto;
10881
- padding-bottom: 24px;
10882
- }
10883
- .du-bois-light-modal.du-bois-light-zoom-enter,
10884
- .du-bois-light-modal.du-bois-lightzoom-appear {
10885
- transform: none;
10886
- opacity: 0;
10887
- animation-duration: 0.3s;
10888
- user-select: none;
10889
- }
10890
- .du-bois-light-modal-mask {
10891
- position: fixed;
10892
- top: 0;
10893
- right: 0;
10894
- bottom: 0;
10895
- left: 0;
10896
- z-index: 1000;
10897
- height: 100%;
10898
- background-color: rgba(0, 0, 0, 0.45);
10899
- }
10900
- .du-bois-light-modal-mask-hidden {
10901
- display: none;
10902
- }
10903
- .du-bois-light-modal-wrap {
10904
- position: fixed;
10905
- top: 0;
10906
- right: 0;
10907
- bottom: 0;
10908
- left: 0;
10909
- overflow: auto;
10910
- outline: 0;
10911
- -webkit-overflow-scrolling: touch;
10912
- }
10913
- .du-bois-light-modal-wrap {
10914
- z-index: 1000;
10915
- }
10916
- .du-bois-light-modal-title {
10917
- margin: 0;
10918
- color: rgba(0, 0, 0, 0.85);
10919
- font-weight: 500;
10920
- font-size: 18px;
10921
- line-height: 22px;
10922
- word-wrap: break-word;
10923
- }
10924
- .du-bois-light-modal-content {
10925
- position: relative;
10926
- background-color: #fff;
10927
- background-clip: padding-box;
10928
- border: 0;
10929
- border-radius: 4px;
10930
- box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
10931
- pointer-events: auto;
10932
- }
10933
- .du-bois-light-modal-close {
10934
- position: absolute;
10935
- top: 0;
10936
- right: 0;
10937
- z-index: 10;
10938
- padding: 0;
10939
- color: #6F6F6F;
10940
- font-weight: 700;
10941
- line-height: 1;
10942
- text-decoration: none;
10943
- background: transparent;
10944
- border: 0;
10945
- outline: 0;
10946
- cursor: pointer;
10947
- transition: color 0.3s;
10948
- }
10949
- .du-bois-light-modal-close-x {
10950
- display: block;
10951
- width: 102px;
10952
- height: 102px;
10953
- font-size: 18px;
10954
- font-style: normal;
10955
- line-height: 102px;
10956
- text-align: center;
10957
- text-transform: none;
10958
- text-rendering: auto;
10959
- }
10960
- .du-bois-light-modal-close:focus,
10961
- .du-bois-light-modal-close:hover {
10962
- color: rgba(0, 0, 0, 0.75);
10963
- text-decoration: none;
10964
- }
10965
- .du-bois-light-modal-header {
10966
- padding: 40px 40px 20px;
10967
- color: #161616;
10968
- background: #fff;
10969
- border-bottom: 0px solid #f0f0f0;
10970
- border-radius: 4px 4px 0 0;
10971
- }
10972
- .du-bois-light-modal-body {
10973
- padding: 0 40px;
10974
- font-size: 13px;
10975
- line-height: 20px;
10976
- word-wrap: break-word;
10977
- }
10978
- .du-bois-light-modal-footer {
10979
- padding: 0px 0px;
10980
- text-align: right;
10981
- background: transparent;
10982
- border-top: 0px solid #f0f0f0;
10983
- border-radius: 0 0 4px 4px;
10984
- }
10985
- .du-bois-light-modal-footer .du-bois-light-btn + .du-bois-light-btn:not(.du-bois-light-dropdown-trigger) {
10986
- margin-bottom: 0;
10987
- margin-left: 8px;
10988
- }
10989
- .du-bois-light-modal-open {
10990
- overflow: hidden;
10991
- }
10992
- .du-bois-light-modal-centered {
10993
- text-align: center;
10994
- }
10995
- .du-bois-light-modal-centered::before {
10996
- display: inline-block;
10997
- width: 0;
10998
- height: 100%;
10999
- vertical-align: middle;
11000
- content: '';
11001
- }
11002
- .du-bois-light-modal-centered .du-bois-light-modal {
11003
- top: 0;
11004
- display: inline-block;
11005
- text-align: left;
11006
- vertical-align: middle;
11007
- }
11008
- @media (max-width: 767px) {
11009
- .du-bois-light-modal {
11010
- max-width: calc(100vw - 16px);
11011
- margin: 8px auto;
11012
- }
11013
- .du-bois-light-modal-centered .du-bois-light-modal {
11014
- flex: 1;
11015
- }
11016
- }
11017
- .du-bois-light-modal-confirm .du-bois-light-modal-header {
11018
- display: none;
11019
- }
11020
- .du-bois-light-modal-confirm .du-bois-light-modal-body {
11021
- padding: 32px 32px 24px;
11022
- }
11023
- .du-bois-light-modal-confirm-body-wrapper::before {
11024
- display: table;
11025
- content: '';
11026
- }
11027
- .du-bois-light-modal-confirm-body-wrapper::after {
11028
- display: table;
11029
- clear: both;
11030
- content: '';
11031
- }
11032
- .du-bois-light-modal-confirm-body .du-bois-light-modal-confirm-title {
11033
- display: block;
11034
- overflow: hidden;
11035
- color: rgba(0, 0, 0, 0.85);
11036
- font-weight: 500;
11037
- font-size: 18px;
11038
- line-height: 1.4;
11039
- }
11040
- .du-bois-light-modal-confirm-body .du-bois-light-modal-confirm-content {
11041
- margin-top: 8px;
11042
- color: #161616;
11043
- font-size: 13px;
11044
- }
11045
- .du-bois-light-modal-confirm-body > .anticon {
11046
- float: left;
11047
- margin-right: 16px;
11048
- font-size: 22px;
11049
- }
11050
- .du-bois-light-modal-confirm-body > .anticon + .du-bois-light-modal-confirm-title + .du-bois-light-modal-confirm-content {
11051
- margin-left: 38px;
11052
- }
11053
- .du-bois-light-modal-confirm .du-bois-light-modal-confirm-btns {
11054
- float: right;
11055
- margin-top: 24px;
11056
- }
11057
- .du-bois-light-modal-confirm .du-bois-light-modal-confirm-btns .du-bois-light-btn + .du-bois-light-btn {
11058
- margin-bottom: 0;
11059
- margin-left: 8px;
11060
- }
11061
- .du-bois-light-modal-confirm-error .du-bois-light-modal-confirm-body > .anticon {
11062
- color: #C82D4C;
11063
- }
11064
- .du-bois-light-modal-confirm-warning .du-bois-light-modal-confirm-body > .anticon,
11065
- .du-bois-light-modal-confirm-confirm .du-bois-light-modal-confirm-body > .anticon {
11066
- color: #AF5B23;
11067
- }
11068
- .du-bois-light-modal-confirm-info .du-bois-light-modal-confirm-body > .anticon {
11069
- color: #64727D;
11070
- }
11071
- .du-bois-light-modal-confirm-success .du-bois-light-modal-confirm-body > .anticon {
11072
- color: #34824F;
11073
- }
11074
-
11075
10861
  /* stylelint-disable at-rule-empty-line-before,at-rule-name-space-after,at-rule-no-unknown */
11076
10862
  /* stylelint-disable no-duplicate-selectors */
11077
10863
  /* stylelint-disable */
@@ -16050,7 +15836,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16050
15836
  * Source: design-system/src/theme/tokens/*.json
16051
15837
  * Regenerate via: yarn theme-regenerate */
16052
15838
 
16053
- :where(:root, .du-bois-light) {
15839
+ :where(:root), :where(.du-bois-light) {
16054
15840
  --db-radius-0: 0px;
16055
15841
  --db-radius-full: 999px;
16056
15842
  --db-radius-lg: 12px;
@@ -16182,50 +15968,64 @@ span.du-bois-light-typography-ellipsis-single-line {
16182
15968
  --db-color-text-validation-success: #277c43;
16183
15969
  --db-color-text-validation-warning: #be501e;
16184
15970
  --db-color-tooltip-background-tooltip: #161616;
15971
+ --db-color-tooltip-text-tooltip: #ffffff;
16185
15972
  }
16186
15973
 
16187
15974
  /* THIS FILE IS AUTOMATICALLY GENERATED FROM Figma tokens. DO NOT EDIT.
16188
15975
  * Source: design-system/src/theme/tokens/*.json
16189
15976
  * Regenerate via: yarn theme-regenerate */
16190
15977
 
16191
- /* Layout primitive classes — internal Du Bois use for now (not a published
16192
- * consumer API yet; see the Stefan/Sheng weekly decision to "give it a try
16193
- * just within the Du Bois components"). Two primitives, both plain CSS so they
16194
- * ride the mortar cascade like the other component styles:
16195
- *
16196
- * .ds-stack — vertical flow, even gap between direct children.
16197
- * .ds-cluster — horizontal group that wraps, even gap between children.
16198
- *
16199
- * Each primitive exposes a small set of `--ds-*` knobs, defaulted on the class
16200
- * itself (not via a `var()` fallback, which would freeze the default at every
16201
- * call site). Override any of them on the element — inline
16202
- * `style={{ '--ds-stack-gap': ... }}` or a more specific selector — without a
16203
- * new modifier class:
16204
- *
16205
- * stack: --ds-stack-gap (spacing), --ds-stack-align (align-items)
16206
- * cluster: --ds-cluster-gap (spacing), --ds-cluster-align (align-items),
16207
- * --ds-cluster-justify (justify-content)
16208
- *
16209
- * Gap defaults point at the system spacing scale (`--db-space-*`). Padding is
16210
- * intentionally NOT a knob — a layout primitive owns the space between children,
16211
- * not its own box padding. */
15978
+ /*
15979
+ Vertical "stack" of elements.
15980
+ Use this for any layout where items are laid out vertically.
15981
+
15982
+ \3c !-- Basic: default gap between each child -->
15983
+ <div class="ds-stack">
15984
+ <h2>Title</h2>
15985
+ <p>Body</p>
15986
+ <button>Action</button>
15987
+ </div>
15988
+
15989
+ \3c !-- Wider gap for this instance -->
15990
+ <div class="ds-stack" style="--ds-stack-gap: var(--db-spacing-lg)">…</div>
16212
15991
 
15992
+ \3c !-- Don't stretch children to full width (e.g. left-aligned buttons) -->
15993
+ <div class="ds-stack" style="--ds-stack-align: flex-start">…</div>
15994
+ */
16213
15995
  .ds-stack {
16214
- --ds-stack-gap: var(--db-space-md);
15996
+ /* These variables act as the *parameters* for the stack instance. */
15997
+ --ds-stack-gap: var(--db-spacing-xs);
16215
15998
  --ds-stack-align: stretch;
15999
+
16216
16000
  display: flex;
16217
16001
  flex-direction: column;
16218
16002
  align-items: var(--ds-stack-align);
16219
16003
  gap: var(--ds-stack-gap);
16220
16004
  }
16221
16005
 
16222
- /* Cluster wraps by design: a long row reflows onto multiple lines rather than
16223
- * overflowing. A row that must NOT wrap (e.g. a single-line control strip) is
16224
- * not a cluster keep it bespoke. */
16006
+ /**
16007
+ Responsive, horizontal "cluster" of elements.
16008
+ Use this for any layout where items are laid out horizontally and should wrap on smaller viewport sizes.
16009
+
16010
+ \3c !-- Basic: items wrap as needed -->
16011
+ <div class="ds-cluster">
16012
+ <span>one</span>
16013
+ <span>two</span>
16014
+ <span>three</span>
16015
+ </div>
16016
+
16017
+ \3c !-- Push children apart (e.g. title left, actions right) -->
16018
+ <div class="ds-cluster" style="--ds-cluster-justify: space-between">…</div>
16019
+
16020
+ \3c !-- Looser gap for this instance -->
16021
+ <div class="ds-cluster" style="--ds-cluster-gap: var(--db-spacing-sm)">…</div>
16022
+ */
16225
16023
  .ds-cluster {
16226
- --ds-cluster-gap: var(--db-space-sm);
16024
+ /* These variables act as the *parameters* for the cluster instance. */
16025
+ --ds-cluster-gap: var(--db-spacing-2xs);
16227
16026
  --ds-cluster-align: center;
16228
16027
  --ds-cluster-justify: flex-start;
16028
+
16229
16029
  display: flex;
16230
16030
  flex-wrap: wrap;
16231
16031
  align-items: var(--ds-cluster-align);
@@ -16233,97 +16033,215 @@ span.du-bois-light-typography-ellipsis-single-line {
16233
16033
  gap: var(--ds-cluster-gap);
16234
16034
  }
16235
16035
 
16236
- /* Category-tier tokens shared by selection-control components:
16237
- * <Checkbox>, <Switch>, <Radio>. Each value here references a SYSTEM token
16238
- * from system-tokens.css — never a raw hex/px literal — so the only place a
16239
- * brand-level theme change has to land is the system tier.
16240
- *
16241
- * Component-tier files (e.g. design-system/Checkbox/tokens.css) inherit from
16242
- * these via `var()` so consumers can override a single selection control by
16243
- * targeting only its component tokens. */
16036
+ :where(:root), :where(.du-bois-light) {
16037
+ /* Neutral */
16038
+ --db-neutral-surface: var(--db-color-background-primary);
16039
+ --db-subtle-neutral-surface: var(--db-color-background-secondary);
16040
+ --db-strong-neutral-surface: initial; /* TODO */
16041
+
16042
+ --db-text-on-neutral-surface: var(--db-color-text-primary);
16043
+ --db-subtle-text-on-neutral-surface: var(--db-color-text-secondary);
16044
+ --db-strong-text-on-neutral-surface: initial; /* TODO */
16045
+
16046
+ --db-neutral-border: var(--db-color-border);
16047
+ --db-subtle-neutral-border: initial; /* TODO */
16048
+ --db-strong-neutral-border: var(--db-color-border-accessible);
16244
16049
 
16245
- /* Re-declared under both theme classes as well as :root: these values are
16246
- * `var()` indirections onto SYSTEM tokens, and a custom property resolves its
16247
- * var() at its DECLARATION site. Declared only at :root, they would freeze at
16248
- * the root (light) system values and never re-read the dark system tokens
16249
- * inside a `.du-bois-dark` subtree. Re-declaring at every theme boundary makes
16250
- * the indirection re-resolve per theme. See DUBOIS-448 dark-mode scoping. */
16251
- :where(:root, .du-bois-light, .du-bois-dark) {
16252
- --db-selection-toggle-bg-default: var(--db-color-background-primary);
16253
- --db-selection-toggle-bg-hover: var(--db-color-action-default-background-hover);
16254
- --db-selection-toggle-bg-press: var(--db-color-action-default-background-press);
16255
- --db-selection-toggle-bg-checked: var(--db-color-action-primary-background-default);
16256
- --db-selection-toggle-bg-checked-hover: var(--db-color-action-primary-background-hover);
16257
- --db-selection-toggle-bg-checked-press: var(--db-color-action-primary-background-press);
16258
- --db-selection-toggle-bg-disabled: var(--db-color-action-disabled-background);
16050
+ --db-neutral-surface-active: var(--db-color-table-background-selected-default);
16051
+ --db-neutral-surface-hover: var(--db-color-table-background-unselected-hover);
16052
+ --db-neutral-surface-pressed: var(--db-color-table-background-selected-hover);
16053
+ --db-neutral-surface-disabled: var(--db-color-action-disabled-background);
16054
+ --db-text-on-neutral-surface-disabled: var(--db-color-action-disabled-text);
16259
16055
 
16260
- --db-selection-toggle-border-default: var(--db-color-action-default-border-default);
16261
- --db-selection-toggle-border-hover: var(--db-color-action-primary-background-hover);
16262
- --db-selection-toggle-border-press: var(--db-color-action-primary-background-press);
16263
- --db-selection-toggle-border-focus: var(--db-color-action-default-border-focus);
16264
- --db-selection-toggle-border-disabled: var(--db-color-action-disabled-border);
16056
+ /* Primary */
16057
+ --db-primary-surface: var(--db-color-action-primary-background-default);
16058
+ --db-subtle-primary-surface: var(--db-color-action-default-background-hover);
16059
+ --db-strong-primary-surface: var(--db-color-action-primary-background-hover);
16265
16060
 
16266
- /* Raw literal, not a system token (exception to the file rule above): the mark
16267
- * sits on the theme-invariant blue checked fill, so it must stay white in BOTH
16268
- * themes. No non-flipping white system token exists — action-primary-icon flips
16269
- * to near-black under .du-bois-dark, which made the mark nearly invisible. */
16270
- --db-selection-toggle-icon-color: #ffffff;
16271
- --db-selection-toggle-icon-color-disabled: var(--db-color-action-disabled-text);
16272
- --db-selection-toggle-text: var(--db-color-text-primary);
16273
- --db-selection-toggle-text-disabled: var(--db-color-action-disabled-text);
16061
+ --db-text-on-primary-surface: var(--db-color-action-primary-text-default);
16062
+ --db-primary-text-on-neutral-surface: var(--db-color-action-link-default);
16063
+ --db-subtle-text-on-primary-surface: initial; /* TODO */
16064
+ --db-strong-text-on-primary-surface: var(--db-color-action-primary-text-default);
16274
16065
 
16275
- --db-selection-toggle-size: 16px;
16276
- --db-selection-toggle-border-radius: var(--db-radius-sm);
16277
- --db-selection-toggle-spacing: var(--db-space-sm);
16066
+ --db-primary-border: var(--db-color-action-primary-background-default);
16067
+ --db-subtle-primary-border: initial; /* TODO */
16068
+ --db-strong-primary-border: var(--db-color-action-primary-background-press);
16069
+
16070
+ --db-primary-surface-active: initial; /* TODO */
16071
+ --db-primary-surface-hover: var(--db-color-action-primary-background-hover);
16072
+ --db-primary-surface-pressed: var(--db-color-action-primary-background-press);
16073
+ --db-primary-surface-disabled: var(--db-color-action-disabled-background);
16074
+ --db-text-on-primary-surface-disabled: var(--db-color-action-disabled-text);
16075
+
16076
+ /* Error */
16077
+ --db-error-surface: var(--db-color-action-danger-primary-background-default);
16078
+ --db-subtle-error-surface: var(--db-color-background-danger);
16079
+ --db-strong-error-surface: var(--db-color-action-danger-primary-background-hover);
16080
+
16081
+ --db-text-on-error-surface: var(--db-color-action-danger-primary-text);
16082
+ --db-error-text-on-neutral-surface: var(--db-color-text-validation-danger);
16083
+ --db-subtle-text-on-error-surface: initial; /* TODO */
16084
+ --db-strong-text-on-error-surface: var(--db-color-action-danger-primary-text);
16085
+
16086
+ --db-error-border: var(--db-color-action-danger-default-border-default);
16087
+ --db-subtle-error-border: var(--db-color-border-danger);
16088
+ --db-strong-error-border: var(--db-color-action-danger-primary-background-press);
16089
+
16090
+ --db-error-surface-active: initial; /* TODO */
16091
+ --db-error-surface-hover: var(--db-color-action-danger-primary-background-hover);
16092
+ --db-error-surface-pressed: var(--db-color-action-danger-primary-background-press);
16093
+ --db-error-surface-disabled: var(--db-color-action-disabled-background);
16094
+ --db-text-on-error-surface-disabled: var(--db-color-action-disabled-text);
16095
+
16096
+ /* Warning */
16097
+ --db-warning-surface: initial; /* TODO */
16098
+ --db-subtle-warning-surface: var(--db-color-background-warning);
16099
+
16100
+ --db-text-on-warning-surface: initial; /* TODO */
16101
+ --db-warning-text-on-neutral-surface: var(--db-color-text-validation-warning);
16102
+
16103
+ --db-warning-border: var(--db-color-border-warning);
16104
+
16105
+ /* Success */
16106
+ --db-success-surface: initial; /* TODO */
16107
+ --db-subtle-success-surface: var(--db-color-background-success);
16108
+
16109
+ --db-text-on-success-surface: initial; /* TODO */
16110
+ --db-success-text-on-neutral-surface: var(--db-color-text-validation-success);
16111
+
16112
+ --db-success-border: initial; /* TODO */
16113
+ }
16114
+
16115
+
16116
+
16117
+ :where(:root), :where(.du-bois-light) {
16118
+ --db-layout-unit: 0.25rem; /* 4px */
16119
+ --db-density-scalar: 1;
16120
+ --db-size-scalar: 1;
16121
+ --db-spacing-scalar: 1;
16122
+
16123
+ /* Size and spacing are the same steps, but with their own scalars included in the calc. */
16124
+
16125
+ --db-size-3xs: calc(var(--db-layout-unit) * 1 * var(--db-density-scalar) * var(--db-size-scalar)); /* 4px */
16126
+ --db-size-2xs: calc(var(--db-layout-unit) * 2 * var(--db-density-scalar) * var(--db-size-scalar)); /* 8px */
16127
+ --db-size-xs: calc(var(--db-layout-unit) * 4 * var(--db-density-scalar) * var(--db-size-scalar)); /* 16px */
16128
+ --db-size-sm: calc(var(--db-layout-unit) * 6 * var(--db-density-scalar) * var(--db-size-scalar)); /* 24px */
16129
+ --db-size-md: calc(var(--db-layout-unit) * 8 * var(--db-density-scalar) * var(--db-size-scalar)); /* 32px */
16130
+ --db-size-lg: calc(var(--db-layout-unit) * 10 * var(--db-density-scalar) * var(--db-size-scalar)); /* 40px */
16131
+
16132
+ --db-spacing-3xs: calc(var(--db-layout-unit) * 1 * var(--db-density-scalar) * var(--db-spacing-scalar)); /* 4px */
16133
+ --db-spacing-2xs: calc(var(--db-layout-unit) * 2 * var(--db-density-scalar) * var(--db-spacing-scalar)); /* 8px */
16134
+ --db-spacing-xs: calc(var(--db-layout-unit) * 4 * var(--db-density-scalar) * var(--db-spacing-scalar)); /* 16px */
16135
+ --db-spacing-sm: calc(var(--db-layout-unit) * 6 * var(--db-density-scalar) * var(--db-spacing-scalar)); /* 24px */
16136
+ --db-spacing-md: calc(var(--db-layout-unit) * 8 * var(--db-density-scalar) * var(--db-spacing-scalar)); /* 32px */
16137
+ --db-spacing-lg: calc(var(--db-layout-unit) * 10 * var(--db-density-scalar) * var(--db-spacing-scalar)); /* 40px */
16138
+ }
16139
+
16140
+ :where(:root), :where(.du-bois-light) {
16141
+ --db-font-family:
16142
+ "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
16143
+ --db-mono-font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
16144
+
16145
+ --db-font-size-2xs: 0.6875rem; /* 11px */
16146
+ --db-font-size-xs: 0.75rem; /* 12px */
16147
+ --db-font-size-base: 0.8125rem; /* 13px */
16148
+ --db-font-size-md: 0.875rem; /* 14px */
16149
+ --db-font-size-lg: 0.9375rem; /* 15px */
16150
+ --db-font-size-xl: 1rem; /* 16px */
16151
+ --db-font-size-2xl: 1.25rem; /* 20px */
16152
+ --db-font-size-3xl: 1.5rem; /* 24px */
16153
+ --db-font-size-4xl: 2rem; /* 32px */
16154
+
16155
+ /* Du Bois v1 ships 400 and 600 only */
16156
+ --db-font-weight-normal: 400;
16157
+ --db-font-weight-medium: initial; /* TODO */
16158
+ --db-font-weight-semibold: 600;
16159
+ --db-font-weight-bold: initial; /* TODO */
16160
+ }
16161
+
16162
+ :where(:root), :where(.du-bois-light) {
16163
+ --db-elevation-inset: initial; /* TODO */
16164
+ --db-elevation-low: 0px 2px 3px -1px rgba(0, 0, 0, 0.05), 0px 1px 0px 0px rgba(0, 0, 0, 0.02);
16165
+ --db-elevation-med: 0px 2px 16px 0px rgba(0, 0, 0, 0.08);
16166
+ --db-elevation-high: 0px 8px 40px 0px rgba(0, 0, 0, 0.13);
16167
+ }
16168
+
16169
+ :where(:root), :where(.du-bois-light) {
16170
+ --db-focus-ring-color: var(--db-color-action-default-border-focus);
16171
+ --db-focus-ring-width: 2px;
16172
+ }
16173
+
16174
+ :where(:root), :where(.du-bois-light) {
16175
+ /* Shape */
16176
+ --db-selection-toggle-border-radius: 4px;
16177
+
16178
+ /* Color */
16179
+ --db-selection-toggle-surface: var(--db-neutral-surface);
16180
+ --db-selection-toggle-mark: var(--db-text-on-primary-surface);
16181
+ --db-selection-toggle-text: var(--db-text-on-neutral-surface);
16182
+ --db-selection-toggle-border: var(--db-strong-neutral-border);
16183
+
16184
+ --db-selection-toggle-surface-hover: var(--db-neutral-surface-hover);
16185
+ --db-selection-toggle-surface-press: var(--db-neutral-surface-pressed);
16186
+ --db-selection-toggle-surface-checked: var(--db-primary-surface);
16187
+ --db-selection-toggle-surface-checked-hover: var(--db-primary-surface-hover);
16188
+ --db-selection-toggle-surface-checked-press: var(--db-primary-surface-pressed);
16189
+ --db-selection-toggle-surface-disabled: var(--db-neutral-surface-disabled);
16190
+ --db-selection-toggle-surface-checked-disabled: var(--db-neutral-surface-disabled);
16191
+
16192
+ --db-selection-toggle-border-hover: var(--db-primary-surface-hover);
16193
+ --db-selection-toggle-border-press: var(--db-primary-surface-pressed);
16194
+ --db-selection-toggle-border-disabled: var(--db-neutral-border);
16195
+
16196
+ --db-selection-toggle-mark-disabled: var(--db-text-on-neutral-surface-disabled);
16197
+ --db-selection-toggle-text-disabled: var(--db-text-on-neutral-surface-disabled);
16278
16198
 
16279
- /* Focus ring matches AntD legacy variant; offset keeps it outside the toggle.
16280
- * Hard-coded for now — Figma export doesn't include shadow tokens. */
16281
16199
  --db-selection-toggle-shadow-checked: 0 0 0 1px var(--db-color-action-primary-background-default);
16282
- --db-selection-toggle-focus-ring-width: 2px;
16283
- --db-selection-toggle-focus-ring-offset: 2px;
16200
+
16201
+ /* Density */
16202
+ --db-selection-toggle-size: var(--db-size-xs);
16203
+ --db-selection-toggle-label-spacing: var(--db-spacing-2xs);
16204
+
16205
+ /* Motion */
16284
16206
  --db-selection-toggle-transition-duration: 120ms;
16285
16207
  }
16286
16208
 
16287
- /* Component-tier tokens for <Checkbox>. Each value defaults to a CATEGORY
16288
- * (selection-toggle) token via var(); consumers can override here to retheme
16289
- * checkboxes without affecting switch / radio. */
16290
-
16291
- /* Re-declared under both theme classes (not just :root) so the var() chain onto
16292
- * category/system tokens re-resolves inside a `.du-bois-dark` subtree instead of
16293
- * freezing at the root (light) values. See DUBOIS-448 dark-mode scoping. */
16294
- :where(:root, .du-bois-light, .du-bois-dark) {
16295
- --db-checkbox-size: var(--db-selection-toggle-size);
16209
+ :where(:root), :where(.du-bois-light) {
16210
+ /* Shape */
16296
16211
  --db-checkbox-border-radius: var(--db-selection-toggle-border-radius);
16297
16212
  --db-checkbox-border-width: 1px;
16298
- --db-checkbox-spacing: var(--db-selection-toggle-spacing);
16299
16213
 
16300
- --db-checkbox-bg-default: var(--db-selection-toggle-bg-default);
16301
- --db-checkbox-bg-hover: var(--db-selection-toggle-bg-hover);
16302
- --db-checkbox-bg-press: var(--db-selection-toggle-bg-press);
16303
- --db-checkbox-bg-checked: var(--db-selection-toggle-bg-checked);
16304
- --db-checkbox-bg-checked-hover: var(--db-selection-toggle-bg-checked-hover);
16305
- --db-checkbox-bg-checked-press: var(--db-selection-toggle-bg-checked-press);
16306
- --db-checkbox-bg-disabled: var(--db-selection-toggle-bg-disabled);
16214
+ /* Color */
16215
+ --db-checkbox-surface: var(--db-selection-toggle-surface);
16216
+ --db-checkbox-surface-hover: var(--db-color-action-default-background-hover);
16217
+ --db-checkbox-surface-press: var(--db-color-action-default-background-press);
16218
+ --db-checkbox-surface-checked: var(--db-selection-toggle-surface-checked);
16219
+ --db-checkbox-surface-checked-hover: var(--db-selection-toggle-surface-checked-hover);
16220
+ --db-checkbox-surface-checked-press: var(--db-selection-toggle-surface-checked-press);
16221
+ --db-checkbox-surface-disabled: var(--db-selection-toggle-surface-disabled);
16307
16222
 
16308
- --db-checkbox-border-default: var(--db-selection-toggle-border-default);
16223
+ --db-checkbox-border: var(--db-color-action-default-border-default);
16309
16224
  --db-checkbox-border-hover: var(--db-selection-toggle-border-hover);
16310
16225
  --db-checkbox-border-press: var(--db-selection-toggle-border-press);
16311
- --db-checkbox-border-focus: var(--db-selection-toggle-border-focus);
16312
- --db-checkbox-border-disabled: var(--db-selection-toggle-border-disabled);
16226
+ --db-checkbox-focus-ring: var(--db-focus-ring-color);
16227
+ --db-checkbox-border-disabled: var(--db-color-action-disabled-border);
16313
16228
 
16314
- --db-checkbox-icon-color: var(--db-selection-toggle-icon-color);
16315
- --db-checkbox-icon-color-disabled: var(--db-selection-toggle-icon-color-disabled);
16229
+ --db-checkbox-mark: #ffffff;
16230
+ --db-checkbox-mark-disabled: var(--db-selection-toggle-mark-disabled);
16316
16231
  --db-checkbox-text: var(--db-selection-toggle-text);
16317
16232
  --db-checkbox-text-disabled: var(--db-selection-toggle-text-disabled);
16318
16233
 
16319
16234
  --db-checkbox-shadow-checked: var(--db-selection-toggle-shadow-checked);
16320
- --db-checkbox-focus-ring-width: var(--db-selection-toggle-focus-ring-width);
16321
- --db-checkbox-focus-ring-offset: var(--db-selection-toggle-focus-ring-offset);
16322
- --db-checkbox-transition-duration: var(--db-selection-toggle-transition-duration);
16323
16235
 
16324
- /* Indeterminate mark — sized to look like AntD's `<inner>` ::after dash. */
16325
- --db-checkbox-indeterminate-mark-width: 8px;
16326
- --db-checkbox-indeterminate-mark-height: 2px;
16236
+ /* Density */
16237
+ --db-checkbox-size: var(--db-selection-toggle-size);
16238
+ --db-checkbox-label-spacing: var(--db-selection-toggle-label-spacing);
16239
+ --db-checkbox-focus-ring-width: var(--db-focus-ring-width);
16240
+ --db-checkbox-indeterminate-mark-width: var(--db-size-2xs); /* 8px */
16241
+ --db-checkbox-indeterminate-mark-height: calc(var(--db-size-3xs) * 0.75); /* 3px */
16242
+
16243
+ /* Motion */
16244
+ --db-checkbox-transition-duration: var(--db-selection-toggle-transition-duration);
16327
16245
  }
16328
16246
 
16329
16247
  /* Native-input <Checkbox> styles. Classic CSS only — no native nesting (the
@@ -16370,35 +16288,34 @@ span.du-bois-light-typography-ellipsis-single-line {
16370
16288
  width: fit-content;
16371
16289
  }
16372
16290
 
16373
- /* Hover/press live on the root (label), not on the input: the input has
16374
- * `pointer-events: none` (so a single click target stays on the label and
16375
- * label/input association toggles the box), which means `input:hover` would
16376
- * never match. Putting `:hover` on the root also makes the entire label area
16291
+ /* Hover/press live on the root (label), not on the input: the input is
16292
+ * visually hidden (opacity:0), so an `input:hover` rule wouldn't be visible
16293
+ * anyway. Putting `:hover` on the root also makes the entire label area
16377
16294
  * — not just the indicator square — drive the visual feedback. */
16378
16295
  .ds-checkbox:hover:has(.ds-checkbox-input:not(:disabled, :checked, :indeterminate)) .ds-checkbox-indicator {
16379
- background-color: var(--db-checkbox-bg-hover);
16296
+ background-color: var(--db-checkbox-surface-hover);
16380
16297
  border-color: var(--db-checkbox-border-hover);
16381
16298
  }
16382
16299
 
16383
16300
  .ds-checkbox:active:has(.ds-checkbox-input:not(:disabled, :checked, :indeterminate)) .ds-checkbox-indicator {
16384
- background-color: var(--db-checkbox-bg-press);
16301
+ background-color: var(--db-checkbox-surface-press);
16385
16302
  border-color: var(--db-checkbox-border-press);
16386
16303
  }
16387
16304
 
16388
16305
  /* Selected fill — checked and indeterminate share the same surface. */
16389
16306
  .ds-checkbox:has(.ds-checkbox-input:is(:checked, :indeterminate)) .ds-checkbox-indicator {
16390
- background-color: var(--db-checkbox-bg-checked);
16391
- border-color: var(--db-checkbox-bg-checked);
16307
+ background-color: var(--db-checkbox-surface-checked);
16308
+ border-color: var(--db-checkbox-surface-checked);
16392
16309
  }
16393
16310
 
16394
16311
  .ds-checkbox:hover:has(.ds-checkbox-input:is(:checked, :indeterminate):not(:disabled)) .ds-checkbox-indicator {
16395
- background-color: var(--db-checkbox-bg-checked-hover);
16396
- border-color: var(--db-checkbox-bg-checked-hover);
16312
+ background-color: var(--db-checkbox-surface-checked-hover);
16313
+ border-color: var(--db-checkbox-surface-checked-hover);
16397
16314
  }
16398
16315
 
16399
16316
  .ds-checkbox:active:has(.ds-checkbox-input:is(:checked, :indeterminate):not(:disabled)) .ds-checkbox-indicator {
16400
- background-color: var(--db-checkbox-bg-checked-press);
16401
- border-color: var(--db-checkbox-bg-checked-press);
16317
+ background-color: var(--db-checkbox-surface-checked-press);
16318
+ border-color: var(--db-checkbox-surface-checked-press);
16402
16319
  }
16403
16320
 
16404
16321
  /* Mark visibility. */
@@ -16412,8 +16329,8 @@ span.du-bois-light-typography-ellipsis-single-line {
16412
16329
 
16413
16330
  /* Focus-visible (keyboard only). */
16414
16331
  .ds-checkbox:has(.ds-checkbox-input:focus-visible) .ds-checkbox-indicator {
16415
- outline: var(--db-checkbox-focus-ring-width) solid var(--db-checkbox-border-focus);
16416
- outline-offset: var(--db-checkbox-focus-ring-offset);
16332
+ outline: var(--db-checkbox-focus-ring-width) solid var(--db-checkbox-focus-ring);
16333
+ outline-offset: 4px;
16417
16334
  }
16418
16335
 
16419
16336
  /* Disabled (covers unchecked, checked, indeterminate). Sourced from
@@ -16428,22 +16345,28 @@ span.du-bois-light-typography-ellipsis-single-line {
16428
16345
  }
16429
16346
 
16430
16347
  .ds-checkbox:has(.ds-checkbox-input:disabled) .ds-checkbox-indicator {
16431
- background-color: var(--db-checkbox-bg-disabled);
16348
+ background-color: var(--db-checkbox-surface-disabled);
16432
16349
  border-color: var(--db-checkbox-border-disabled);
16433
16350
  box-shadow: none;
16434
16351
  }
16435
16352
 
16436
16353
  .ds-checkbox:has(.ds-checkbox-input:disabled) .ds-checkbox-checkmark {
16437
- color: var(--db-checkbox-icon-color-disabled);
16354
+ color: var(--db-checkbox-mark-disabled);
16438
16355
  }
16439
16356
 
16440
16357
  .ds-checkbox:has(.ds-checkbox-input:disabled) .ds-checkbox-dash {
16441
- background-color: var(--db-checkbox-icon-color-disabled);
16358
+ background-color: var(--db-checkbox-mark-disabled);
16442
16359
  }
16443
16360
 
16444
- /* Visually-hidden native input, kept interactive and in the tab order so
16445
- * `:has()` lookups above can read its state. Pointer events fall through to
16446
- * the label, so clicking anywhere toggles the box. */
16361
+ /* Visually-hidden native input (opacity:0) overlaying the indicator square,
16362
+ * kept interactive and in the tab order so `:has()` lookups above can read its
16363
+ * state. It stays pointer-clickable matching AntD's `.ant-checkbox-input`
16364
+ * so it is the top-most hit-test target over the box: `getByRole('checkbox').click()`
16365
+ * (Playwright, and any coordinate click that lands on the box) resolves to the
16366
+ * real control instead of the decorative indicator overlay. Making the input
16367
+ * `pointer-events: none` (the prior native-only behavior) is what regressed
16368
+ * interaction tests vs. the AntD variant. `cursor: inherit` tracks the label's
16369
+ * pointer / disabled `not-allowed` cursor so the box keeps AntD's cursor too. */
16447
16370
  .ds-checkbox .ds-checkbox-input {
16448
16371
  position: absolute;
16449
16372
  inset: 0;
@@ -16451,7 +16374,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16451
16374
  block-size: var(--db-checkbox-size);
16452
16375
  margin: 0;
16453
16376
  opacity: 0;
16454
- pointer-events: none;
16377
+ cursor: inherit;
16455
16378
  }
16456
16379
 
16457
16380
  /* Indicator — square with the border/fill that responds to state above.
@@ -16462,12 +16385,18 @@ span.du-bois-light-typography-ellipsis-single-line {
16462
16385
  display: grid;
16463
16386
  place-items: center;
16464
16387
  flex-shrink: 0;
16388
+ /* Decorative only — the overlaid input owns hit-testing. Without this, the
16389
+ * indicator (and its inherited checkmark/dash children) intercept
16390
+ * `getByRole('checkbox').click()`; clicks on any edge sliver the input does
16391
+ * not cover fall through to the label, which toggles via label/input
16392
+ * association. */
16393
+ pointer-events: none;
16465
16394
  inline-size: var(--db-checkbox-size);
16466
16395
  block-size: var(--db-checkbox-size);
16467
16396
  margin-top: calc((var(--db-line-height-base, 20px) - var(--db-checkbox-size)) / 2);
16468
- border: var(--db-checkbox-border-width) solid var(--db-checkbox-border-default);
16397
+ border: var(--db-checkbox-border-width) solid var(--db-checkbox-border);
16469
16398
  border-radius: var(--db-checkbox-border-radius);
16470
- background-color: var(--db-checkbox-bg-default);
16399
+ background-color: var(--db-checkbox-surface);
16471
16400
  box-sizing: border-box;
16472
16401
  transition:
16473
16402
  background-color var(--db-checkbox-transition-duration) ease,
@@ -16479,7 +16408,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16479
16408
  grid-area: 1 / 1;
16480
16409
  inline-size: 100%;
16481
16410
  block-size: 100%;
16482
- color: var(--db-checkbox-icon-color);
16411
+ color: var(--db-checkbox-mark);
16483
16412
  opacity: 0;
16484
16413
  transition: opacity var(--db-checkbox-transition-duration) ease;
16485
16414
  }
@@ -16496,8 +16425,10 @@ span.du-bois-light-typography-ellipsis-single-line {
16496
16425
  grid-area: 1 / 1;
16497
16426
  inline-size: var(--db-checkbox-indeterminate-mark-width);
16498
16427
  block-size: var(--db-checkbox-indeterminate-mark-height);
16499
- border-radius: 1px;
16500
- background-color: var(--db-checkbox-icon-color);
16428
+ /* CSS clamps this to half the 3px height, giving fully rounded end caps so the
16429
+ * dash reads as a pill rather than a flat bar. */
16430
+ border-radius: 4px;
16431
+ background-color: var(--db-checkbox-mark);
16501
16432
  opacity: 0;
16502
16433
  transition: opacity var(--db-checkbox-transition-duration) ease;
16503
16434
  }
@@ -16509,7 +16440,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16509
16440
  * as the AntD variant. */
16510
16441
  .ds-checkbox .ds-checkbox-label {
16511
16442
  color: var(--db-checkbox-text);
16512
- padding-inline: var(--db-checkbox-spacing);
16443
+ padding-inline: var(--db-checkbox-label-spacing);
16513
16444
  word-break: break-word;
16514
16445
  }
16515
16446
 
@@ -16534,7 +16465,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16534
16465
  .ds-checkbox.ds-checkbox + .du-bois-dark-form-message,
16535
16466
  .ds-checkbox.ds-checkbox + .du-bois-light-hint + .du-bois-light-form-message,
16536
16467
  .ds-checkbox.ds-checkbox + .du-bois-dark-hint + .du-bois-dark-form-message {
16537
- padding-left: var(--db-space-lg);
16468
+ padding-left: var(--db-spacing-sm);
16538
16469
  margin-top: 0;
16539
16470
  }
16540
16471
 
@@ -16545,7 +16476,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16545
16476
  .du-bois-dark-hint + .ds-checkbox-group.ds-checkbox-group,
16546
16477
  .ds-checkbox-group.ds-checkbox-group + .du-bois-light-form-message,
16547
16478
  .ds-checkbox-group.ds-checkbox-group + .du-bois-dark-form-message {
16548
- margin-top: var(--db-space-sm);
16479
+ margin-top: var(--db-spacing-2xs);
16549
16480
  }
16550
16481
 
16551
16482
  /* CheckboxGroup layout. Vertical delegates to the `.ds-stack` primitive; the
@@ -16561,82 +16492,51 @@ span.du-bois-light-typography-ellipsis-single-line {
16561
16492
  * off the vertical element so it never fights the stack primitive's gap. */
16562
16493
  .ds-checkbox-group:not(.ds-stack) {
16563
16494
  flex-wrap: nowrap;
16564
- column-gap: var(--db-checkbox-spacing);
16495
+ column-gap: var(--db-checkbox-label-spacing);
16565
16496
  row-gap: 0;
16566
16497
  }
16567
16498
 
16568
16499
  /* Vertical: .ds-stack supplies flex-direction + gap; we only retarget the knob. */
16569
16500
  .ds-checkbox-group.ds-stack {
16570
- --ds-stack-gap: var(--db-checkbox-spacing);
16501
+ --ds-stack-gap: var(--db-checkbox-label-spacing);
16571
16502
  }
16572
16503
 
16573
- /* Component-tier tokens for <Radio>. Each value defaults to a CATEGORY
16574
- * (selection-toggle) token via var(); consumers can override here to retheme
16575
- * radios without affecting checkbox / switch.
16576
- *
16577
- * Radio differs from Checkbox in two ways: the indicator is a full circle
16578
- * (border-radius) and the "mark" is a filled dot rather than a checkmark/dash. */
16579
-
16580
- /* Re-declared under both theme classes (not just :root) so the var() chain onto
16581
- * category/system tokens re-resolves inside a `.du-bois-dark` subtree instead of
16582
- * freezing at the root (light) values. See DUBOIS-448 dark-mode scoping. */
16583
- :where(:root, .du-bois-light, .du-bois-dark) {
16584
- --db-radio-size: var(--db-selection-toggle-size);
16585
- /* Circle, not a rounded square — the one shape token that does NOT inherit
16586
- * the category (square) radius. */
16504
+ :where(:root), :where(.du-bois-light) {
16505
+ /* Shape */
16587
16506
  --db-radio-border-radius: var(--db-radius-full);
16588
16507
  --db-radio-border-width: 1px;
16589
- --db-radio-spacing: var(--db-selection-toggle-spacing);
16590
16508
 
16591
- --db-radio-bg-default: var(--db-selection-toggle-bg-default);
16592
- --db-radio-bg-hover: var(--db-selection-toggle-bg-hover);
16593
- --db-radio-bg-press: var(--db-selection-toggle-bg-press);
16594
- --db-radio-bg-checked: var(--db-selection-toggle-bg-checked);
16595
- --db-radio-bg-checked-hover: var(--db-selection-toggle-bg-checked-hover);
16596
- /* AntD checked active/press background is actionDefaultBackgroundPress (NOT the
16597
- * primary press), so this maps to the default press bg category token — see
16598
- * getRadioInputStyles checked active in AntDRadioInternal.tsx. */
16599
- --db-radio-bg-checked-press: var(--db-selection-toggle-bg-press);
16600
- --db-radio-bg-disabled: var(--db-selection-toggle-bg-disabled);
16509
+ /* Color */
16510
+ --db-radio-surface: var(--db-selection-toggle-surface);
16511
+ --db-radio-surface-hover: var(--db-color-action-default-background-hover);
16512
+ --db-radio-surface-press: var(--db-color-action-default-background-press);
16513
+ --db-radio-surface-checked: var(--db-selection-toggle-surface-checked);
16514
+ --db-radio-surface-checked-hover: var(--db-selection-toggle-surface-checked-hover);
16515
+ --db-radio-surface-checked-press: var(--db-color-action-default-background-press);
16516
+ --db-radio-surface-disabled: var(--db-selection-toggle-surface-disabled);
16601
16517
 
16602
- --db-radio-border-default: var(--db-selection-toggle-border-default);
16518
+ --db-radio-border: var(--db-color-action-default-border-default);
16603
16519
  --db-radio-border-hover: var(--db-selection-toggle-border-hover);
16604
16520
  --db-radio-border-press: var(--db-selection-toggle-border-press);
16605
- --db-radio-border-focus: var(--db-selection-toggle-border-focus);
16606
- --db-radio-border-disabled: var(--db-selection-toggle-border-disabled);
16607
-
16608
- /* Two-tone checked hover/press border ring (AntD getRadioInputStyles checked
16609
- * states): the border is a DARKER shade than the fill, not equal to it.
16610
- * - checked hover border = actionPrimaryBackgroundPress (== the press category
16611
- * token, which is action-primary-background-press).
16612
- * - checked press border = actionDefaultBorderPress; no selection-toggle
16613
- * category token equals this color, so reference the system token directly. */
16521
+ --db-radio-border-focus: var(--db-focus-ring-color);
16522
+ --db-radio-border-disabled: var(--db-color-action-disabled-border);
16614
16523
  --db-radio-border-checked-hover: var(--db-selection-toggle-border-press);
16615
16524
  --db-radio-border-checked-press: var(--db-color-action-default-border-press);
16525
+ --db-radio-border-unchecked-focus: var(--db-color-action-primary-background-default);
16526
+ --db-radio-outline-checked-focus: var(--db-color-action-primary-background-default);
16616
16527
 
16617
- /* Unchecked keyboard-focus border (AntD getRadioInputStyles unchecked focus):
16618
- * borderColor = actionPrimaryBackgroundDefault, with NO outline ring. No
16619
- * selection-toggle category token equals this color (the closest is a bg
16620
- * token), so reference the system token directly. */
16621
- --db-radio-border-focus-unchecked: var(--db-color-action-primary-background-default);
16622
- /* Checked focus-visible outline color (AntD: outline 1px solid
16623
- * actionPrimaryBackgroundDefault, outlineOffset 1). */
16624
- --db-radio-focus-outline-checked-color: var(--db-color-action-primary-background-default);
16625
-
16626
- /* The dot. Shares the category icon-color token (white over the filled
16627
- * primary surface) so a retheme moves checkbox checkmark + radio dot together. */
16628
- --db-radio-dot-color: var(--db-selection-toggle-icon-color);
16629
- --db-radio-dot-color-disabled: var(--db-selection-toggle-icon-color-disabled);
16528
+ --db-radio-mark: #ffffff;
16529
+ --db-radio-mark-disabled: var(--db-selection-toggle-mark-disabled);
16630
16530
  --db-radio-text: var(--db-selection-toggle-text);
16631
16531
  --db-radio-text-disabled: var(--db-selection-toggle-text-disabled);
16632
16532
 
16633
- --db-radio-focus-ring-width: var(--db-selection-toggle-focus-ring-width);
16634
- --db-radio-focus-ring-offset: var(--db-selection-toggle-focus-ring-offset);
16635
- --db-radio-transition-duration: var(--db-selection-toggle-transition-duration);
16533
+ /* Density */
16534
+ --db-radio-size: var(--db-selection-toggle-size);
16535
+ --db-radio-label-spacing: var(--db-selection-toggle-label-spacing);
16536
+ --db-radio-mark-size: var(--db-size-3xs);
16636
16537
 
16637
- /* Diameter of the inner dot. Mirrors the AntD checked `::after` size, which uses
16638
- * `theme.spacing.xs` (4px) — see getRadioInputStyles in AntDRadioInternal.tsx. */
16639
- --db-radio-dot-size: var(--db-space-xs);
16538
+ /* Motion */
16539
+ --db-radio-transition-duration: var(--db-selection-toggle-transition-duration);
16640
16540
  }
16641
16541
 
16642
16542
  /* Native-input <Radio> styles. Classic CSS only — no native nesting (the
@@ -16675,36 +16575,36 @@ span.du-bois-light-typography-ellipsis-single-line {
16675
16575
  width: fit-content;
16676
16576
  }
16677
16577
 
16678
- /* Hover/press live on the root (label), not on the input: the input has
16679
- * `pointer-events: none`, so `input:hover` would never match, and the whole
16680
- * label area should drive the feedback. */
16578
+ /* Hover/press live on the root (label), not on the input: the input is
16579
+ * visually hidden (opacity:0), so an `input:hover` rule wouldn't be visible
16580
+ * anyway, and the whole label area should drive the feedback. */
16681
16581
  .ds-radio:hover:has(input:not(:disabled, :checked)) .ds-radio-indicator {
16682
- background-color: var(--db-radio-bg-hover);
16582
+ background-color: var(--db-radio-surface-hover);
16683
16583
  border-color: var(--db-radio-border-hover);
16684
16584
  }
16685
16585
 
16686
16586
  .ds-radio:active:has(input:not(:disabled, :checked)) .ds-radio-indicator {
16687
- background-color: var(--db-radio-bg-press);
16587
+ background-color: var(--db-radio-surface-press);
16688
16588
  border-color: var(--db-radio-border-press);
16689
16589
  }
16690
16590
 
16691
16591
  /* Selected fill. */
16692
16592
  .ds-radio:has(input:checked) .ds-radio-indicator {
16693
- background-color: var(--db-radio-bg-checked);
16694
- border-color: var(--db-radio-bg-checked);
16593
+ background-color: var(--db-radio-surface-checked);
16594
+ border-color: var(--db-radio-surface-checked);
16695
16595
  }
16696
16596
 
16697
16597
  /* AntD getRadioInputStyles checked hover: background = actionPrimaryBackgroundHover,
16698
16598
  * borderColor = actionPrimaryBackgroundPress (a darker ring than the fill). */
16699
16599
  .ds-radio:hover:has(input:checked:not(:disabled)) .ds-radio-indicator {
16700
- background-color: var(--db-radio-bg-checked-hover);
16600
+ background-color: var(--db-radio-surface-checked-hover);
16701
16601
  border-color: var(--db-radio-border-checked-hover);
16702
16602
  }
16703
16603
 
16704
16604
  /* AntD getRadioInputStyles checked active: background = actionDefaultBackgroundPress,
16705
16605
  * borderColor = actionDefaultBorderPress (two-tone, not flat). */
16706
16606
  .ds-radio:active:has(input:checked:not(:disabled)) .ds-radio-indicator {
16707
- background-color: var(--db-radio-bg-checked-press);
16607
+ background-color: var(--db-radio-surface-checked-press);
16708
16608
  border-color: var(--db-radio-border-checked-press);
16709
16609
  }
16710
16610
 
@@ -16719,16 +16619,16 @@ span.du-bois-light-typography-ellipsis-single-line {
16719
16619
  * UNCHECKED focus (AntD `&:not(disabled) > input:focus + inner`): only the border
16720
16620
  * color changes to actionPrimaryBackgroundDefault — NO outline ring. */
16721
16621
  .ds-radio:has(input:focus-visible:not(:checked)) .ds-radio-indicator {
16722
- border-color: var(--db-radio-border-focus-unchecked);
16622
+ border-color: var(--db-radio-border-unchecked-focus);
16723
16623
  }
16724
16624
 
16725
16625
  /* CHECKED focus-visible (AntD `&.checked &:not(disabled) > input:focus-visible + inner`):
16726
16626
  * background = actionPrimaryBackgroundDefault, borderColor = actionDefaultBorderFocus,
16727
16627
  * outline = 1px solid actionPrimaryBackgroundDefault, outlineOffset = 1. */
16728
16628
  .ds-radio:has(input:focus-visible:checked) .ds-radio-indicator {
16729
- background-color: var(--db-radio-bg-checked);
16629
+ background-color: var(--db-radio-surface-checked);
16730
16630
  border-color: var(--db-radio-border-focus);
16731
- outline: 1px solid var(--db-radio-focus-outline-checked-color);
16631
+ outline: 1px solid var(--db-radio-outline-checked-focus);
16732
16632
  outline-offset: 1px;
16733
16633
  }
16734
16634
 
@@ -16743,18 +16643,24 @@ span.du-bois-light-typography-ellipsis-single-line {
16743
16643
  }
16744
16644
 
16745
16645
  .ds-radio:has(input:disabled) .ds-radio-indicator {
16746
- background-color: var(--db-radio-bg-disabled);
16646
+ background-color: var(--db-radio-surface-disabled);
16747
16647
  border-color: var(--db-radio-border-disabled);
16748
16648
  box-shadow: none;
16749
16649
  }
16750
16650
 
16751
16651
  .ds-radio:has(input:disabled) .ds-radio-dot {
16752
- background-color: var(--db-radio-dot-color-disabled);
16652
+ background-color: var(--db-radio-mark-disabled);
16753
16653
  }
16754
16654
 
16755
- /* Visually-hidden native input, kept interactive and in the tab order so the
16756
- * `:has()` lookups above can read its state. Pointer events fall through to the
16757
- * label, so clicking anywhere toggles the radio. */
16655
+ /* Visually-hidden native input (opacity:0) overlaying the indicator circle,
16656
+ * kept interactive and in the tab order so the `:has()` lookups above can read
16657
+ * its state. It stays pointer-clickable matching AntD's `.ant-radio-input`
16658
+ * so it is the top-most hit-test target over the circle: `getByRole('radio').click()`
16659
+ * (Playwright, and any coordinate click that lands on the circle) resolves to the
16660
+ * real control instead of the decorative indicator overlay. Making the input
16661
+ * `pointer-events: none` (the prior native-only behavior) is what regressed
16662
+ * interaction tests vs. the AntD variant. `cursor: inherit` tracks the label's
16663
+ * pointer / disabled `not-allowed` cursor so the circle keeps AntD's cursor too. */
16758
16664
  .ds-radio input {
16759
16665
  position: absolute;
16760
16666
  inset: 0;
@@ -16762,7 +16668,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16762
16668
  block-size: var(--db-radio-size);
16763
16669
  margin: 0;
16764
16670
  opacity: 0;
16765
- pointer-events: none;
16671
+ cursor: inherit;
16766
16672
  }
16767
16673
 
16768
16674
  /* Indicator — circle with the border/fill that responds to state above.
@@ -16772,12 +16678,17 @@ span.du-bois-light-typography-ellipsis-single-line {
16772
16678
  display: grid;
16773
16679
  place-items: center;
16774
16680
  flex-shrink: 0;
16681
+ /* Decorative only — the overlaid input owns hit-testing. Without this, the
16682
+ * indicator (and its inherited dot child) intercept `getByRole('radio').click()`;
16683
+ * clicks on any edge sliver the input does not cover fall through to the label,
16684
+ * which toggles via label/input association. */
16685
+ pointer-events: none;
16775
16686
  inline-size: var(--db-radio-size);
16776
16687
  block-size: var(--db-radio-size);
16777
16688
  margin-top: calc((var(--db-line-height-base, 20px) - var(--db-radio-size)) / 2);
16778
- border: var(--db-radio-border-width) solid var(--db-radio-border-default);
16689
+ border: var(--db-radio-border-width) solid var(--db-radio-border);
16779
16690
  border-radius: var(--db-radio-border-radius);
16780
- background-color: var(--db-radio-bg-default);
16691
+ background-color: var(--db-radio-surface);
16781
16692
  box-sizing: border-box;
16782
16693
  transition:
16783
16694
  background-color var(--db-radio-transition-duration) ease,
@@ -16787,10 +16698,10 @@ span.du-bois-light-typography-ellipsis-single-line {
16787
16698
 
16788
16699
  .ds-radio .ds-radio-indicator > .ds-radio-dot {
16789
16700
  grid-area: 1 / 1;
16790
- inline-size: var(--db-radio-dot-size);
16791
- block-size: var(--db-radio-dot-size);
16701
+ inline-size: var(--db-radio-mark-size);
16702
+ block-size: var(--db-radio-mark-size);
16792
16703
  border-radius: var(--db-radius-full);
16793
- background-color: var(--db-radio-dot-color);
16704
+ background-color: var(--db-radio-mark);
16794
16705
  opacity: 0;
16795
16706
  transition: opacity var(--db-radio-transition-duration) ease;
16796
16707
  }
@@ -16808,7 +16719,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16808
16719
  * trailing whitespace that separates adjacent radios in a row. */
16809
16720
  .ds-radio .ds-radio-label {
16810
16721
  color: var(--db-radio-text);
16811
- padding-inline: var(--db-radio-spacing);
16722
+ padding-inline: var(--db-radio-label-spacing);
16812
16723
  word-break: break-word;
16813
16724
  }
16814
16725
 
@@ -16822,7 +16733,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16822
16733
  .ds-radio.ds-radio + .du-bois-dark-form-message,
16823
16734
  .ds-radio.ds-radio + .du-bois-light-hint + .du-bois-light-form-message,
16824
16735
  .ds-radio.ds-radio + .du-bois-dark-hint + .du-bois-dark-form-message {
16825
- padding-inline-start: var(--db-space-lg);
16736
+ padding-inline-start: var(--db-spacing-sm);
16826
16737
  margin-top: 0;
16827
16738
  }
16828
16739
 
@@ -16838,8 +16749,8 @@ span.du-bois-light-typography-ellipsis-single-line {
16838
16749
  .ds-radio-group.ds-stack > .ds-radio.ds-radio + .du-bois-dark-form-message,
16839
16750
  .ds-radio-group.ds-stack > .ds-radio.ds-radio + .du-bois-light-hint + .du-bois-light-form-message,
16840
16751
  .ds-radio-group.ds-stack > .ds-radio.ds-radio + .du-bois-dark-hint + .du-bois-dark-form-message {
16841
- margin-top: calc(-1 * var(--db-space-sm));
16842
- margin-bottom: var(--db-space-sm);
16752
+ margin-top: calc(-1 * var(--db-spacing-2xs));
16753
+ margin-bottom: var(--db-spacing-2xs);
16843
16754
  }
16844
16755
 
16845
16756
  /* AntD `& > label:last-of-type + hint { marginTop: 0 }`: the last radio has no
@@ -16857,7 +16768,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16857
16768
  .du-bois-dark-hint + .ds-radio-group.ds-radio-group,
16858
16769
  .ds-radio-group.ds-radio-group + .du-bois-light-form-message,
16859
16770
  .ds-radio-group.ds-radio-group + .du-bois-dark-form-message {
16860
- margin-top: var(--db-space-sm);
16771
+ margin-top: var(--db-spacing-2xs);
16861
16772
  }
16862
16773
 
16863
16774
  /* RadioGroup layout. Vertical (the default) delegates flex-direction to the
@@ -16873,12 +16784,12 @@ span.du-bois-light-typography-ellipsis-single-line {
16873
16784
  * no gap of its own, so we zero out the gap and reproduce the rhythm via
16874
16785
  * padding-bottom on each radio. */
16875
16786
  .ds-radio-group.ds-stack {
16876
- --ds-stack-gap: var(--db-space-0);
16787
+ --ds-stack-gap: 0;
16877
16788
  }
16878
16789
 
16879
16790
  /* AntD `& > label { paddingBottom: sm }`. */
16880
16791
  .ds-radio-group.ds-stack > .ds-radio {
16881
- padding-bottom: var(--db-space-sm);
16792
+ padding-bottom: var(--db-spacing-2xs);
16882
16793
  }
16883
16794
 
16884
16795
  /* AntD `& > label:last-of-type { paddingBottom: 0 }`. */
@@ -16894,7 +16805,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16894
16805
  .ds-radio-group.ds-stack > .du-bois-light-radio-tile + .du-bois-dark-radio-tile,
16895
16806
  .ds-radio-group.ds-stack > .du-bois-dark-radio-tile + .du-bois-light-radio-tile,
16896
16807
  .ds-radio-group.ds-stack > .du-bois-dark-radio-tile + .du-bois-dark-radio-tile {
16897
- margin-top: var(--db-space-md);
16808
+ margin-top: var(--db-spacing-xs);
16898
16809
  }
16899
16810
 
16900
16811
  /* Horizontal: AntD `getHorizontalRadioGroupStyles` is a TWO-ROW grid (NOT a flex
@@ -16907,7 +16818,7 @@ span.du-bois-light-typography-ellipsis-single-line {
16907
16818
  display: grid;
16908
16819
  grid-template-rows: [label] auto [hint] auto;
16909
16820
  grid-auto-columns: max-content;
16910
- column-gap: var(--db-space-md);
16821
+ column-gap: var(--db-spacing-xs);
16911
16822
  }
16912
16823
 
16913
16824
  /* Equal column widths: AntD `gridAutoColumns: minmax(0, 1fr)`. */
@@ -16940,64 +16851,52 @@ span.du-bois-light-typography-ellipsis-single-line {
16940
16851
  * the group itself gets a top margin (room above the two-row grid). */
16941
16852
  .ds-radio-group--horizontal:has(> .du-bois-light-hint),
16942
16853
  .ds-radio-group--horizontal:has(> .du-bois-dark-hint) {
16943
- margin-top: var(--db-space-sm);
16854
+ margin-top: var(--db-spacing-2xs);
16944
16855
  }
16945
16856
 
16946
16857
  /* AntD `&& + form-message { marginTop: sm }` (horizontal): a form-message following
16947
16858
  * the whole group is separated by sm. */
16948
16859
  .ds-radio-group--horizontal + .du-bois-light-form-message,
16949
16860
  .ds-radio-group--horizontal + .du-bois-dark-form-message {
16950
- margin-top: var(--db-space-sm);
16861
+ margin-top: var(--db-spacing-2xs);
16951
16862
  }
16952
16863
 
16953
- /* Component-tier tokens for <Switch>. Colors default to the selection-toggle category tokens;
16954
- * geometry is hand-authored (the pill track + sliding thumb are unique to Switch). */
16955
-
16956
- /* Re-declared under both theme classes (not just :root) so the var() chain onto
16957
- * category/system tokens re-resolves inside a `.du-bois-dark` subtree instead of
16958
- * freezing at the root (light) values. See DUBOIS-448 dark-mode scoping. */
16959
- :where(:root, .du-bois-light, .du-bois-dark) {
16960
- --db-switch-track-width: 28px;
16961
- --db-switch-track-height: 16px;
16962
- /* Thumb fills the track height by design; expressed via track-height so the two can't drift. */
16963
- --db-switch-thumb-size: var(--db-switch-track-height);
16964
- /* Pill radius overrides the category (square) radius, mirroring Radio's circular override. */
16864
+ :where(:root), :where(.du-bois-light) {
16865
+ /* Shape */
16965
16866
  --db-switch-border-radius: var(--db-radius-full);
16966
16867
  --db-switch-border-width: 1px;
16967
- --db-switch-spacing: var(--db-selection-toggle-spacing);
16968
16868
 
16969
- --db-switch-bg-default: var(--db-selection-toggle-bg-default);
16970
- --db-switch-bg-hover: var(--db-selection-toggle-bg-hover);
16971
- --db-switch-bg-press: var(--db-selection-toggle-bg-press);
16972
- --db-switch-bg-checked: var(--db-selection-toggle-bg-checked);
16973
- --db-switch-bg-checked-hover: var(--db-selection-toggle-bg-checked-hover);
16974
- --db-switch-bg-checked-press: var(--db-selection-toggle-bg-checked-press);
16975
- --db-switch-bg-disabled: var(--db-selection-toggle-bg-disabled);
16869
+ /* Color */
16870
+ --db-switch-surface: var(--db-selection-toggle-surface);
16871
+ --db-switch-surface-hover: var(--db-color-action-default-background-hover);
16872
+ --db-switch-surface-press: var(--db-color-action-default-background-press);
16873
+ --db-switch-surface-checked: var(--db-selection-toggle-surface-checked);
16874
+ --db-switch-surface-checked-hover: var(--db-selection-toggle-surface-checked-hover);
16875
+ --db-switch-surface-checked-press: var(--db-selection-toggle-surface-checked-press);
16876
+ --db-switch-surface-disabled: var(--db-selection-toggle-surface-disabled);
16877
+ --db-switch-surface-checked-disabled: var(--db-color-action-disabled-text);
16976
16878
 
16977
- --db-switch-border-default: var(--db-selection-toggle-border-default);
16879
+ --db-switch-border: var(--db-color-action-default-border-default);
16978
16880
  --db-switch-border-hover: var(--db-selection-toggle-border-hover);
16979
16881
  --db-switch-border-press: var(--db-selection-toggle-border-press);
16980
- --db-switch-border-disabled: var(--db-selection-toggle-border-disabled);
16981
- /* AntD paints the checked track border equal to the checked fill, so these alias the checked bg. */
16982
- --db-switch-border-checked: var(--db-selection-toggle-bg-checked);
16983
- --db-switch-border-checked-hover: var(--db-selection-toggle-bg-checked-hover);
16984
- --db-switch-border-checked-press: var(--db-selection-toggle-bg-checked-press);
16985
- --db-switch-border-focus: var(--db-selection-toggle-bg-checked);
16986
- /* AntD fills the disabled+checked track with actionDisabledText; no category token matches, so
16987
- * reference the system token directly (same escape hatch Radio uses for its checked-press border). */
16988
- --db-switch-bg-checked-disabled: var(--db-color-action-disabled-text);
16882
+ --db-switch-border-disabled: var(--db-color-action-disabled-border);
16883
+ --db-switch-border-checked: var(--db-selection-toggle-surface-checked);
16884
+ --db-switch-border-checked-hover: var(--db-selection-toggle-surface-checked-hover);
16885
+ --db-switch-border-checked-press: var(--db-selection-toggle-surface-checked-press);
16886
+ --db-switch-border-focus: var(--db-selection-toggle-surface-checked);
16989
16887
 
16990
- /* AntD paints the handle the off-track surface color in every state. */
16991
- --db-switch-thumb-color: var(--db-selection-toggle-bg-default);
16888
+ --db-switch-thumb: var(--db-selection-toggle-surface);
16992
16889
 
16993
- /* A token (not inherit) so the label text flips in dark mode. */
16994
- --db-switch-text: var(--db-color-text-primary);
16890
+ --db-switch-text: var(--db-selection-toggle-text);
16995
16891
  --db-switch-text-disabled: var(--db-selection-toggle-text-disabled);
16996
16892
 
16997
- /* AntD's focus ring is a 1px outline (the category default is 2px). */
16998
- --db-switch-focus-ring-width: 1px;
16999
- --db-switch-focus-ring-offset: 1px;
17000
- --db-switch-focus-ring-color: var(--db-selection-toggle-border-focus);
16893
+ /* Density */
16894
+ --db-switch-track-width: calc(var(--db-size-xs) * 1.75); /* 28px */
16895
+ --db-switch-track-height: var(--db-size-xs); /* 16px */
16896
+ --db-switch-thumb-size: var(--db-switch-track-height);
16897
+ --db-switch-label-spacing: var(--db-selection-toggle-label-spacing);
16898
+
16899
+ /* Motion */
17001
16900
  --db-switch-transition-duration: var(--db-selection-toggle-transition-duration);
17002
16901
  }
17003
16902
 
@@ -17006,116 +16905,111 @@ span.du-bois-light-typography-ellipsis-single-line {
17006
16905
  * (e.g. a following FormMessage) down a few px, breaking the form-flow spacing. */
17007
16906
  display: flex;
17008
16907
  align-items: center;
17009
- position: relative;
17010
16908
  cursor: pointer;
17011
16909
  user-select: none;
17012
16910
  width: fit-content;
17013
- margin-inline-end: var(--db-switch-spacing);
16911
+ margin-inline-end: var(--db-switch-label-spacing);
16912
+ }
16913
+
16914
+ .ds-switch:has(input:disabled) {
16915
+ cursor: not-allowed;
17014
16916
  }
17015
16917
 
17016
- /* Hover/press live on the root (label), not the input: the input has `pointer-events: none`. */
17017
- .ds-switch:hover:has(input:not(:disabled, :checked)) .ds-switch-track {
17018
- background-color: var(--db-switch-bg-hover);
16918
+ /* The track. `appearance: none` strips the native checkbox rendering so the input itself can be styled. */
16919
+ .ds-switch input {
16920
+ appearance: none;
16921
+ position: relative;
16922
+ flex-shrink: 0;
16923
+ margin: 0;
16924
+ cursor: pointer;
16925
+ inline-size: var(--db-switch-track-width);
16926
+ block-size: var(--db-switch-track-height);
16927
+ border: var(--db-switch-border-width) solid var(--db-switch-border);
16928
+ border-radius: var(--db-switch-border-radius);
16929
+ background-color: var(--db-switch-surface);
16930
+ box-sizing: border-box;
16931
+ transition:
16932
+ background-color var(--db-switch-transition-duration) ease,
16933
+ border-color var(--db-switch-transition-duration) ease;
16934
+ }
16935
+
16936
+ /* The thumb. A pseudo-element keeps the input the switch's only element, so nothing can overlay it
16937
+ * and intercept clicks. Offset left by the border width to sit flush with the track's outer edge. */
16938
+ .ds-switch input::before {
16939
+ content: '';
16940
+ position: absolute;
16941
+ top: 50%;
16942
+ left: calc(-1 * var(--db-switch-border-width));
16943
+ inline-size: var(--db-switch-thumb-size);
16944
+ block-size: var(--db-switch-thumb-size);
16945
+ border: var(--db-switch-border-width) solid;
16946
+ border-color: inherit;
16947
+ border-radius: var(--db-switch-border-radius);
16948
+ background-color: var(--db-switch-thumb);
16949
+ box-sizing: border-box;
16950
+ transform: translateY(-50%);
16951
+ transition: transform var(--db-switch-transition-duration) ease;
16952
+ }
16953
+
16954
+ /* `<label for>` propagates `:hover` to the input, so scope hover/press to the control, not `input:hover`. */
16955
+ .ds-switch:hover input:not(:disabled):not(:checked) {
16956
+ background-color: var(--db-switch-surface-hover);
17019
16957
  border-color: var(--db-switch-border-hover);
17020
16958
  }
17021
16959
 
17022
- .ds-switch:active:has(input:not(:disabled, :checked)) .ds-switch-track {
17023
- background-color: var(--db-switch-bg-press);
16960
+ .ds-switch:active input:not(:disabled):not(:checked) {
16961
+ background-color: var(--db-switch-surface-press);
17024
16962
  border-color: var(--db-switch-border-press);
17025
16963
  }
17026
16964
 
17027
- .ds-switch:has(input:checked) .ds-switch-track {
17028
- background-color: var(--db-switch-bg-checked);
16965
+ .ds-switch input:checked {
16966
+ background-color: var(--db-switch-surface-checked);
17029
16967
  border-color: var(--db-switch-border-checked);
17030
16968
  }
17031
16969
 
17032
- .ds-switch:hover:has(input:checked:not(:disabled)) .ds-switch-track {
17033
- background-color: var(--db-switch-bg-checked-hover);
16970
+ .ds-switch:hover input:checked:not(:disabled) {
16971
+ background-color: var(--db-switch-surface-checked-hover);
17034
16972
  border-color: var(--db-switch-border-checked-hover);
17035
16973
  }
17036
16974
 
17037
- .ds-switch:active:has(input:checked:not(:disabled)) .ds-switch-track {
17038
- background-color: var(--db-switch-bg-checked-press);
16975
+ .ds-switch:active input:checked:not(:disabled) {
16976
+ background-color: var(--db-switch-surface-checked-press);
17039
16977
  border-color: var(--db-switch-border-checked-press);
17040
16978
  }
17041
16979
 
17042
- .ds-switch:has(input:checked) .ds-switch-thumb {
16980
+ .ds-switch input:checked::before {
17043
16981
  transform: translateY(-50%) translateX(calc(var(--db-switch-track-width) - var(--db-switch-thumb-size)));
17044
16982
  }
17045
16983
 
17046
- /* On focus, recolor the track border to the checked-fill color on top of the outline ring. Matching
17047
- * AntD, the ring sits flush when off and gains a 1px offset when checked (see the checked rule below). */
17048
- .ds-switch:has(input:focus-visible) .ds-switch-track {
16984
+ /* On focus, recolor the border to the checked-fill color on top of the outline ring. Matching AntD,
16985
+ * the ring sits flush when off and gains a 1px offset when checked.
16986
+ * TODO: width/offset are hardcoded 1px to preserve the AntD look; adopt the system 2px focus ring
16987
+ * (var(--db-focus-ring-width)) in a separate change. */
16988
+ .ds-switch input:focus-visible {
17049
16989
  border-color: var(--db-switch-border-focus);
17050
- outline: var(--db-switch-focus-ring-width) solid var(--db-switch-focus-ring-color);
16990
+ outline: 1px solid var(--db-focus-ring-color);
17051
16991
  outline-offset: 0;
17052
16992
  }
17053
16993
 
17054
- .ds-switch:has(input:checked:focus-visible) .ds-switch-track {
17055
- outline-offset: var(--db-switch-focus-ring-offset);
16994
+ .ds-switch input:checked:focus-visible {
16995
+ outline-offset: 1px;
17056
16996
  }
17057
16997
 
17058
- .ds-switch:has(input:disabled) {
16998
+ .ds-switch input:disabled {
17059
16999
  cursor: not-allowed;
17060
- }
17061
-
17062
- .ds-switch:has(input:disabled) .ds-switch-track {
17063
- background-color: var(--db-switch-bg-disabled);
17000
+ background-color: var(--db-switch-surface-disabled);
17064
17001
  border-color: var(--db-switch-border-disabled);
17065
17002
  }
17066
17003
 
17067
17004
  /* Disabled + on: more specific than the plain disabled rule, so it wins regardless of source order. */
17068
- .ds-switch:has(input:checked:disabled) .ds-switch-track {
17069
- background-color: var(--db-switch-bg-checked-disabled);
17070
- border-color: var(--db-switch-bg-checked-disabled);
17071
- }
17072
-
17073
- /* Hidden but still focusable/in tab order so `:has()` can read its state; pointer events fall through
17074
- * to the label. */
17075
- .ds-switch input {
17076
- position: absolute;
17077
- inset: 0;
17078
- inline-size: var(--db-switch-track-width);
17079
- block-size: var(--db-switch-track-height);
17080
- margin: 0;
17081
- opacity: 0;
17082
- pointer-events: none;
17083
- }
17084
-
17085
- .ds-switch-track {
17086
- position: relative;
17087
- flex-shrink: 0;
17088
- inline-size: var(--db-switch-track-width);
17089
- block-size: var(--db-switch-track-height);
17090
- border: var(--db-switch-border-width) solid var(--db-switch-border-default);
17091
- border-radius: var(--db-switch-border-radius);
17092
- background-color: var(--db-switch-bg-default);
17093
- box-sizing: border-box;
17094
- transition:
17095
- background-color var(--db-switch-transition-duration) ease,
17096
- border-color var(--db-switch-transition-duration) ease;
17097
- }
17098
-
17099
- /* `border-color: inherit` picks up the track's per-state color, so it's only set on the track. */
17100
- .ds-switch-thumb {
17101
- position: absolute;
17102
- top: 50%;
17103
- /* Pull left by the border width so the thumb sits flush with the track's outer edge, not inside it. */
17104
- left: calc(-1 * var(--db-switch-border-width));
17105
- inline-size: var(--db-switch-thumb-size);
17106
- block-size: var(--db-switch-thumb-size);
17107
- border: var(--db-switch-border-width) solid;
17108
- border-color: inherit;
17109
- border-radius: var(--db-switch-border-radius);
17110
- background-color: var(--db-switch-thumb-color);
17111
- box-sizing: border-box;
17112
- transform: translateY(-50%);
17113
- transition: transform var(--db-switch-transition-duration) ease;
17005
+ .ds-switch input:checked:disabled {
17006
+ background-color: var(--db-switch-surface-checked-disabled);
17007
+ border-color: var(--db-switch-surface-checked-disabled);
17114
17008
  }
17115
17009
 
17116
17010
  @media (prefers-reduced-motion: reduce) {
17117
- .ds-switch-track,
17118
- .ds-switch-thumb {
17011
+ .ds-switch input,
17012
+ .ds-switch input::before {
17119
17013
  transition: none;
17120
17014
  }
17121
17015
  }
@@ -17127,13 +17021,13 @@ span.du-bois-light-typography-ellipsis-single-line {
17127
17021
 
17128
17022
  .ds-switch-wrapper .ds-switch-state-message {
17129
17023
  margin-inline-start: auto;
17130
- margin-inline-end: var(--db-switch-spacing);
17024
+ margin-inline-end: var(--db-switch-label-spacing);
17131
17025
  }
17132
17026
 
17133
17027
  /* `:first-child` scopes this to the label-first layout; the plain layout renders the label last. */
17134
17028
  .ds-switch-wrapper > .du-bois-light-label:first-child,
17135
17029
  .ds-switch-wrapper > .du-bois-dark-label:first-child {
17136
- margin-inline-end: var(--db-switch-spacing);
17030
+ margin-inline-end: var(--db-switch-label-spacing);
17137
17031
  }
17138
17032
 
17139
17033
  .ds-switch-state-message {
@@ -17152,7 +17046,7 @@ span.du-bois-light-typography-ellipsis-single-line {
17152
17046
  + :is(.du-bois-light-hint, .du-bois-dark-hint, .du-bois-light-form-message, .du-bois-dark-form-message), :is(.ds-switch.ds-switch, .ds-switch-wrapper.ds-switch-wrapper)
17153
17047
  + :is(.du-bois-light-hint, .du-bois-dark-hint)
17154
17048
  + :is(.du-bois-light-form-message, .du-bois-dark-form-message) {
17155
- padding-inline-start: calc(var(--db-space-sm) + var(--db-switch-track-width));
17049
+ padding-inline-start: calc(var(--db-spacing-2xs) + var(--db-switch-track-width));
17156
17050
  }
17157
17051
 
17158
17052
  :is(.ds-switch.ds-switch, .ds-switch-wrapper.ds-switch-wrapper)