@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,707 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── The field ──────────────────────────────────────────────────────────
4
+ *
5
+ * One control, its name, its necessity, its help and its error. The box has
6
+ * no ground and no border of its own: a field inherits the rhythm of whatever
7
+ * placed it — a `Stack`, a `field-group`, a table cell — and everything it
8
+ * draws is text beside a control it does not own.
9
+ *
10
+ * The grid is two columns and every child spans both, so the only parts that
11
+ * need a rule of their own are the two that do not: the label takes the first
12
+ * column of the first row, and the counter the second. That is what lets the
13
+ * description and the error be another family's elements — they are
14
+ * `inline-message` roots, they carry `data-ui='inline-message'`, and the field
15
+ * places them without ever selecting them.
16
+ *
17
+ * The field is its own container. `labelPlacement='side'` is a layout that
18
+ * depends on how wide the field is rather than on how wide the window is, and
19
+ * a field in a 240-pixel drawer has to stack while the same field in a page
20
+ * grid stays beside its control.
21
+ */
22
+ [data-ui='field'][data-part='root'] {
23
+ /**
24
+ * Type, control height and glyph come from the control scales, the only
25
+ * ones the theme restates per density, so a field in a dense table shrinks
26
+ * whole rather than in parts. The control height is read for one reason:
27
+ * the side label is centred on the control's first line, and that is the
28
+ * only distance in the family that depends on the control's own size.
29
+ */
30
+ --_font-size: var(--slotted-control-font-size-md, 13px);
31
+ --_control-block-size: var(--slotted-control-height-md, 34px);
32
+
33
+ /**
34
+ * The distance between the label, the control and the message. One value
35
+ * for all three rows: a label closer to its control than the message is
36
+ * would say the message belongs to the field below, which is the mistake a
37
+ * form makes exactly once and then everywhere.
38
+ */
39
+ --_row-gap: var(--slotted-field-row-gap, var(--slotted-space-3, 0.375rem));
40
+ /** The distance from a side label to the control it names. */
41
+ --_column-gap: var(--slotted-field-column-gap, var(--slotted-space-5, 0.75rem));
42
+
43
+ /* The field is as tall as its rows. Stretched — a grid track taller than
44
+ its content, a dialog body filling a phone's height — the rows would
45
+ share the surplus and stand the label a finger's width from the control
46
+ it names. The surplus belongs to whatever stretched the field. */
47
+ align-content: start;
48
+ container-name: slotted-field;
49
+ container-type: inline-size;
50
+ display: grid;
51
+ font-family: var(--slotted-field-font-family, var(--slotted-control-font-family, sans-serif));
52
+ /**
53
+ * Three tracks, stated once and never restated. An element cannot query its
54
+ * own container — `container-type` makes a box a container for what is
55
+ * *inside* it — so a rule that changed the template under `@container`
56
+ * would apply to nothing, silently, while the child rules beside it applied
57
+ * normally. The picture would still look right at one width and be laid out
58
+ * on the wrong tracks at every other, which is what the first capture of
59
+ * this family showed: a label holding 235 pixels and its control 185.
60
+ *
61
+ * So the tracks never change, and only the placement of the children does.
62
+ * With the label above the control every child spans all three, and the
63
+ * split between the first two is invisible; with the label beside it, the
64
+ * first track is the label's and the cap is what stops a long one from
65
+ * taking the row.
66
+ *
67
+ * There is no `column-gap`. A gutter beside an empty counter track would
68
+ * inset every label by that distance for a part that is not there, so the
69
+ * two parts that need separation carry it as their own padding.
70
+ */
71
+ grid-template-columns:
72
+ minmax(0, var(--slotted-field-label-inline-size, 12rem))
73
+ minmax(0, 1fr)
74
+ auto;
75
+ /* A field inside a grid track narrower than its content would otherwise
76
+ refuse to shrink, and take the control's placeholder with it. */
77
+ min-inline-size: 0;
78
+ row-gap: var(--_row-gap);
79
+ }
80
+
81
+ /* Every child spans the field, and the two that do not say so below. */
82
+ [data-ui='field'][data-part='root'] > * {
83
+ grid-column: 1 / -1;
84
+ }
85
+
86
+ /**
87
+ * The whole of what the field does to the control it does not own. A grid item
88
+ * refuses to shrink below its own intrinsic width — about twenty characters
89
+ * for an `input` — so a field in a 240-pixel drawer would overflow the drawer
90
+ * rather than the control. Nothing here paints the control, sizes its type or
91
+ * touches its border: `text-field` owns all three.
92
+ */
93
+ [data-ui='field'] > [data-part='control'] {
94
+ min-inline-size: 0;
95
+ }
96
+
97
+ /* ── Size ─────────────────────────────────────────────────────────────
98
+ *
99
+ * Three steps, matching the control the field wraps. Fluent ships the same
100
+ * three; Angular Material ships none and sizes its field from the control
101
+ * inside it, which makes a field with no control an unsized box.
102
+ */
103
+
104
+ [data-ui='field'][data-part='root'][data-size='sm'] {
105
+ --_help-glyph: max(
106
+ var(--slotted-field-icon-size-min, 14px),
107
+ var(--slotted-control-icon-size-sm, 14px)
108
+ );
109
+ --_help-inner-size: var(--slotted-control-inner-size-sm, 22px);
110
+ --_font-size: var(--slotted-control-font-size-sm, 12px);
111
+ --_control-block-size: var(--slotted-control-height-sm, 30px);
112
+ }
113
+
114
+ [data-ui='field'][data-part='root'][data-size='md'] {
115
+ --_help-glyph: max(
116
+ var(--slotted-field-icon-size-min, 14px),
117
+ var(--slotted-control-icon-size-sm, 14px)
118
+ );
119
+ --_help-inner-size: var(--slotted-control-inner-size-sm, 22px);
120
+ --_font-size: var(--slotted-control-font-size-md, 13px);
121
+ --_control-block-size: var(--slotted-control-height-md, 34px);
122
+ }
123
+
124
+ [data-ui='field'][data-part='root'][data-size='lg'] {
125
+ --_help-glyph: max(
126
+ var(--slotted-field-icon-size-min, 14px),
127
+ var(--slotted-control-icon-size-md, 16px)
128
+ );
129
+ --_help-inner-size: var(--slotted-control-inner-size-md, 24px);
130
+ --_font-size: var(--slotted-control-font-size-lg, 14px);
131
+ --_control-block-size: var(--slotted-control-height-lg, 38px);
132
+ }
133
+
134
+ /* ── The label ────────────────────────────────────────────────────────
135
+ *
136
+ * A native `label`, carrying `for`. The APG's naming practice calls the
137
+ * explicit association the one with the broadest support, and the implicit
138
+ * form — wrapping the control — the one some assistive technologies fail to
139
+ * treat as a name at all.
140
+ *
141
+ * The leading is the text scale rather than the control's `1`: a control's
142
+ * line height is for a box holding one line, and a label of twelve words
143
+ * beside a narrow control holds three.
144
+ */
145
+ [data-ui='field'] > [data-part='label'],
146
+ [data-ui='field'] > [data-part='header'] > [data-part='label'] {
147
+ color: var(--slotted-field-label-color, var(--slotted-text));
148
+ font-size: var(--_font-size);
149
+ font-weight: var(--slotted-field-label-font-weight, var(--slotted-font-weight-medium, 500));
150
+ line-height: var(--slotted-field-line-height, var(--slotted-line-height-sm, 1.45));
151
+ min-inline-size: 0;
152
+ /* A compound noun no language can break — a German insurance number, a
153
+ column name from a database — otherwise runs out of the label's track and
154
+ under the control, which is where the first capture of this family put
155
+ `Kraftfahrzeug-Haftpflichtversicherungsnummer`. Nothing is removed: the
156
+ whole word stays in the DOM and in the accessible name. */
157
+ overflow-wrap: anywhere;
158
+ transition: color var(--slotted-control-transition-duration)
159
+ var(--slotted-control-transition-easing);
160
+ }
161
+
162
+ /**
163
+ * The first row is the label's, or the header's when the label has company.
164
+ * Either spans the field when the label sits above the control.
165
+ */
166
+ [data-ui='field'] > [data-part='label'],
167
+ [data-ui='field'] > [data-part='header'] {
168
+ grid-column: 1 / -1;
169
+ grid-row: 1;
170
+ }
171
+
172
+ /**
173
+ * The label stops before the counter's track only when there is a counter.
174
+ * Two grid items in one cell overlap, and a field with a count would print its
175
+ * label under it; a field without one would otherwise lose the counter's track
176
+ * from the label's width for a part that is not there.
177
+ */
178
+ [data-ui='field'][data-part='root']:has(> [data-part='counter']) > [data-part='label'] {
179
+ grid-column: 1 / 3;
180
+ }
181
+
182
+ /**
183
+ * The necessity marker. Real text rather than generated content, because the
184
+ * two word forms — `(required)` and `(optional)` — are information a reader
185
+ * hears and a page search finds, and because generated content cannot be
186
+ * translated by an application.
187
+ *
188
+ * The glyph form is the one this rule paints. It takes the danger ink because
189
+ * a red asterisk is the convention every surveyed implementation follows, and
190
+ * the field deliberately does *not* repaint the label when it is invalid: a
191
+ * red marker on a red label is a marker nobody can see, and the error already
192
+ * says the same thing in words, in colour and in a glyph.
193
+ */
194
+ [data-ui='field'] > [data-part='label'] > [data-part='mark'],
195
+ [data-ui='field'] > [data-part='header'] > [data-part='label'] > [data-part='mark'] {
196
+ color: var(--slotted-field-mark-color, var(--slotted-tone-danger-text));
197
+ margin-inline-start: var(--slotted-field-mark-gap, var(--slotted-space-2, 0.25rem));
198
+ /* The label breaks anywhere; the necessity word never does. `(required)`
199
+ split across two lines as `(re` and `quired)` in the 240-pixel capture,
200
+ because a rule for one unbreakable German noun had reached the one part
201
+ of the label that is always a word. */
202
+ overflow-wrap: normal;
203
+ /**
204
+ * Its own bidi run. Latin label text in a right-to-left document forms one
205
+ * left-to-right run, and the marker joined it — so the distance written as
206
+ * `margin-inline-start` landed outside the run instead of between the two,
207
+ * and `CNPJ` and `(required)` touched. Isolated, the marker is ordered by
208
+ * the field's direction rather than by the label's characters.
209
+ */
210
+ unicode-bidi: isolate;
211
+ }
212
+
213
+ /**
214
+ * The word forms are not a severity, so they are not painted like one. Each is
215
+ * the quietest thing in the row: muted ink, the regular weight the label is
216
+ * not, and one type step down, so `E-mail (optional)` reads as one label with
217
+ * a qualifier rather than as two labels. `optional` writes the word only on
218
+ * the fields a reader may skip; `words` writes both.
219
+ */
220
+ [data-ui='field']:is([data-necessity='optional'], [data-necessity='words'])
221
+ > [data-part='label']
222
+ > [data-part='mark'],
223
+ [data-ui='field']:is([data-necessity='optional'], [data-necessity='words'])
224
+ > [data-part='header']
225
+ > [data-part='label']
226
+ > [data-part='mark'] {
227
+ color: var(--slotted-field-mark-text-color, var(--slotted-text-muted));
228
+ font-size: var(--slotted-control-font-size-sm, 12px);
229
+ font-weight: var(--slotted-font-weight-regular, 400);
230
+ }
231
+
232
+ /* ── The header ───────────────────────────────────────────────────────
233
+ *
234
+ * The label row, when the label has company: the help behind an icon, an
235
+ * indicator such as `Beta`, an action such as `Forgot password?`, and the
236
+ * counter. ReUI writes the same row by hand in four of its examples — a
237
+ * `div` with `justify-between` around the label — and centres every item in
238
+ * it; here the row is a part, and it aligns its items on the label's first
239
+ * baseline instead, so a 13-pixel label, a 12-pixel count and an emblem with
240
+ * a box of its own sit on one line of text rather than on one centre.
241
+ *
242
+ * The row takes the label's type, so `1lh`, `1cap` and `1ex` measured by
243
+ * anything inside it are the label's line. It wraps: in a narrow field the
244
+ * action and the counter move to a second line, still at its end.
245
+ */
246
+ [data-ui='field'] > [data-part='header'] {
247
+ align-items: baseline;
248
+ column-gap: var(--slotted-field-header-gap, var(--slotted-space-3, 0.375rem));
249
+ display: flex;
250
+ flex-wrap: wrap;
251
+ font-size: var(--_font-size);
252
+ line-height: var(--slotted-field-line-height, var(--slotted-line-height-sm, 1.45));
253
+ min-inline-size: 0;
254
+ }
255
+
256
+ [data-ui='field'] > [data-part='header'] > [data-part='label'] {
257
+ flex: 0 1 auto;
258
+ }
259
+
260
+ /**
261
+ * The action and the counter belong to the end of the row. The first of the
262
+ * two that is present takes the free space; a counter after an action stands
263
+ * a second step of the row gap away from it, twelve pixels in all, the same
264
+ * distance a side label keeps from its control, so a link and a number do
265
+ * not read as one phrase.
266
+ */
267
+ [data-ui='field'] > [data-part='header'] > [data-part='action'],
268
+ [data-ui='field'] > [data-part='header'] > [data-part='counter'] {
269
+ margin-inline-start: auto;
270
+ }
271
+
272
+ [data-ui='field'] > [data-part='header'] > [data-part='action'] ~ [data-part='counter'] {
273
+ margin-inline-start: var(--slotted-space-3, 0.375rem);
274
+ }
275
+
276
+ /* ── The help ─────────────────────────────────────────────────────────
277
+ *
278
+ * A glyph beside the label that opens the tooltip holding the field's help.
279
+ * It is an inner control (R2, `inner-control.test.mjs`): no frame, no ground
280
+ * at rest, and hover and press move the ground one step each and nothing
281
+ * else — ReUI's trigger changes its ink on hover and draws the same picture
282
+ * on press, which is the press the craft bar fails.
283
+ *
284
+ * The box is the glyph and a step of air a side, capped at the inside of a
285
+ * control at the field's step (`--slotted-control-inner-size-*`), the box
286
+ * `tag` gives its remove; the pointer target is a transparent halo that
287
+ * reaches twenty-four pixels around it. The box holds one line of the
288
+ * label's type at its own height and gives the difference back in the block
289
+ * axis, so a field with a help icon is exactly as tall as one without. The
290
+ * line inside it is the label's own — `font: inherit` — and a `button`
291
+ * centres its content in the block axis, so the button's baseline stands
292
+ * where the label's does; a line as tall as the box put it 0.44 pixels lower
293
+ * at comfortable and 0.69 at dense, and the row grew by that much. Only
294
+ * the block axis gives it back: a negative inline margin would pull the box
295
+ * under the last word of the label and strike the focus ring through it,
296
+ * which is what `description-list` measured on its copy control. The row gap
297
+ * before it is taken down to one step instead, so the glyph stands six
298
+ * pixels from the label at `md`.
299
+ *
300
+ * The glyph is placed on the label's text rather than on its line box: the
301
+ * button holds one line of the label's type, and the glyph sits on that
302
+ * line's baseline and centred on the band between the middle of the
303
+ * capitals and the middle of the lowercase — `(1cap + 1ex) / 2` — the band
304
+ * `toast` settled on (`docs/build-briefing.md`, a mark beside a line of
305
+ * text). The first capture raised the glyph's bottom by the band less half
306
+ * the glyph, which put its centre on the band's top: four pixels high, and a
307
+ * line box 3.3 pixels taller than the label's.
308
+ */
309
+ [data-ui='field'] > [data-part='header'] > [data-part='help'] {
310
+ /* Never shorter than the label's line: at dense the inside of a control is
311
+ 16 pixels and the line 17.39, and a button shorter than its own line
312
+ overflows downward and pushes the row 0.69 pixels taller. */
313
+ --_box: max(
314
+ min(calc(var(--_help-glyph) + 2 * var(--slotted-space-2, 0.25rem)), var(--_help-inner-size)),
315
+ 1lh
316
+ );
317
+ --slotted-icon-size: var(--_help-glyph);
318
+
319
+ appearance: none;
320
+ background-color: transparent;
321
+ block-size: var(--_box);
322
+ border: 0;
323
+ border-radius: var(--slotted-field-help-radius, var(--slotted-control-radius, 4px));
324
+ color: var(--slotted-field-help-color, var(--slotted-text-muted));
325
+ cursor: pointer;
326
+ display: inline-block;
327
+ flex: none;
328
+ font: inherit;
329
+ inline-size: var(--_box);
330
+ margin-block: calc(
331
+ (
332
+ var(--_font-size) *
333
+ var(--slotted-field-line-height, var(--slotted-line-height-sm, 1.45)) - var(--_box)
334
+ ) /
335
+ 2
336
+ );
337
+ margin-inline-start: calc(
338
+ var(--slotted-space-1, 0.125rem) -
339
+ var(--slotted-field-header-gap, var(--slotted-space-3, 0.375rem))
340
+ );
341
+ padding: 0;
342
+ position: relative;
343
+ text-align: center;
344
+ transition: background-color var(--slotted-control-transition-duration)
345
+ var(--slotted-control-transition-easing);
346
+ }
347
+
348
+ /* The pointer target: a transparent square centred on the box that reaches
349
+ the WCAG minimum wherever the box falls short of it — 22 pixels at
350
+ comfortable, 16 at dense. It takes no room, so the row keeps its height. */
351
+ [data-ui='field'] > [data-part='header'] > [data-part='help']::before {
352
+ content: '';
353
+ inset: min(0px, calc((100% - var(--slotted-target-min, 24px)) / 2));
354
+ position: absolute;
355
+ }
356
+
357
+ [data-ui='field'] > [data-part='header'] > [data-part='help'] > [data-ui='icon'] {
358
+ vertical-align: calc(((1cap + 1ex) / 2 - var(--_help-glyph)) / 2);
359
+ }
360
+
361
+ /**
362
+ * Hover and press move the ground and nothing else. An open hint keeps the
363
+ * hover ground while its tooltip is showing, so the reader sees which icon
364
+ * the layer belongs to after the pointer has moved onto the layer.
365
+ */
366
+ [data-ui='field'] > [data-part='header'] > [data-part='help']:enabled:hover,
367
+ [data-ui='field'] > [data-part='header'] > [data-part='help'][data-open] {
368
+ background-color: var(
369
+ --slotted-field-help-surface-hover,
370
+ var(--slotted-tone-secondary-subtle-hover, ButtonFace)
371
+ );
372
+ }
373
+
374
+ [data-ui='field'] > [data-part='header'] > [data-part='help']:enabled:active {
375
+ background-color: var(
376
+ --slotted-field-help-surface-active,
377
+ var(--slotted-tone-secondary-subtle-active, ButtonFace)
378
+ );
379
+ }
380
+
381
+ [data-ui='field'] > [data-part='header'] > [data-part='help']:focus-visible {
382
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
383
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
384
+ }
385
+
386
+ /* ── The indicator ────────────────────────────────────────────────────
387
+ *
388
+ * What qualifies the field — `Beta`, `Pro`, `New` — as one or more `badge`s
389
+ * after the label. It stands outside the `label` so the necessity mark stays
390
+ * against the label's last word, and it is read with the control's
391
+ * description rather than with its name. The badges are the badge family's;
392
+ * the field only spaces them.
393
+ */
394
+ [data-ui='field'] > [data-part='header'] > [data-part='indicator'] {
395
+ align-items: center;
396
+ /* A badge is a box, not a line of text. Set on the label's baseline, its
397
+ own inset stood it 1.77 pixels above the label's line and the row grew
398
+ by that much; centred on the line, an 18.8-pixel badge fits in the
399
+ 18.85-pixel line and the row is the label's height with or without it. */
400
+ align-self: center;
401
+ column-gap: var(--slotted-space-2, 0.25rem);
402
+ display: inline-flex;
403
+ flex-wrap: wrap;
404
+ }
405
+
406
+ /* ── The action ───────────────────────────────────────────────────────
407
+ *
408
+ * A link or a button at the end of the label row: `Forgot password?`,
409
+ * `Generate`, `Use the billing address`. It is a text control, so it speaks
410
+ * the vocabulary `link` settled for text that answers a pointer: accent ink
411
+ * at rest, a hover a third of the way to the body colour with the underline
412
+ * drawn, and a press two thirds of the way. ReUI paints the same action in
413
+ * muted ink, where it reads as inert text beside the counter, and answers
414
+ * press with a one-pixel shift of a line of 12-pixel type.
415
+ *
416
+ * The box is 24 pixels in the block axis for the pointer and gives the line
417
+ * its height back; in the inline axis the text is the box, so the focus ring
418
+ * hugs the words. It is a flex box so its height is stated rather than summed
419
+ * from a padding and a line — the sum measured 23.98 — and a flex box's
420
+ * baseline is its words', so the row still aligns on it.
421
+ */
422
+ [data-ui='field'] > [data-part='header'] > [data-part='action'] {
423
+ --_rest: var(--slotted-field-action-color, var(--slotted-tone-accent-text, LinkText));
424
+
425
+ align-items: center;
426
+ appearance: none;
427
+ background: none;
428
+ block-size: var(--slotted-target-min, 24px);
429
+ border: 0;
430
+ border-radius: var(--slotted-field-action-radius, var(--slotted-control-radius, 4px));
431
+ color: var(--_rest);
432
+ cursor: pointer;
433
+ display: inline-flex;
434
+ flex: none;
435
+ font-family: inherit;
436
+ font-size: var(--slotted-control-font-size-sm, 12px);
437
+ font-weight: var(--slotted-font-weight-regular, 400);
438
+ line-height: var(--slotted-field-line-height, var(--slotted-line-height-sm, 1.45));
439
+ margin-block: calc((1lh - var(--slotted-target-min, 24px)) / 2);
440
+ padding: 0;
441
+ text-decoration-color: transparent;
442
+ text-decoration-line: underline;
443
+ text-decoration-thickness: from-font;
444
+ text-underline-offset: 0.15em;
445
+ transition:
446
+ color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing),
447
+ text-decoration-color var(--slotted-control-transition-duration)
448
+ var(--slotted-control-transition-easing);
449
+ /* Ordered by its own words rather than by the page's direction. A Latin
450
+ `Forgot password?` on a right-to-left page printed its question mark
451
+ first, because the run took the page's direction; an Arabic action on
452
+ the same page is still ordered right to left. */
453
+ unicode-bidi: plaintext;
454
+ }
455
+
456
+ [data-ui='field']
457
+ > [data-part='header']
458
+ > [data-part='action']:not(:disabled, [aria-disabled='true']):hover {
459
+ color: var(
460
+ --slotted-field-action-color-hover,
461
+ color-mix(in oklab, var(--_rest) 65%, var(--slotted-text, CanvasText))
462
+ );
463
+ text-decoration-color: currentColor;
464
+ }
465
+
466
+ [data-ui='field']
467
+ > [data-part='header']
468
+ > [data-part='action']:not(:disabled, [aria-disabled='true']):active {
469
+ color: var(
470
+ --slotted-field-action-color-active,
471
+ color-mix(in oklab, var(--_rest) 35%, var(--slotted-text, CanvasText))
472
+ );
473
+ text-decoration-color: currentColor;
474
+ }
475
+
476
+ [data-ui='field'] > [data-part='header'] > [data-part='action']:focus-visible {
477
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
478
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
479
+ text-decoration-color: currentColor;
480
+ }
481
+
482
+ [data-ui='field']
483
+ > [data-part='header']
484
+ > [data-part='action']:is(:disabled, [aria-disabled='true']) {
485
+ color: var(--slotted-disabled-foreground, GrayText);
486
+ cursor: not-allowed;
487
+ }
488
+
489
+ /**
490
+ * On a finger both controls of the row reach the comfortable target with a
491
+ * transparent halo centred on the box. The halo takes no room, so the row
492
+ * keeps its height and the ground and the ring stay the box a mouse sees.
493
+ */
494
+ @media (pointer: coarse) {
495
+ [data-ui='field'] > [data-part='header'] > [data-part='action'] {
496
+ position: relative;
497
+ }
498
+
499
+ [data-ui='field'] > [data-part='header'] > [data-part='help']::before,
500
+ [data-ui='field'] > [data-part='header'] > [data-part='action']::before {
501
+ content: '';
502
+ inset: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
503
+ position: absolute;
504
+ }
505
+ }
506
+
507
+ /* ── The counter ──────────────────────────────────────────────────────
508
+ *
509
+ * A count the consumer owns — `text-field` will own it in wave 3 — sitting at
510
+ * the end of the label row, which is where Carbon puts it. Angular Material
511
+ * puts it in the subscript beside the error, where a count that appears on the
512
+ * first keystroke shares a row with the message and pushes it.
513
+ *
514
+ * Tabular figures, because a counter that jitters as it counts is a counter
515
+ * the eye follows instead of the field.
516
+ */
517
+ [data-ui='field'] > [data-part='counter'],
518
+ [data-ui='field'] > [data-part='header'] > [data-part='counter'] {
519
+ color: var(--slotted-field-counter-color, var(--slotted-text-muted));
520
+ font-size: var(--slotted-control-font-size-sm, 12px);
521
+ font-variant-numeric: tabular-nums;
522
+ line-height: var(--slotted-field-line-height, var(--slotted-line-height-sm, 1.45));
523
+ transition: color var(--slotted-control-transition-duration)
524
+ var(--slotted-control-transition-easing);
525
+ }
526
+
527
+ /**
528
+ * The counter the family draws on a field with no header: the end of the
529
+ * label row, in the third track, apart from the label by the side gap.
530
+ */
531
+ [data-ui='field'] > [data-part='counter'] {
532
+ align-self: end;
533
+ grid-column: 3;
534
+ grid-row: 1;
535
+ justify-self: end;
536
+ padding-inline-start: var(--_column-gap);
537
+ }
538
+
539
+ /**
540
+ * Past the limit. The counter says so before the form does: a count can pass
541
+ * its maximum while validation has not yet run, and a counter that only turned
542
+ * at submit would say nothing at the moment it is being read.
543
+ */
544
+ [data-ui='field'] > [data-part='counter'][data-invalid],
545
+ [data-ui='field'] > [data-part='header'] > [data-part='counter'][data-invalid] {
546
+ color: var(--slotted-field-counter-invalid-color, var(--slotted-tone-danger-text));
547
+ font-weight: var(--slotted-font-weight-medium, 500);
548
+ }
549
+
550
+ /* ── The messages ─────────────────────────────────────────────────────
551
+ *
552
+ * `inline-message` roots, placed by the grid and styled by their own family.
553
+ * The field adds the rules below: one withdraws, and two set the type of
554
+ * what a field says — the size and, for an outcome, the weight.
555
+ *
556
+ * A message with nothing to say is withdrawn rather than left as an empty
557
+ * line. `inline-message` already withdraws its mark and its severity word in
558
+ * that case; what it cannot do from inside is remove its own row from a grid
559
+ * it knows nothing about. `[data-reserve]` is the deliberate exception — a
560
+ * form that renders its error unconditionally so nothing below it moves when
561
+ * the error arrives.
562
+ */
563
+ [data-ui='field'] > [data-ui='inline-message']:not([data-reserve]):has([data-part='text']:empty) {
564
+ display: none;
565
+ }
566
+
567
+ /**
568
+ * What a field says under its control, and how (F1). The type is one step
569
+ * under the smallest control type, from the type scale rather than the
570
+ * control scale: a message is quieter than the control it is about at every
571
+ * size the field takes, and it does not grow with the control. The message's
572
+ * own `size` still places its mark — sized in `em`, it follows this.
573
+ *
574
+ * The selector carries the root's part so it outweighs the message family's
575
+ * own root rule, which has the same two attributes; equal specificity would
576
+ * leave the winner to stylesheet order.
577
+ */
578
+ [data-ui='field'][data-part='root'] > [data-ui='inline-message'] {
579
+ font-size: var(--slotted-font-size-xs, 0.75rem);
580
+ }
581
+
582
+ /**
583
+ * An outcome — the value is wrong, or it was accepted — is set a weight up
584
+ * from the help under it. The help is muted ink at the regular weight and
585
+ * draws no mark; the outcome draws the tone's own silhouette at the type's
586
+ * size (`inline-message`, R5) and its own ink, and the weight is what makes
587
+ * the two read as two kinds of sentence rather than one.
588
+ */
589
+ [data-ui='field'][data-part='root'] > [data-ui='inline-message'][data-tone='danger'],
590
+ [data-ui='field'][data-part='root'] > [data-ui='inline-message'][data-tone='success'] {
591
+ font-weight: var(--slotted-font-weight-medium, 500);
592
+ }
593
+
594
+ /* ── Placement: the label above the control, or beside it ─────────────
595
+ *
596
+ * The axis Fluent calls `orientation`, Primer `layout` and Spectrum
597
+ * `labelPosition`. A leading track for the label or the header, everything
598
+ * else in the second, and the counter at the end of the label's track.
599
+ *
600
+ * `--slotted-field-label-inline-size` is the one literal in the family, and
601
+ * it is a line length rather than a step on a scale: `12rem` is the width at
602
+ * which a label of about twenty characters at the `md` step sits on one line.
603
+ * No scale in `docs/token-foundation.md` holds a line length, and inventing
604
+ * one for a single family is what the component layer's own rule forbids.
605
+ */
606
+ @container slotted-field (min-width: 320px) {
607
+ /**
608
+ * The second track alone, not the second through the last. A control
609
+ * spanning to the end would meet the counter's cell on the first row and be
610
+ * pushed to a row of its own — which is the side layout undone, and it is
611
+ * what the second capture of this family showed: `Assunto` above its input
612
+ * rather than beside it.
613
+ *
614
+ * Nothing is lost when there is no counter: the third track is then zero
615
+ * wide, and there is no gutter for it to leave behind.
616
+ *
617
+ * Every child keeps its own height. A row is as tall as its tallest cell,
618
+ * and a label of three lines — or a header whose action wrapped under the
619
+ * label — stretched a one-line input beside it to 43 pixels.
620
+ */
621
+ [data-ui='field'][data-part='root'][data-label-placement='side'] > * {
622
+ align-self: start;
623
+ grid-column: 2 / 3;
624
+ }
625
+
626
+ /**
627
+ * Centred on the control's first line rather than on the control, so the
628
+ * label stays level with the text a reader is typing when the control is a
629
+ * textarea four lines tall. `max()` keeps a label taller than its control —
630
+ * three wrapped lines beside a 30-pixel input — from being pushed down.
631
+ */
632
+ [data-ui='field'][data-part='root'][data-label-placement='side'] > [data-part='label'],
633
+ [data-ui='field'][data-part='root'][data-label-placement='side'] > [data-part='header'] {
634
+ grid-column: 1;
635
+ grid-row: 1;
636
+ padding-block-start: max(0px, calc((var(--_control-block-size) - 1lh) / 2));
637
+ padding-inline-end: var(--_column-gap);
638
+ }
639
+
640
+ /**
641
+ * Under the label, at the end of the label's track, which is where a header
642
+ * puts its own counter as well (below), so a side field says its count in
643
+ * one place whether the page wrote a header or not; the count after the
644
+ * control, where it sat until the header existed, was a second place. Restated inside the query because `> *` above is one selector
645
+ * more specific than the counter's own rule.
646
+ */
647
+ [data-ui='field'][data-part='root'][data-label-placement='side'] > [data-part='counter'] {
648
+ grid-column: 1;
649
+ grid-row: 2;
650
+ justify-self: end;
651
+ padding-inline: 0 var(--_column-gap);
652
+ }
653
+
654
+ /**
655
+ * The same place for the counter a header holds: a line of its own under
656
+ * the label, at the end of the label's track. Beside the label it read as
657
+ * part of the name — `Assunto 12/60` — and it stood one line higher than
658
+ * the counter a field without a header draws.
659
+ */
660
+ [data-ui='field'][data-part='root'][data-label-placement='side']
661
+ > [data-part='header']
662
+ > [data-part='counter'] {
663
+ flex-basis: 100%;
664
+ margin-inline-start: 0;
665
+ text-align: end;
666
+ }
667
+ }
668
+
669
+ /* ── Disabled ─────────────────────────────────────────────────────────
670
+ *
671
+ * Muted to the colour the theme measures rather than faded by opacity: a
672
+ * label nobody can read is a field nobody can identify, and a form that
673
+ * disables a section still has to say what the section was for.
674
+ *
675
+ * The messages need no rule here. The field passes `disabled` to them, and
676
+ * `inline-message` mutes itself to the same colour and stops its own ring.
677
+ */
678
+ [data-ui='field'][data-part='root'][data-disabled] > [data-part='label'],
679
+ [data-ui='field'][data-part='root'][data-disabled] > [data-part='counter'],
680
+ [data-ui='field'][data-part='root'][data-disabled] > [data-part='header'] > [data-part='label'],
681
+ [data-ui='field'][data-part='root'][data-disabled]
682
+ > [data-part='header']
683
+ > [data-part='counter'] {
684
+ color: var(--slotted-disabled-foreground);
685
+ }
686
+
687
+ [data-ui='field'][data-part='root'][data-disabled] > [data-part='label'] > [data-part='mark'],
688
+ [data-ui='field'][data-part='root'][data-disabled]
689
+ > [data-part='header']
690
+ > [data-part='label']
691
+ > [data-part='mark'] {
692
+ color: var(--slotted-disabled-foreground);
693
+ }
694
+
695
+ /**
696
+ * `disabled` sits above `invalid` in `STATE_PRECEDENCE`, so a disabled field
697
+ * whose counter is over its limit paints the counter muted rather than red.
698
+ * A control nobody can type in is not over a limit; it is off.
699
+ */
700
+ [data-ui='field'][data-part='root'][data-disabled] > [data-part='counter'][data-invalid],
701
+ [data-ui='field'][data-part='root'][data-disabled]
702
+ > [data-part='header']
703
+ > [data-part='counter'][data-invalid] {
704
+ color: var(--slotted-disabled-foreground);
705
+ font-weight: var(--slotted-font-weight-regular, 400);
706
+ }
707
+ }