@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,980 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── The region that stands in for content ──────────────────────────────
4
+ *
5
+ * A mark, a title, a description, the controls that get the reader out of
6
+ * the situation, and a line of documentation under them. It does not sit
7
+ * beside the content the way `alert` does — it is where the content would
8
+ * have been.
9
+ *
10
+ * The box is a `section`, not a live region. MDN's `alert` role reference
11
+ * says the role "should only be used for text content, not interactive
12
+ * elements such as links or buttons", and this family has a row of buttons
13
+ * in it. The region that announces is `content`, which holds the title and
14
+ * the description and nothing else; `media`, `actions` and `footer` are its
15
+ * siblings outside it. It is `alert`'s shape, deliberately: two neighbouring
16
+ * families answering the same question differently would be two answers to
17
+ * one question.
18
+ *
19
+ * The family owns its own container, because both of its composition changes
20
+ * answer the width of the box rather than the width of the window: a run of
21
+ * actions stacks when the box is narrow, and the `inline` row becomes a
22
+ * column at the same point.
23
+ */
24
+ [data-ui='result-state'][data-part='root'] {
25
+ /**
26
+ * Prose sizes come from the type scale, which does not vary by density,
27
+ * and the mark comes from the control scales, which do. That is where
28
+ * density reaches this family: the mark and the consumer's own buttons
29
+ * tighten, and the words keep their size.
30
+ *
31
+ * The alternative was `alert`'s — control type for the prose as well — and
32
+ * it does not survive `page`, where the largest control font size is
33
+ * fourteen pixels and a route-level headline needs twenty-four. A family
34
+ * that read one scale at two reaches and another at the third would be two
35
+ * scales pretending to be one.
36
+ *
37
+ * The ladder is `sm` / `xl` / `3xl` for the title against `xs` / `md` /
38
+ * `lg` for the description, which is two steps of the scale between the two
39
+ * lines at every reach. It started one step apart at `section` — sixteen
40
+ * over fourteen — and the 720-pixel capture showed the title and the
41
+ * sentence under it reading as one block of text with one of them in bold.
42
+ */
43
+ --_title-font-size: var(
44
+ --slotted-result-state-title-font-size,
45
+ var(--slotted-font-size-xl, 1.125rem)
46
+ );
47
+ --_title-line-height: var(--slotted-line-height-xl, 1.45);
48
+ --_description-font-size: var(
49
+ --slotted-result-state-description-font-size,
50
+ var(--slotted-font-size-md, 0.875rem)
51
+ );
52
+
53
+ /**
54
+ * The box artwork the page supplies takes, and the geometry a raster
55
+ * illustration inherits from it. Because the box is sized before its
56
+ * content arrives, an image that has not loaded reserves the space it will
57
+ * occupy and nothing below it moves when it does. Atlassian spends four
58
+ * props on this and Polaris a skeleton and an effect.
59
+ *
60
+ * `page` is a proportion of the largest control height rather than a sixth
61
+ * step on a scale. Control geometry is the only size scale the theme
62
+ * restates per density, and a proportion of a box is geometry — the rule
63
+ * Avatar's own scale is written under. The three values it produces are
64
+ * whole pixels at all three densities.
65
+ */
66
+ --_media-size: var(--slotted-result-state-media-size, var(--slotted-control-height-md, 34px));
67
+
68
+ /**
69
+ * Each measure is named once and a reach moves only the value it falls
70
+ * back to, so an application that retunes `--slotted-result-state-row-gap`
71
+ * retunes all three reaches rather than discovering that the name it set
72
+ * was the one the default reach happened to read.
73
+ */
74
+ --_inset-block: var(--slotted-result-state-padding-block, var(--slotted-space-9, 2rem));
75
+ --_inset-inline: var(--slotted-result-state-padding-inline, var(--slotted-space-6, 1rem));
76
+ --_row-gap: var(--slotted-result-state-row-gap, var(--slotted-space-6, 1rem));
77
+ --_column-gap: var(--slotted-result-state-column-gap, var(--slotted-space-4, 0.5rem));
78
+ /**
79
+ * Eight pixels between the title and the sentence under it. Six glued the
80
+ * description to an eighteen- and a twenty-four-pixel title; ReUI's three
81
+ * blocks hold eight (`docs/history/designs/2026-09-25-result-state-reui-dossier.md`
82
+ * § 3).
83
+ */
84
+ --_text-gap: var(--slotted-result-state-text-gap, var(--slotted-space-4, 0.5rem));
85
+ /**
86
+ * The distance from the message to the controls under it, one step wider
87
+ * than the row gap. The picture and the words are one statement and the
88
+ * controls are the answer to it, so the eye is given the pause between the
89
+ * two rather than between the picture and its title. ReUI holds 28 pixels
90
+ * there against 16 above the title (dossier § 3); 28 has no step, and 24 at
91
+ * `section` and 32 at `page` keep the one-step difference the reach already
92
+ * keeps everywhere else.
93
+ */
94
+ --_actions-gap: var(--slotted-result-state-actions-block-gap, var(--slotted-space-8, 1.5rem));
95
+ /**
96
+ * Headline tracking, the value `page-header` and `section` set on their own
97
+ * titles. ReUI closes its titles by 0.025em, which at eighteen pixels of this
98
+ * theme's face starts to touch the round letters.
99
+ */
100
+ --_title-tracking: var(--slotted-result-state-title-letter-spacing, -0.01em);
101
+
102
+ /**
103
+ * The one length every drawing is built from: the largest control height,
104
+ * so the illustration tightens with density the way the old mark did and
105
+ * the words do not. Each drawing derives its own boxes from it below, and
106
+ * every box it produces is a whole pixel at all three densities.
107
+ */
108
+ --_art: var(--slotted-control-height-lg, 38px);
109
+ --_art-glyph: var(--slotted-control-icon-size-lg, 18px);
110
+
111
+ /**
112
+ * A container name rather than the anonymous form, because a result state
113
+ * inside a card inside a page would otherwise resolve against whichever
114
+ * ancestor happened to be a container first.
115
+ */
116
+ container-name: slotted-result-state;
117
+ container-type: inline-size;
118
+ /**
119
+ * `container-type: inline-size` applies `contain: inline-size`, which makes
120
+ * the box's intrinsic width zero. In normal flow the box fills its parent
121
+ * and nothing is wrong; in a column that shrink-wraps its children the
122
+ * whole region collapses to one character and breaks its text a letter per
123
+ * line. `collapsible`, `pagination` and `stepper` each shipped that way,
124
+ * and `specs/story-layout.test.mjs` is what refuses it now.
125
+ */
126
+ inline-size: 100%;
127
+
128
+ box-sizing: border-box;
129
+ color: var(--slotted-text);
130
+ display: grid;
131
+ font-family: var(
132
+ --slotted-result-state-font-family,
133
+ var(--slotted-font-family-sans, sans-serif)
134
+ );
135
+ /**
136
+ * The root's own type is the title's, so `1lh` on any child resolves
137
+ * against the line box the title actually draws. It is what puts the mark
138
+ * and the row of actions on the message's first line at `inline` reach
139
+ * without a number saying how — the rule `alert` and `status-indicator`
140
+ * both draw their marks with.
141
+ *
142
+ * Stating it here rather than on the mark is the correction the first draft
143
+ * needed: `1lh` read on the mark itself resolved against the mark's own
144
+ * inherited twelve pixels and `normal`, which is a fourteen-pixel line box
145
+ * against the title's nineteen. The mark sat two and a half pixels above
146
+ * the line it was supposed to be centred on, which is visible and was
147
+ * reported from the picture rather than by a test.
148
+ */
149
+ font-size: var(--_title-font-size);
150
+ grid-template-columns: minmax(0, 1fr);
151
+ /**
152
+ * The layers behind a stack of cards paint beneath the front card, and a
153
+ * layer with a negative stacking order paints beneath the nearest
154
+ * stacking context's own blocks. Without one here, that context is
155
+ * whatever the page happens to have — a card around the region, say — and
156
+ * the layers vanish under its surface.
157
+ */
158
+ isolation: isolate;
159
+ line-height: var(--_title-line-height);
160
+ padding-block: var(--_inset-block);
161
+ padding-inline: var(--_inset-inline);
162
+ row-gap: var(--_row-gap);
163
+ /**
164
+ * The entry, which runs only where the arrival is the message (the
165
+ * `@starting-style` rule under Motion). A transition is read from the
166
+ * state being entered, so the shown box carries the entering curve and the
167
+ * hidden box carries the leaving one.
168
+ */
169
+ transition:
170
+ opacity var(--slotted-duration-short) var(--slotted-easing-enter),
171
+ display var(--slotted-duration-short) var(--slotted-easing-enter);
172
+ transition-behavior: allow-discrete;
173
+ }
174
+
175
+ /* ── Status: what the region is reporting ─────────────────────────────
176
+ *
177
+ * Seven values, and the stylesheet draws none of them (RS1).
178
+ *
179
+ * Each one used to set a tone and a silhouette — a tray, a struck magnifier,
180
+ * a lock — painted as a mask above the title. R5's limit is what removed it:
181
+ * a tone glyph alone on an empty surface, at no distance from anything and
182
+ * in relation to nothing, is the pattern the rule exists to refuse, and an
183
+ * empty state is a title, a description and an action. Nothing is lost by not
184
+ * painting it, because what the region is reporting is in the words; the
185
+ * attribute is still on the root, which is what a page keys its own
186
+ * illustration on.
187
+ */
188
+
189
+ /* ── Reach: which scope the message applies to ────────────────────────
190
+ *
191
+ * The same three words `alert` uses, with the same meaning. It is not a size
192
+ * axis: a size would say the same message can be drawn large or small, and
193
+ * this says which scope it applies to, with the geometry following.
194
+ */
195
+
196
+ /**
197
+ * A table cell, a tile, a row. One line of type, the mark at control-glyph
198
+ * size, and no illustration box at all — the guide requires a compact state
199
+ * for card, panel and cell, and requires that an illustration not dominate a
200
+ * dense operational screen.
201
+ *
202
+ * The row is packed to its own content rather than stretched, so `align`
203
+ * decides where it sits in the cell instead of the text alignment deciding
204
+ * it. The middle track can still shrink below its content, which is what
205
+ * lets a long sentence wrap inside a narrow cell.
206
+ */
207
+ [data-ui='result-state'][data-part='root'][data-reach='inline'] {
208
+ --_title-font-size: var(
209
+ --slotted-result-state-title-font-size,
210
+ var(--slotted-font-size-sm, 0.8125rem)
211
+ );
212
+ --_title-line-height: var(--slotted-line-height-sm, 1.45);
213
+ --_description-font-size: var(
214
+ --slotted-result-state-description-font-size,
215
+ var(--slotted-font-size-xs, 0.75rem)
216
+ );
217
+ --_media-size: var(
218
+ --slotted-result-state-media-size,
219
+ var(--slotted-control-icon-size-md, 16px)
220
+ );
221
+ --_inset-block: var(--slotted-result-state-padding-block, var(--slotted-space-4, 0.5rem));
222
+ --_inset-inline: var(--slotted-result-state-padding-inline, var(--slotted-space-4, 0.5rem));
223
+ --_row-gap: var(--slotted-result-state-row-gap, var(--slotted-space-3, 0.375rem));
224
+ --_title-tracking: var(--slotted-result-state-title-letter-spacing, 0);
225
+
226
+ /* No column gap: the distance from the mark to the words belongs to the
227
+ mark, and the distance from the words to the controls to the controls,
228
+ so a row with no mark starts its words at the inset. */
229
+ grid-template-columns: auto minmax(0, auto) auto;
230
+ }
231
+
232
+ /**
233
+ * The whole route. A mark half again the largest control, and the title at
234
+ * the type scale's top step — the size a page-level heading takes in this
235
+ * library, and one no control font size can reach.
236
+ */
237
+ [data-ui='result-state'][data-part='root'][data-reach='page'] {
238
+ --_title-font-size: var(
239
+ --slotted-result-state-title-font-size,
240
+ var(--slotted-font-size-3xl, 1.5rem)
241
+ );
242
+ --_title-line-height: var(--slotted-line-height-3xl, 1.3);
243
+ --_description-font-size: var(
244
+ --slotted-result-state-description-font-size,
245
+ var(--slotted-font-size-lg, 1rem)
246
+ );
247
+ --_media-size: var(
248
+ --slotted-result-state-media-size,
249
+ calc(var(--slotted-control-height-lg, 38px) * 1.5)
250
+ );
251
+ --_inset-block: var(--slotted-result-state-padding-block, var(--slotted-space-12, 4rem));
252
+ /**
253
+ * One step further apart than `section`, because the things being kept
254
+ * apart are larger: a fifty-seven-pixel mark and a twenty-four-pixel
255
+ * headline read as crowded at the distance a thirty-four-pixel mark and an
256
+ * eighteen-pixel one read as settled.
257
+ */
258
+ --_row-gap: var(--slotted-result-state-row-gap, var(--slotted-space-8, 1.5rem));
259
+ --_actions-gap: var(--slotted-result-state-actions-block-gap, var(--slotted-space-9, 2rem));
260
+ /* Half again, the proportion the page's own media box already takes. */
261
+ --_art: calc(var(--slotted-control-height-lg, 38px) * 1.5);
262
+ --_art-glyph: calc(var(--slotted-control-icon-size-lg, 18px) * 1.5);
263
+ }
264
+
265
+ /* ── Align ────────────────────────────────────────────────────────────
266
+ *
267
+ * Carbon left-aligns its empty states inside data-dense views; the other six
268
+ * surveyed implementations centre unconditionally. Both readings are real,
269
+ * and one axis is cheaper than a second family.
270
+ *
271
+ * `justify-items` places the boxes and `text-align` places the words inside
272
+ * them, because a centred box holding left-aligned prose is the defect this
273
+ * would otherwise ship: the title looks centred until the description wraps
274
+ * onto a second line.
275
+ */
276
+ [data-ui='result-state'][data-part='root'][data-align='center'] {
277
+ justify-items: center;
278
+ text-align: center;
279
+ }
280
+
281
+ [data-ui='result-state'][data-part='root'][data-align='start'] {
282
+ justify-items: start;
283
+ text-align: start;
284
+ }
285
+
286
+ [data-ui='result-state'][data-part='root'][data-reach='inline'][data-align='center'] {
287
+ justify-content: center;
288
+ justify-items: stretch;
289
+ }
290
+
291
+ [data-ui='result-state'][data-part='root'][data-reach='inline'][data-align='start'] {
292
+ justify-content: start;
293
+ justify-items: stretch;
294
+ }
295
+
296
+ /* ── The picture, when there is one ───────────────────────────────────
297
+ *
298
+ * The box holds artwork the page supplies, and nothing else. It held a mask
299
+ * per status until RS1 — a tray, a lock, a circled exclamation, drawn at the
300
+ * title's size above the title — and R5's limit is what removed it.
301
+ *
302
+ * With nothing in it the box is withdrawn rather than left standing at zero:
303
+ * a box of no height is still an item in the grid, and the region's row gap
304
+ * would keep a band of empty space above the title exactly where the glyph
305
+ * used to be. Withdrawn, the region is the title, the description and the
306
+ * action, with one gap between them.
307
+ *
308
+ * `--slotted-result-state-media` is the way to put a picture there without
309
+ * projecting a node: the page names its own illustration and shows the box in
310
+ * the same rule, which is one snippet in the family's documentation. It is
311
+ * painted as an image rather than as a mask, because what goes there now is a
312
+ * drawing in its own colours and not a silhouette in a tone; and when nothing
313
+ * names it, the declaration is invalid at computed-value time and the box
314
+ * paints nothing at all.
315
+ */
316
+ [data-ui='result-state'] > [data-part='media']:empty {
317
+ background: var(--slotted-result-state-media) center / contain no-repeat;
318
+ block-size: var(--_media-size);
319
+ display: none;
320
+ inline-size: var(--_media-size);
321
+ }
322
+
323
+ /**
324
+ * Artwork the page projected into the box.
325
+ *
326
+ * The block size is the illustration's box and the inline size is released:
327
+ * the height is what reserves the space, and an illustration is rarely
328
+ * square. Anything inside is held to the box's height and keeps its own
329
+ * ratio, so a wide drawing and a square one both land on the same baseline.
330
+ * Because the box is sized before its content arrives, an image that has not
331
+ * loaded reserves the room it will take and nothing below it moves when it
332
+ * does.
333
+ */
334
+ [data-ui='result-state'] > [data-part='media']:not(:empty) {
335
+ align-items: center;
336
+ background-color: transparent;
337
+ block-size: var(--_media-size);
338
+ display: flex;
339
+ inline-size: auto;
340
+ justify-content: center;
341
+ min-inline-size: var(--_media-size);
342
+ }
343
+
344
+ [data-ui='result-state'] > [data-part='media']:not(:empty) > * {
345
+ block-size: 100%;
346
+ inline-size: auto;
347
+ max-inline-size: 100%;
348
+ }
349
+
350
+ /** Supplied artwork on the same line, centred on the same axis by its own size. */
351
+ [data-ui='result-state'][data-reach='inline'] > [data-part='media']:not(:empty) {
352
+ align-self: start;
353
+ grid-column: 1;
354
+ grid-row: 1;
355
+ margin-block-start: calc((1lh - var(--_media-size)) / 2);
356
+ margin-inline-end: var(--_column-gap);
357
+ }
358
+
359
+ /* ── Illustration: the picture the family draws around the page's glyph ─
360
+ *
361
+ * Three drawings, each made of the surface and border roles a card is
362
+ * painted in, with the page's glyph in the muted text role. R5's third band
363
+ * refuses a tone glyph enlarged on an empty surface and admits an
364
+ * illustration drawn for the space; none of these takes a tone, and each
365
+ * gives the glyph a geometric relation to something — a frame, a stack, a
366
+ * row it stands in for.
367
+ *
368
+ * `inline` reach draws none of them: a table cell holds a line of text, and
369
+ * the guide forbids an illustration from dominating a dense screen. The
370
+ * artwork the page supplied is drawn there as it is.
371
+ *
372
+ * Under forced colours the browser would replace every fill with `Canvas`
373
+ * and leave each drawing as outlines laid on top of one another. The theme
374
+ * already maps the roles used here to system colours in that mode, so the
375
+ * drawing opts out of the browser's adjustment and keeps the theme's.
376
+ *
377
+ * The measurements, and where each came from, are in
378
+ * `docs/history/designs/2026-09-25-result-state-reui-dossier.md` § 3.
379
+ */
380
+
381
+ /**
382
+ * A framed tile: a ring on the sunken surface around a raised card, with
383
+ * the glyph in the card. The inner card is the largest control height, the
384
+ * ring one step of air around it, so the whole tile is 46, 40 and 38 pixels
385
+ * at the three densities and its corners stay concentric — the outer radius
386
+ * is the inner one plus the ring.
387
+ */
388
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='tile']
389
+ > [data-part='media']:not(:empty) {
390
+ --_ring: var(--slotted-space-2, 0.25rem);
391
+ --_inner-radius: var(--slotted-radius-lg, 8px);
392
+
393
+ background-color: var(--slotted-surface-sunken);
394
+ block-size: calc(var(--_art) + 2 * var(--_ring));
395
+ border: var(--slotted-border-width-thin, 1px) solid var(--slotted-border-subtle);
396
+ border-radius: calc(var(--_inner-radius) + var(--_ring));
397
+ box-sizing: border-box;
398
+ color: var(--slotted-text-muted);
399
+ forced-color-adjust: none;
400
+ inline-size: calc(var(--_art) + 2 * var(--_ring));
401
+ min-inline-size: 0;
402
+ position: relative;
403
+ transition:
404
+ opacity var(--slotted-duration-medium) var(--slotted-easing-enter),
405
+ scale var(--slotted-duration-medium) var(--slotted-easing-enter);
406
+ }
407
+
408
+ /**
409
+ * The inner card, set in from the ring by the ring less the border it sits
410
+ * inside, so it is exactly `--_art` square. It paints beneath the glyph
411
+ * because the root is the stacking context (`isolation` above) and the tile
412
+ * is not one.
413
+ */
414
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='tile']
415
+ > [data-part='media']:not(:empty)::before {
416
+ background-color: var(--slotted-surface-raised);
417
+ border: var(--slotted-border-width-thin, 1px) solid var(--slotted-border-subtle);
418
+ border-radius: var(--_inner-radius);
419
+ box-shadow: var(--slotted-shadow-xs);
420
+ content: '';
421
+ inset: calc(var(--_ring) - var(--slotted-border-width-thin, 1px));
422
+ position: absolute;
423
+ z-index: -1;
424
+ }
425
+
426
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='tile']
427
+ > [data-part='media']:not(:empty)
428
+ > * {
429
+ block-size: var(--_art-glyph);
430
+ inline-size: var(--_art-glyph);
431
+ position: relative;
432
+ }
433
+
434
+ /**
435
+ * Three layers leaning back from the reader, the glyph on the front one.
436
+ *
437
+ * Each layer is a square of `--_side` — the largest control height plus a
438
+ * step, 42, 36 and 34 pixels — sheared by `skewY(-26deg)` and narrowed by
439
+ * `scaleX(0.9)`: the matrix ReUI's stack draws with, `matrix(1, -0.4877, 0,
440
+ * 1, 0, 0)`, where 0.4877 is the tangent of 26 degrees. The layers behind
441
+ * step back by (−0.36, −0.3) of a side in the tile's own coordinates, which
442
+ * after the shear and the narrowing is the (−13.65, −6.04) pixels ReUI steps
443
+ * its layers by at a 42-pixel side.
444
+ *
445
+ * Three layers and two pseudo-elements: the front face is `::before`, the
446
+ * middle layer `::after`, and the farthest is the box's own shadow, drawn
447
+ * twice — a fill, then a pixel wider in the border colour — because a
448
+ * shadow has no border of its own. The box itself paints nothing, since a
449
+ * transformed box is a stacking context and its own background would sit
450
+ * above nothing and beneath both pseudo-elements.
451
+ *
452
+ * The drawing's visual bounds are wider and taller than the box, so the box
453
+ * reserves the difference in its margins and is moved back onto the centre
454
+ * of those bounds: 0.325 of a side along the lean and 0.145 down, the
455
+ * centre of the sheared stack measured against the centre of the square.
456
+ */
457
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='stack']
458
+ > [data-part='media']:not(:empty) {
459
+ --_side: calc(var(--_art) + var(--slotted-space-2, 0.25rem));
460
+ --_lean: 1;
461
+ --_step-x: calc(var(--_side) * -0.36 * var(--_lean));
462
+ --_step-y: calc(var(--_side) * -0.3);
463
+ --_layer-border: var(--slotted-border-width-thin, 1px);
464
+ --_far: color-mix(in oklab, var(--slotted-border-subtle) 60%, transparent);
465
+
466
+ block-size: var(--_side);
467
+ border-radius: var(--slotted-radius-lg, 8px);
468
+ box-shadow:
469
+ calc(2 * var(--_step-x)) calc(2 * var(--_step-y)) 0 0 var(--slotted-surface-raised),
470
+ calc(2 * var(--_step-x)) calc(2 * var(--_step-y)) 0 var(--_layer-border) var(--_far);
471
+ box-sizing: border-box;
472
+ color: var(--slotted-text-muted);
473
+ forced-color-adjust: none;
474
+ inline-size: var(--_side);
475
+ margin-block: calc(var(--_side) * 0.37);
476
+ margin-inline: calc(var(--_side) * 0.28);
477
+ min-inline-size: 0;
478
+ position: relative;
479
+ transform: skewY(calc(-26deg * var(--_lean))) scaleX(0.9);
480
+ transition: box-shadow var(--slotted-duration-long) var(--slotted-easing-enter);
481
+ translate: calc(var(--_side) * 0.325 * var(--_lean)) calc(var(--_side) * 0.145);
482
+ }
483
+
484
+ /** Depth is read from the reading edge, so the stack leans the other way. */
485
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='stack']:dir(rtl)
486
+ > [data-part='media']:not(:empty) {
487
+ --_lean: -1;
488
+ }
489
+
490
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='stack']
491
+ > [data-part='media']:not(:empty)::before,
492
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='stack']
493
+ > [data-part='media']:not(:empty)::after {
494
+ background-color: var(--slotted-surface-raised);
495
+ border: var(--_layer-border) solid var(--slotted-border-subtle);
496
+ border-radius: inherit;
497
+ content: '';
498
+ inset: 0;
499
+ position: absolute;
500
+ }
501
+
502
+ /**
503
+ * The front face, a shade stronger at its edge than the layers behind it
504
+ * — ReUI's front stroke is half again as opaque as the others — with a
505
+ * lift under it for the ground the stack stands on. The shade is mixed
506
+ * from the two border roles rather than borrowed from the control edge,
507
+ * because a face drawn in the control edge is read by `field-surface.test.mjs`
508
+ * as a field, and this is a drawing.
509
+ */
510
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='stack']
511
+ > [data-part='media']:not(:empty)::before {
512
+ border-color: color-mix(
513
+ in oklab,
514
+ var(--slotted-border-subtle),
515
+ var(--slotted-border-strong) 30%
516
+ );
517
+ box-shadow: var(--slotted-shadow-sm);
518
+ z-index: -1;
519
+ }
520
+
521
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='stack']
522
+ > [data-part='media']:not(:empty)::after {
523
+ transition: translate var(--slotted-duration-long) var(--slotted-easing-enter);
524
+ translate: var(--_step-x) var(--_step-y);
525
+ z-index: -2;
526
+ }
527
+
528
+ /**
529
+ * The glyph on the front face, sheared with it. Half a side is 21, 18 and
530
+ * 17 pixels, where ReUI sets 24 on a 42-pixel face; the face here is the
531
+ * same size and the glyph is a size smaller, because a glyph as tall as
532
+ * the title's line box competes with the title.
533
+ */
534
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='stack']
535
+ > [data-part='media']:not(:empty)
536
+ > * {
537
+ block-size: calc(var(--_side) * 0.5);
538
+ inline-size: calc(var(--_side) * 0.5);
539
+ }
540
+
541
+ /**
542
+ * A stack of cards: the front card holds the page's glyph where a row's
543
+ * thumbnail would be and two lines where its text would be, and two cards
544
+ * behind it show a step of their top edges above it.
545
+ *
546
+ * Every length is ReUI's (`c-empty-15`, dossier § 3) on the nearest step:
547
+ * the card is 208 pixels wide, its padding sixteen, the thumbnail the
548
+ * smallest control height, the gap to the lines twelve, each card behind
549
+ * set in twelve pixels a side and twelve pixels higher. The card's height is
550
+ * the thumbnail plus its padding, 62, 58 and 56 pixels.
551
+ *
552
+ * The cards behind are the two pseudo-elements, beneath the front card
553
+ * because the root is the stacking context and the card is not one; they
554
+ * stand above the box, which reserves their two steps in its top margin.
555
+ *
556
+ * ReUI fades the bottom of the drawing into `--background`. That supposes
557
+ * the colour of the ground, and a result state inside a card or on the
558
+ * sunken surface is on another one; a mask would clip the cards behind,
559
+ * which stand outside the box. The drawing does not fade.
560
+ */
561
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='cards']
562
+ > [data-part='media'] {
563
+ --_pad: var(--slotted-space-6, 1rem);
564
+ --_gap: var(--slotted-space-5, 0.75rem);
565
+ --_thumb: var(--slotted-control-height-sm, 30px);
566
+ --_step: var(--slotted-space-5, 0.75rem);
567
+ --_line: var(--slotted-space-4, 0.5rem);
568
+ --_line-2: var(--slotted-space-3, 0.375rem);
569
+ --_line-gap: var(--slotted-space-3, 0.375rem);
570
+ /* Where the lines start: after the thumbnail when there is one. */
571
+ --_lines-x: calc(var(--_pad) + var(--_thumb) + var(--_gap));
572
+ /* The two lines are 75 and 50 per cent of the room ReUI's card leaves them. */
573
+ --_line-1-length: calc(
574
+ (
575
+ var(--slotted-space-11, 3rem) * 4 + var(--slotted-space-6, 1rem) - var(--_lines-x) -
576
+ var(--_pad)
577
+ ) *
578
+ 0.75
579
+ );
580
+ --_line-2-length: calc(
581
+ (
582
+ var(--slotted-space-11, 3rem) * 4 + var(--slotted-space-6, 1rem) - var(--_lines-x) -
583
+ var(--_pad)
584
+ ) *
585
+ 0.5
586
+ );
587
+ /* A length, not a percentage: a percentage in a background offset is a
588
+ share of the room the layer leaves, which differs for each line height
589
+ and set the two lines four and three pixels above centre. */
590
+ --_line-1-y: calc(
591
+ (var(--_thumb) + 2 * var(--_pad) - var(--_line) - var(--_line-gap) - var(--_line-2)) / 2
592
+ );
593
+ /* `background-position` has no logical keyword, so the edge is a value. */
594
+ --_edge: left;
595
+ --_ink: var(--slotted-border-subtle);
596
+ /**
597
+ * Mixed with the card's own surface rather than with transparency: each
598
+ * cap overlaps its bar by half a line, and a translucent ink doubles where
599
+ * the two overlap, which drew a darker bead at both ends of the line.
600
+ */
601
+ --_ink-2: color-mix(in oklab, var(--slotted-border-subtle) 60%, var(--slotted-surface-raised));
602
+
603
+ align-items: center;
604
+ /**
605
+ * The lines are drawn in the card's own background, each a bar with a
606
+ * round cap at either end — a disc the line's height across, then the bar
607
+ * between the two discs — so the ends are the pill a skeleton line is,
608
+ * not the square end a gradient on its own draws.
609
+ */
610
+ background:
611
+ radial-gradient(closest-side, var(--_ink) calc(100% - 0.5px), transparent) var(--_edge)
612
+ var(--_lines-x) top var(--_line-1-y) / var(--_line) var(--_line) no-repeat,
613
+ radial-gradient(closest-side, var(--_ink) calc(100% - 0.5px), transparent) var(--_edge)
614
+ calc(var(--_lines-x) + var(--_line-1-length) - var(--_line)) top var(--_line-1-y) /
615
+ var(--_line) var(--_line) no-repeat,
616
+ linear-gradient(var(--_ink), var(--_ink)) var(--_edge)
617
+ calc(var(--_lines-x) + var(--_line) / 2) top var(--_line-1-y) /
618
+ calc(var(--_line-1-length) - var(--_line)) var(--_line) no-repeat,
619
+ radial-gradient(closest-side, var(--_ink-2) calc(100% - 0.5px), transparent) var(--_edge)
620
+ var(--_lines-x) top calc(var(--_line-1-y) + var(--_line) + var(--_line-gap)) /
621
+ var(--_line-2) var(--_line-2) no-repeat,
622
+ radial-gradient(closest-side, var(--_ink-2) calc(100% - 0.5px), transparent) var(--_edge)
623
+ calc(var(--_lines-x) + var(--_line-2-length) - var(--_line-2)) top
624
+ calc(var(--_line-1-y) + var(--_line) + var(--_line-gap)) / var(--_line-2) var(--_line-2)
625
+ no-repeat,
626
+ linear-gradient(var(--_ink-2), var(--_ink-2)) var(--_edge)
627
+ calc(var(--_lines-x) + var(--_line-2) / 2) top
628
+ calc(var(--_line-1-y) + var(--_line) + var(--_line-gap)) /
629
+ calc(var(--_line-2-length) - var(--_line-2)) var(--_line-2) no-repeat,
630
+ var(--slotted-surface-raised);
631
+ /* Offsets are measured from the card's outer edge, where the thumbnail's
632
+ padding is measured from too. */
633
+ background-origin: border-box;
634
+ block-size: calc(var(--_thumb) + 2 * var(--_pad));
635
+ border: var(--slotted-border-width-thin, 1px) solid var(--slotted-border-subtle);
636
+ border-radius: var(--slotted-radius-lg, 8px);
637
+ box-shadow: var(--slotted-shadow-sm);
638
+ box-sizing: border-box;
639
+ color: var(--slotted-text-muted);
640
+ display: flex;
641
+ forced-color-adjust: none;
642
+ inline-size: calc(var(--slotted-space-11, 3rem) * 4 + var(--slotted-space-6, 1rem));
643
+ justify-content: flex-start;
644
+ margin-block-start: calc(2 * var(--_step));
645
+ max-inline-size: 100%;
646
+ min-inline-size: 0;
647
+ padding-inline: calc(var(--_pad) - var(--slotted-border-width-thin, 1px));
648
+ position: relative;
649
+ }
650
+
651
+ /** No thumbnail without a glyph: the lines start at the padding. */
652
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='cards']
653
+ > [data-part='media']:empty {
654
+ --_lines-x: var(--_pad);
655
+ }
656
+
657
+ /**
658
+ * Right to left, the thumbnail moves to the inline start by itself and the
659
+ * lines are placed from the right edge. The card is not mirrored with a
660
+ * transform: a transformed box is a stacking context, and the cards behind
661
+ * would then paint over the front one.
662
+ */
663
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='cards']:dir(rtl)
664
+ > [data-part='media'] {
665
+ --_edge: right;
666
+ }
667
+
668
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='cards']
669
+ > [data-part='media']::before,
670
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='cards']
671
+ > [data-part='media']::after {
672
+ background-color: var(--slotted-surface-sunken);
673
+ block-size: 100%;
674
+ border: var(--slotted-border-width-thin, 1px) solid var(--slotted-border-subtle);
675
+ border-radius: inherit;
676
+ box-sizing: border-box;
677
+ content: '';
678
+ inset-block-start: calc(-1 * var(--slotted-border-width-thin, 1px));
679
+ position: absolute;
680
+ transition: translate var(--slotted-duration-long) var(--slotted-easing-enter);
681
+ z-index: -1;
682
+ }
683
+
684
+ /** The farthest card, painted first. */
685
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='cards']
686
+ > [data-part='media']::before {
687
+ border-color: var(--_ink-2);
688
+ inset-inline: calc(2 * var(--_step) - var(--slotted-border-width-thin, 1px));
689
+ translate: 0 calc(-2 * var(--_step));
690
+ }
691
+
692
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='cards']
693
+ > [data-part='media']::after {
694
+ inset-inline: calc(var(--_step) - var(--slotted-border-width-thin, 1px));
695
+ translate: 0 calc(-1 * var(--_step));
696
+ }
697
+
698
+ /**
699
+ * The thumbnail is the page's glyph on the sunken surface, padded from its
700
+ * edge to the glyph size.
701
+ */
702
+ [data-ui='result-state']:not([data-reach='inline'])[data-illustration='cards']
703
+ > [data-part='media']
704
+ > * {
705
+ background-color: var(--slotted-surface-sunken);
706
+ block-size: var(--_thumb);
707
+ border-radius: var(--slotted-radius-sm, 4px);
708
+ box-sizing: border-box;
709
+ flex: none;
710
+ inline-size: var(--_thumb);
711
+ padding: calc((var(--_thumb) - var(--slotted-control-icon-size-md, 16px)) / 2);
712
+ }
713
+
714
+ /* ── The words, which are the live region ─────────────────────────────
715
+ *
716
+ * `min-inline-size: 0` is what lets the column shrink below its content
717
+ * inside the grid, and it is the half of the pair that `minmax(0, …)` on the
718
+ * track cannot supply on its own.
719
+ */
720
+ [data-ui='result-state'] > [data-part='content'] {
721
+ display: grid;
722
+ min-inline-size: 0;
723
+ row-gap: var(--_text-gap);
724
+ }
725
+
726
+ [data-ui='result-state'][data-reach='inline'] > [data-part='content'] {
727
+ grid-column: 2;
728
+ grid-row: 1;
729
+ }
730
+
731
+ /**
732
+ * `balance` is what keeps a two-line title from leaving one word on the
733
+ * second line, and it is the reason a centred region reads as a shape rather
734
+ * than as a ragged edge. It is capped by the browser at a handful of lines,
735
+ * so a long title is unaffected rather than slow.
736
+ *
737
+ * `break-word` breaks the one string a result state is likeliest to carry
738
+ * that no language can break — a resource id, a host name without a hyphen.
739
+ * Nothing is removed: the whole string stays in the DOM, in the accessibility
740
+ * tree, and findable by a page search.
741
+ */
742
+ [data-ui='result-state'] [data-part='title'] {
743
+ font-family: var(
744
+ --slotted-result-state-title-font-family,
745
+ var(
746
+ --slotted-font-family-heading,
747
+ var(--slotted-font-family-sans, ui-sans-serif, system-ui, sans-serif)
748
+ )
749
+ );
750
+ font-size: var(--_title-font-size);
751
+ font-weight: var(
752
+ --slotted-result-state-title-font-weight,
753
+ var(--slotted-font-weight-semibold, 600)
754
+ );
755
+ letter-spacing: var(--_title-tracking);
756
+ line-height: var(--_title-line-height);
757
+ margin: 0;
758
+ min-inline-size: 0;
759
+ overflow-wrap: break-word;
760
+ text-wrap: balance;
761
+ }
762
+
763
+ /**
764
+ * The muted text role, because the title is what the reader is meant to read
765
+ * first and two lines of equal weight give them no order to read in. It is
766
+ * the pair the theme measures against all three neutral surfaces.
767
+ */
768
+ [data-ui='result-state'] [data-part='description'] {
769
+ color: var(--slotted-text-muted);
770
+ font-size: var(--_description-font-size);
771
+ line-height: var(--slotted-line-height-md, 1.5);
772
+ margin: 0;
773
+ min-inline-size: 0;
774
+ overflow-wrap: break-word;
775
+ }
776
+
777
+ /* ── The actions ──────────────────────────────────────────────────────
778
+ *
779
+ * Outside the live region, so a reader hearing the message is not read the
780
+ * labels of two buttons in the middle of it. What goes in is the consumer's
781
+ * own `button` and `a`, because those families already own what a button and
782
+ * a link are.
783
+ */
784
+ [data-ui='result-state'] > [data-part='actions'] {
785
+ align-items: center;
786
+ display: flex;
787
+ flex-wrap: wrap;
788
+ gap: var(--slotted-result-state-actions-gap, var(--slotted-space-4, 0.5rem));
789
+ min-inline-size: 0;
790
+ }
791
+
792
+ [data-ui='result-state'][data-align='center'] > [data-part='actions'] {
793
+ justify-content: center;
794
+ }
795
+
796
+ /** The pause between the message and its answer (`--_actions-gap`). */
797
+ [data-ui='result-state']:not([data-reach='inline'])
798
+ > [data-part='content']
799
+ + [data-part='actions'] {
800
+ margin-block-start: calc(var(--_actions-gap) - var(--_row-gap));
801
+ }
802
+
803
+ /**
804
+ * On the same line as the mark, and for the same reason. The grid row is as
805
+ * tall as its tallest item, so a control taller than a line of text made the
806
+ * row thirty pixels deep: the mark and the words then sat at the top of it
807
+ * while the control sat in the middle, and a row with one thing at the top
808
+ * and another in the centre reads as a mistake. Reported from the picture.
809
+ *
810
+ * The box is one line box tall and the control is centred in it, which lets
811
+ * the control stand proud of the line by the same distance above and below —
812
+ * a distance the region's own block inset already holds.
813
+ */
814
+ [data-ui='result-state'][data-reach='inline'] > [data-part='actions'] {
815
+ /**
816
+ * `align-content` rather than `align-items`, because the row is allowed to
817
+ * wrap and a wrapping flex container aligns its *lines*: with the line
818
+ * taller than the box, `align-items: center` centres the control inside a
819
+ * line that is itself parked at the top, which left the control exactly
820
+ * half its overhang too low.
821
+ */
822
+ align-content: center;
823
+ align-self: start;
824
+ block-size: 1lh;
825
+ grid-column: 3;
826
+ grid-row: 1;
827
+ margin-inline-start: var(--_column-gap);
828
+ }
829
+
830
+ /**
831
+ * The line under the actions: the documentation link that is not a call to
832
+ * action. Polaris calls it `footerContent` and Atlassian a `tertiaryAction`,
833
+ * and both are right that it is neither of the two buttons above it — so it
834
+ * is set one step down and in the muted role rather than made a third
835
+ * control.
836
+ */
837
+ [data-ui='result-state'] > [data-part='footer'] {
838
+ color: var(--slotted-text-muted);
839
+ font-size: var(--slotted-font-size-sm, 0.8125rem);
840
+ line-height: var(--slotted-line-height-sm, 1.45);
841
+ min-inline-size: 0;
842
+ }
843
+
844
+ [data-ui='result-state'][data-reach='inline'] > [data-part='footer'] {
845
+ grid-column: 2;
846
+ grid-row: 2;
847
+ }
848
+
849
+ /* ── Focus ────────────────────────────────────────────────────────────
850
+ *
851
+ * The root carries `tabindex="-1"`, so an application that has just emptied
852
+ * a table can send the reader to the message; a reader who arrives that way
853
+ * has to see where they are. It is the only state the family paints, and it
854
+ * is not animated: a focus indicator that fades in is a focus indicator that
855
+ * is not there yet.
856
+ */
857
+ [data-ui='result-state'][data-part='root']:focus-visible {
858
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
859
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
860
+ }
861
+
862
+ /* ── A narrow box ─────────────────────────────────────────────────────
863
+ *
864
+ * Two buttons wrapping into two ragged lines is worse than two buttons
865
+ * stacked, and the `inline` row has nowhere left to put a third column. This
866
+ * is the composition change the 240-pixel capture exists to check.
867
+ */
868
+ @container slotted-result-state (max-width: 20rem) {
869
+ [data-ui='result-state'] > [data-part='actions'] {
870
+ /**
871
+ * Stacked, and each control still its own width. How wide a control is
872
+ * belongs to the control, and `button` already ships `fullWidth` for a
873
+ * consumer who wants it.
874
+ */
875
+ flex-direction: column;
876
+ }
877
+
878
+ [data-ui='result-state'][data-align='center'] > [data-part='actions'] {
879
+ align-items: center;
880
+ }
881
+
882
+ [data-ui='result-state'][data-align='start'] > [data-part='actions'] {
883
+ align-items: flex-start;
884
+ }
885
+
886
+ [data-ui='result-state'][data-reach='inline'] {
887
+ grid-template-columns: auto minmax(0, 1fr);
888
+ }
889
+
890
+ /**
891
+ * Below the words now, so the box goes back to its own height: a row of
892
+ * controls held to one line box only makes sense while it is on that line.
893
+ */
894
+ [data-ui='result-state'][data-reach='inline'] > [data-part='actions'] {
895
+ block-size: auto;
896
+ grid-column: 2;
897
+ grid-row: 2;
898
+ margin-inline-start: 0;
899
+ }
900
+
901
+ [data-ui='result-state'][data-reach='inline'] > [data-part='footer'] {
902
+ grid-column: 2;
903
+ grid-row: 3;
904
+ }
905
+ }
906
+
907
+ /* ── Motion ───────────────────────────────────────────────────────────
908
+ *
909
+ * The exit. A hidden region keeps its element for the reason a hidden
910
+ * `alert` does — a live region has to be in the document before its text
911
+ * changes — and fades out on the leaving curve, carrying `display` so the
912
+ * box holds its place until the fade is over. `display: none` is restated
913
+ * because the root's own `display: grid` would win over the user agent's
914
+ * rule for `[hidden]`.
915
+ */
916
+ [data-ui='result-state'][data-part='root'][hidden] {
917
+ display: none;
918
+ opacity: 0;
919
+ transition:
920
+ opacity var(--slotted-duration-short) var(--slotted-easing-exit),
921
+ display var(--slotted-duration-short) var(--slotted-easing-exit);
922
+ }
923
+
924
+ /**
925
+ * The entry belongs to a region that announces, for `alert`'s reason:
926
+ * `@starting-style` applies on first paint as well, and a region with
927
+ * `live="off"` is one the page has decided is not an arrival. The words
928
+ * fade in; the drawing assembles — the layers behind a stack and the cards
929
+ * behind a card start hidden behind the front one and open to where they
930
+ * rest, the second a short step after the first, and a tile settles from a
931
+ * shade smaller. Every duration is on the motion scale, which the theme
932
+ * collapses under reduced motion.
933
+ */
934
+ @starting-style {
935
+ [data-ui='result-state'][data-part='root']:is([data-live='polite'], [data-live='assertive']) {
936
+ opacity: 0;
937
+ }
938
+
939
+ [data-ui='result-state'][data-part='root']:is([data-live='polite'], [data-live='assertive'])
940
+ > [data-part='media'] {
941
+ --_step-x: 0px;
942
+ --_step-y: 0px;
943
+ }
944
+
945
+ [data-ui='result-state'][data-part='root']:is(
946
+ [data-live='polite'],
947
+ [data-live='assertive']
948
+ )[data-illustration='tile']
949
+ > [data-part='media'] {
950
+ opacity: 0;
951
+ scale: 0.96;
952
+ }
953
+
954
+ [data-ui='result-state'][data-part='root']:is(
955
+ [data-live='polite'],
956
+ [data-live='assertive']
957
+ )[data-illustration='cards']
958
+ > [data-part='media']::before,
959
+ [data-ui='result-state'][data-part='root']:is(
960
+ [data-live='polite'],
961
+ [data-live='assertive']
962
+ )[data-illustration='cards']
963
+ > [data-part='media']::after {
964
+ translate: 0 0;
965
+ }
966
+ }
967
+
968
+ /** The farther of two moving layers leaves a short step after the nearer. */
969
+ [data-ui='result-state'][data-illustration='cards'] > [data-part='media']::before {
970
+ transition-delay: var(--slotted-duration-short);
971
+ }
972
+
973
+ /* ── Forced colours ───────────────────────────────────────────────────
974
+ *
975
+ * Nothing beyond the drawings' own `forced-color-adjust`, above. The
976
+ * operating system replaces every author colour, the theme already remaps
977
+ * `--slotted-text` and `--slotted-text-muted`, and the words carry the
978
+ * region as they do everywhere else.
979
+ */
980
+ }