@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,1175 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * The jobs an application runs away from the page — imports and exports —
4
+ * and everything the reader can do about each one.
5
+ *
6
+ * ┌──────────────────────────────────────────────────────────────┐
7
+ * │ header ▸ title (count) · clear · actions │
8
+ * ├──────────────────────────────────────────────────────────────┤
9
+ * │ views ▸ tabs (list only) │
10
+ * ├──────────────────────────────────────────────────────────────┤
11
+ * │ list ▸ job … │
12
+ * │ job ▸ visual · body ▸ heading ▸ job-title │
13
+ * │ meta │
14
+ * │ status ▸ mark · word · stage │
15
+ * │ progress ▸ bar · progress-text │
16
+ * │ summary · message │
17
+ * │ controls ▸ download · retry · cancel · toggle │
18
+ * │ · job-actions · remove │
19
+ * │ details ▸ counts · files · errors │
20
+ * │ more · empty · error │
21
+ * ├──────────────────────────────────────────────────────────────┤
22
+ * │ footer │
23
+ * └──────────────────────────────────────────────────────────────┘
24
+ *
25
+ * The bar, the buttons, the tabs, the table, the skeleton and the
26
+ * result-state are their families'. This sheet arranges them and reaches
27
+ * them only through its own parts, with child combinators, so a `title` or
28
+ * a `label` of theirs is never restyled.
29
+ *
30
+ * Below 40rem a job is two columns — the tile, and everything else with the
31
+ * controls under the words. From 40rem the status, the bar and the message
32
+ * take a column of their own beside the name, and a list of jobs reads as a
33
+ * table: the reader scans the names down one edge and the states down
34
+ * another. The threshold is the family's own, for the reason `list-item`
35
+ * and `card` keep theirs: it answers the job's content, not the page.
36
+ */
37
+ [data-ui='import-export-center'] {
38
+ --_text: var(--slotted-text, CanvasText);
39
+ --_muted: var(--slotted-text-muted, GrayText);
40
+ --_rule: var(--slotted-import-export-center-border, var(--slotted-border-subtle, ButtonBorder));
41
+ --_ground: var(--slotted-import-export-center-background, var(--slotted-surface, Canvas));
42
+ --_hover: var(--slotted-tone-secondary-subtle-hover, ButtonFace);
43
+ --_active: var(--slotted-tone-secondary-subtle-active, ButtonFace);
44
+ --_inset-inline: var(
45
+ --slotted-import-export-center-inset-inline-md,
46
+ var(--slotted-space-6, 1rem)
47
+ );
48
+ --_inset-block: var(
49
+ --slotted-import-export-center-inset-block-md,
50
+ var(--slotted-space-5, 0.75rem)
51
+ );
52
+ --_gap: var(--slotted-import-export-center-gap-md, var(--slotted-space-5, 0.75rem));
53
+ --_title-size: var(--slotted-font-size-lg, 1rem);
54
+ --_title-line-height: var(--slotted-line-height-lg, 1.5);
55
+ --_job-title-size: var(--slotted-font-size-md, 0.875rem);
56
+ --_job-title-line-height: var(--slotted-line-height-md, 1.5);
57
+ --_meta-size: var(--slotted-font-size-sm, 0.8125rem);
58
+ --_meta-line-height: var(--slotted-line-height-sm, 1.45);
59
+ --_small-size: var(--slotted-font-size-xs, 0.75rem);
60
+ --_small-line-height: var(--slotted-line-height-xs, 1.4);
61
+ /**
62
+ * The tile: two glyphs wide at the control scale, which is the square
63
+ * `upload` draws a file in. A CSV is the same tile in the field it was
64
+ * chosen from and in the job that imports it.
65
+ */
66
+ --_glyph: var(--slotted-control-icon-size-md, 16px);
67
+ --_tile: calc(2 * var(--_glyph));
68
+ /** The family's own icon control: the glyph at the small step, the box capped by the inner-control scale. */
69
+ --_control-glyph: var(--slotted-control-icon-size-sm, 14px);
70
+ --_control: min(
71
+ calc(var(--_control-glyph) + 2 * var(--slotted-space-2, 0.25rem)),
72
+ var(--slotted-control-inner-size-md, 24px)
73
+ );
74
+ /** A count beside words: the chip `notification-center` draws, a step below the meta size. */
75
+ --_count-size: var(--slotted-font-size-xs, 0.75rem);
76
+ --_count-box: calc(
77
+ var(--_count-size) + 2 * var(--slotted-space-1, 0.125rem) + 2 *
78
+ var(--slotted-border-width-thin, 1px)
79
+ );
80
+ --_rule-size: var(--slotted-border-width-thin, 1px);
81
+ /**
82
+ * The air between a status mark and its words. A step below the 8 pixels
83
+ * the other marks keep: this mark is the line's own size, 13 pixels at
84
+ * `md`, and its artwork is inset a pixel inside its box, so eight read as
85
+ * a gap the eye had to cross.
86
+ */
87
+ --_mark-gap: var(--slotted-space-3, 0.375rem);
88
+ /** The dot between two items of a line, and the gap it hangs in. */
89
+ --_separator: 3px;
90
+ --_separator-gap: var(--slotted-space-5, 0.75rem);
91
+ /** The narrowest the status column may be in the wide job: its controls fit on one line. */
92
+ --_status-column: var(--slotted-import-export-center-status-column, 16rem);
93
+ --_duration: var(--slotted-control-transition-duration);
94
+ --_easing: var(--slotted-control-transition-easing);
95
+
96
+ background-color: var(--_ground);
97
+ color: var(--_text);
98
+ container-name: import-export-center;
99
+ container-type: inline-size;
100
+ display: flex;
101
+ flex-direction: column;
102
+ font-family: var(--slotted-font-family-sans, ui-sans-serif, system-ui, sans-serif);
103
+ min-inline-size: 0;
104
+ }
105
+
106
+ /**
107
+ * The popover's and the drawer's step. A root with inline-size containment
108
+ * contributes no intrinsic width, so inside a panel sized to its content it
109
+ * would collapse to nothing; `sm` states a floor capped by the viewport, as
110
+ * `notification-center` does for the same host.
111
+ */
112
+ [data-ui='import-export-center'][data-size='sm'] {
113
+ min-inline-size: var(
114
+ --slotted-import-export-center-min-inline-size-sm,
115
+ min(24rem, calc(100vw - var(--slotted-space-8, 2rem)))
116
+ );
117
+ --_inset-inline: var(
118
+ --slotted-import-export-center-inset-inline-sm,
119
+ var(--slotted-space-5, 0.75rem)
120
+ );
121
+ --_inset-block: var(
122
+ --slotted-import-export-center-inset-block-sm,
123
+ var(--slotted-space-4, 0.5rem)
124
+ );
125
+ --_gap: var(--slotted-import-export-center-gap-sm, var(--slotted-space-4, 0.5rem));
126
+ --_title-size: var(--slotted-font-size-md, 0.875rem);
127
+ --_title-line-height: var(--slotted-line-height-md, 1.5);
128
+ --_job-title-size: var(--slotted-font-size-sm, 0.8125rem);
129
+ --_job-title-line-height: var(--slotted-line-height-sm, 1.45);
130
+ --_meta-size: var(--slotted-font-size-xs, 0.75rem);
131
+ --_meta-line-height: var(--slotted-line-height-xs, 1.4);
132
+ --_glyph: var(--slotted-control-icon-size-sm, 14px);
133
+ --_control: min(
134
+ calc(var(--_control-glyph) + 2 * var(--slotted-space-2, 0.25rem)),
135
+ var(--slotted-control-inner-size-sm, 22px)
136
+ );
137
+ }
138
+
139
+ /* ── The header ──────────────────────────────────────────────────────── */
140
+
141
+ /**
142
+ * The title pushes the rest to the end; a control that wraps lands at the
143
+ * end of its own line, under the one before it.
144
+ */
145
+ [data-ui='import-export-center'] > [data-part='header'] {
146
+ align-items: center;
147
+ border-block-end: var(--_rule-size) solid var(--_rule);
148
+ display: flex;
149
+ flex-wrap: wrap;
150
+ gap: var(--slotted-space-3, 0.375rem) var(--_gap);
151
+ justify-content: flex-end;
152
+ min-inline-size: 0;
153
+ padding-block: var(--_inset-block);
154
+ padding-inline: var(--_inset-inline);
155
+ }
156
+
157
+ [data-ui='import-export-center'] > [data-part='header'] > [data-part='title'] {
158
+ align-items: center;
159
+ color: var(--_text);
160
+ display: inline-flex;
161
+ flex-wrap: wrap;
162
+ font-family: var(
163
+ --slotted-font-family-heading,
164
+ var(--slotted-font-family-sans, ui-sans-serif, system-ui, sans-serif)
165
+ );
166
+ font-size: var(--_title-size);
167
+ font-weight: var(--slotted-font-weight-semibold, 600);
168
+ gap: var(--slotted-space-3, 0.375rem);
169
+ letter-spacing: -0.01em;
170
+ line-height: var(--_title-line-height);
171
+ margin: 0;
172
+ margin-inline-end: auto;
173
+ min-inline-size: 0;
174
+ }
175
+
176
+ /**
177
+ * How many jobs are still moving: a chip on the smallest type step in
178
+ * tabular figures, in the accent pair, because what it counts is what is
179
+ * running. Absent at nought.
180
+ */
181
+ [data-ui='import-export-center']
182
+ > [data-part='header']
183
+ > [data-part='title']
184
+ > [data-part='count'] {
185
+ align-items: center;
186
+ background-color: var(--slotted-tone-accent-surface, Canvas);
187
+ block-size: var(--_count-box);
188
+ border: var(--slotted-border-width-thin, 1px) solid
189
+ color-mix(in oklab, currentcolor 20%, transparent);
190
+ border-radius: var(--slotted-radius-full, 9999px);
191
+ box-sizing: border-box;
192
+ color: var(--slotted-tone-accent-text, Highlight);
193
+ display: inline-flex;
194
+ font-size: var(--_count-size);
195
+ font-variant-numeric: tabular-nums;
196
+ font-weight: var(--slotted-font-weight-semibold, 600);
197
+ justify-content: center;
198
+ letter-spacing: 0;
199
+ line-height: 1;
200
+ min-inline-size: var(--_count-box);
201
+ padding-block: 0;
202
+ padding-inline: var(--slotted-space-3, 0.375rem);
203
+ white-space: nowrap;
204
+ }
205
+
206
+ /**
207
+ * The family's clear and the consumer's actions wrap as one group, so a
208
+ * narrow header keeps the title on its line and the controls together on
209
+ * the next, at the end.
210
+ */
211
+ [data-ui='import-export-center'] > [data-part='header'] > [data-part='tools'] {
212
+ align-items: center;
213
+ display: flex;
214
+ flex-wrap: wrap;
215
+ gap: var(--slotted-control-gap-sm, 6px);
216
+ justify-content: flex-end;
217
+ min-inline-size: 0;
218
+ }
219
+
220
+ [data-ui='import-export-center'] [data-part='tools'] > [data-part='clear'],
221
+ [data-ui='import-export-center'] [data-part='tools'] > [data-part='actions'] {
222
+ align-items: center;
223
+ display: inline-flex;
224
+ flex-wrap: wrap;
225
+ gap: var(--slotted-control-gap-sm, 6px);
226
+ }
227
+
228
+ /* ── The views ───────────────────────────────────────────────────────── */
229
+
230
+ /** The strip sits on the header's rule, so the tabs family's own track is off. */
231
+ [data-ui='import-export-center'] > [data-part='views'] {
232
+ border-block-end: var(--_rule-size) solid var(--_rule);
233
+ min-inline-size: 0;
234
+ padding-inline: var(--_inset-inline);
235
+ }
236
+
237
+ /* ── The list ────────────────────────────────────────────────────────── */
238
+
239
+ /**
240
+ * The one part that gives way. A host with a height — a popover, a drawer
241
+ * — bounds the list alone and the header keeps its row; a page gets the
242
+ * whole list and no bar.
243
+ */
244
+ [data-ui='import-export-center'] > [data-part='list'] {
245
+ display: flex;
246
+ flex: 1 1 auto;
247
+ flex-direction: column;
248
+ list-style: none;
249
+ margin: 0;
250
+ min-block-size: 0;
251
+ min-inline-size: 0;
252
+ overflow-y: auto;
253
+ overscroll-behavior: contain;
254
+ padding: 0;
255
+ scrollbar-color: var(--slotted-border-strong, ButtonBorder) transparent;
256
+ scrollbar-width: thin;
257
+ }
258
+
259
+ /** The list is where focus lands when the last job it held leaves; it draws the ring inward. */
260
+ [data-ui='import-export-center'] > [data-part='list']:focus-visible {
261
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
262
+ outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
263
+ }
264
+
265
+ /* ── A job ───────────────────────────────────────────────────────────── */
266
+
267
+ /**
268
+ * The tile, the words, the controls. A rule under each, so a list of forty
269
+ * reads as rows and not as a column of cards. The tile sits on the job
270
+ * title's first line; the details, when shown, run under the words and the
271
+ * controls, never under the tile.
272
+ */
273
+ [data-ui='import-export-center'] > [data-part='list'] > [data-part='job'] {
274
+ /**
275
+ * The status, in the tone of the outcome. The rows below retune the roles;
276
+ * the status glyph itself is the binding's, chosen from the same state.
277
+ */
278
+ --_tone-text: var(--slotted-tone-secondary-text, CanvasText);
279
+ --_tone-solid: var(--slotted-tone-secondary-solid, CanvasText);
280
+
281
+ align-items: start;
282
+ border-block-end: var(--_rule-size) solid var(--_rule);
283
+ column-gap: var(--_gap);
284
+ display: grid;
285
+ grid-template-areas:
286
+ 'visual body'
287
+ 'visual controls'
288
+ '. details';
289
+ grid-template-columns: var(--_tile) minmax(0, 1fr);
290
+ min-inline-size: 0;
291
+ padding-block: var(--_inset-block);
292
+ padding-inline: var(--_inset-inline);
293
+ row-gap: var(--slotted-space-4, 0.5rem);
294
+ }
295
+
296
+ [data-ui='import-export-center'] > [data-part='list'] > [data-part='job']:last-child {
297
+ border-block-end: 0;
298
+ }
299
+
300
+ [data-ui='import-export-center'] > [data-part='list'] > [data-part='job'][data-status='running'] {
301
+ --_tone-text: var(--slotted-tone-accent-text, Highlight);
302
+ --_tone-solid: var(--slotted-tone-accent-solid, Highlight);
303
+ }
304
+
305
+ [data-ui='import-export-center']
306
+ > [data-part='list']
307
+ > [data-part='job'][data-outcome='success'] {
308
+ --_tone-text: var(--slotted-tone-success-text, CanvasText);
309
+ --_tone-solid: var(--slotted-tone-success-solid, CanvasText);
310
+ }
311
+
312
+ [data-ui='import-export-center']
313
+ > [data-part='list']
314
+ > [data-part='job'][data-outcome='partial'] {
315
+ --_tone-text: var(--slotted-tone-warning-text, CanvasText);
316
+ --_tone-solid: var(--slotted-tone-warning-solid, CanvasText);
317
+ }
318
+
319
+ [data-ui='import-export-center'] > [data-part='list'] > [data-part='job'][data-outcome='failed'] {
320
+ --_tone-text: var(--slotted-tone-danger-text, CanvasText);
321
+ --_tone-solid: var(--slotted-tone-danger-solid, CanvasText);
322
+ }
323
+
324
+ [data-ui='import-export-center']
325
+ > [data-part='list']
326
+ > [data-part='job'][data-outcome='canceled'] {
327
+ --_tone-text: var(--_muted);
328
+ --_tone-solid: var(--_muted);
329
+ }
330
+
331
+ /**
332
+ * The tile. The kind's colour from the File kind scale `upload` owns, the
333
+ * kind's glyph — an `Icon` the binding draws from the kind — knocked out of
334
+ * it in the scale's foreground. Aligned to the job title's first line box,
335
+ * so the tile and the name start on one line.
336
+ */
337
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'] {
338
+ --_kind-tile: var(--slotted-upload-kind-other);
339
+ --slotted-icon-size: var(--_glyph);
340
+
341
+ align-items: center;
342
+ background-color: var(--_kind-tile);
343
+ block-size: var(--_tile);
344
+ border-radius: var(--slotted-radius-sm, 4px);
345
+ color: var(--slotted-upload-kind-foreground);
346
+ display: inline-flex;
347
+ grid-area: visual;
348
+ inline-size: var(--_tile);
349
+ justify-content: center;
350
+ /*
351
+ * Centred on the name and the first line of meta, the pair the eye reads
352
+ * as the job's label, rather than hung from the name's line box: the tile
353
+ * is shorter than the two lines, and top-aligned it stood above them.
354
+ */
355
+ margin-block-start: round(
356
+ nearest,
357
+ calc(
358
+ (
359
+ var(--_job-title-size) * var(--_job-title-line-height) + var(--_meta-size) *
360
+ var(--_meta-line-height) - var(--_tile)
361
+ ) /
362
+ 2
363
+ ),
364
+ 1px
365
+ );
366
+ }
367
+
368
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'][data-kind='pdf'] {
369
+ --_kind-tile: var(--slotted-upload-kind-pdf);
370
+ }
371
+
372
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'][data-kind='document'] {
373
+ --_kind-tile: var(--slotted-upload-kind-document);
374
+ }
375
+
376
+ [data-ui='import-export-center']
377
+ [data-part='job']
378
+ > [data-part='visual'][data-kind='spreadsheet'] {
379
+ --_kind-tile: var(--slotted-upload-kind-spreadsheet);
380
+ }
381
+
382
+ [data-ui='import-export-center']
383
+ [data-part='job']
384
+ > [data-part='visual'][data-kind='presentation'] {
385
+ --_kind-tile: var(--slotted-upload-kind-presentation);
386
+ }
387
+
388
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'][data-kind='image'] {
389
+ --_kind-tile: var(--slotted-upload-kind-image);
390
+ }
391
+
392
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'][data-kind='video'] {
393
+ --_kind-tile: var(--slotted-upload-kind-video);
394
+ }
395
+
396
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'][data-kind='audio'] {
397
+ --_kind-tile: var(--slotted-upload-kind-audio);
398
+ }
399
+
400
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'][data-kind='archive'] {
401
+ --_kind-tile: var(--slotted-upload-kind-archive);
402
+ }
403
+
404
+ /* ── What a job says ─────────────────────────────────────────────────── */
405
+
406
+ /**
407
+ * The column that shrinks. Its rows are the heading, the status, the bar,
408
+ * the summary and the message, each present only when it has something to
409
+ * say; the gap between them is the one the meta line keeps from the title.
410
+ */
411
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='body'] {
412
+ display: grid;
413
+ gap: var(--slotted-space-3, 0.375rem);
414
+ grid-area: body;
415
+ grid-template-columns: minmax(0, 1fr);
416
+ min-inline-size: 0;
417
+ }
418
+
419
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='body'] > [data-part='heading'] {
420
+ display: flex;
421
+ flex-direction: column;
422
+ gap: var(--slotted-space-1, 0.125rem);
423
+ min-inline-size: 0;
424
+ }
425
+
426
+ /**
427
+ * The job's name, on the line the tile's top edge is aligned with: the
428
+ * tile is two glyphs tall and the name's line box is shorter, so the name
429
+ * is set on a line of the tile's own height, and the meta line under it
430
+ * starts where the tile ends.
431
+ */
432
+ [data-ui='import-export-center'] [data-part='heading'] > [data-part='job-title'] {
433
+ align-self: flex-start;
434
+ color: var(--_text);
435
+ font-size: var(--_job-title-size);
436
+ font-weight: var(--slotted-font-weight-semibold, 600);
437
+ line-height: var(--_job-title-line-height);
438
+ min-inline-size: 0;
439
+ overflow-wrap: anywhere;
440
+ }
441
+
442
+ [data-ui='import-export-center'] [data-part='heading'] > a[data-part='job-title'] {
443
+ border-radius: var(--slotted-radius-xs, 2px);
444
+ text-decoration-color: transparent;
445
+ text-decoration-line: underline;
446
+ text-decoration-thickness: from-font;
447
+ text-underline-offset: 0.2em;
448
+ transition: text-decoration-color var(--_duration) var(--_easing);
449
+ }
450
+
451
+ [data-ui='import-export-center']
452
+ [data-part='heading']
453
+ > a[data-part='job-title']:not([data-disabled]):hover {
454
+ text-decoration-color: currentcolor;
455
+ }
456
+
457
+ [data-ui='import-export-center'] [data-part='heading'] > a[data-part='job-title']:focus-visible {
458
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
459
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
460
+ }
461
+
462
+ /** A title the family focuses — reveal(), a withdrawn control — without making it a tab stop. */
463
+ [data-ui='import-export-center']
464
+ [data-part='heading']
465
+ > span[data-part='job-title']:focus-visible {
466
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
467
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
468
+ }
469
+
470
+ /**
471
+ * What the job is about, in the muted voice on one line that wraps between
472
+ * its items and never inside one: direction, format, the file, its size,
473
+ * who ran it, when. The items are separated by a dot drawn as a shape — a
474
+ * character in `content` would be read aloud — hung in the middle of the
475
+ * gap before each item. The line clips its inline overflow, so the dot of
476
+ * an item that wrapped to the start of a line hangs outside the box and is
477
+ * not drawn: a line never begins with a separator.
478
+ */
479
+ [data-ui='import-export-center'] [data-part='heading'] > [data-part='meta'] {
480
+ align-items: baseline;
481
+ color: var(--_muted);
482
+ display: flex;
483
+ flex-wrap: wrap;
484
+ font-size: var(--_meta-size);
485
+ gap: 0 var(--_separator-gap);
486
+ line-height: var(--_meta-line-height);
487
+ margin: 0;
488
+ min-inline-size: 0;
489
+ overflow-x: clip;
490
+ }
491
+
492
+ /**
493
+ * An item of a secondary line wraps as a unit — "1.204 de 5.000 linhas"
494
+ * never leaves "linhas" alone on the next line — and an item longer than
495
+ * the whole line shrinks to an ellipsis rather than overflowing it.
496
+ *
497
+ * The item clips with a margin the width of the gap, so the separator it
498
+ * hangs in that gap is still painted; `overflow: hidden` cut the dot off.
499
+ * The margin is a bare `var()`: a `calc()` there computes to nought
500
+ * (`docs/token-foundation.md`, rule 7).
501
+ */
502
+ [data-ui='import-export-center'] [data-part='meta'] > *,
503
+ [data-ui='import-export-center'] [data-part='summary'] > *,
504
+ [data-ui='import-export-center'] [data-part='progress-text'] > * {
505
+ max-inline-size: 100%;
506
+ min-inline-size: 0;
507
+ overflow: clip;
508
+ overflow-clip-margin: var(--_separator-gap);
509
+ text-overflow: ellipsis;
510
+ white-space: nowrap;
511
+ }
512
+
513
+ [data-ui='import-export-center'] [data-part='meta'] > * + *::before,
514
+ [data-ui='import-export-center'] [data-part='summary'] > * + *::before,
515
+ [data-ui='import-export-center'] [data-part='progress-text'] > * + *::before,
516
+ [data-ui='import-export-center'] [data-part='status-label'] > [data-part='stage']::before {
517
+ background-color: currentcolor;
518
+ block-size: var(--_separator);
519
+ border-radius: var(--slotted-radius-full, 9999px);
520
+ content: '';
521
+ display: inline-block;
522
+ inline-size: var(--_separator);
523
+ /* Hung in the middle of the gap before the item: the two margins add up to
524
+ minus the dot's own width, so the words do not move. */
525
+ margin-inline-end: calc((var(--_separator-gap) - var(--_separator)) / 2);
526
+ margin-inline-start: calc((var(--_separator-gap) + var(--_separator)) / -2);
527
+ opacity: 0.6;
528
+ /* The dot's centre on the middle of the x-height, measured from the
529
+ baseline rather than from the line box, so it sits where the lowercase
530
+ letters are at every size and in every face. */
531
+ vertical-align: calc(0.5ex - var(--_separator) / 2);
532
+ }
533
+
534
+ /**
535
+ * A file name is content the family did not choose. The stem shrinks with
536
+ * an ellipsis and the extension does not, so the part that says what the
537
+ * file is survives; the whole name stays in the DOM. The run is one
538
+ * bidi-isolated item in the name's own direction.
539
+ */
540
+ /*
541
+ * The name is one item of the line, and the item is a plain span in the
542
+ * line's own direction: the separator hangs on the item's inline start, and
543
+ * an item carrying `dir="auto"` would hang it on the wrong side of an
544
+ * Arabic name in a left-to-right page.
545
+ */
546
+ [data-ui='import-export-center'] [data-part='meta'] > :has(> [data-part='file-name']) {
547
+ max-inline-size: 100%;
548
+ white-space: nowrap;
549
+ }
550
+
551
+ [data-ui='import-export-center'] [data-part='meta'] [data-part='file-name'] {
552
+ display: inline-flex;
553
+ max-inline-size: 100%;
554
+ min-inline-size: 0;
555
+ unicode-bidi: isolate;
556
+ }
557
+
558
+ [data-ui='import-export-center'] [data-part='file-name'] > [data-part='name'] {
559
+ min-inline-size: 1ch;
560
+ overflow: hidden;
561
+ text-overflow: ellipsis;
562
+ white-space: nowrap;
563
+ }
564
+
565
+ [data-ui='import-export-center'] [data-part='file-name'] > [data-part='extension'] {
566
+ flex: none;
567
+ white-space: nowrap;
568
+ }
569
+
570
+ [data-ui='import-export-center'] [data-part='meta'] > [data-part='time'] {
571
+ font-variant-numeric: tabular-nums;
572
+ white-space: nowrap;
573
+ }
574
+
575
+ /**
576
+ * The status line: the mark, the word in the outcome's tone, and the
577
+ * consumer's stage in the muted voice. The mark takes the line's own size
578
+ * and sits a step of air before the word.
579
+ *
580
+ * It is centred on the band `toast` measured for a mark beside a line of
581
+ * text: the midpoint of the cap height and the x-height, `(1cap + 1ex) / 2`
582
+ * tall from the baseline, so the mark's centre is half that band above the
583
+ * baseline. The box is baseline-aligned — its bottom edge on the baseline,
584
+ * its centre `0.5em` above it — and moved down by the difference, rounded
585
+ * to a whole pixel so the mark snaps with the glyphs beside it. The first
586
+ * version put the centre on the band's top instead of its middle, and the
587
+ * mark stood four pixels above the words at every size.
588
+ */
589
+ [data-ui='import-export-center'] [data-part='body'] > [data-part='status'] {
590
+ align-items: baseline;
591
+ color: var(--_tone-text);
592
+ column-gap: var(--_mark-gap);
593
+ display: grid;
594
+ font-size: var(--_meta-size);
595
+ font-weight: var(--slotted-font-weight-medium, 500);
596
+ grid-template-columns: auto minmax(0, 1fr);
597
+ line-height: var(--_meta-line-height);
598
+ min-inline-size: 0;
599
+ }
600
+
601
+ /**
602
+ * The mark has a column of its own and the words the column beside it, so
603
+ * the two never part: a narrow job wraps the words inside their column,
604
+ * under the first word and never under the mark.
605
+ */
606
+ [data-ui='import-export-center'] [data-part='status'] > [data-part='mark'] {
607
+ --slotted-icon-size: 1em;
608
+ --slotted-spinner-size: 1em;
609
+
610
+ align-self: baseline;
611
+ block-size: 1em;
612
+ inline-size: 1em;
613
+ position: relative;
614
+ inset-block-start: round(nearest, calc(0.5em - (1cap + 1ex) / 4), 1px);
615
+ }
616
+
617
+ /**
618
+ * The word and the stage, one run: the stage follows the word on its line
619
+ * while there is room and starts the next line flush with the word when
620
+ * there is not, its separator clipped as the meta line clips its own.
621
+ */
622
+ [data-ui='import-export-center'] [data-part='status'] > [data-part='status-label'] {
623
+ align-items: baseline;
624
+ display: flex;
625
+ flex-wrap: wrap;
626
+ gap: 0 var(--_separator-gap);
627
+ min-inline-size: 0;
628
+ overflow-wrap: anywhere;
629
+ overflow-x: clip;
630
+ }
631
+
632
+ [data-ui='import-export-center'] [data-part='status-label'] > * {
633
+ min-inline-size: 0;
634
+ }
635
+
636
+ /**
637
+ * The stage is one line. It is the consumer's phrase for what the server is
638
+ * doing now, it changes while the reader watches, and five wrapped lines of
639
+ * it at a narrow width pushed the bar out of the row. It shrinks to an
640
+ * ellipsis on its own line when it does not fit beside the word; the whole
641
+ * phrase stays in the DOM, and the binding repeats it in `title`.
642
+ */
643
+ [data-ui='import-export-center'] [data-part='status-label'] > [data-part='stage'] {
644
+ max-inline-size: 100%;
645
+ overflow: clip;
646
+ overflow-clip-margin: var(--_separator-gap);
647
+ text-overflow: ellipsis;
648
+ white-space: nowrap;
649
+ }
650
+
651
+ /*
652
+ * The icon fills the mark out of flow. The mark then has no content to take
653
+ * a baseline from, so it sits on the line by its bottom edge, which is what
654
+ * the offset above measures from; an icon in flow gave the mark the icon's
655
+ * baseline and raised it off the line.
656
+ */
657
+ [data-ui='import-export-center'] [data-part='status'] > [data-part='mark'] > [data-ui='icon'],
658
+ [data-ui='import-export-center'] [data-part='status'] > [data-part='mark'] > [data-ui='spinner'] {
659
+ inset: 0;
660
+ position: absolute;
661
+ }
662
+
663
+ [data-ui='import-export-center'] [data-part='status-label'] > [data-part='stage'] {
664
+ color: var(--_muted);
665
+ font-weight: var(--slotted-font-weight-regular, 400);
666
+ }
667
+
668
+ /**
669
+ * A running job's mark is `spinner`, the ring every family shows for an
670
+ * indeterminate wait: an arc that opens and closes around a faint track,
671
+ * repainted by angle rather than a glyph set turning. It stands in the
672
+ * glyph's box at the glyph's size — the ring keeps the inset the icon set
673
+ * keeps — so the running line and the finished line are one measure, and
674
+ * it freezes on its own track under reduced motion. The first version
675
+ * turned `loader-circle` here, the static arc the spinner was built to
676
+ * replace.
677
+ */
678
+
679
+ /**
680
+ * The bar and what it measures. The bar is `progress-indicator`'s, at its
681
+ * small step; the words beside it are the family's, in tabular figures so
682
+ * a number that moves does not move the rest of the line.
683
+ */
684
+ [data-ui='import-export-center'] [data-part='body'] > [data-part='progress'] {
685
+ display: grid;
686
+ gap: var(--slotted-space-2, 0.25rem);
687
+ min-inline-size: 0;
688
+ }
689
+
690
+ [data-ui='import-export-center'] [data-part='progress'] > [data-part='progress-text'] {
691
+ color: var(--_muted);
692
+ display: flex;
693
+ flex-wrap: wrap;
694
+ gap: 0 var(--_separator-gap);
695
+ overflow-x: clip;
696
+ font-size: var(--_small-size);
697
+ font-variant-numeric: tabular-nums;
698
+ line-height: var(--_small-line-height);
699
+ min-inline-size: 0;
700
+ }
701
+
702
+ [data-ui='import-export-center'] [data-part='body'] > [data-part='summary'] {
703
+ color: var(--_muted);
704
+ display: flex;
705
+ flex-wrap: wrap;
706
+ gap: 0 var(--_separator-gap);
707
+ overflow-x: clip;
708
+ font-size: var(--_meta-size);
709
+ font-variant-numeric: tabular-nums;
710
+ line-height: var(--_meta-line-height);
711
+ margin: 0;
712
+ min-inline-size: 0;
713
+ }
714
+
715
+ /**
716
+ * The sentence about the job. A failure and a partial result say it in
717
+ * the outcome's tone, because it is what went wrong; an expiry or a
718
+ * permission says it in the muted voice, because it is what to know.
719
+ */
720
+ [data-ui='import-export-center'] [data-part='body'] > [data-part='message'] {
721
+ color: var(--_muted);
722
+ font-size: var(--_meta-size);
723
+ line-height: var(--_meta-line-height);
724
+ margin: 0;
725
+ min-inline-size: 0;
726
+ overflow-wrap: anywhere;
727
+ }
728
+
729
+ [data-ui='import-export-center']
730
+ [data-part='job'][data-outcome='failed']
731
+ [data-part='body']
732
+ > [data-part='message'],
733
+ [data-ui='import-export-center']
734
+ [data-part='job'][data-outcome='partial']
735
+ [data-part='body']
736
+ > [data-part='message'] {
737
+ color: var(--_tone-text);
738
+ }
739
+
740
+ /* ── The controls ────────────────────────────────────────────────────── */
741
+
742
+ /**
743
+ * Under the words, from the words' own edge. The family's text controls
744
+ * are `button`'s at its small step, each in a slot named for the part; the
745
+ * remove control is the family's own icon button and sits at the far end,
746
+ * away from the controls that start something.
747
+ */
748
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='controls'] {
749
+ align-items: center;
750
+ display: flex;
751
+ flex-wrap: wrap;
752
+ gap: var(--slotted-control-gap-sm, 6px);
753
+ grid-area: controls;
754
+ min-inline-size: 0;
755
+ }
756
+
757
+ [data-ui='import-export-center'] [data-part='controls'] > [data-part='download'],
758
+ [data-ui='import-export-center'] [data-part='controls'] > [data-part='cancel'],
759
+ [data-ui='import-export-center'] [data-part='controls'] > [data-part='retry'],
760
+ [data-ui='import-export-center'] [data-part='controls'] > [data-part='toggle'],
761
+ [data-ui='import-export-center'] [data-part='controls'] > [data-part='job-actions'] {
762
+ align-items: center;
763
+ display: inline-flex;
764
+ gap: var(--slotted-control-gap-sm, 6px);
765
+ }
766
+
767
+ [data-ui='import-export-center'] [data-part='controls'] > [data-part='remove'] {
768
+ margin-inline-start: auto;
769
+ }
770
+
771
+ /**
772
+ * The disclosure's mark, inside the button's end slot: a chevron that
773
+ * turns to point at the details it opened. The turn is a state the eye
774
+ * follows, so it carries the control's own transition.
775
+ */
776
+ [data-ui='import-export-center'] [data-part='toggle'] [data-part='chevron'] {
777
+ --slotted-icon-size: var(--_control-glyph);
778
+
779
+ block-size: var(--_control-glyph);
780
+ display: flex;
781
+ inline-size: var(--_control-glyph);
782
+ transition: transform var(--_duration) var(--_easing);
783
+ }
784
+
785
+ [data-ui='import-export-center'] [data-part='toggle'][data-expanded] [data-part='chevron'] {
786
+ transform: rotate(180deg);
787
+ }
788
+
789
+ /** The family's own icon control: muted at rest, the text ink under the pointer. */
790
+ [data-ui='import-export-center'] button[data-part='remove'] {
791
+ align-items: center;
792
+ appearance: none;
793
+ background-color: transparent;
794
+ block-size: var(--_control);
795
+ border: 0;
796
+ border-radius: var(--slotted-control-radius, 4px);
797
+ color: var(--_muted);
798
+ cursor: pointer;
799
+ display: inline-flex;
800
+ flex: none;
801
+ inline-size: var(--_control);
802
+ justify-content: center;
803
+ padding: 0;
804
+ position: relative;
805
+ transition:
806
+ background-color var(--_duration) var(--_easing),
807
+ color var(--_duration) var(--_easing);
808
+ }
809
+
810
+ /** The target reaches the WCAG minimum through a transparent halo, as every inner control does. */
811
+ [data-ui='import-export-center'] button[data-part='remove']::after {
812
+ content: '';
813
+ inset: min(0px, calc((var(--_control) - var(--slotted-target-min, 24px)) / 2));
814
+ position: absolute;
815
+ }
816
+
817
+ /* The cross is an `Icon` the binding draws inside the control. */
818
+ [data-ui='import-export-center'] button[data-part='remove'] > [data-ui='icon'] {
819
+ --slotted-icon-size: var(--_control-glyph);
820
+ }
821
+
822
+ [data-ui='import-export-center'] button[data-part='remove']:not([data-disabled]):hover {
823
+ background-color: var(--_hover);
824
+ color: var(--_text);
825
+ }
826
+
827
+ [data-ui='import-export-center'] button[data-part='remove']:not([data-disabled]):active {
828
+ background-color: var(--_active);
829
+ }
830
+
831
+ [data-ui='import-export-center'] button[data-part='remove']:focus-visible {
832
+ color: var(--_text);
833
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
834
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
835
+ }
836
+
837
+ /* ── The details ─────────────────────────────────────────────────────── */
838
+
839
+ /**
840
+ * What the toggle shows, under the words and the controls: the counts, the
841
+ * files and the rows that failed, on the sunken ground so the region reads
842
+ * as the job's own and not as the next job.
843
+ */
844
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='details'] {
845
+ background-color: var(--slotted-surface-sunken, Canvas);
846
+ /* The family's rule as the region's edge: faint on the sunken ground in light and dark, and the one separation left where high-contrast paints the sunken ground as the page. */
847
+ border: var(--_rule-size) solid var(--_rule);
848
+ border-radius: var(--slotted-radius-md, 6px);
849
+ display: grid;
850
+ gap: var(--_gap);
851
+ grid-area: details;
852
+ grid-template-columns: minmax(0, 1fr);
853
+ min-inline-size: 0;
854
+ padding-block: var(--slotted-space-5, 0.75rem);
855
+ padding-inline: var(--slotted-space-5, 0.75rem);
856
+ }
857
+
858
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='details'][hidden] {
859
+ display: none;
860
+ }
861
+
862
+ /**
863
+ * The counts: figures a reader compares, so each is a label over a
864
+ * number, in tabular figures, laid out in as many columns as fit.
865
+ */
866
+ [data-ui='import-export-center'] [data-part='details'] > [data-part='counts'] {
867
+ display: grid;
868
+ gap: var(--slotted-space-4, 0.5rem) var(--slotted-space-7, 1.25rem);
869
+ grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
870
+ margin: 0;
871
+ min-inline-size: 0;
872
+ }
873
+
874
+ [data-ui='import-export-center'] [data-part='counts'] > div {
875
+ display: flex;
876
+ flex-direction: column;
877
+ gap: var(--slotted-space-1, 0.125rem);
878
+ min-inline-size: 0;
879
+ }
880
+
881
+ [data-ui='import-export-center'] [data-part='counts'] dt {
882
+ color: var(--_muted);
883
+ font-size: var(--_small-size);
884
+ line-height: var(--_small-line-height);
885
+ }
886
+
887
+ [data-ui='import-export-center'] [data-part='counts'] dd {
888
+ color: var(--_text);
889
+ font-size: var(--_job-title-size);
890
+ font-variant-numeric: tabular-nums;
891
+ font-weight: var(--slotted-font-weight-semibold, 600);
892
+ line-height: var(--_job-title-line-height);
893
+ margin: 0;
894
+ }
895
+
896
+ [data-ui='import-export-center'] [data-part='counts'] > div[data-count='failed'] dd {
897
+ color: var(--slotted-tone-danger-text, CanvasText);
898
+ }
899
+
900
+ /** The files: one row each — what the file is, its name, its availability, its control. */
901
+ [data-ui='import-export-center'] [data-part='details'] > [data-part='files'] {
902
+ display: grid;
903
+ gap: var(--slotted-space-3, 0.375rem);
904
+ list-style: none;
905
+ margin: 0;
906
+ min-inline-size: 0;
907
+ padding: 0;
908
+ }
909
+
910
+ [data-ui='import-export-center'] [data-part='files'] > [data-part='file'] {
911
+ align-items: center;
912
+ display: flex;
913
+ flex-wrap: wrap;
914
+ font-size: var(--_meta-size);
915
+ gap: var(--slotted-space-2, 0.25rem) var(--slotted-space-4, 0.5rem);
916
+ justify-content: space-between;
917
+ line-height: var(--_meta-line-height);
918
+ min-inline-size: 0;
919
+ }
920
+
921
+ /** The words take the row and the control follows them; a row too narrow for both puts the control under them. */
922
+ [data-ui='import-export-center'] [data-part='file'] > [data-part='meta'] {
923
+ flex: 1 1 14rem;
924
+ align-items: baseline;
925
+ color: var(--_muted);
926
+ display: flex;
927
+ flex-wrap: wrap;
928
+ gap: 0 var(--_separator-gap);
929
+ min-inline-size: 0;
930
+ overflow-x: clip;
931
+ }
932
+
933
+ [data-ui='import-export-center'] [data-part='file'] > [data-part='meta'] > strong {
934
+ color: var(--_text);
935
+ font-weight: var(--slotted-font-weight-medium, 500);
936
+ }
937
+
938
+ [data-ui='import-export-center'] [data-part='file'] > [data-part='download'] {
939
+ display: inline-flex;
940
+ }
941
+
942
+ /**
943
+ * The rows that failed: `table`'s, framed, in a box of a stated block
944
+ * size that scrolls, so twelve thousand rows do not become the page. The
945
+ * caption is the table's; the note under it is the family's.
946
+ */
947
+ [data-ui='import-export-center'] [data-part='details'] > [data-part='errors'] {
948
+ display: grid;
949
+ gap: var(--slotted-space-3, 0.375rem);
950
+ min-inline-size: 0;
951
+ }
952
+
953
+ [data-ui='import-export-center'] [data-part='errors'] > [data-ui='table'] {
954
+ max-block-size: var(--slotted-import-export-center-errors-max-block-size, 16rem);
955
+ min-inline-size: 0;
956
+ overflow: auto;
957
+ }
958
+
959
+ [data-ui='import-export-center'] [data-part='errors'] > [data-part='errors-note'] {
960
+ align-items: center;
961
+ color: var(--_muted);
962
+ display: flex;
963
+ flex-wrap: wrap;
964
+ font-size: var(--_small-size);
965
+ gap: var(--slotted-space-3, 0.375rem) var(--slotted-space-5, 0.75rem);
966
+ justify-content: space-between;
967
+ line-height: var(--_small-line-height);
968
+ margin: 0;
969
+ }
970
+
971
+ /* ── More, empty, error, footer ──────────────────────────────────────── */
972
+
973
+ /** The end of what has been loaded: a pill on the control scale, the idiom `notification-center` set. */
974
+ [data-ui='import-export-center'] > button[data-part='more'] {
975
+ align-items: center;
976
+ appearance: none;
977
+ background-color: var(--_ground);
978
+ border: var(--_rule-size) solid var(--_rule);
979
+ border-radius: var(--slotted-radius-full, 9999px);
980
+ color: var(--_text);
981
+ cursor: pointer;
982
+ display: flex;
983
+ font: inherit;
984
+ font-size: var(--_meta-size);
985
+ font-weight: var(--slotted-font-weight-medium, 500);
986
+ gap: var(--slotted-control-gap-sm, 6px);
987
+ inline-size: fit-content;
988
+ justify-content: center;
989
+ line-height: var(--slotted-control-line-height, 1);
990
+ margin-block: var(--_inset-block);
991
+ margin-inline: auto;
992
+ min-block-size: var(--slotted-control-height-sm, 30px);
993
+ padding-inline: var(--slotted-control-padding-inline-md, 13px);
994
+ transition:
995
+ background-color var(--_duration) var(--_easing),
996
+ border-color var(--_duration) var(--_easing);
997
+ }
998
+
999
+ [data-ui='import-export-center'] > button[data-part='more']:not([data-loading]):enabled:hover {
1000
+ background-color: var(--_hover);
1001
+ }
1002
+
1003
+ [data-ui='import-export-center'] > button[data-part='more']:not([data-loading]):enabled:active {
1004
+ background-color: var(--_active);
1005
+ }
1006
+
1007
+ [data-ui='import-export-center'] > button[data-part='more'][data-loading] {
1008
+ color: var(--_muted);
1009
+ cursor: progress;
1010
+ }
1011
+
1012
+ [data-ui='import-export-center'] > button[data-part='more']:focus-visible {
1013
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
1014
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
1015
+ }
1016
+
1017
+ [data-ui='import-export-center'] > [data-part='empty'],
1018
+ [data-ui='import-export-center'] > [data-part='error'] {
1019
+ min-inline-size: 0;
1020
+ padding-block: var(--slotted-space-9, 2rem);
1021
+ padding-inline: var(--_inset-inline);
1022
+ }
1023
+
1024
+ [data-ui='import-export-center'] > [data-part='footer'] {
1025
+ align-items: center;
1026
+ border-block-start: var(--_rule-size) solid var(--_rule);
1027
+ display: flex;
1028
+ flex-wrap: wrap;
1029
+ font-size: var(--_meta-size);
1030
+ gap: var(--_gap);
1031
+ justify-content: center;
1032
+ line-height: var(--_meta-line-height);
1033
+ padding-block: var(--_inset-block);
1034
+ padding-inline: var(--_inset-inline);
1035
+ }
1036
+
1037
+ /* ── Loading ─────────────────────────────────────────────────────────── */
1038
+
1039
+ /**
1040
+ * The first wait: skeleton jobs with the anatomy of a job — the tile, the
1041
+ * name, the meta line and the bar — in the boxes the loaded jobs occupy.
1042
+ */
1043
+ [data-ui='import-export-center']
1044
+ > [data-part='list']
1045
+ > [data-part='job'][aria-hidden='true']
1046
+ > [data-part='visual'] {
1047
+ background-color: transparent;
1048
+ }
1049
+
1050
+ [data-ui='import-export-center']
1051
+ [data-part='job'][aria-hidden='true']
1052
+ > [data-part='visual']
1053
+ > [data-ui='skeleton'] {
1054
+ block-size: 100%;
1055
+ inline-size: 100%;
1056
+ }
1057
+
1058
+ /**
1059
+ * Below 22rem the details give up the tile's column: a table of errors
1060
+ * needs the width more than the edge needs to line up with the words.
1061
+ */
1062
+ @container import-export-center (inline-size < 22rem) {
1063
+ [data-ui='import-export-center'] > [data-part='list'] > [data-part='job'] {
1064
+ grid-template-areas:
1065
+ 'visual body'
1066
+ 'visual controls'
1067
+ 'details details';
1068
+ }
1069
+ }
1070
+
1071
+ /* ── The wide job ────────────────────────────────────────────────────── */
1072
+
1073
+ /**
1074
+ * From 42rem the list is one grid and every job a subgrid of it, so the
1075
+ * columns line up down the whole list: the tile, the name and its meta,
1076
+ * and the status column — the state, the bar, the summary, the message and
1077
+ * under them the controls. A list of jobs then reads as a table with one
1078
+ * edge of names and one of states, and the remove control of every job
1079
+ * sits on one line at the end. The body lets its parts into the job's
1080
+ * grid (`display: contents`; a div has no semantics to lose), the heading
1081
+ * spans the status column's rows, and the details run under both.
1082
+ *
1083
+ * The tile's track is `auto`: a subgrid's padding is added to its edge
1084
+ * tracks, and a track stated at the tile's width could not hold it.
1085
+ *
1086
+ * The job's rows have no gap, because an empty row would still hold one;
1087
+ * the status column spaces its own parts instead.
1088
+ */
1089
+ @container import-export-center (inline-size >= 42rem) {
1090
+ [data-ui='import-export-center'] > [data-part='list'] {
1091
+ column-gap: var(--_gap);
1092
+ display: grid;
1093
+ grid-template-columns: auto minmax(0, 6fr) minmax(var(--_status-column), 5fr);
1094
+ }
1095
+
1096
+ [data-ui='import-export-center'] > [data-part='list'] > [data-part='job'] {
1097
+ grid-column: 1 / -1;
1098
+ grid-template-areas: none;
1099
+ grid-template-columns: subgrid;
1100
+ grid-template-rows: repeat(5, auto) auto;
1101
+ row-gap: 0;
1102
+ }
1103
+
1104
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'] {
1105
+ grid-column: 1;
1106
+ grid-row: 1 / span 5;
1107
+ }
1108
+
1109
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='body'] {
1110
+ display: contents;
1111
+ }
1112
+
1113
+ [data-ui='import-export-center']
1114
+ [data-part='job']
1115
+ > [data-part='body']
1116
+ > [data-part='heading'] {
1117
+ grid-column: 2;
1118
+ grid-row: 1 / span 5;
1119
+ }
1120
+
1121
+ [data-ui='import-export-center']
1122
+ [data-part='job']
1123
+ > [data-part='body']
1124
+ > :not([data-part='heading']) {
1125
+ grid-column: 3;
1126
+ }
1127
+
1128
+ [data-ui='import-export-center']
1129
+ [data-part='job']
1130
+ > [data-part='body']
1131
+ > :not([data-part='heading'])
1132
+ + :not([data-part='heading']) {
1133
+ margin-block-start: var(--slotted-space-3, 0.375rem);
1134
+ }
1135
+
1136
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='controls'] {
1137
+ grid-column: 3;
1138
+ grid-row: 5;
1139
+ margin-block-start: var(--slotted-space-4, 0.5rem);
1140
+ }
1141
+
1142
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='details'] {
1143
+ grid-column: 2 / -1;
1144
+ grid-row: 6;
1145
+ margin-block-start: var(--_gap);
1146
+ }
1147
+ }
1148
+
1149
+ /* ── Forced colours ──────────────────────────────────────────────────── */
1150
+
1151
+ @media (forced-colors: active) {
1152
+ /**
1153
+ * The separator dot is a painted background, and this mode replaces a
1154
+ * painted background with the system's own. `forced-color-adjust: none`
1155
+ * keeps the author's `currentcolor`, which has already been forced, so the
1156
+ * dot is drawn in the system's palette.
1157
+ */
1158
+ [data-ui='import-export-center'] [data-part='meta'] > * + *::before,
1159
+ [data-ui='import-export-center'] [data-part='summary'] > * + *::before,
1160
+ [data-ui='import-export-center'] [data-part='progress-text'] > * + *::before,
1161
+ [data-ui='import-export-center'] [data-part='status-label'] > [data-part='stage']::before {
1162
+ forced-color-adjust: none;
1163
+ }
1164
+
1165
+ /** The tile loses its kind's colour, as every tone does here; its edge keeps the square. */
1166
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='visual'] {
1167
+ border: var(--slotted-border-width-thin, 1px) solid CanvasText;
1168
+ color: CanvasText;
1169
+ }
1170
+
1171
+ [data-ui='import-export-center'] [data-part='job'] > [data-part='details'] {
1172
+ border-color: CanvasText;
1173
+ }
1174
+ }
1175
+ }