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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,757 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── A frame of typed values, with a field that adds more ────────────────
4
+ *
5
+ * One subtree, where the consumer wrote it. Nothing is portalled and
6
+ * nothing opens: the input is a text box, and the values beside it are the
7
+ * texts the reader typed.
8
+ *
9
+ * ┌─ root ─ the frame ─────────────────────────────────────────┐
10
+ * │ ┌─ control ─ role="grid" ───────────────┐ │
11
+ * │ │ ┌─ chips ─ role="row" ─ wraps ──────┐ │ counter clear │
12
+ * │ │ │ tag ▸ tag ▸ tag(invalid) ▸ +N │ │ │
13
+ * │ │ │ field ▸ input │ │ │
14
+ * │ │ └───────────────────────────────────┘ │ │
15
+ * │ └───────────────────────────────────────┘ │
16
+ * │ hint · message ─ for assistive technology only │
17
+ * └────────────────────────────────────────────────────────────┘
18
+ *
19
+ * ── What this sheet does not decide ──────────────────────────────────
20
+ *
21
+ * **Nothing about a chip.** The chips are `tag`'s, worn as `data-ui` beside
22
+ * this family's own parts, so the pill, the small step, the `danger` tone an
23
+ * invalid value wears, and the remove control floored at
24
+ * `--slotted-target-min` are all stated once in `tag/tag.css`. This sheet
25
+ * decides where the row is, how it wraps, and the one mark it adds.
26
+ *
27
+ * **The frame.** `text-field`'s arithmetic and `multi-select`'s: the same
28
+ * control on the same form, so the numbers are the same numbers. The control
29
+ * grows by whole rows of chips and by nothing else — an empty control is
30
+ * exactly the height of a text field beside it, and three rows is where it
31
+ * stops growing and starts scrolling.
32
+ *
33
+ * ── What this sheet decides on its own ───────────────────────────────
34
+ *
35
+ * **An invalid value is a chip with a mark.** The tone is `tag`'s `danger`,
36
+ * written in the DOM; the alert glyph in the chip's `start` slot is the
37
+ * `Glyph` element the binding renders there, because `tag` has no opinion
38
+ * about what a slot holds. Colour, mark and — in the tree — a description,
39
+ * which is what §2.5 asks of an invalid state.
40
+ *
41
+ * **A collapsed row opens where the reader is.** Under `overflow='collapse'`
42
+ * the row is one line and a `+N` at rest, and every chip while the control
43
+ * has focus within — `data-expanded`, written by the binding. There is no
44
+ * popup to hold the hidden chips, so the row itself is where they are shown,
45
+ * and it is shown exactly when the reader is about to act on them.
46
+ *
47
+ * **Two parts are for assistive technology alone.** `hint` names the keys
48
+ * the row answers, `message` names why a value is wrong. Both are removed
49
+ * from sight with the rule `visually-hidden/visually-hidden.css` states,
50
+ * restated here because a part of this family cannot wear another family's
51
+ * `data-ui` and mean two things.
52
+ */
53
+
54
+ /* ── The frame ────────────────────────────────────────────────────────── */
55
+
56
+ [data-ui='tags-input'][data-part='root'] {
57
+ --_font-size: var(--slotted-control-font-size-md, 13px);
58
+ --_height: var(--slotted-control-height-md, 34px);
59
+ --_padding-inline: var(--slotted-control-padding-inline-md, 13px);
60
+ --_gap: var(--slotted-control-gap-md, 8px);
61
+ /** The floor under the glyph scale at the dense step; a family token so a theme can retune it. */
62
+ --_icon-floor: var(--slotted-tags-input-icon-size-min, 14px);
63
+ --_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-md, 16px));
64
+
65
+ /* `text-field`'s arithmetic, because this is the same button in the same
66
+ frame and a second answer would drift from the first. */
67
+ --_action-size: var(
68
+ --slotted-tags-input-action-size,
69
+ min(calc(var(--_icon-size) + 2 * var(--slotted-space-2, 0.25rem)), var(--_inner-size))
70
+ );
71
+
72
+ /**
73
+ * The air above and below a row of chips: a space step, kept at every
74
+ * density. It is the chip that yields, below — not the air — so a control
75
+ * holding one row of chips is the height of an empty one beside it and the
76
+ * chip never touches the frame.
77
+ */
78
+ --_row-air: var(--slotted-space-1, 0.125rem);
79
+ /**
80
+ * One row's height is the height the foundation gives the inside of a
81
+ * control at this size step, `--slotted-control-inner-size-*`: the chip
82
+ * takes it through the property the row writes below, so a `dense` frame
83
+ * of 26 pixels holds an 18-pixel chip with four pixels of air a side, and
84
+ * three rows plus their gaps divide the cap below with no sliver of a
85
+ * fourth. The type stays 12px; the chip's line and inset are derived from
86
+ * the height in `tag.css`, and the remove control keeps its 24-pixel target
87
+ * through `tag`'s own halo.
88
+ */
89
+ --_inner-size: var(--slotted-control-inner-size-md, 24px);
90
+ --_row-size: var(--_inner-size);
91
+ --_row-gap: var(--slotted-space-2, 0.25rem);
92
+
93
+ align-items: center;
94
+ background-color: var(--slotted-tags-input-background, var(--slotted-control-surface, Field));
95
+ border: var(--slotted-control-border-width, 1px) solid
96
+ var(--slotted-tags-input-border-color, var(--slotted-control-border-color, ButtonBorder));
97
+ border-radius: var(--slotted-tags-input-radius, var(--slotted-control-radius, 4px));
98
+ box-shadow: var(--slotted-tags-input-shadow, var(--slotted-control-shadow, none));
99
+ box-sizing: border-box;
100
+ color: var(--slotted-tags-input-color, var(--slotted-text, CanvasText));
101
+ display: flex;
102
+ font-family: var(--slotted-control-font-family, system-ui, sans-serif);
103
+ font-size: var(--_font-size);
104
+ gap: var(--slotted-space-1, 0.125rem);
105
+ inline-size: 100%;
106
+ min-block-size: var(--_height);
107
+ min-inline-size: 0;
108
+ padding-inline-start: var(--_padding-inline);
109
+ /* The end padding is the button's gutter rather than the frame's, so the
110
+ glyph — not the button's box — ends where the text begins on the other
111
+ side. `text-field` states the same arithmetic. */
112
+ padding-inline-end: max(
113
+ 0px,
114
+ calc(var(--_padding-inline) - (var(--_action-size) - var(--_icon-size)) / 2)
115
+ );
116
+ /* The containing block of the two hidden parts. */
117
+ position: relative;
118
+ transition:
119
+ background-color var(--slotted-control-transition-duration)
120
+ var(--slotted-control-transition-easing),
121
+ border-color var(--slotted-control-transition-duration)
122
+ var(--slotted-control-transition-easing),
123
+ box-shadow var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
124
+ }
125
+
126
+ [data-ui='tags-input'][data-part='root']:not([data-full-width]) {
127
+ inline-size: auto;
128
+ }
129
+
130
+ /**
131
+ * The grid. It holds one row and gives up every visual decision to it: the
132
+ * role is what the layout-grid pattern asks for, and the geometry belongs to
133
+ * the row that wraps.
134
+ */
135
+ [data-ui='tags-input'] > [data-part='control'] {
136
+ display: flex;
137
+ flex: 1 1 auto;
138
+ min-inline-size: 0;
139
+ align-self: stretch;
140
+ }
141
+
142
+ /**
143
+ * The distance between the values and the controls that act on them: the
144
+ * row's own gap rather than the frame's tighter one, so the boundary between
145
+ * what is typed and what acts on it is never narrower than the rhythm inside
146
+ * it. `multi-select` measured the two-pixel version of this and rejected it.
147
+ */
148
+ [data-ui='tags-input'] > [data-part='control'] + * {
149
+ margin-inline-start: var(--_row-gap);
150
+ }
151
+
152
+ /**
153
+ * The row. One DOM row that wraps onto as many visual lines as it needs, so
154
+ * the reading order stays linear and "previous" and "next" have one meaning
155
+ * each — which is why the grid answers neither `ArrowDown` nor `ArrowUp`.
156
+ */
157
+ [data-ui='tags-input'] [data-part='chips'] {
158
+ /* `safe`, because this box scrolls: centring a scroll container's content
159
+ pushes the first line above the scrollport when there is more than fits,
160
+ and nothing can scroll back to it. `multi-select` found the first three
161
+ chips unreachable at 240 pixels without it. */
162
+ align-content: safe center;
163
+ align-items: center;
164
+ /* The cap below counts rows, gaps and the row's own air, so it has to be a
165
+ border box. */
166
+ box-sizing: border-box;
167
+ column-gap: var(--_row-gap);
168
+ display: flex;
169
+ flex: 1 1 auto;
170
+ flex-wrap: wrap;
171
+ min-inline-size: 0;
172
+ padding-block: var(--_row-air);
173
+ /* A box that scrolls on one axis clips on both, and a chip's remove control
174
+ takes the rest of its target from a halo outside the chip: the row keeps
175
+ two pixels of inline padding for it and takes them back with a negative
176
+ margin, so the chips stand where the gutter puts them. */
177
+ padding-inline: var(--_row-air);
178
+ margin-inline: calc(-1 * var(--_row-air));
179
+ row-gap: var(--_row-gap);
180
+ /* Three whole rows, then it scrolls. Every chip stays in the DOM either
181
+ way, which is what the feature guide asks of an overflow. */
182
+ max-block-size: calc(3 * var(--_row-size) + 2 * var(--_row-gap) + 2 * var(--_row-air));
183
+ overflow-y: auto;
184
+ overscroll-behavior: contain;
185
+ /**
186
+ * The row scrolls and draws no scrollbar. A form control has one frame, and
187
+ * a bar inside it takes width from the chips, moves them when it appears,
188
+ * and paints a second edge inside the control's own. The wheel and every
189
+ * arrow key still reach the rows above and below, because a chip is
190
+ * focusable and the browser scrolls focus into view; what says there is
191
+ * more is the counter and the row's own `aria-label` carrying the count.
192
+ */
193
+ scrollbar-width: none;
194
+ }
195
+
196
+ [data-ui='tags-input'] [data-part='chips']::-webkit-scrollbar {
197
+ display: none;
198
+ }
199
+
200
+ /**
201
+ * One line high at rest, under `overflow='collapse'`: what does not fit is
202
+ * collapsed by `createCollapse` into the counting chip. There is no popup to
203
+ * hold the rest, so the row itself opens — the rule after this one — while
204
+ * the control has focus within.
205
+ */
206
+ [data-ui='tags-input'][data-overflow='collapse']:not([data-expanded]) [data-part='chips'] {
207
+ flex-wrap: nowrap;
208
+ max-block-size: none;
209
+ overflow: hidden;
210
+ }
211
+
212
+ /**
213
+ * The expanded row is the wrapped row: the same three-line cap and the same
214
+ * scroll past it, so a reader who has learnt one shape has learnt both. The
215
+ * counting chip leaves while every chip is shown, and `createCollapse` is
216
+ * paused by the binding so it does not measure a row that is not clipping.
217
+ *
218
+ * No transition. The row's height changes as focus arrives, and a transition
219
+ * would make the reader wait for the chip they are about to reach.
220
+ */
221
+ [data-ui='tags-input'][data-overflow='collapse'][data-expanded]
222
+ [data-part='chips']
223
+ > [data-count] {
224
+ display: none;
225
+ }
226
+
227
+ /**
228
+ * A chip being edited. The grid pattern's own answer to a cell holding
229
+ * editable content is a text field inside the cell, so that is what it is —
230
+ * and it gives up every mark of a field, because the chip around it is
231
+ * already the box. Selected by element rather than by part: the field
232
+ * belongs to the chip, and the query's own input is told apart by the part it
233
+ * does have.
234
+ */
235
+ [data-ui='tags-input'] [data-part='chips'] input:not([data-part='input']) {
236
+ background-color: transparent;
237
+ border: 0;
238
+ color: inherit;
239
+ font: inherit;
240
+ min-inline-size: 0;
241
+ outline: none;
242
+ padding: 0;
243
+ }
244
+
245
+ /**
246
+ * A chip never shrinks: it either fits on the line or goes to the next one,
247
+ * and the only chip that gives way is one wider than the whole row, which is
248
+ * capped here and truncated by `tag.css`. Its height is the row's own — the
249
+ * target minimum — so three of them plus their gaps divide the cap above
250
+ * exactly, and no fourth row shows as a sliver under the third.
251
+ */
252
+ [data-ui='tags-input'] [data-part='chips'] > :not([data-part='field']) {
253
+ flex: 0 0 auto;
254
+ max-inline-size: 100%;
255
+ min-block-size: var(--_row-size);
256
+ min-inline-size: 0;
257
+ }
258
+
259
+ /**
260
+ * The chip takes the height the inside of this control has, through the
261
+ * property `tag` reads for it. Set on the row, inherited by every chip, and
262
+ * no rule of this sheet names `[data-ui='tag']`: the host stands beside the
263
+ * tag sheet and never reaches into it.
264
+ */
265
+ [data-ui='tags-input'] [data-part='chips'] {
266
+ --slotted-control-inner-size: var(--_inner-size);
267
+ }
268
+
269
+ /**
270
+ * The cell that holds the caret. It is the last cell of the row, so it wraps
271
+ * with the chips rather than being pushed to a line of its own, and it asks
272
+ * — rather than demands — for a word's worth of width, so the reader always
273
+ * has somewhere to type and a 240-pixel control holding two values does not
274
+ * stand two rows tall with one row empty.
275
+ */
276
+ [data-ui='tags-input'] [data-part='field'] {
277
+ align-items: center;
278
+ display: flex;
279
+ flex: 1 1 var(--slotted-tags-input-field-basis, 4rem);
280
+ min-block-size: var(--_row-size);
281
+ min-inline-size: var(--slotted-tags-input-field-min, 2.5rem);
282
+ }
283
+
284
+ /**
285
+ * The control's text. It gives up its own frame entirely and keeps
286
+ * everything that makes it a text control: the caret, the selection, IME
287
+ * composition, autofill, the browser's own completion from a `datalist`, and
288
+ * every native attribute the consumer wrote.
289
+ */
290
+ [data-ui='tags-input'] [data-part='input'] {
291
+ background-color: transparent;
292
+ border: 0;
293
+ color: inherit;
294
+ flex: 1 1 auto;
295
+ font: inherit;
296
+ /* The frame draws the ring for it, so two rings never nest. */
297
+ outline: none;
298
+ padding: 0;
299
+ /* The intrinsic width of an `input` is about twenty characters, and a flex
300
+ item refuses to shrink below it without this. */
301
+ min-inline-size: 0;
302
+ text-overflow: ellipsis;
303
+ }
304
+
305
+ [data-ui='tags-input'] [data-part='input']::placeholder {
306
+ color: var(--slotted-tags-input-placeholder-color, var(--slotted-text-muted, GrayText));
307
+ text-overflow: ellipsis;
308
+ }
309
+
310
+ /**
311
+ * Autofill. Chrome paints its own ground over the control's, and a
312
+ * hundred-pixel inset shadow is the only way to reach it. The signal is kept
313
+ * rather than erased, in the accent surface the theme owns — the repair
314
+ * `text-field` makes, for the same reason.
315
+ */
316
+ [data-ui='tags-input'] [data-part='input']:autofill {
317
+ box-shadow: inset 0 0 0 100px
318
+ var(--slotted-tags-input-autofill-background, var(--slotted-tone-accent-surface));
319
+ -webkit-text-fill-color: var(--slotted-tags-input-color, var(--slotted-text, CanvasText));
320
+ }
321
+
322
+ /**
323
+ * A chip that holds focus. The cell takes the ring rather than the remove
324
+ * button inside it — the departure the contract records against the grid
325
+ * pattern — so the ring is drawn around the value, which is the thing
326
+ * `Delete` acts on. It follows the chip's own radius by being an outline on
327
+ * the pill itself.
328
+ *
329
+ * The ring is drawn one width inside the chip, not at the theme's offset
330
+ * outside it. The row around the chip scrolls, or clips under
331
+ * `overflow='collapse'`, and either way it cuts at its padding edge, two
332
+ * pixels past the chip; a ring two pixels further out lost its outer half on
333
+ * every side, at every density. One width inside is `listbox`'s answer for an
334
+ * option in a scrolling list: the ring covers the chip's own edge and reads
335
+ * as the chip's edge turned to the ring colour, whole, with the text clear
336
+ * of it even at `dense`, where the chip has no inset to spare. `tag` draws
337
+ * its own inner ring two widths in to keep a sliver of ground outside it;
338
+ * here that sliver would cost the text its leading.
339
+ */
340
+ [data-ui='tags-input'] [data-part='chips'] > :not([data-part='field']):focus-visible {
341
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
342
+ outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
343
+ }
344
+
345
+ /**
346
+ * The chip that already holds the value the reader just typed again. It
347
+ * takes focus, and for one long step of the motion scale its edge is the
348
+ * accent's, so a reader who looked away from the ring still sees which chip
349
+ * answered — through the edge token `tag` reads, so this sheet names
350
+ * `[data-ui='tag']` nowhere.
351
+ */
352
+ [data-ui='tags-input'] [data-part='chips'] > [data-current] {
353
+ --slotted-tag-border-color: var(
354
+ --slotted-tags-input-current-border-color,
355
+ var(--slotted-tone-accent-border)
356
+ );
357
+ }
358
+
359
+ /**
360
+ * The chip that counts what did not fit, under `overflow='collapse'`. It is a
361
+ * chip and not a number beside them, so the row reads as one run of chips
362
+ * whose last one happens to be a count, and `createCollapse` measures it the
363
+ * way it measures every other unit.
364
+ */
365
+ [data-ui='tags-input'] [data-part='chips'] > [data-count] {
366
+ cursor: pointer;
367
+ flex: none;
368
+ }
369
+
370
+ /**
371
+ * The count of what is held, against the limit that holds it. It is drawn
372
+ * only where it answers something — while `max` is set, or while the frame is
373
+ * too narrow for a chip — because a counter with nothing to count against is
374
+ * furniture.
375
+ */
376
+ [data-ui='tags-input'] > [data-part='counter'] {
377
+ align-self: center;
378
+ color: var(--slotted-tags-input-counter-color, var(--slotted-text-muted, GrayText));
379
+ flex: none;
380
+ font-size: var(--slotted-font-size-xs, 0.75rem);
381
+ font-variant-numeric: tabular-nums;
382
+ line-height: var(--slotted-line-height-sm, 1.45);
383
+ padding-inline: var(--slotted-space-1, 0.125rem);
384
+ /* Its own bidi run, ordered by its own content: "3 of 5" is a European
385
+ number, a Latin word and another number, and in a right-to-left document
386
+ the neutral spaces resolve to the paragraph and the runs swap. */
387
+ unicode-bidi: plaintext;
388
+ white-space: nowrap;
389
+ }
390
+
391
+ /**
392
+ * A full control says so where the count is, in the accent the family already
393
+ * uses for a chosen value. Not a warning tone: reaching the limit is the
394
+ * reader arriving somewhere, not going wrong.
395
+ */
396
+ [data-ui='tags-input'][data-complete] > [data-part='counter'] {
397
+ color: var(--slotted-tags-input-counter-complete-color, var(--slotted-tone-accent-text));
398
+ font-weight: var(--slotted-font-weight-medium, 500);
399
+ }
400
+
401
+ /* Too narrow for a chip: the count is the whole answer. */
402
+ [data-ui='tags-input'][data-narrow] [data-part='chips'] > :not([data-part='field']) {
403
+ display: none;
404
+ }
405
+
406
+ /**
407
+ * ── The two parts for assistive technology ───────────────────────────
408
+ *
409
+ * Removed from sight and left in the tree: the rule
410
+ * `visually-hidden/visually-hidden.css` states, restated because these are
411
+ * this family's parts and a part cannot wear another family's `data-ui`.
412
+ * The `message` lives inside the chip and the `hint` beside the row; both
413
+ * are positioned against the frame, which is the nearest containing block.
414
+ */
415
+ [data-ui='tags-input'] :is([data-part='message'], [data-part='hint']) {
416
+ block-size: 1px;
417
+ border: 0;
418
+ clip-path: inset(50%);
419
+ inline-size: 1px;
420
+ margin: -1px;
421
+ overflow: hidden;
422
+ padding: 0;
423
+ position: absolute;
424
+ white-space: nowrap;
425
+ }
426
+
427
+ /* ── The button inside the frame ──────────────────────────────────────── */
428
+
429
+ [data-ui='tags-input'] > [data-part='clear'] {
430
+ align-items: center;
431
+ align-self: center;
432
+ appearance: none;
433
+ background-color: transparent;
434
+ block-size: var(--_action-size);
435
+ border: 0;
436
+ border-radius: var(--slotted-tags-input-radius, var(--slotted-control-radius, 4px));
437
+ color: var(--slotted-tags-input-action-color, var(--slotted-text-muted, GrayText));
438
+ cursor: pointer;
439
+ display: inline-flex;
440
+ flex: 0 0 auto;
441
+ inline-size: var(--_action-size);
442
+ justify-content: center;
443
+ /* The user agent pads a button, and inside a box sized to its glyph that
444
+ padding squeezed the glyph to twelve pixels. */
445
+ padding: 0;
446
+ /* The containing block of the hit area below. */
447
+ position: relative;
448
+ touch-action: manipulation;
449
+ transition:
450
+ background-color var(--slotted-control-transition-duration)
451
+ var(--slotted-control-transition-easing),
452
+ color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
453
+ -webkit-tap-highlight-color: transparent;
454
+ }
455
+
456
+ /**
457
+ * The hit area, recovered outside the paint. At `sm` with `dense` the whole
458
+ * control is 24 pixels tall — the WCAG 2.2 minimum — so nothing drawn inside
459
+ * it can also be 24.
460
+ */
461
+ [data-ui='tags-input'] > [data-part='clear']::after {
462
+ content: '';
463
+ inset: min(0px, calc((100% - var(--slotted-target-min, 24px)) / 2));
464
+ position: absolute;
465
+ }
466
+
467
+ /* On a finger the target is the comfortable size in both axes and the box
468
+ is the one a mouse sees: the ground and the focus ring stay square, and
469
+ the hit area above grows to 44 pixels around them. It does not reach back
470
+ over the chips, where the last chip's remove stands a few pixels away. */
471
+ @media (pointer: coarse) {
472
+ [data-ui='tags-input'] > [data-part='clear']::after {
473
+ inset: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
474
+ inset-inline-start: 0;
475
+ }
476
+ }
477
+
478
+ /* The cross is the `Glyph` element the binding renders inside the button,
479
+ drawn at the control's own icon step. */
480
+ [data-ui='tags-input'] > [data-part='clear'] {
481
+ --slotted-icon-size: var(--_icon-size);
482
+ }
483
+
484
+ /* ── Size ─────────────────────────────────────────────────────────────── */
485
+
486
+ [data-ui='tags-input'][data-part='root'][data-size='sm'] {
487
+ --_font-size: var(--slotted-control-font-size-sm, 12px);
488
+ --_height: var(--slotted-control-height-sm, 30px);
489
+ --_inner-size: var(--slotted-control-inner-size-sm, 22px);
490
+ --_padding-inline: var(--slotted-control-padding-inline-sm, 10px);
491
+ --_gap: var(--slotted-control-gap-sm, 6px);
492
+ --_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-sm, 14px));
493
+ }
494
+
495
+ [data-ui='tags-input'][data-part='root'][data-size='md'] {
496
+ --_font-size: var(--slotted-control-font-size-md, 13px);
497
+ --_height: var(--slotted-control-height-md, 34px);
498
+ --_padding-inline: var(--slotted-control-padding-inline-md, 13px);
499
+ --_gap: var(--slotted-control-gap-md, 8px);
500
+ --_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-md, 16px));
501
+ --_inner-size: var(--slotted-control-inner-size-md, 24px);
502
+ }
503
+
504
+ [data-ui='tags-input'][data-part='root'][data-size='lg'] {
505
+ --_font-size: var(--slotted-control-font-size-lg, 14px);
506
+ --_height: var(--slotted-control-height-lg, 38px);
507
+ --_inner-size: var(--slotted-control-inner-size-lg, 28px);
508
+ --_padding-inline: var(--slotted-control-padding-inline-lg, 16px);
509
+ --_gap: var(--slotted-control-gap-lg, 8px);
510
+ --_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-lg, 18px));
511
+ }
512
+
513
+ /* ── Variant ──────────────────────────────────────────────────────────── */
514
+
515
+ [data-ui='tags-input'][data-part='root'][data-variant='subtle'] {
516
+ background-color: var(
517
+ --slotted-tags-input-subtle-background,
518
+ var(--slotted-surface-sunken, Canvas)
519
+ );
520
+ border-color: var(
521
+ --slotted-tags-input-subtle-border-color,
522
+ var(--slotted-border-subtle, ButtonBorder)
523
+ );
524
+ }
525
+
526
+ /* No edge, no lift, no ground and no corner of its own: the cell it sits in
527
+ is the box, the row is the ground, a cell has no corner, and the resting
528
+ shadow would draw the cell where there is none. */
529
+ [data-ui='tags-input'][data-part='root'][data-variant='plain'] {
530
+ background-color: transparent;
531
+ border-color: transparent;
532
+ border-radius: var(--slotted-radius-none, 0px);
533
+ box-shadow: none;
534
+ }
535
+
536
+ @media (forced-colors: active) {
537
+ [data-ui='tags-input'][data-part='root'][data-variant='plain'] {
538
+ border-color: ButtonBorder;
539
+ }
540
+ }
541
+
542
+ /* ── States on the control ────────────────────────────────────────────── */
543
+
544
+ [data-ui='tags-input'][data-part='root']:hover:not([data-disabled]):not([data-readonly]):not(
545
+ [data-invalid]
546
+ ) {
547
+ border-color: var(--slotted-tags-input-hover-border-color, var(--slotted-tone-accent-border));
548
+ }
549
+
550
+ [data-ui='tags-input'][data-part='root'][data-variant='subtle']:hover:not([data-disabled]):not(
551
+ [data-readonly]
552
+ ):not([data-invalid]) {
553
+ background-color: var(
554
+ --slotted-tags-input-subtle-hover-background,
555
+ var(--slotted-tone-secondary-subtle-hover)
556
+ );
557
+ }
558
+
559
+ [data-ui='tags-input'][data-part='root'][data-variant='plain']:hover:not([data-disabled]):not(
560
+ [data-readonly]
561
+ ):not([data-invalid]) {
562
+ background-color: var(
563
+ --slotted-tags-input-plain-hover-background,
564
+ var(--slotted-tone-secondary-subtle-hover)
565
+ );
566
+ /* The accent edge the other variants take would draw the cell's outline. */
567
+ border-color: transparent;
568
+ }
569
+
570
+ /**
571
+ * The frame carries the ring for whatever inside it holds focus — the input
572
+ * or a chip — because the frame is the control a reader is operating.
573
+ */
574
+ [data-ui='tags-input'][data-part='root']:has([data-part='input']:focus-visible),
575
+ [data-ui='tags-input'][data-part='root']:has(
576
+ [data-part='chips'] > :not([data-part='field']):focus-visible
577
+ ) {
578
+ box-shadow: var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
579
+ var(--slotted-focus-ring-color, Highlight);
580
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
581
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
582
+ }
583
+
584
+ /**
585
+ * The ring of a control whose box is not its own is drawn inside that box,
586
+ * the way the inner controls draw theirs inside the frame: two pixels past
587
+ * the control is two pixels over the next row's rule. No lift either — a
588
+ * shadow that appears only under focus is a cell that changes size when it
589
+ * is used.
590
+ */
591
+ [data-ui='tags-input'][data-part='root'][data-variant='plain']:has(
592
+ [data-part='input']:focus-visible
593
+ ),
594
+ [data-ui='tags-input'][data-part='root'][data-variant='plain']:has(
595
+ [data-part='chips'] > :not([data-part='field']):focus-visible
596
+ ) {
597
+ box-shadow: none;
598
+ outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
599
+ }
600
+
601
+ /**
602
+ * A chip already wears the ring, and the frame around it wearing a second one
603
+ * is two rings for one focus. The frame keeps its lift and gives up the
604
+ * outline while the ring is inside it.
605
+ */
606
+ [data-ui='tags-input'][data-part='root']:has(
607
+ [data-part='chips'] > :not([data-part='field']):focus-visible
608
+ ) {
609
+ outline: none;
610
+ }
611
+
612
+ [data-ui='tags-input'][data-part='root'][data-invalid] {
613
+ --slotted-focus-ring-color: var(
614
+ --slotted-tags-input-invalid-focus-ring-color,
615
+ var(--slotted-focus-ring-color-invalid, Highlight)
616
+ );
617
+ --_invalid-edge-width: var(
618
+ --slotted-tags-input-invalid-edge-width,
619
+ var(--slotted-control-invalid-edge-width, 1px)
620
+ );
621
+ --_invalid-edge-color: var(
622
+ --slotted-tags-input-invalid-border-color,
623
+ var(--slotted-tone-danger-border)
624
+ );
625
+ --_invalid-edge: inset 0 0 0 var(--_invalid-edge-width) var(--_invalid-edge-color);
626
+
627
+ border-color: var(--slotted-tags-input-invalid-border-color, var(--slotted-tone-danger-border));
628
+ /*
629
+ * Width as well as colour (WCAG 1.4.1), the edge `text-field` draws: in
630
+ * `high-contrast` the danger border is the resting edge's black. The line
631
+ * is a shadow inside the border, so neither box nor text moves, and it
632
+ * takes the resting lift's place.
633
+ */
634
+ box-shadow: var(--_invalid-edge);
635
+ }
636
+
637
+ [data-ui='tags-input'][data-part='root'][data-invalid]:has([data-part='input']:focus-visible),
638
+ [data-ui='tags-input'][data-part='root'][data-invalid]:has(
639
+ [data-part='chips'] > :not([data-part='field']):focus-visible
640
+ ) {
641
+ box-shadow:
642
+ var(--_invalid-edge),
643
+ var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
644
+ var(--slotted-focus-ring-color, Highlight);
645
+ }
646
+
647
+ [data-ui='tags-input'][data-part='root'][data-variant='plain'][data-invalid]:has(
648
+ [data-part='input']:focus-visible
649
+ ),
650
+ [data-ui='tags-input'][data-part='root'][data-variant='plain'][data-invalid]:has(
651
+ [data-part='chips'] > :not([data-part='field']):focus-visible
652
+ ) {
653
+ /* The ring lies inside the box here, over the border and an edge as wide as
654
+ it; the edge reaches past the ring. */
655
+ box-shadow: inset 0 0 0
656
+ calc(
657
+ var(--slotted-focus-ring-offset, 2px) - var(--slotted-control-border-width, 1px) +
658
+ var(--_invalid-edge-width)
659
+ )
660
+ var(--_invalid-edge-color);
661
+ }
662
+
663
+ /*
664
+ * Forced colours remove every box shadow, and the edge with them. The
665
+ * width comes back as an outline inside the border, and a focused invalid
666
+ * control draws its ring double, which a valid ring is not.
667
+ */
668
+ @media (forced-colors: active) {
669
+ [data-ui='tags-input'][data-part='root'][data-invalid] {
670
+ outline: var(--_invalid-edge-width) solid CanvasText;
671
+ outline-offset: calc(
672
+ -1 * (var(--slotted-control-border-width, 1px) + var(--_invalid-edge-width))
673
+ );
674
+ }
675
+
676
+ [data-ui='tags-input'][data-part='root'][data-invalid]:has([data-part='input']:focus-visible) {
677
+ outline: calc(var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width)) double
678
+ var(--slotted-focus-ring-color, Highlight);
679
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
680
+ }
681
+
682
+ [data-ui='tags-input'][data-part='root'][data-variant='plain'][data-invalid]:has(
683
+ [data-part='input']:focus-visible
684
+ ) {
685
+ outline: calc(var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width)) double
686
+ var(--slotted-focus-ring-color, Highlight);
687
+ outline-offset: calc(
688
+ -1 * (var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width))
689
+ );
690
+ }
691
+
692
+ [data-ui='tags-input'][data-part='root'][data-invalid]:has(
693
+ [data-part='chips'] > :not([data-part='field']):focus-visible
694
+ ),
695
+ [data-ui='tags-input'][data-part='root'][data-variant='plain'][data-invalid]:has(
696
+ [data-part='chips'] > :not([data-part='field']):focus-visible
697
+ ) {
698
+ outline: var(--_invalid-edge-width) solid CanvasText;
699
+ outline-offset: calc(
700
+ -1 * (var(--slotted-control-border-width, 1px) + var(--_invalid-edge-width))
701
+ );
702
+ }
703
+ }
704
+
705
+ /**
706
+ * Read-only keeps the chips, the caret, the selection and the copy, and
707
+ * withholds every remove control. The native `readonly` gives the text half;
708
+ * the rest is the family's.
709
+ */
710
+ [data-ui='tags-input'][data-part='root'][data-readonly] {
711
+ background-color: var(
712
+ --slotted-tags-input-readonly-background,
713
+ var(--slotted-tone-secondary-subtle-hover)
714
+ );
715
+ }
716
+
717
+ /**
718
+ * `:disabled` on the input is matched beside `data-disabled` on the frame,
719
+ * because a disabled `fieldset` disables every control inside it and the
720
+ * control has no way to say so.
721
+ */
722
+ [data-ui='tags-input'][data-part='root'][data-disabled],
723
+ [data-ui='tags-input'][data-part='root']:has([data-part='input']:disabled) {
724
+ background-color: var(
725
+ --slotted-tags-input-disabled-background,
726
+ var(--slotted-disabled-background)
727
+ );
728
+ border-color: var(--slotted-tags-input-disabled-border-color, var(--slotted-disabled-border));
729
+ box-shadow: none;
730
+ color: var(--slotted-tags-input-disabled-color, var(--slotted-disabled-foreground));
731
+ cursor: not-allowed;
732
+ }
733
+
734
+ [data-ui='tags-input'] > [data-part='clear']:hover:not(:disabled):not([data-disabled]) {
735
+ background-color: var(
736
+ --slotted-tags-input-action-hover-background,
737
+ var(--slotted-tone-secondary-subtle-hover)
738
+ );
739
+ }
740
+
741
+ [data-ui='tags-input'] > [data-part='clear']:active:not(:disabled):not([data-disabled]) {
742
+ background-color: var(
743
+ --slotted-tags-input-action-active-background,
744
+ var(--slotted-tone-secondary-subtle-active)
745
+ );
746
+ }
747
+
748
+ /**
749
+ * The button carries its own ring rather than borrowing the frame's: tabbing
750
+ * from the input to it has to move something visible, and a ring around the
751
+ * whole frame would sit still while focus moved inside it.
752
+ */
753
+ [data-ui='tags-input'] > [data-part='clear']:focus-visible {
754
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
755
+ outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
756
+ }
757
+ }