@slotted/styles 0.0.0-stage → 0.1.0-beta.1

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 (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/package.json +276 -3
  4. package/src/accordion/accordion.css +96 -0
  5. package/src/accordion/accordion.tokens.json +14 -0
  6. package/src/action-bar/action-bar.css +455 -0
  7. package/src/action-bar/action-bar.tokens.json +50 -0
  8. package/src/action-sheet/action-sheet.css +462 -0
  9. package/src/action-sheet/action-sheet.tokens.json +59 -0
  10. package/src/alert/alert.css +764 -0
  11. package/src/alert/alert.tokens.json +77 -0
  12. package/src/app-shell/app-shell.css +1899 -0
  13. package/src/app-shell/app-shell.tokens.json +88 -0
  14. package/src/aspect-ratio/aspect-ratio.css +131 -0
  15. package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
  16. package/src/attachment/attachment.css +906 -0
  17. package/src/attachment/attachment.tokens.json +85 -0
  18. package/src/avatar/avatar.css +598 -0
  19. package/src/avatar/avatar.tokens.json +64 -0
  20. package/src/avatar-group/avatar-group.css +268 -0
  21. package/src/avatar-group/avatar-group.tokens.json +16 -0
  22. package/src/badge/badge.css +462 -0
  23. package/src/badge/badge.tokens.json +58 -0
  24. package/src/breadcrumb/breadcrumb.css +441 -0
  25. package/src/breadcrumb/breadcrumb.tokens.json +50 -0
  26. package/src/button/button.css +754 -0
  27. package/src/button/button.tokens.json +72 -0
  28. package/src/button-group/button-group.css +455 -0
  29. package/src/button-group/button-group.tokens.json +11 -0
  30. package/src/calendar/calendar.css +846 -0
  31. package/src/calendar/calendar.tokens.json +67 -0
  32. package/src/card/card.css +602 -0
  33. package/src/card/card.tokens.json +68 -0
  34. package/src/carousel/carousel.css +860 -0
  35. package/src/carousel/carousel.tokens.json +62 -0
  36. package/src/cascader/cascader.css +1320 -0
  37. package/src/cascader/cascader.tokens.json +103 -0
  38. package/src/chart/chart.css +1473 -0
  39. package/src/chart/chart.tokens.json +107 -0
  40. package/src/checkbox/checkbox.css +1011 -0
  41. package/src/checkbox/checkbox.tokens.json +102 -0
  42. package/src/checkbox-group/checkbox-group.css +70 -0
  43. package/src/checkbox-group/checkbox-group.tokens.json +6 -0
  44. package/src/code-block/code-block.css +555 -0
  45. package/src/code-block/code-block.tokens.json +69 -0
  46. package/src/collapsible/collapsible.css +546 -0
  47. package/src/collapsible/collapsible.tokens.json +55 -0
  48. package/src/color-picker/color-picker.css +607 -0
  49. package/src/color-picker/color-picker.tokens.json +58 -0
  50. package/src/column-manager/column-manager.css +452 -0
  51. package/src/column-manager/column-manager.tokens.json +43 -0
  52. package/src/combobox/combobox.css +1048 -0
  53. package/src/combobox/combobox.tokens.json +112 -0
  54. package/src/command-palette/command-palette.css +1000 -0
  55. package/src/command-palette/command-palette.tokens.json +75 -0
  56. package/src/container/container.css +198 -0
  57. package/src/container/container.tokens.json +18 -0
  58. package/src/context-menu/context-menu.css +104 -0
  59. package/src/context-menu/context-menu.tokens.json +11 -0
  60. package/src/currency-field/currency-field.css +787 -0
  61. package/src/currency-field/currency-field.tokens.json +80 -0
  62. package/src/dashboard-grid/dashboard-grid.css +748 -0
  63. package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
  64. package/src/data-grid/data-grid.css +2484 -0
  65. package/src/data-grid/data-grid.tokens.json +100 -0
  66. package/src/data-list/data-list.css +455 -0
  67. package/src/data-list/data-list.tokens.json +35 -0
  68. package/src/date-field/date-field.css +560 -0
  69. package/src/date-field/date-field.tokens.json +80 -0
  70. package/src/date-picker/date-picker.css +420 -0
  71. package/src/date-picker/date-picker.tokens.json +49 -0
  72. package/src/date-range-picker/date-range-picker.css +983 -0
  73. package/src/date-range-picker/date-range-picker.tokens.json +109 -0
  74. package/src/datetime-field/datetime-field.css +850 -0
  75. package/src/datetime-field/datetime-field.tokens.json +91 -0
  76. package/src/datetime-picker/datetime-picker.css +843 -0
  77. package/src/datetime-picker/datetime-picker.tokens.json +78 -0
  78. package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
  79. package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
  80. package/src/description-list/description-list.css +675 -0
  81. package/src/description-list/description-list.tokens.json +66 -0
  82. package/src/detail-panel/detail-panel.css +329 -0
  83. package/src/detail-panel/detail-panel.tokens.json +33 -0
  84. package/src/dialog/dialog.css +968 -0
  85. package/src/dialog/dialog.tokens.json +66 -0
  86. package/src/divider/divider.css +131 -0
  87. package/src/divider/divider.tokens.json +18 -0
  88. package/src/drawer/drawer.css +1303 -0
  89. package/src/drawer/drawer.tokens.json +75 -0
  90. package/src/entity-picker/entity-picker.css +1367 -0
  91. package/src/entity-picker/entity-picker.tokens.json +118 -0
  92. package/src/event-calendar/event-calendar.css +2148 -0
  93. package/src/event-calendar/event-calendar.tokens.json +87 -0
  94. package/src/field/field.css +707 -0
  95. package/src/field/field.tokens.json +58 -0
  96. package/src/field-group/field-group.css +226 -0
  97. package/src/field-group/field-group.tokens.json +33 -0
  98. package/src/filter-bar/filter-bar.css +1306 -0
  99. package/src/filter-bar/filter-bar.tokens.json +78 -0
  100. package/src/form/form.css +218 -0
  101. package/src/form/form.tokens.json +32 -0
  102. package/src/fullscreen/fullscreen.css +376 -0
  103. package/src/fullscreen/fullscreen.tokens.json +50 -0
  104. package/src/grid/grid.css +173 -0
  105. package/src/grid/grid.tokens.json +20 -0
  106. package/src/highlight/highlight.css +135 -0
  107. package/src/highlight/highlight.tokens.json +16 -0
  108. package/src/hover-card/hover-card.css +93 -0
  109. package/src/hover-card/hover-card.tokens.json +17 -0
  110. package/src/icon/icon.css +136 -0
  111. package/src/icon/icon.tokens.json +14 -0
  112. package/src/image/image.css +449 -0
  113. package/src/image/image.tokens.json +27 -0
  114. package/src/import-export-center/import-export-center.css +1175 -0
  115. package/src/import-export-center/import-export-center.tokens.json +84 -0
  116. package/src/inline/inline.css +149 -0
  117. package/src/inline/inline.tokens.json +14 -0
  118. package/src/inline-message/inline-message.css +396 -0
  119. package/src/inline-message/inline-message.tokens.json +19 -0
  120. package/src/kbd/kbd.css +490 -0
  121. package/src/kbd/kbd.tokens.json +40 -0
  122. package/src/link/link.css +237 -0
  123. package/src/link/link.tokens.json +25 -0
  124. package/src/list/list.css +240 -0
  125. package/src/list/list.tokens.json +42 -0
  126. package/src/list-item/list-item.css +937 -0
  127. package/src/list-item/list-item.tokens.json +114 -0
  128. package/src/listbox/listbox.css +674 -0
  129. package/src/listbox/listbox.tokens.json +72 -0
  130. package/src/loading-overlay/loading-overlay.css +730 -0
  131. package/src/loading-overlay/loading-overlay.tokens.json +48 -0
  132. package/src/markdown/markdown.css +168 -0
  133. package/src/markdown/markdown.tokens.json +18 -0
  134. package/src/menu/menu.css +817 -0
  135. package/src/menu/menu.tokens.json +78 -0
  136. package/src/menubar/menubar.css +170 -0
  137. package/src/menubar/menubar.tokens.json +32 -0
  138. package/src/message/message.css +1453 -0
  139. package/src/message/message.tokens.json +85 -0
  140. package/src/message-scroller/message-scroller.css +371 -0
  141. package/src/message-scroller/message-scroller.tokens.json +47 -0
  142. package/src/multi-select/multi-select.css +1427 -0
  143. package/src/multi-select/multi-select.tokens.json +114 -0
  144. package/src/navigation-menu/navigation-menu.css +1029 -0
  145. package/src/navigation-menu/navigation-menu.tokens.json +70 -0
  146. package/src/notification-center/notification-center.css +856 -0
  147. package/src/notification-center/notification-center.tokens.json +84 -0
  148. package/src/number-field/number-field.css +794 -0
  149. package/src/number-field/number-field.tokens.json +80 -0
  150. package/src/otp-input/otp-input.css +525 -0
  151. package/src/otp-input/otp-input.tokens.json +69 -0
  152. package/src/page/page.css +179 -0
  153. package/src/page/page.tokens.json +20 -0
  154. package/src/page-header/page-header.css +1181 -0
  155. package/src/page-header/page-header.tokens.json +71 -0
  156. package/src/pagination/pagination.css +500 -0
  157. package/src/pagination/pagination.tokens.json +56 -0
  158. package/src/popover/popover.css +526 -0
  159. package/src/popover/popover.tokens.json +60 -0
  160. package/src/progress-indicator/progress-indicator.css +1584 -0
  161. package/src/progress-indicator/progress-indicator.tokens.json +50 -0
  162. package/src/prompt-composer/prompt-composer.css +680 -0
  163. package/src/prompt-composer/prompt-composer.tokens.json +99 -0
  164. package/src/prose/prose.css +733 -0
  165. package/src/prose/prose.tokens.json +79 -0
  166. package/src/radio-group/radio-group.css +778 -0
  167. package/src/radio-group/radio-group.tokens.json +103 -0
  168. package/src/rating/rating.css +1071 -0
  169. package/src/rating/rating.tokens.json +88 -0
  170. package/src/result-state/result-state.css +980 -0
  171. package/src/result-state/result-state.tokens.json +63 -0
  172. package/src/runtime-properties.mjs +321 -0
  173. package/src/saved-views/saved-views.css +394 -0
  174. package/src/saved-views/saved-views.tokens.json +41 -0
  175. package/src/scroll-area/scroll-area.css +481 -0
  176. package/src/scroll-area/scroll-area.tokens.json +15 -0
  177. package/src/section/section.css +177 -0
  178. package/src/section/section.tokens.json +39 -0
  179. package/src/segmented-control/segmented-control.css +564 -0
  180. package/src/segmented-control/segmented-control.tokens.json +67 -0
  181. package/src/select/select.css +1593 -0
  182. package/src/select/select.tokens.json +110 -0
  183. package/src/side-navigation/side-navigation.css +1096 -0
  184. package/src/side-navigation/side-navigation.tokens.json +87 -0
  185. package/src/skeleton/skeleton.css +431 -0
  186. package/src/skeleton/skeleton.tokens.json +29 -0
  187. package/src/slider/slider.css +792 -0
  188. package/src/slider/slider.tokens.json +75 -0
  189. package/src/sparkline/sparkline.css +282 -0
  190. package/src/sparkline/sparkline.tokens.json +45 -0
  191. package/src/spinner/spinner.css +224 -0
  192. package/src/spinner/spinner.tokens.json +8 -0
  193. package/src/split-button/split-button.css +253 -0
  194. package/src/split-button/split-button.tokens.json +12 -0
  195. package/src/splitter/splitter.css +336 -0
  196. package/src/splitter/splitter.tokens.json +24 -0
  197. package/src/stack/stack.css +128 -0
  198. package/src/stack/stack.tokens.json +14 -0
  199. package/src/stat-card/stat-card.css +641 -0
  200. package/src/stat-card/stat-card.tokens.json +95 -0
  201. package/src/status-indicator/status-indicator.css +481 -0
  202. package/src/status-indicator/status-indicator.tokens.json +38 -0
  203. package/src/stepper/stepper.css +629 -0
  204. package/src/stepper/stepper.tokens.json +72 -0
  205. package/src/switch/switch.css +703 -0
  206. package/src/switch/switch.tokens.json +75 -0
  207. package/src/table/table.css +1482 -0
  208. package/src/table/table.tokens.json +69 -0
  209. package/src/table-of-contents/table-of-contents.css +533 -0
  210. package/src/table-of-contents/table-of-contents.tokens.json +53 -0
  211. package/src/tabs/tabs.css +998 -0
  212. package/src/tabs/tabs.tokens.json +82 -0
  213. package/src/tag/tag.css +768 -0
  214. package/src/tag/tag.tokens.json +85 -0
  215. package/src/tags-input/tags-input.css +757 -0
  216. package/src/tags-input/tags-input.tokens.json +84 -0
  217. package/src/text-field/text-field.css +900 -0
  218. package/src/text-field/text-field.tokens.json +87 -0
  219. package/src/textarea/textarea.css +365 -0
  220. package/src/textarea/textarea.tokens.json +59 -0
  221. package/src/time-field/time-field.css +719 -0
  222. package/src/time-field/time-field.tokens.json +86 -0
  223. package/src/time-picker/time-picker.css +665 -0
  224. package/src/time-picker/time-picker.tokens.json +66 -0
  225. package/src/time-range-picker/time-range-picker.css +1287 -0
  226. package/src/time-range-picker/time-range-picker.tokens.json +134 -0
  227. package/src/timeline/timeline.css +1596 -0
  228. package/src/timeline/timeline.tokens.json +96 -0
  229. package/src/toast/toast.css +943 -0
  230. package/src/toast/toast.tokens.json +90 -0
  231. package/src/toggle/toggle.css +290 -0
  232. package/src/toggle/toggle.tokens.json +54 -0
  233. package/src/toggle-group/toggle-group.css +463 -0
  234. package/src/toggle-group/toggle-group.tokens.json +54 -0
  235. package/src/toolbar/toolbar.css +434 -0
  236. package/src/toolbar/toolbar.tokens.json +49 -0
  237. package/src/tooltip/tooltip.css +368 -0
  238. package/src/tooltip/tooltip.tokens.json +39 -0
  239. package/src/top-navigation/top-navigation.css +1287 -0
  240. package/src/top-navigation/top-navigation.tokens.json +91 -0
  241. package/src/tour/tour.css +680 -0
  242. package/src/tour/tour.tokens.json +67 -0
  243. package/src/transfer/transfer.css +571 -0
  244. package/src/transfer/transfer.tokens.json +49 -0
  245. package/src/tree/tree.css +1000 -0
  246. package/src/tree/tree.tokens.json +80 -0
  247. package/src/typography/typography.css +211 -0
  248. package/src/typography/typography.tokens.json +31 -0
  249. package/src/upload/upload.css +1706 -0
  250. package/src/upload/upload.tokens.json +123 -0
  251. package/src/visually-hidden/visually-hidden.css +52 -0
  252. package/src/visually-hidden/visually-hidden.tokens.json +1 -0
  253. package/src/wizard/wizard.css +740 -0
  254. package/src/wizard/wizard.tokens.json +63 -0
@@ -0,0 +1,792 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── A scale, a rail and one thumb per value ────────────────────────────
4
+ *
5
+ * Every thumb is a real `input[type="range"]`, so the `slider` role, the
6
+ * value set, form submission, form reset and `disabled` come from the
7
+ * platform. The input is invisible and unhittable — `opacity: 0` and
8
+ * `pointer-events: none`, filling the thumb it lives in — because the thumb
9
+ * a reader sees is this family's own element and the drag is the family's
10
+ * own gesture.
11
+ *
12
+ * `track` is the containing block for everything that has a position on the
13
+ * scale: the fill, every mark and every thumb. It is inset by half a thumb
14
+ * at each end of the control, so a thumb at either bound is contained rather
15
+ * than half outside, and the focus ring around it is never clipped.
16
+ *
17
+ * Every position is a private custom property written by the binding —
18
+ * `--_position` on a thumb or a mark, `--_start` and `--_end` on the fill.
19
+ * A percentage of a track is geometry and geometry is not a token.
20
+ */
21
+ [data-ui='slider'][data-part='root'] {
22
+ /**
23
+ * Type, glyph and gap come from the control scales — the only ones the
24
+ * theme restates per density — so a slider in a dense row shrinks whole
25
+ * rather than in parts.
26
+ */
27
+ --_font-size: var(--slotted-control-font-size-md, 13px);
28
+ --_gap: var(--slotted-control-gap-md, 8px);
29
+ --_icon-size: var(--slotted-control-icon-size-md, 16px);
30
+
31
+ /**
32
+ * The thumb is the control glyph plus one space step. It is arithmetic
33
+ * over two scales rather than a literal, and it is not a component token:
34
+ * the component layer's bar is that a family may not restate a scale that
35
+ * already exists.
36
+ */
37
+ --_thumb-size: var(
38
+ --slotted-slider-thumb-size,
39
+ calc(var(--_icon-size) + var(--slotted-space-2, 0.25rem))
40
+ );
41
+
42
+ /**
43
+ * The rail's weight does not change with the size. A rail is a channel
44
+ * rather than a control, so only the thumb, the type and the target grow.
45
+ * Six pixels is a one-pixel edge on each side and four of interior, which
46
+ * is the smallest channel a fill can be seen inside.
47
+ */
48
+ --_track-size: var(--slotted-slider-track-size, var(--slotted-space-3, 0.375rem));
49
+
50
+ /**
51
+ * The band the pointer aims at, floored at the WCAG 2.2 minimum. A thumb
52
+ * at the tightest step is twenty pixels across, and the correction of a
53
+ * target short in one axis is the family's rather than the theme's.
54
+ */
55
+ --_control-size: max(var(--slotted-target-min, 24px), var(--_thumb-size));
56
+
57
+ /**
58
+ * Where a mark's tick begins: past the thumb, so a tick is never drawn
59
+ * under one. Marks are ruler ticks outside the rail rather than dots on
60
+ * it, because a dot on the rail has to be legible against the fill and
61
+ * against the empty channel at once, and in the `high-contrast` scheme —
62
+ * where the palette is two colours — it cannot be both.
63
+ */
64
+ --_mark-gap: calc(
65
+ (var(--_thumb-size) - var(--_track-size)) / 2 + var(--slotted-space-1, 0.125rem)
66
+ );
67
+ --_mark-length: var(--slotted-space-2, 0.25rem);
68
+ --_mark-label-line: calc(
69
+ var(--slotted-font-size-xs, 0.75rem) * var(--slotted-line-height-xs, 1.4)
70
+ );
71
+ /**
72
+ * How wide a mark's label may be before it wraps: three thumbs, which is
73
+ * about two words at the medium step.
74
+ *
75
+ * The family declares no container and asks no query. One was written — a
76
+ * narrower cap for the labels below 320 pixels — and taken out again,
77
+ * because a label of one long word cannot wrap at any cap, so the query
78
+ * only ever moved the multi-word ones and a scale of five single words was
79
+ * unchanged by it. A slider is fluid rather than reflowing: the rail
80
+ * shrinks, the thumb and the type do not, and a label longer than the space
81
+ * between two ticks overflows its own box rather than being clipped or
82
+ * removed.
83
+ */
84
+ --_mark-label-size: calc(var(--_thumb-size) * 3);
85
+
86
+ /**
87
+ * The room the bubble stands in, reserved whether or not it is showing.
88
+ * Reserved, the control does not move when a drag starts, and the bubble
89
+ * does not land on the read-out above it — which is what the first capture
90
+ * of the `content` scene showed, with a value printed over its own number.
91
+ */
92
+ --_bubble-size: calc(
93
+ var(--slotted-font-size-xs, 0.75rem) * var(--slotted-line-height-xs, 1.4) +
94
+ var(--slotted-space-1, 0.125rem) * 2 + var(--slotted-space-2, 0.25rem)
95
+ );
96
+
97
+ color: var(--slotted-slider-color, var(--slotted-text, CanvasText));
98
+ display: flex;
99
+ flex-direction: column;
100
+ font-family: var(--slotted-control-font-family, system-ui, sans-serif);
101
+ font-size: var(--_font-size);
102
+ gap: var(--_gap);
103
+ /* A slider in a grid track narrower than its intrinsic width has to shrink. */
104
+ min-inline-size: 0;
105
+ }
106
+
107
+ /**
108
+ * A horizontal slider takes the width it is offered, the way every other
109
+ * control in this library does. It has no intrinsic width of its own — the
110
+ * rail is a percentage of a box that is a percentage of the root — so in a
111
+ * shrink-to-fit column it collapsed to the width of its own read-out, and the
112
+ * React reference page showed three numbers with three bare thumbs under
113
+ * them and no rail at all. A vertical slider is left alone: its cross
114
+ * measurement is the band, and its length is its own.
115
+ */
116
+ [data-ui='slider'][data-part='root'][data-orientation='horizontal'] {
117
+ inline-size: 100%;
118
+ }
119
+
120
+ [data-ui='slider'][data-part='root'][data-size='sm'] {
121
+ --_font-size: var(--slotted-control-font-size-sm, 12px);
122
+ --_gap: var(--slotted-control-gap-sm, 6px);
123
+ --_icon-size: var(--slotted-control-icon-size-sm, 14px);
124
+ }
125
+
126
+ [data-ui='slider'][data-part='root'][data-size='md'] {
127
+ --_font-size: var(--slotted-control-font-size-md, 13px);
128
+ --_gap: var(--slotted-control-gap-md, 8px);
129
+ --_icon-size: var(--slotted-control-icon-size-md, 16px);
130
+ }
131
+
132
+ [data-ui='slider'][data-part='root'][data-size='lg'] {
133
+ --_font-size: var(--slotted-control-font-size-lg, 14px);
134
+ --_gap: var(--slotted-control-gap-lg, 8px);
135
+ --_icon-size: var(--slotted-control-icon-size-lg, 18px);
136
+ }
137
+
138
+ /* ── The read-out ─────────────────────────────────────────────────────
139
+ *
140
+ * The label is the field's; this is the value. It is set at full strength
141
+ * rather than muted, because it is the datum a reader came for, and in
142
+ * tabular figures because a number that changes under a drag must not change
143
+ * width while it does.
144
+ */
145
+ [data-ui='slider'] > [data-part='output'] {
146
+ align-self: flex-end;
147
+ color: var(--slotted-slider-output-color, var(--slotted-text, CanvasText));
148
+ font-variant-numeric: tabular-nums;
149
+ font-weight: var(--slotted-font-weight-medium, 500);
150
+ line-height: var(--slotted-line-height-sm, 1.45);
151
+ /* Its own bidi run: a number has no strong character to order it. */
152
+ unicode-bidi: plaintext;
153
+ }
154
+
155
+ /* ── The band ─────────────────────────────────────────────────────────
156
+ *
157
+ * The whole of the pointer target, and the containing block the track is
158
+ * inset inside. It is `touch-action: none` because a drag along the scale
159
+ * and a scroll of the page are the same gesture, and the one the pointer
160
+ * started on the control is the drag.
161
+ */
162
+ [data-ui='slider'] [data-part='control'] {
163
+ align-items: center;
164
+ /**
165
+ * The reserve for the two half thumbs comes out of the band rather than
166
+ * being added to it. Written as padding on a content box, a band told to
167
+ * fill its root measured a whole thumb wider than the root — 260px inside
168
+ * 240px — and the overflow travelled up through `stack` and `field` to the
169
+ * stage, which then scrolled. The band is what the root gives it; the
170
+ * scale inside is what is left after the reserve.
171
+ */
172
+ box-sizing: border-box;
173
+ cursor: pointer;
174
+ display: flex;
175
+ justify-content: center;
176
+ position: relative;
177
+ touch-action: none;
178
+ -webkit-tap-highlight-color: transparent;
179
+ }
180
+
181
+ [data-ui='slider'][data-orientation='horizontal'] [data-part='control'] {
182
+ block-size: var(--_control-size);
183
+ inline-size: 100%;
184
+ padding-inline: calc(var(--_thumb-size) / 2);
185
+ }
186
+
187
+ /**
188
+ * The room the bubble stands in, less the gap the root already put there.
189
+ * Added whole, the two stacked: the `marks` capture showed the read-out a
190
+ * finger's width above its own rail, reading as a separate line rather than
191
+ * as this control's value.
192
+ */
193
+ [data-ui='slider'][data-orientation='horizontal']:not([data-value-label='none'])
194
+ [data-part='control'] {
195
+ margin-block-start: max(0px, calc(var(--_bubble-size) - var(--_gap)));
196
+ }
197
+
198
+ /**
199
+ * The vertical bubble reserves nothing. It stands beside its own thumb, and
200
+ * the read-out it could collide with is above the control rather than beside
201
+ * it; reserving four thumb widths of empty column on every vertical slider
202
+ * cost more than the overlap it prevented.
203
+ */
204
+
205
+ [data-ui='slider'][data-orientation='vertical'] [data-part='control'] {
206
+ /**
207
+ * A vertical slider has no intrinsic length, so it takes one: ten thumbs
208
+ * is a scale a reader can point at, and a consumer who wants another one
209
+ * writes it on the root. The value is arithmetic over the thumb, not a
210
+ * scale of its own.
211
+ *
212
+ * The token stays the scale. On a border box the reserve is inside the
213
+ * band, so the band is the scale plus the two half thumbs — which leaves
214
+ * the track measuring exactly what the consumer asked for, as it did
215
+ * before the box changed.
216
+ */
217
+ block-size: calc(
218
+ var(--slotted-slider-length, calc(var(--_thumb-size) * 10)) + var(--_thumb-size)
219
+ );
220
+ inline-size: var(--_control-size);
221
+ padding-block: calc(var(--_thumb-size) / 2);
222
+ }
223
+
224
+ /**
225
+ * The room a scale of marks takes outside the rail. It is reserved rather
226
+ * than discovered, so a family below the slider does not move when a label
227
+ * appears.
228
+ */
229
+ [data-ui='slider'][data-orientation='horizontal'][data-marks='ticks'] [data-part='control'] {
230
+ margin-block-end: var(--_mark-length);
231
+ }
232
+
233
+ [data-ui='slider'][data-orientation='horizontal'][data-marks='labelled'] [data-part='control'] {
234
+ margin-block-end: calc(
235
+ var(--_mark-length) + var(--slotted-space-1, 0.125rem) + var(--_mark-label-line)
236
+ );
237
+ }
238
+
239
+ [data-ui='slider'][data-orientation='vertical'][data-marks='ticks'] [data-part='control'] {
240
+ margin-inline-end: var(--_mark-length);
241
+ }
242
+
243
+ [data-ui='slider'][data-orientation='vertical'][data-marks='labelled'] [data-part='control'] {
244
+ margin-inline-end: calc(
245
+ var(--_mark-length) + var(--slotted-space-1, 0.125rem) + var(--_mark-label-size)
246
+ );
247
+ }
248
+
249
+ /* ── The rail ─────────────────────────────────────────────────────────
250
+ *
251
+ * A channel rather than a line: an edge that holds the 3:1 a non-text
252
+ * element needs against every surface, and an interior the fill is seen
253
+ * inside. A rail painted as one flat neutral cannot do both — in the
254
+ * `high-contrast` scheme every neutral is the same black, and the first
255
+ * capture showed a black rail with a nearly black fill on it.
256
+ *
257
+ * It is inset by half a thumb at each end of the control, so the scale's two
258
+ * bounds are the two places a thumb's centre can reach and the thumb itself
259
+ * stays inside the band.
260
+ */
261
+ [data-ui='slider'] [data-part='track'] {
262
+ background-color: var(--slotted-slider-track-color, var(--slotted-surface-sunken, Canvas));
263
+ border: var(--slotted-control-border-width, 1px) solid
264
+ var(--slotted-slider-track-border-color, var(--slotted-control-border-color, ButtonBorder));
265
+ border-radius: var(--slotted-radius-full, 9999px);
266
+ box-sizing: border-box;
267
+ position: relative;
268
+ }
269
+
270
+ [data-ui='slider'][data-orientation='horizontal'] [data-part='track'] {
271
+ block-size: var(--_track-size);
272
+ inline-size: 100%;
273
+ }
274
+
275
+ [data-ui='slider'][data-orientation='vertical'] [data-part='track'] {
276
+ block-size: 100%;
277
+ inline-size: var(--_track-size);
278
+ }
279
+
280
+ /**
281
+ * The filled portion, between the origin and the value. `--_start` and
282
+ * `--_end` are two percentages rather than a length and an offset, so a
283
+ * range fills between its thumbs and a slider with a centred origin fills
284
+ * outward from the middle with the same two declarations.
285
+ *
286
+ * On the cross axis it is laid against the track's *border* box and not its
287
+ * padding box, which is one negative inset and the whole of SR1. An
288
+ * absolutely positioned box is placed inside the padding of its containing
289
+ * block, so a fill left at nought stopped a pixel short of each edge and the
290
+ * channel's own neutral line ran across the accent: on a track of six pixels
291
+ * the fill was four, with the edge painted over the top and the bottom of it.
292
+ * A filled scale is one solid band, and the rim belongs to the part of the
293
+ * scale that is still empty.
294
+ *
295
+ * The main axis keeps the padding box, so the two ends of the channel keep
296
+ * their rim: the fill runs from a percentage of the scale, and a fill that
297
+ * overhung there would leave a pixel of accent past the value at one end and
298
+ * cover the cap at the other.
299
+ */
300
+ [data-ui='slider'] [data-part='indicator'] {
301
+ --_edge-overlap: calc(var(--slotted-control-border-width, 1px) * -1);
302
+
303
+ background-color: var(--slotted-slider-indicator-color, var(--slotted-tone-accent-solid));
304
+ border-radius: inherit;
305
+ position: absolute;
306
+ }
307
+
308
+ [data-ui='slider'][data-orientation='horizontal'] [data-part='indicator'] {
309
+ inset-block: var(--_edge-overlap);
310
+ inset-inline-start: calc(var(--_start, 0) * 1%);
311
+ inline-size: calc((var(--_end, 0) - var(--_start, 0)) * 1%);
312
+ }
313
+
314
+ [data-ui='slider'][data-orientation='vertical'] [data-part='indicator'] {
315
+ inset-inline: var(--_edge-overlap);
316
+ inset-block-end: calc(var(--_start, 0) * 1%);
317
+ block-size: calc((var(--_end, 0) - var(--_start, 0)) * 1%);
318
+ }
319
+
320
+ /* ── Marks ────────────────────────────────────────────────────────────
321
+ *
322
+ * Ruler ticks alongside the rail, with the label under each one. A tick on
323
+ * the rail would have to read against the fill and against the empty channel
324
+ * at once; beside it, it reads against the page in every scheme.
325
+ */
326
+ [data-ui='slider'] [data-part='mark'] {
327
+ background-color: var(--slotted-slider-mark-color, var(--slotted-border-strong, CanvasText));
328
+ position: absolute;
329
+ }
330
+
331
+ [data-ui='slider'][data-orientation='horizontal'] [data-part='mark'] {
332
+ block-size: var(--_mark-length);
333
+ inline-size: var(--slotted-border-width-thin, 1px);
334
+ inset-block-start: calc(100% + var(--_mark-gap));
335
+ inset-inline-start: calc(var(--_position, 0) * 1%);
336
+ margin-inline-start: calc(var(--slotted-border-width-thin, 1px) / -2);
337
+ }
338
+
339
+ [data-ui='slider'][data-orientation='vertical'] [data-part='mark'] {
340
+ block-size: var(--slotted-border-width-thin, 1px);
341
+ inline-size: var(--_mark-length);
342
+ inset-inline-start: calc(100% + var(--_mark-gap));
343
+ inset-block-end: calc(var(--_position, 0) * 1%);
344
+ margin-block-end: calc(var(--slotted-border-width-thin, 1px) / -2);
345
+ }
346
+
347
+ [data-ui='slider'] [data-part='mark-label'] {
348
+ color: var(--slotted-slider-mark-label-color, var(--slotted-text-muted, GrayText));
349
+ display: block;
350
+ font-size: var(--slotted-font-size-xs, 0.75rem);
351
+ inline-size: max-content;
352
+ line-height: var(--slotted-line-height-xs, 1.4);
353
+ max-inline-size: var(--_mark-label-size);
354
+ /**
355
+ * The cap is three thumbs, and one word can be wider than three thumbs
356
+ * without a space to break at: `Reduzido` measured 55px inside 51px at
357
+ * `dense`, and those four pixels were read at the mark, which is one pixel
358
+ * wide and forgives only what the label's placement explains. A label
359
+ * breaks inside a word rather than standing outside its own box.
360
+ */
361
+ overflow-wrap: anywhere;
362
+ position: absolute;
363
+ text-align: center;
364
+ unicode-bidi: plaintext;
365
+ }
366
+
367
+ [data-ui='slider'][data-orientation='horizontal'] [data-part='mark-label'] {
368
+ inset-block-start: calc(100% + var(--slotted-space-1, 0.125rem));
369
+ inset-inline-start: 50%;
370
+ translate: -50% 0;
371
+ }
372
+
373
+ /**
374
+ * The label at either end of the scale is aligned inside rather than centred
375
+ * on its tick. Centred, half of it hangs off the control: the first capture
376
+ * of the `marks` scene showed "Máximo" clipped by the edge of the cell, and
377
+ * a scale whose last label cannot be read is a scale with four labels.
378
+ */
379
+ [data-ui='slider'][data-orientation='horizontal']
380
+ [data-part='mark'][data-edge='start']
381
+ [data-part='mark-label'] {
382
+ inset-inline-start: 0;
383
+ text-align: start;
384
+ translate: 0 0;
385
+ }
386
+
387
+ /**
388
+ * An edge label takes its own measure and grows inward. The shared cap makes
389
+ * a word longer than the cap overflow toward the inline end, which for the
390
+ * label at the end of the scale is off the control: the 240-pixel capture
391
+ * printed "Máximo" over the edge of its own cell.
392
+ */
393
+ [data-ui='slider'][data-orientation='horizontal']
394
+ [data-part='mark'][data-edge]
395
+ [data-part='mark-label'] {
396
+ max-inline-size: none;
397
+ }
398
+
399
+ [data-ui='slider'][data-orientation='horizontal']
400
+ [data-part='mark'][data-edge='end']
401
+ [data-part='mark-label'] {
402
+ inset-inline-end: 0;
403
+ inset-inline-start: auto;
404
+ text-align: end;
405
+ translate: 0 0;
406
+ }
407
+
408
+ /**
409
+ * The one place this family names a side, and only in the mirrored document.
410
+ * `translate` is a physical transform: a percentage along the inline axis
411
+ * moves the box left in both directions, so a right-to-left page would hang
412
+ * every centred label half a box off its own tick.
413
+ */
414
+ [data-ui='slider'][data-orientation='horizontal']:dir(rtl)
415
+ [data-part='mark']:not([data-edge])
416
+ [data-part='mark-label'] {
417
+ translate: 50% 0;
418
+ }
419
+
420
+ [data-ui='slider'][data-orientation='vertical'] [data-part='mark-label'] {
421
+ inset-block-start: 50%;
422
+ inset-inline-start: calc(100% + var(--slotted-space-1, 0.125rem));
423
+ text-align: start;
424
+ translate: 0 -50%;
425
+ }
426
+
427
+ /* ── The thumb ────────────────────────────────────────────────────────
428
+ *
429
+ * Centred on its position by a logical margin rather than by `translate`, so
430
+ * the mirrored document needs no rule of its own: `margin-inline-start`
431
+ * measures from whichever edge `inset-inline-start` measured from.
432
+ */
433
+ [data-ui='slider'] [data-part='thumb'] {
434
+ background-color: var(--slotted-slider-thumb-color, var(--slotted-surface, Canvas));
435
+ block-size: var(--_thumb-size);
436
+ border: var(--slotted-border-width-thick, 2px) solid
437
+ var(--slotted-slider-thumb-border-color, var(--slotted-tone-accent-solid));
438
+ border-radius: var(--slotted-radius-full, 9999px);
439
+ box-shadow: var(--slotted-slider-thumb-shadow, var(--slotted-control-shadow, none));
440
+ box-sizing: border-box;
441
+ cursor: grab;
442
+ display: block;
443
+ inline-size: var(--_thumb-size);
444
+ position: absolute;
445
+ transition:
446
+ background-color var(--slotted-control-transition-duration)
447
+ var(--slotted-control-transition-easing),
448
+ border-color var(--slotted-control-transition-duration)
449
+ var(--slotted-control-transition-easing),
450
+ box-shadow var(--slotted-control-transition-duration) var(--slotted-control-transition-easing),
451
+ scale var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
452
+ }
453
+
454
+ [data-ui='slider'][data-orientation='horizontal'] [data-part='thumb'] {
455
+ inset-block-start: 50%;
456
+ inset-inline-start: calc(var(--_position, 0) * 1%);
457
+ margin-block-start: calc(var(--_thumb-size) / -2);
458
+ margin-inline-start: calc(var(--_thumb-size) / -2);
459
+ }
460
+
461
+ [data-ui='slider'][data-orientation='vertical'] [data-part='thumb'] {
462
+ inset-block-end: calc(var(--_position, 0) * 1%);
463
+ inset-inline-start: 50%;
464
+ margin-block-end: calc(var(--_thumb-size) / -2);
465
+ margin-inline-start: calc(var(--_thumb-size) / -2);
466
+ }
467
+
468
+ /**
469
+ * The control itself, invisible and unhittable. It keeps focus, the role,
470
+ * the value set and its place in the form; the box around it is what a
471
+ * reader sees, and the family's own pointer handling is what moves it.
472
+ */
473
+ [data-ui='slider'] [data-part='input'] {
474
+ appearance: none;
475
+ block-size: 100%;
476
+ inline-size: 100%;
477
+ inset: 0;
478
+ margin: 0;
479
+ opacity: 0;
480
+ /* The ring is drawn by the thumb, so two rings never nest. */
481
+ outline: none;
482
+ padding: 0;
483
+ pointer-events: none;
484
+ position: absolute;
485
+ }
486
+
487
+ /**
488
+ * The family draws its own thumb, so the browser's is not a second one on the
489
+ * screen — it goes with the input's `opacity` — but it keeps the intrinsic
490
+ * size the browser gives it, and that size is sixteen pixels while a thumb at
491
+ * `dense` is thirteen. `tools/harness/audit.mjs` read the difference as
492
+ * content that ran out of its box on every dense stage. The native parts are
493
+ * withdrawn to nothing, as `text-field` withdraws the search decorations.
494
+ */
495
+ [data-ui='slider'] [data-part='input']::-webkit-slider-thumb {
496
+ appearance: none;
497
+ block-size: 0;
498
+ inline-size: 0;
499
+ }
500
+
501
+ [data-ui='slider'] [data-part='input']::-webkit-slider-runnable-track {
502
+ block-size: 0;
503
+ }
504
+
505
+ /* ── The bubble ───────────────────────────────────────────────────────
506
+ *
507
+ * The same number as the read-out, on the thumb, where a reader's eye
508
+ * already is during a drag. It is out of the accessibility tree: the input
509
+ * beneath it already announces the value, and a second copy would announce
510
+ * it twice.
511
+ */
512
+ [data-ui='slider'] [data-part='bubble'] {
513
+ background-color: var(--slotted-slider-bubble-background, var(--slotted-surface-inverse));
514
+ border-radius: var(--slotted-radius-sm, 4px);
515
+ color: var(--slotted-slider-bubble-color, var(--slotted-text-inverse));
516
+ font-size: var(--slotted-font-size-xs, 0.75rem);
517
+ font-variant-numeric: tabular-nums;
518
+ inline-size: max-content;
519
+ line-height: var(--slotted-line-height-xs, 1.4);
520
+ /**
521
+ * A long value wraps rather than running off the end of the scale. It can
522
+ * still extend past the control at either bound, which is what a bubble
523
+ * over a thumb does; a value that is a sentence rather than a number
524
+ * belongs in the read-out, which is what `valueLabel="none"` is for.
525
+ */
526
+ max-inline-size: calc(var(--_thumb-size) * 4);
527
+ opacity: 0;
528
+ padding-block: var(--slotted-space-1, 0.125rem);
529
+ padding-inline: var(--slotted-space-3, 0.375rem);
530
+ pointer-events: none;
531
+ position: absolute;
532
+ text-align: center;
533
+ transition: opacity var(--slotted-control-transition-duration)
534
+ var(--slotted-control-transition-easing);
535
+ unicode-bidi: plaintext;
536
+ }
537
+
538
+ [data-ui='slider'][data-orientation='horizontal'] [data-part='bubble'] {
539
+ inset-block-end: calc(100% + var(--slotted-space-2, 0.25rem));
540
+ inset-inline-start: 50%;
541
+ translate: -50% 0;
542
+ }
543
+
544
+ [data-ui='slider'][data-orientation='horizontal']:dir(rtl) [data-part='bubble'] {
545
+ translate: 50% 0;
546
+ }
547
+
548
+ /**
549
+ * A vertical bubble stands on the inline-start side, because the marks stand
550
+ * on the other one. Two overlays on one edge is a scale whose labels sit
551
+ * under its own values.
552
+ */
553
+ [data-ui='slider'][data-orientation='vertical'] [data-part='bubble'] {
554
+ inset-block-start: 50%;
555
+ inset-inline-end: calc(100% + var(--slotted-space-2, 0.25rem));
556
+ translate: 0 -50%;
557
+ }
558
+
559
+ /**
560
+ * `auto` shows the number while the value is moving or while the thumb has
561
+ * the caret; `always` shows it at rest as well. The transition is on opacity
562
+ * alone, so nothing moves under a reader who asked for stillness — the
563
+ * duration token collapses and the bubble simply appears.
564
+ */
565
+ [data-ui='slider'][data-value-label='always'] [data-part='bubble'],
566
+ [data-ui='slider'][data-dragging] [data-part='thumb'][data-active] [data-part='bubble'],
567
+ [data-ui='slider']
568
+ [data-part='thumb']:has(> [data-part='input']:focus-visible)
569
+ [data-part='bubble'] {
570
+ opacity: 1;
571
+ }
572
+
573
+ [data-ui='slider'][data-value-label='none'] [data-part='bubble'] {
574
+ display: none;
575
+ }
576
+
577
+ /* ── States ───────────────────────────────────────────────────────────
578
+ *
579
+ * Written strongest last, and each weaker one guarded against the stronger
580
+ * ones it can meet, which is the order `STATE_PRECEDENCE` sets.
581
+ */
582
+
583
+ [data-ui='slider']:not([data-disabled]):not([data-readonly])
584
+ [data-part='thumb']:hover:not(:disabled) {
585
+ background-color: var(
586
+ --slotted-slider-thumb-hover-background,
587
+ var(--slotted-tone-accent-surface)
588
+ );
589
+ }
590
+
591
+ /**
592
+ * The thumb grows under the press rather than only changing colour. It is
593
+ * the one movement in the family that carries information — the control has
594
+ * taken the gesture — and it collapses with the duration token under reduced
595
+ * motion.
596
+ */
597
+ [data-ui='slider']:not([data-disabled]):not([data-readonly])
598
+ [data-part='thumb']:active:not(:disabled),
599
+ [data-ui='slider'][data-dragging]:not([data-disabled]):not([data-readonly])
600
+ [data-part='thumb'][data-active] {
601
+ cursor: grabbing;
602
+ scale: 1.15;
603
+ }
604
+
605
+ /**
606
+ * The ring belongs to the thumb and answers the input's focus. The input is
607
+ * `opacity: 0`, so nothing else in the family could draw it.
608
+ */
609
+ [data-ui='slider'] [data-part='thumb']:has(> [data-part='input']:focus-visible) {
610
+ box-shadow: var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
611
+ var(--slotted-focus-ring-color, Highlight);
612
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
613
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
614
+ }
615
+
616
+ /**
617
+ * Invalid outranks hover and is written after it for that reason. The ring is
618
+ * retargeted rather than repainted: every rule that draws focus reads
619
+ * `--slotted-focus-ring-color`, so pointing that one name at the invalid
620
+ * colour moves the outline and the shadow together.
621
+ */
622
+ [data-ui='slider'][data-part='root'][data-invalid] {
623
+ --slotted-focus-ring-color: var(
624
+ --slotted-slider-invalid-focus-ring-color,
625
+ var(--slotted-focus-ring-color-invalid, Highlight)
626
+ );
627
+ }
628
+
629
+ [data-ui='slider'][data-invalid] [data-part='indicator'] {
630
+ background-color: var(
631
+ --slotted-slider-invalid-indicator-color,
632
+ var(--slotted-tone-danger-solid)
633
+ );
634
+ }
635
+
636
+ [data-ui='slider'][data-invalid] [data-part='thumb'] {
637
+ --_invalid-edge-width: var(
638
+ --slotted-slider-invalid-edge-width,
639
+ var(--slotted-control-invalid-edge-width, 1px)
640
+ );
641
+ --_invalid-edge-color: var(
642
+ --slotted-slider-invalid-thumb-border-color,
643
+ var(--slotted-tone-danger-border)
644
+ );
645
+ --_invalid-edge: inset 0 0 0 var(--_invalid-edge-width) var(--_invalid-edge-color);
646
+
647
+ border-color: var(
648
+ --slotted-slider-invalid-thumb-border-color,
649
+ var(--slotted-tone-danger-border)
650
+ );
651
+ /*
652
+ * Width as well as colour (WCAG 1.4.1), the edge `text-field` draws: in
653
+ * `high-contrast` the danger fill and border are the accent's black. The
654
+ * thumb carries it, as a shadow inside its border, so the thumb keeps its
655
+ * size and its place on the track; it takes the resting lift's place.
656
+ */
657
+ box-shadow: var(--_invalid-edge);
658
+ }
659
+
660
+ [data-ui='slider'][data-invalid] [data-part='thumb']:has(> [data-part='input']:focus-visible) {
661
+ box-shadow:
662
+ var(--_invalid-edge),
663
+ var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
664
+ var(--slotted-focus-ring-color, Highlight);
665
+ }
666
+
667
+ /**
668
+ * Read-only stays focusable, stays announced and stays submitted, and must
669
+ * not be mistakable for disabled: the ink keeps its full strength, because
670
+ * the value is real. What changes is the tone — the scale steps off the
671
+ * accent and onto a neutral ink, which says "not yours to change" without
672
+ * saying "not readable". A read-only slider that painted nothing at all was
673
+ * the first capture's defect, and it is the one `number-field` found in the
674
+ * same state.
675
+ */
676
+ [data-ui='slider'][data-part='root'][data-readonly] [data-part='control'],
677
+ [data-ui='slider'][data-part='root'][data-readonly] [data-part='thumb'] {
678
+ cursor: default;
679
+ }
680
+
681
+ [data-ui='slider'][data-part='root'][data-readonly] [data-part='indicator'] {
682
+ background-color: var(--slotted-slider-readonly-indicator-color, var(--slotted-text-muted));
683
+ }
684
+
685
+ /**
686
+ * The thumb takes the control edge rather than the muted ink. Both read-only
687
+ * and disabled paint a neutral scale, and in the dark scheme the two neutrals
688
+ * sat within a step of each other; the control edge and the disabled edge are
689
+ * two tokens the theme keeps apart in every scheme, which is what makes the
690
+ * two states tell themselves apart.
691
+ */
692
+ [data-ui='slider'][data-part='root'][data-readonly] [data-part='thumb'] {
693
+ border-color: var(
694
+ --slotted-slider-readonly-thumb-border-color,
695
+ var(--slotted-control-border-color, ButtonBorder)
696
+ );
697
+ }
698
+
699
+ /**
700
+ * `:disabled` on an input is matched beside `data-disabled` on the root,
701
+ * because a control can be disabled by something that never told it so: a
702
+ * disabled `fieldset` disables every control inside it.
703
+ */
704
+ [data-ui='slider'][data-part='root'][data-disabled] [data-part='track'],
705
+ [data-ui='slider'][data-part='root']:has([data-part='input']:disabled) [data-part='track'] {
706
+ background-color: var(
707
+ --slotted-slider-disabled-track-color,
708
+ var(--slotted-disabled-background)
709
+ );
710
+ border-color: var(--slotted-slider-disabled-border-color, var(--slotted-disabled-border));
711
+ }
712
+
713
+ [data-ui='slider'][data-part='root'][data-disabled] [data-part='indicator'],
714
+ [data-ui='slider'][data-part='root']:has([data-part='input']:disabled) [data-part='indicator'] {
715
+ background-color: var(
716
+ --slotted-slider-disabled-indicator-color,
717
+ var(--slotted-disabled-foreground)
718
+ );
719
+ }
720
+
721
+ [data-ui='slider'][data-part='root'][data-disabled] [data-part='thumb'],
722
+ [data-ui='slider'][data-part='root']:has([data-part='input']:disabled) [data-part='thumb'] {
723
+ background-color: var(
724
+ --slotted-slider-disabled-thumb-color,
725
+ var(--slotted-disabled-background)
726
+ );
727
+ border-color: var(--slotted-slider-disabled-border-color, var(--slotted-disabled-border));
728
+ /* Nothing a person cannot reach is lifted off the page. */
729
+ box-shadow: none;
730
+ cursor: not-allowed;
731
+ }
732
+
733
+ [data-ui='slider'][data-part='root'][data-disabled] [data-part='control'],
734
+ [data-ui='slider'][data-part='root'][data-disabled] > [data-part='output'],
735
+ [data-ui='slider'][data-part='root'][data-disabled] [data-part='mark-label'] {
736
+ color: var(--slotted-disabled-foreground);
737
+ cursor: not-allowed;
738
+ }
739
+
740
+ [data-ui='slider'][data-part='root'][data-disabled] [data-part='mark'] {
741
+ background-color: var(--slotted-disabled-foreground);
742
+ }
743
+
744
+ /**
745
+ * The one block the theme cannot write for the family. Under forced colours
746
+ * a background is repainted by the operating system, and the channel, the
747
+ * fill and the thumb are three backgrounds that have to stay three different
748
+ * things — a fill flattened to the channel's colour would leave a slider
749
+ * with no value on it at all.
750
+ */
751
+ @media (forced-colors: active) {
752
+ [data-ui='slider'] [data-part='track'] {
753
+ background-color: ButtonFace;
754
+ border-color: ButtonBorder;
755
+ }
756
+
757
+ [data-ui='slider'] [data-part='indicator'] {
758
+ background-color: Highlight;
759
+ }
760
+
761
+ [data-ui='slider'] [data-part='thumb'] {
762
+ background-color: ButtonFace;
763
+ border-color: ButtonBorder;
764
+ }
765
+
766
+ [data-ui='slider'] [data-part='mark'] {
767
+ background-color: CanvasText;
768
+ }
769
+
770
+ [data-ui='slider'][data-part='root'][data-disabled] [data-part='indicator'],
771
+ [data-ui='slider'][data-part='root'][data-disabled] [data-part='thumb'] {
772
+ background-color: Canvas;
773
+ border-color: GrayText;
774
+ }
775
+
776
+ /* The invalid edge is a shadow, which forced colours remove: it comes back
777
+ as an outline inside the thumb's border, and a focused invalid thumb
778
+ draws its ring double. */
779
+ [data-ui='slider'][data-invalid] [data-part='thumb'] {
780
+ outline: var(--_invalid-edge-width) solid CanvasText;
781
+ outline-offset: calc(
782
+ -1 * (var(--slotted-border-width-thick, 2px) + var(--_invalid-edge-width))
783
+ );
784
+ }
785
+
786
+ [data-ui='slider'][data-invalid] [data-part='thumb']:has(> [data-part='input']:focus-visible) {
787
+ outline: calc(var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width)) double
788
+ var(--slotted-focus-ring-color, Highlight);
789
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
790
+ }
791
+ }
792
+ }