@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,860 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * A set of slides shown a page at a time, and the controls that move it.
4
+ *
5
+ * The root is a one-cell grid, and every control written as its direct child
6
+ * is placed in that cell over the viewport rather than positioned over it:
7
+ * the previous and next controls sit on the two ends of the axis, the bar
8
+ * at the foot. A control written inside `controls` takes the bar's row
9
+ * instead. Where a control stands is therefore where the consumer wrote it,
10
+ * and no prop restates it.
11
+ *
12
+ * ┌────────────────────────────────────────┐
13
+ * │ ◀ viewport ▶ │ arrows="inset"
14
+ * │ ● ━━ ● ● │ controls placement="overlay"
15
+ * └────────────────────────────────────────┘
16
+ * ⏸ ◀ ● ━━ ● ● ▶ 2 / 4 controls placement="below"
17
+ */
18
+ [data-ui='carousel'] {
19
+ --_control-size: var(--slotted-control-height-md, 34px);
20
+ --_icon-size: var(--slotted-control-icon-size-md, 16px);
21
+ --_gap: var(--slotted-carousel-gap, var(--slotted-space-6, 1rem));
22
+ --_peek: var(--slotted-carousel-peek, 0px);
23
+ --_per-view: var(--slotted-carousel-slides-per-view, 1);
24
+ --_radius: var(--slotted-carousel-radius, var(--slotted-radius-lg, 8px));
25
+ /**
26
+ * How far an inset control stands from the viewport's edge: one step of
27
+ * air past the ring, so a focused control's ring never touches the edge it
28
+ * is drawn against.
29
+ */
30
+ --_inset: var(--slotted-space-5, 0.75rem);
31
+ /**
32
+ * The scroll the engine animates runs on a critically damped spring whose
33
+ * stiffness is read from this duration in the viewport's computed style,
34
+ * so the theme's motion scale — and its collapse to an instant under
35
+ * reduced motion — reaches a movement no `transition` describes. At this
36
+ * duration less than one per cent of the way is left; the spring carries
37
+ * the speed of the hand that let go, which no easing curve can.
38
+ */
39
+ --_scroll-duration: var(--slotted-carousel-duration, var(--slotted-duration-long));
40
+ /**
41
+ * A dot, and the bar the current dot stretches into. The bar is three dots
42
+ * long so it reads as a different shape, not a bigger dot: shape, not
43
+ * colour alone, says which page is shown (WCAG 1.4.1).
44
+ */
45
+ --_dot: var(--slotted-space-4, 0.5rem);
46
+ --_dot-current: var(--slotted-space-8, 1.5rem);
47
+ --_dot-air: var(--slotted-space-3, 0.375rem);
48
+ --_line: var(--slotted-border-width-thick, 2px);
49
+ --_thumbnail: var(--slotted-carousel-thumbnail-size, var(--slotted-space-12, 4rem));
50
+
51
+ display: grid;
52
+ grid-template-columns: minmax(0, 1fr);
53
+ grid-template-rows: auto;
54
+ min-inline-size: 0;
55
+ row-gap: var(--slotted-carousel-controls-gap, var(--slotted-space-5, 0.75rem));
56
+ }
57
+
58
+ [data-ui='carousel'][data-size='sm'] {
59
+ --_control-size: var(--slotted-control-height-sm, 30px);
60
+ --_icon-size: var(--slotted-control-icon-size-sm, 14px);
61
+ }
62
+
63
+ [data-ui='carousel'][data-size='lg'] {
64
+ --_control-size: var(--slotted-control-height-lg, 38px);
65
+ --_icon-size: var(--slotted-control-icon-size-lg, 18px);
66
+ }
67
+
68
+ /**
69
+ * Outside the viewport the two controls take columns of their own, so a row
70
+ * of cards keeps its whole width for cards and no arrow covers the first
71
+ * one's corner — ReUI's `-left-12`, measured at 48 pixels outside the
72
+ * viewport, without the absolute positioning that puts it outside the
73
+ * component's box.
74
+ */
75
+ [data-ui='carousel'][data-arrows='outside'] {
76
+ column-gap: var(--slotted-space-4, 0.5rem);
77
+ grid-template-columns: auto minmax(0, 1fr) auto;
78
+ }
79
+
80
+ /* ── The viewport ─────────────────────────────────────────────────────── */
81
+
82
+ /**
83
+ * The scroller, and the one element the family moves. Touch, a trackpad and
84
+ * the keyboard scroll it natively and snap does the paging, so the family
85
+ * works before any script and a swipe is the platform's own swipe. The
86
+ * slides are grid columns sized from the slides-per-view count, so a
87
+ * container query that writes `--slotted-carousel-slides-per-view` changes
88
+ * the layout and the engine reads the new pages from it.
89
+ */
90
+ [data-ui='carousel'] > [data-part='viewport'] {
91
+ /**
92
+ * The share of the row a slide takes, never below the slide's own floor:
93
+ * three cards per view at 240 pixels are 64-pixel cards, and the floor
94
+ * turns the same carousel into one card and the edge of the next. The
95
+ * engine reads the pages from the boxes, so the floor needs no script.
96
+ */
97
+ --_track: max(
98
+ var(--slotted-carousel-slide-min-size, 0px),
99
+ calc((100% - (var(--_per-view) - 1) * var(--_gap)) / var(--_per-view))
100
+ );
101
+
102
+ border-radius: var(--_radius);
103
+ display: grid;
104
+ gap: var(--_gap);
105
+ grid-area: 1 / 1;
106
+ grid-auto-columns: var(--_track);
107
+ grid-auto-flow: column;
108
+ min-inline-size: 0;
109
+ outline: none;
110
+ overflow-x: auto;
111
+ overflow-y: hidden;
112
+ overscroll-behavior-inline: contain;
113
+ padding-inline: var(--_peek);
114
+ scroll-behavior: auto;
115
+ scroll-padding-inline: var(--_peek);
116
+ scroll-snap-type: x mandatory;
117
+ /**
118
+ * The scrollbar is not the affordance: the controls and the indicators
119
+ * are, and a scrollbar under a row of slides reads as a page that did not
120
+ * fit. The viewport stays scrollable by touch, trackpad and keyboard.
121
+ */
122
+ scrollbar-width: none;
123
+ }
124
+
125
+ [data-ui='carousel'][data-arrows='outside'] > [data-part='viewport'] {
126
+ grid-area: 1 / 2;
127
+ }
128
+
129
+ [data-ui='carousel'] > [data-part='viewport']::-webkit-scrollbar {
130
+ display: none;
131
+ }
132
+
133
+ [data-ui='carousel'] > [data-part='viewport']:focus-visible {
134
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
135
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
136
+ }
137
+
138
+ /**
139
+ * While the engine moves the scroll, and while a mouse drags it, snap is
140
+ * off: a snapping scroller pulls every intermediate position back to the
141
+ * nearest page. The engine writes `data-moving` in the same task as the
142
+ * movement — the root's `data-dragging` comes from a framework render a
143
+ * frame later, and the first frames of a drag were snapped back under the
144
+ * pointer. Both movements end exactly on a page, so snap returns without
145
+ * moving anything.
146
+ */
147
+ [data-ui='carousel'] > [data-part='viewport'][data-moving] {
148
+ scroll-snap-type: none;
149
+ }
150
+
151
+ /**
152
+ * A mouse can drag the row, and the cursor says so before the press. The
153
+ * rule is gated on a fine pointer: a finger drags the scroller natively and
154
+ * has no cursor to change.
155
+ */
156
+ @media (hover: hover) and (pointer: fine) {
157
+ [data-ui='carousel'][data-draggable]:not([data-transition='fade']) > [data-part='viewport'] {
158
+ cursor: grab;
159
+ }
160
+ }
161
+
162
+ [data-ui='carousel'][data-dragging] > [data-part='viewport'] {
163
+ cursor: grabbing;
164
+ user-select: none;
165
+ }
166
+
167
+ /** A picture inside a draggable row would otherwise start the browser's own image drag. */
168
+ [data-ui='carousel'][data-draggable] > [data-part='viewport'] img {
169
+ -webkit-user-drag: none;
170
+ }
171
+
172
+ [data-ui='carousel'][data-orientation='vertical'] > [data-part='viewport'] {
173
+ /**
174
+ * A column of slides needs a height to divide, and the content cannot
175
+ * give one: the tallest slide would make the viewport as tall as the
176
+ * column. Twenty rem is a card and a half at comfortable density.
177
+ */
178
+ block-size: var(--slotted-carousel-viewport-size, 20rem);
179
+ grid-auto-columns: 100%;
180
+ grid-auto-flow: row;
181
+ grid-auto-rows: calc((100% - (var(--_per-view) - 1) * var(--_gap)) / var(--_per-view));
182
+ overflow-x: hidden;
183
+ overflow-y: auto;
184
+ overscroll-behavior-block: contain;
185
+ padding-block: var(--_peek);
186
+ padding-inline: 0;
187
+ scroll-padding-block: var(--_peek);
188
+ scroll-padding-inline: 0;
189
+ scroll-snap-type: y mandatory;
190
+ }
191
+
192
+ /* ── The slides ───────────────────────────────────────────────────────── */
193
+
194
+ /**
195
+ * A scroller cannot go past its ends, so a drag that pulls past one moves
196
+ * the slides instead, by the distance the engine writes as
197
+ * `--slotted-carousel-overscroll` — less and less the further the hand
198
+ * goes — and springs it back to nothing on release.
199
+ */
200
+ [data-ui='carousel'] > [data-part='viewport'] > [data-part='slide'] {
201
+ min-block-size: 0;
202
+ min-inline-size: 0;
203
+ position: relative;
204
+ scroll-snap-align: start;
205
+ translate: var(--slotted-carousel-overscroll, none);
206
+ }
207
+
208
+ [data-ui='carousel'][data-align='center'] > [data-part='viewport'] > [data-part='slide'] {
209
+ scroll-snap-align: center;
210
+ }
211
+
212
+ /**
213
+ * Once the engine has read the pages, only a slide a page starts at is a
214
+ * snap point. Before that every slide is one, which is the right paging for
215
+ * a server response and for one slide per view.
216
+ */
217
+ [data-ui='carousel'][data-measured]
218
+ > [data-part='viewport']
219
+ > [data-part='slide']:not([data-snap]) {
220
+ scroll-snap-align: none;
221
+ }
222
+
223
+ /**
224
+ * ── Fade ───────────────────────────────────────────────────────────────
225
+ *
226
+ * The slides are stacked in one cell and only the current one is shown.
227
+ * The viewport does not scroll, so a finger's horizontal swipe is the
228
+ * family's and a vertical one stays the page's.
229
+ *
230
+ * The arriving slide fades in on the enter curve over the long step; the
231
+ * leaving one fades out on the exit curve over the medium step, so the exit
232
+ * is never slower than the enter. The two overlap for the medium step
233
+ * rather than following each other, which keeps the cell from going empty
234
+ * between them. `visibility` interpolates as visible while either end is,
235
+ * so it hides the leaving slide when its fade ends and nothing in it can be
236
+ * reached once it is gone.
237
+ */
238
+ [data-ui='carousel'][data-transition='fade'] > [data-part='viewport'] {
239
+ grid-auto-columns: 100%;
240
+ grid-template-areas: 'stack';
241
+ overflow: hidden;
242
+ scroll-snap-type: none;
243
+ touch-action: pan-y;
244
+ }
245
+
246
+ [data-ui='carousel'][data-transition='fade'] > [data-part='viewport'] > [data-part='slide'] {
247
+ grid-area: stack;
248
+ opacity: 0;
249
+ transition:
250
+ opacity var(--slotted-duration-medium) var(--slotted-easing-exit, ease-in),
251
+ visibility var(--slotted-duration-medium) linear;
252
+ visibility: hidden;
253
+ }
254
+
255
+ [data-ui='carousel'][data-transition='fade']
256
+ > [data-part='viewport']
257
+ > [data-part='slide'][data-current] {
258
+ opacity: 1;
259
+ transition:
260
+ opacity var(--slotted-duration-long) var(--slotted-easing-enter, ease-out),
261
+ visibility var(--slotted-duration-long) linear;
262
+ visibility: visible;
263
+ }
264
+
265
+ /* ── Previous, next and the rotation control ──────────────────────────── */
266
+
267
+ /**
268
+ * One round control for all three, on the raised surface with the control
269
+ * shadow, because the inset pair stands over a picture and has to read as
270
+ * a thing on top of it in both schemes. ReUI measures 28 pixels with a
271
+ * 16-pixel mark; the family takes the control scale, 34 at `md`, so the
272
+ * pair is a step larger than the dots and matches a toolbar's buttons.
273
+ */
274
+ [data-ui='carousel'] [data-part='previous'],
275
+ [data-ui='carousel'] [data-part='next'],
276
+ [data-ui='carousel'] [data-part='autoplay'] {
277
+ --slotted-icon-size: var(--_icon-size);
278
+
279
+ align-items: center;
280
+ appearance: none;
281
+ background: var(--slotted-control-surface, Field);
282
+ block-size: var(--_control-size);
283
+ border: var(--slotted-control-border-width, 1px) solid
284
+ var(--slotted-control-border-color, ButtonBorder);
285
+ border-radius: var(--slotted-radius-full, 9999px);
286
+ box-shadow: var(--slotted-control-shadow, none);
287
+ color: var(--slotted-text, ButtonText);
288
+ cursor: pointer;
289
+ display: inline-flex;
290
+ flex: none;
291
+ inline-size: var(--_control-size);
292
+ justify-content: center;
293
+ margin: 0;
294
+ padding: 0;
295
+ transition:
296
+ background-color var(--slotted-control-transition-duration)
297
+ var(--slotted-control-transition-easing, ease),
298
+ border-color var(--slotted-control-transition-duration)
299
+ var(--slotted-control-transition-easing, ease),
300
+ box-shadow var(--slotted-control-transition-duration)
301
+ var(--slotted-control-transition-easing, ease),
302
+ color var(--slotted-control-transition-duration)
303
+ var(--slotted-control-transition-easing, ease),
304
+ scale var(--slotted-control-transition-duration)
305
+ var(--slotted-control-transition-easing, ease);
306
+ }
307
+
308
+ /** Over the viewport, at the two ends of its axis. */
309
+ [data-ui='carousel'] > [data-part='previous'],
310
+ [data-ui='carousel'] > [data-part='next'] {
311
+ align-self: center;
312
+ grid-area: 1 / 1;
313
+ margin-inline: var(--_inset);
314
+ z-index: 1;
315
+ }
316
+
317
+ [data-ui='carousel'] > [data-part='previous'] {
318
+ justify-self: start;
319
+ }
320
+
321
+ [data-ui='carousel'] > [data-part='next'] {
322
+ justify-self: end;
323
+ }
324
+
325
+ [data-ui='carousel'][data-arrows='outside'] > [data-part='previous'] {
326
+ grid-area: 1 / 1;
327
+ margin-inline: 0;
328
+ }
329
+
330
+ [data-ui='carousel'][data-arrows='outside'] > [data-part='next'] {
331
+ grid-area: 1 / 3;
332
+ margin-inline: 0;
333
+ }
334
+
335
+ [data-ui='carousel'][data-orientation='vertical'] > [data-part='previous'],
336
+ [data-ui='carousel'][data-orientation='vertical'] > [data-part='next'] {
337
+ justify-self: center;
338
+ margin-block: var(--_inset);
339
+ margin-inline: 0;
340
+ }
341
+
342
+ [data-ui='carousel'][data-orientation='vertical'] > [data-part='previous'] {
343
+ align-self: start;
344
+ }
345
+
346
+ [data-ui='carousel'][data-orientation='vertical'] > [data-part='next'] {
347
+ align-self: end;
348
+ }
349
+
350
+ /**
351
+ * The chevron is drawn once, pointing along the reading direction, and the
352
+ * icon box mirrors it in a right-to-left document. Previous turns it round;
353
+ * a vertical carousel turns both a quarter so they point along the column.
354
+ */
355
+ [data-ui='carousel'] [data-part='previous'] > [data-ui='icon'] {
356
+ rotate: 180deg;
357
+ }
358
+
359
+ [data-ui='carousel'][data-orientation='vertical'] [data-part='previous'] > [data-ui='icon'] {
360
+ rotate: -90deg;
361
+ }
362
+
363
+ [data-ui='carousel'][data-orientation='vertical'] [data-part='next'] > [data-ui='icon'] {
364
+ rotate: 90deg;
365
+ }
366
+
367
+ /**
368
+ * A column does not run along the reading direction, so a right-to-left
369
+ * document leaves its arrows alone. The icon box mirrors before it turns,
370
+ * and a mirrored chevron turned a quarter points the other way along the
371
+ * column.
372
+ */
373
+ [data-ui='carousel'][data-orientation='vertical']
374
+ :is([data-part='previous'], [data-part='next'])
375
+ > [data-ui='icon']:dir(rtl) {
376
+ scale: none;
377
+ }
378
+
379
+ [data-ui='carousel'] [data-part='previous']:hover:not([data-disabled]):not(:disabled),
380
+ [data-ui='carousel'] [data-part='next']:hover:not([data-disabled]):not(:disabled),
381
+ [data-ui='carousel'] [data-part='autoplay']:hover:not([data-disabled]):not(:disabled) {
382
+ background: var(--slotted-tone-secondary-subtle-hover, ButtonFace);
383
+ }
384
+
385
+ /**
386
+ * A press lands at once and releases at the control's pace. The round
387
+ * control shrinks by six per cent rather than dropping a hairline: a circle
388
+ * standing over a picture has no floor to be put down on, and a scale is
389
+ * the press that reads on a shape with no bottom edge.
390
+ */
391
+ [data-ui='carousel'] [data-part='previous']:active:not([data-disabled]):not(:disabled),
392
+ [data-ui='carousel'] [data-part='next']:active:not([data-disabled]):not(:disabled),
393
+ [data-ui='carousel'] [data-part='autoplay']:active:not([data-disabled]):not(:disabled) {
394
+ background: var(--slotted-tone-secondary-subtle-active, ButtonFace);
395
+ box-shadow: none;
396
+ scale: 0.94;
397
+ transition-duration: var(--slotted-duration-instant);
398
+ }
399
+
400
+ [data-ui='carousel'] [data-part='previous']:focus-visible,
401
+ [data-ui='carousel'] [data-part='next']:focus-visible,
402
+ [data-ui='carousel'] [data-part='autoplay']:focus-visible {
403
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
404
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
405
+ }
406
+
407
+ /**
408
+ * At an end without a loop the control stays where it is and stays
409
+ * focusable — `aria-disabled`, never `disabled`, so the focus it holds is
410
+ * not dropped onto the page — and says it has nowhere to go in the
411
+ * foundation's disabled ink, with its ground kept so it still reads as a
412
+ * control over a picture.
413
+ */
414
+ [data-ui='carousel'] :is([data-part='previous'], [data-part='next'])[data-disabled] {
415
+ border-color: var(--slotted-disabled-border, GrayText);
416
+ box-shadow: none;
417
+ color: var(--slotted-disabled-foreground, GrayText);
418
+ cursor: default;
419
+ }
420
+
421
+ /* ── The bar ──────────────────────────────────────────────────────────── */
422
+
423
+ /**
424
+ * The bar wraps rather than overflows: five dots and a counter are 180
425
+ * pixels, and a carousel in a third of a dashboard is narrower than that.
426
+ * The counter drops under the dots, centred, before anything is clipped.
427
+ */
428
+ [data-ui='carousel'] > [data-part='controls'] {
429
+ align-items: center;
430
+ display: flex;
431
+ flex-wrap: wrap;
432
+ gap: var(--slotted-space-4, 0.5rem);
433
+ grid-column: 1 / -1;
434
+ justify-content: center;
435
+ min-inline-size: 0;
436
+ }
437
+
438
+ [data-ui='carousel'][data-arrows='outside'] > [data-part='controls'] {
439
+ grid-column: 2;
440
+ }
441
+
442
+ /**
443
+ * Over the picture, at its foot, on a pill of the raised surface. Solid
444
+ * rather than translucent: the dots are the one thing on the picture that
445
+ * has to read in every scheme, and a ground that lets the picture through
446
+ * gives the dots a different ground on every slide.
447
+ */
448
+ [data-ui='carousel'] > [data-part='controls'][data-placement='overlay'] {
449
+ align-self: end;
450
+ background: var(--slotted-surface-raised, Canvas);
451
+ border-radius: var(--slotted-radius-full, 9999px);
452
+ box-shadow: var(--slotted-shadow-sm, none);
453
+ gap: var(--slotted-space-2, 0.25rem);
454
+ grid-area: 1 / 1;
455
+ justify-self: center;
456
+ margin-block-end: var(--_inset);
457
+ padding-block: var(--slotted-space-2, 0.25rem);
458
+ padding-inline: var(--slotted-space-3, 0.375rem);
459
+ z-index: 1;
460
+ }
461
+
462
+ /**
463
+ * Inside the pill the round controls give their frame to the pill: a
464
+ * bordered circle inside a bordered pill is two edges where one is enough.
465
+ * They take the height the foundation gives the inside of a control, so
466
+ * the pill is that height and a step of air either side of it.
467
+ */
468
+ [data-ui='carousel']
469
+ > [data-part='controls'][data-placement='overlay']
470
+ > :is([data-part='previous'], [data-part='next'], [data-part='autoplay']) {
471
+ --_control-size: var(--slotted-control-inner-size-md, 24px);
472
+
473
+ background: transparent;
474
+ border-color: transparent;
475
+ box-shadow: none;
476
+ }
477
+
478
+ [data-ui='carousel'][data-size='sm']
479
+ > [data-part='controls'][data-placement='overlay']
480
+ > :is([data-part='previous'], [data-part='next'], [data-part='autoplay']) {
481
+ --_control-size: var(--slotted-control-inner-size-sm, 22px);
482
+ }
483
+
484
+ [data-ui='carousel'][data-size='lg']
485
+ > [data-part='controls'][data-placement='overlay']
486
+ > :is([data-part='previous'], [data-part='next'], [data-part='autoplay']) {
487
+ --_control-size: var(--slotted-control-inner-size-lg, 28px);
488
+ }
489
+
490
+ [data-ui='carousel'][data-arrows='outside'] > [data-part='controls'][data-placement='overlay'] {
491
+ grid-area: 1 / 2;
492
+ }
493
+
494
+ [data-ui='carousel'] > [data-part='controls'] > [data-part='indicators'][data-variant='line'] {
495
+ flex: 1 1 auto;
496
+ }
497
+
498
+ /* ── The indicators ───────────────────────────────────────────────────── */
499
+
500
+ [data-ui='carousel'] [data-part='indicators'] {
501
+ align-items: center;
502
+ display: flex;
503
+ /* A dot's box is twenty pixels; four between two boxes puts their centres twenty-four apart. */
504
+ gap: var(--slotted-space-2, 0.25rem);
505
+ justify-content: center;
506
+ min-inline-size: 0;
507
+ }
508
+
509
+ /**
510
+ * A dot is eight pixels and the button around it is a 24-pixel row: the
511
+ * mark is drawn by the button's own `::before`, and the box is what the
512
+ * pointer hits. Two boxes side by side stand twenty-four pixels centre to
513
+ * centre, which is the spacing WCAG 2.2 SC 2.5.8 accepts for a target
514
+ * smaller than twenty-four.
515
+ */
516
+ [data-ui='carousel'] [data-part='indicator'] {
517
+ appearance: none;
518
+ background: transparent;
519
+ block-size: var(--slotted-target-min, 24px);
520
+ border: 0;
521
+ border-radius: var(--slotted-radius-full, 9999px);
522
+ color: inherit;
523
+ cursor: pointer;
524
+ flex: none;
525
+ inline-size: calc(var(--_dot) + 2 * var(--_dot-air));
526
+ margin: 0;
527
+ padding: 0;
528
+ position: relative;
529
+ transition: inline-size var(--slotted-duration-medium) var(--slotted-easing-standard, ease);
530
+ }
531
+
532
+ [data-ui='carousel'] [data-part='indicator'][data-current] {
533
+ inline-size: calc(var(--_dot-current) + 2 * var(--_dot-air));
534
+ }
535
+
536
+ [data-ui='carousel']
537
+ [data-part='indicators']:not([data-variant='thumbnails'])
538
+ > [data-part='indicator']::before,
539
+ [data-ui='carousel']
540
+ [data-part='indicators']:not([data-variant='thumbnails'])
541
+ > [data-part='indicator']::after {
542
+ block-size: var(--_dot);
543
+ border-radius: var(--slotted-radius-full, 9999px);
544
+ content: '';
545
+ inset-block-start: calc(50% - var(--_dot) / 2);
546
+ inset-inline: var(--_dot-air);
547
+ position: absolute;
548
+ }
549
+
550
+ /**
551
+ * The resting dot is the line between two surfaces, which holds 3:1 on
552
+ * every surface a carousel stands on; the current one is the ink, and its
553
+ * shape already differs.
554
+ */
555
+ [data-ui='carousel']
556
+ [data-part='indicators']:not([data-variant='thumbnails'])
557
+ > [data-part='indicator']::before {
558
+ background: var(--slotted-border-strong, transparent);
559
+ transition: background-color var(--slotted-control-transition-duration)
560
+ var(--slotted-control-transition-easing, ease);
561
+ }
562
+
563
+ [data-ui='carousel']
564
+ [data-part='indicators']:not([data-variant='thumbnails'])
565
+ > [data-part='indicator']:hover:not([data-current]):not([data-disabled])::before {
566
+ background: var(--slotted-text-muted, transparent);
567
+ }
568
+
569
+ [data-ui='carousel']
570
+ [data-part='indicators']:not([data-variant='thumbnails'])
571
+ > [data-part='indicator']:active:not([data-current]):not([data-disabled])::before {
572
+ background: var(--slotted-text, transparent);
573
+ transition-duration: var(--slotted-duration-instant);
574
+ }
575
+
576
+ [data-ui='carousel']
577
+ [data-part='indicators']:not([data-variant='thumbnails'])
578
+ > [data-part='indicator'][data-current]::before {
579
+ background: var(--slotted-text, transparent);
580
+ }
581
+
582
+ /**
583
+ * ── The time left ──────────────────────────────────────────────────────
584
+ *
585
+ * While the rotation runs the current mark becomes a track and fills with
586
+ * the ink over exactly the delay the timer was given, because it reads the
587
+ * same number: `--slotted-carousel-autoplay-delay`, written by the binding.
588
+ * Hover and a hidden document pause the timer, and `data-paused` freezes
589
+ * the fill at the same instant, so the picture and the timer never
590
+ * disagree. The fill grows its own inline size from the inline start, like
591
+ * `toast`'s countdown, so there is no origin to mirror.
592
+ */
593
+ [data-ui='carousel'][data-playing]
594
+ [data-part='indicators']:not([data-variant='thumbnails'])
595
+ > [data-part='indicator'][data-current]::before {
596
+ background: var(--slotted-border-strong, transparent);
597
+ }
598
+
599
+ [data-ui='carousel'][data-playing]
600
+ [data-part='indicators']:not([data-variant='thumbnails'])
601
+ > [data-part='indicator'][data-current]::after {
602
+ animation: slotted-carousel-countdown
603
+ var(--slotted-carousel-autoplay-delay, var(--slotted-duration-loop-slow)) linear forwards;
604
+ background: var(--slotted-text, transparent);
605
+ inset-inline-end: auto;
606
+ }
607
+
608
+ [data-ui='carousel'][data-playing][data-paused]
609
+ [data-part='indicators']
610
+ > [data-part='indicator'][data-current]::after {
611
+ animation-play-state: paused;
612
+ }
613
+
614
+ /* From a dot rather than from nothing: a fill one pixel wide with round caps reads as a tick. */
615
+ @keyframes slotted-carousel-countdown {
616
+ from {
617
+ inline-size: var(--_dot);
618
+ }
619
+
620
+ to {
621
+ inline-size: calc(100% - 2 * var(--_dot-air));
622
+ }
623
+ }
624
+
625
+ /**
626
+ * Past eight pages a row of dots is a ruler nobody reads. The engine writes
627
+ * each dot's distance from the current one; two steps away a dot shrinks by
628
+ * a third, and beyond the window it collapses to nothing. A collapsed dot
629
+ * stays a tab in the arrow ring, and moving onto it makes it current, which
630
+ * brings the window to it.
631
+ */
632
+ [data-ui='carousel']
633
+ [data-part='indicators'][data-adaptive]
634
+ > [data-part='indicator'][data-distance='2']::before {
635
+ scale: 0.66;
636
+ }
637
+
638
+ [data-ui='carousel']
639
+ [data-part='indicators'][data-adaptive]
640
+ > [data-part='indicator'][data-distance='far'] {
641
+ inline-size: 0;
642
+ overflow: hidden;
643
+ }
644
+
645
+ /**
646
+ * ── Line ───────────────────────────────────────────────────────────────
647
+ *
648
+ * Segments that share the row. The mark is a two-pixel rule rather than a
649
+ * dot, and the current one is the ink — the progress line ReUI's `blog-3`
650
+ * draws as a single pixel, at the thickness the foundation gives a marker.
651
+ */
652
+ [data-ui='carousel'] [data-part='indicators'][data-variant='line'] {
653
+ gap: var(--slotted-space-2, 0.25rem);
654
+ }
655
+
656
+ [data-ui='carousel'] [data-part='indicators'][data-variant='line'] > [data-part='indicator'],
657
+ [data-ui='carousel']
658
+ [data-part='indicators'][data-variant='line']
659
+ > [data-part='indicator'][data-current] {
660
+ flex: 1 1 0;
661
+ inline-size: auto;
662
+ min-inline-size: var(--slotted-target-min, 24px);
663
+ }
664
+
665
+ [data-ui='carousel']
666
+ [data-part='indicators'][data-variant='line']
667
+ > [data-part='indicator']::before,
668
+ [data-ui='carousel']
669
+ [data-part='indicators'][data-variant='line']
670
+ > [data-part='indicator']::after {
671
+ block-size: var(--_line);
672
+ border-radius: var(--slotted-radius-full, 9999px);
673
+ inset-block-start: calc(50% - var(--_line) / 2);
674
+ inset-inline: 0;
675
+ }
676
+
677
+ [data-ui='carousel'][data-playing]
678
+ [data-part='indicators'][data-variant='line']
679
+ > [data-part='indicator'][data-current]::after {
680
+ animation-name: slotted-carousel-countdown-line;
681
+ }
682
+
683
+ @keyframes slotted-carousel-countdown-line {
684
+ from {
685
+ inline-size: 0;
686
+ }
687
+
688
+ to {
689
+ inline-size: 100%;
690
+ }
691
+ }
692
+
693
+ /**
694
+ * ── Thumbnails ─────────────────────────────────────────────────────────
695
+ *
696
+ * Each indicator holds the consumer's picture. The strip scrolls on its own
697
+ * when it holds more than it can show, and the engine keeps the current one
698
+ * in view. The resting pictures are held back so the current one is the
699
+ * brightest thing in the strip; the current one carries an inset ring of
700
+ * the ink, inside its own box, so the focus ring drawn outside it is never
701
+ * confused with it.
702
+ */
703
+ [data-ui='carousel'] [data-part='indicators'][data-variant='thumbnails'] {
704
+ gap: var(--slotted-space-4, 0.5rem);
705
+ justify-content: flex-start;
706
+ overflow-x: auto;
707
+ overscroll-behavior-inline: contain;
708
+ /* Room for the focus ring, which the scroller would otherwise clip. */
709
+ padding: calc(var(--slotted-focus-ring-width, 2px) + var(--slotted-focus-ring-offset, 2px));
710
+ scrollbar-width: none;
711
+ }
712
+
713
+ [data-ui='carousel']
714
+ [data-part='indicators'][data-variant='thumbnails']
715
+ > [data-part='indicator'],
716
+ [data-ui='carousel']
717
+ [data-part='indicators'][data-variant='thumbnails']
718
+ > [data-part='indicator'][data-current] {
719
+ block-size: var(--_thumbnail);
720
+ border-radius: var(--slotted-radius-md, 6px);
721
+ inline-size: var(--_thumbnail);
722
+ overflow: hidden;
723
+ transition: none;
724
+ }
725
+
726
+ [data-ui='carousel']
727
+ [data-part='indicators'][data-variant='thumbnails']
728
+ > [data-part='indicator']
729
+ > * {
730
+ block-size: 100%;
731
+ display: block;
732
+ inline-size: 100%;
733
+ object-fit: cover;
734
+ opacity: 0.6;
735
+ transition: opacity var(--slotted-control-transition-duration)
736
+ var(--slotted-control-transition-easing, ease);
737
+ }
738
+
739
+ [data-ui='carousel']
740
+ [data-part='indicators'][data-variant='thumbnails']
741
+ > [data-part='indicator']:hover:not([data-current]):not([data-disabled])
742
+ > * {
743
+ opacity: 0.85;
744
+ }
745
+
746
+ [data-ui='carousel']
747
+ [data-part='indicators'][data-variant='thumbnails']
748
+ > [data-part='indicator'][data-current]
749
+ > * {
750
+ opacity: 1;
751
+ }
752
+
753
+ [data-ui='carousel']
754
+ [data-part='indicators'][data-variant='thumbnails']
755
+ > [data-part='indicator']::after {
756
+ border-radius: inherit;
757
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px)
758
+ var(--slotted-border-subtle, transparent);
759
+ content: '';
760
+ inset: 0;
761
+ pointer-events: none;
762
+ position: absolute;
763
+ transition: box-shadow var(--slotted-control-transition-duration)
764
+ var(--slotted-control-transition-easing, ease);
765
+ }
766
+
767
+ /**
768
+ * The ring answers the pointer as well as the picture does: a step darker
769
+ * under hover, and the ink under the press, so the part itself carries the
770
+ * state and not only the picture inside it.
771
+ */
772
+ [data-ui='carousel']
773
+ [data-part='indicators'][data-variant='thumbnails']
774
+ > [data-part='indicator']:hover:not([data-current]):not([data-disabled])::after {
775
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px)
776
+ var(--slotted-border-strong, transparent);
777
+ }
778
+
779
+ [data-ui='carousel']
780
+ [data-part='indicators'][data-variant='thumbnails']
781
+ > [data-part='indicator']:active:not([data-current]):not([data-disabled])::after {
782
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thick, 2px)
783
+ var(--slotted-border-strong, transparent);
784
+ transition-duration: var(--slotted-duration-instant);
785
+ }
786
+
787
+ [data-ui='carousel']
788
+ [data-part='indicators'][data-variant='thumbnails']
789
+ > [data-part='indicator'][data-current]::after {
790
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thick, 2px) var(--slotted-text, transparent);
791
+ }
792
+
793
+ [data-ui='carousel'] [data-part='indicator']:focus-visible {
794
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
795
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
796
+ }
797
+
798
+ /**
799
+ * A dot on a line drawn inside a 24-pixel row would put the ring four
800
+ * pixels round a box much taller than the mark. The ring of a dot or a
801
+ * segment hugs the row instead, which is the box the pointer hits.
802
+ */
803
+ [data-ui='carousel']
804
+ [data-part='indicators']:not([data-variant='thumbnails'])
805
+ > [data-part='indicator']:focus-visible {
806
+ outline-offset: calc(var(--slotted-focus-ring-width, 2px) * -1);
807
+ }
808
+
809
+ /* ── The counter ──────────────────────────────────────────────────────── */
810
+
811
+ /**
812
+ * Tabular figures, so "9 / 12" and "10 / 12" are the same width and the
813
+ * controls beside the counter do not move when the page changes.
814
+ */
815
+ [data-ui='carousel'] [data-part='counter'] {
816
+ color: var(--slotted-text-muted, GrayText);
817
+ font-family: var(--slotted-font-family-sans, sans-serif);
818
+ font-size: var(--slotted-font-size-sm, 0.8125rem);
819
+ font-variant-numeric: tabular-nums;
820
+ line-height: var(--slotted-line-height-sm, 1.45);
821
+ /**
822
+ * "3 / 8" is a fraction and reads first-to-last in every script; left to
823
+ * the bidirectional algorithm in a right-to-left page the neutral slash
824
+ * turned it into "8 / 3".
825
+ */
826
+ direction: ltr;
827
+ unicode-bidi: isolate;
828
+ white-space: nowrap;
829
+ }
830
+
831
+ /**
832
+ * The marks are painted by pseudo-elements, and forced colours repaint a
833
+ * pseudo-element's ground as the page's and lose the mark. The theme has
834
+ * already mapped the tokens the marks read to system colours, so the rule
835
+ * only stops the repaint, and moves the current mark to the accent tone,
836
+ * which forced colours map to the highlight.
837
+ */
838
+ @media (forced-colors: active) {
839
+ [data-ui='carousel'] [data-part='indicator']::before,
840
+ [data-ui='carousel'] [data-part='indicator']::after {
841
+ forced-color-adjust: none;
842
+ }
843
+
844
+ [data-ui='carousel']
845
+ [data-part='indicators']:not([data-variant='thumbnails'])
846
+ > [data-part='indicator'][data-current]::before,
847
+ [data-ui='carousel']
848
+ [data-part='indicators']:not([data-variant='thumbnails'])
849
+ > [data-part='indicator'][data-current]::after {
850
+ background: var(--slotted-tone-accent-solid, transparent);
851
+ }
852
+
853
+ [data-ui='carousel']
854
+ [data-part='indicators'][data-variant='thumbnails']
855
+ > [data-part='indicator'][data-current]::after {
856
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thick, 2px)
857
+ var(--slotted-tone-accent-solid, transparent);
858
+ }
859
+ }
860
+ }