@slotted/styles 0.1.0-beta.0 → 0.1.0-beta.10

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 (176) hide show
  1. package/package.json +1 -1
  2. package/src/accordion/accordion.css +10 -10
  3. package/src/action-bar/action-bar.css +31 -32
  4. package/src/action-sheet/action-sheet.css +36 -36
  5. package/src/alert/alert.css +43 -35
  6. package/src/alert/alert.tokens.json +5 -0
  7. package/src/app-shell/app-shell.css +356 -301
  8. package/src/aspect-ratio/aspect-ratio.css +9 -9
  9. package/src/attachment/attachment.css +91 -99
  10. package/src/avatar/avatar.css +71 -41
  11. package/src/avatar/avatar.tokens.json +7 -0
  12. package/src/avatar-group/avatar-group.css +21 -22
  13. package/src/badge/badge.css +45 -37
  14. package/src/badge/badge.tokens.json +5 -0
  15. package/src/breadcrumb/breadcrumb.css +37 -37
  16. package/src/button/button.css +139 -64
  17. package/src/button/button.tokens.json +10 -0
  18. package/src/button-group/button-group.css +76 -72
  19. package/src/button-group/button-group.tokens.json +2 -0
  20. package/src/calendar/calendar.css +93 -103
  21. package/src/card/card.css +54 -61
  22. package/src/carousel/carousel.css +150 -161
  23. package/src/cascader/cascader.css +152 -153
  24. package/src/cascader/cascader.tokens.json +1 -0
  25. package/src/chart/chart.css +242 -239
  26. package/src/chart/chart.tokens.json +1 -0
  27. package/src/checkbox/checkbox.css +119 -124
  28. package/src/checkbox-group/checkbox-group.css +7 -7
  29. package/src/code-block/code-block.css +81 -85
  30. package/src/collapsible/collapsible.css +69 -76
  31. package/src/color-picker/color-picker.css +83 -91
  32. package/src/column-manager/column-manager.css +106 -114
  33. package/src/combobox/combobox.css +132 -107
  34. package/src/combobox/combobox.tokens.json +1 -0
  35. package/src/command-palette/command-palette.css +84 -90
  36. package/src/container/container.css +24 -24
  37. package/src/context-menu/context-menu.css +8 -8
  38. package/src/currency-field/currency-field.css +210 -88
  39. package/src/currency-field/currency-field.tokens.json +13 -0
  40. package/src/dashboard-grid/dashboard-grid.css +148 -116
  41. package/src/data-grid/data-grid.css +504 -469
  42. package/src/data-grid/data-grid.tokens.json +2 -0
  43. package/src/data-list/data-list.css +81 -70
  44. package/src/data-list/data-list.tokens.json +2 -1
  45. package/src/date-field/date-field.css +55 -52
  46. package/src/date-field/date-field.tokens.json +1 -0
  47. package/src/date-picker/date-picker.css +40 -42
  48. package/src/date-range-picker/date-range-picker.css +114 -118
  49. package/src/datetime-field/datetime-field.css +78 -80
  50. package/src/datetime-field/datetime-field.tokens.json +1 -0
  51. package/src/datetime-picker/datetime-picker.css +61 -63
  52. package/src/datetime-range-picker/datetime-range-picker.css +149 -156
  53. package/src/description-list/description-list.css +61 -64
  54. package/src/detail-panel/detail-panel.css +70 -70
  55. package/src/dialog/dialog.css +334 -153
  56. package/src/dialog/dialog.tokens.json +5 -0
  57. package/src/divider/divider.css +18 -18
  58. package/src/drawer/drawer.css +186 -209
  59. package/src/entity-picker/entity-picker.css +238 -241
  60. package/src/entity-picker/entity-picker.tokens.json +1 -0
  61. package/src/event-calendar/event-calendar.css +343 -385
  62. package/src/field/field.css +74 -78
  63. package/src/field-group/field-group.css +22 -25
  64. package/src/filter-bar/filter-bar.css +193 -209
  65. package/src/form/form.css +34 -24
  66. package/src/form/form.tokens.json +1 -0
  67. package/src/fullscreen/fullscreen.css +24 -25
  68. package/src/grid/grid.css +28 -28
  69. package/src/highlight/highlight.css +6 -6
  70. package/src/hover-card/hover-card.css +6 -6
  71. package/src/icon/icon.css +19 -15
  72. package/src/icon/icon.tokens.json +1 -0
  73. package/src/image/image.css +39 -39
  74. package/src/import-export-center/import-export-center.css +135 -156
  75. package/src/inline/inline.css +27 -27
  76. package/src/inline-message/inline-message.css +52 -28
  77. package/src/inline-message/inline-message.tokens.json +4 -0
  78. package/src/kbd/kbd.css +30 -26
  79. package/src/link/link.css +15 -15
  80. package/src/list/list.css +44 -17
  81. package/src/list/list.tokens.json +4 -0
  82. package/src/list-item/list-item.css +80 -66
  83. package/src/list-item/list-item.tokens.json +7 -0
  84. package/src/listbox/listbox.css +56 -59
  85. package/src/loading-overlay/loading-overlay.css +75 -92
  86. package/src/markdown/markdown.css +17 -17
  87. package/src/menu/menu.css +83 -63
  88. package/src/menubar/menubar.css +13 -13
  89. package/src/message/message.css +182 -202
  90. package/src/message/message.tokens.json +5 -0
  91. package/src/message-scroller/message-scroller.css +41 -42
  92. package/src/multi-select/multi-select.css +152 -145
  93. package/src/multi-select/multi-select.tokens.json +1 -0
  94. package/src/navigation-menu/navigation-menu.css +167 -188
  95. package/src/notification-center/notification-center.css +140 -148
  96. package/src/notification-center/notification-center.tokens.json +3 -0
  97. package/src/number-field/number-field.css +84 -83
  98. package/src/number-field/number-field.tokens.json +1 -0
  99. package/src/otp-input/otp-input.css +67 -57
  100. package/src/otp-input/otp-input.tokens.json +1 -0
  101. package/src/page/page.css +23 -23
  102. package/src/page-header/page-header.css +268 -281
  103. package/src/page-header/page-header.tokens.json +1 -0
  104. package/src/pagination/pagination.css +68 -72
  105. package/src/popover/popover.css +40 -49
  106. package/src/progress-indicator/progress-indicator.css +177 -120
  107. package/src/progress-indicator/progress-indicator.tokens.json +1 -1
  108. package/src/prompt-composer/prompt-composer.css +221 -102
  109. package/src/prompt-composer/prompt-composer.tokens.json +15 -0
  110. package/src/prose/prose.css +71 -75
  111. package/src/radio-group/radio-group.css +98 -103
  112. package/src/rating/rating.css +136 -132
  113. package/src/rating/rating.tokens.json +1 -0
  114. package/src/result-state/result-state.css +74 -77
  115. package/src/runtime-properties.mjs +2 -0
  116. package/src/saved-views/saved-views.css +41 -47
  117. package/src/scroll-area/scroll-area.css +39 -32
  118. package/src/section/section.css +161 -41
  119. package/src/section/section.tokens.json +7 -2
  120. package/src/segmented-control/segmented-control.css +254 -97
  121. package/src/segmented-control/segmented-control.tokens.json +15 -11
  122. package/src/select/select.css +118 -117
  123. package/src/select/select.tokens.json +1 -0
  124. package/src/side-navigation/side-navigation.css +179 -182
  125. package/src/side-navigation/side-navigation.tokens.json +1 -0
  126. package/src/skeleton/skeleton.css +47 -48
  127. package/src/slider/slider.css +86 -88
  128. package/src/sparkline/sparkline.css +62 -40
  129. package/src/sparkline/sparkline.tokens.json +2 -0
  130. package/src/spinner/spinner.css +39 -182
  131. package/src/spinner/spinner.tokens.json +0 -2
  132. package/src/split-button/split-button.css +30 -31
  133. package/src/split-button/split-button.tokens.json +1 -0
  134. package/src/splitter/splitter.css +35 -35
  135. package/src/stack/stack.css +24 -24
  136. package/src/stat-card/stat-card.css +341 -224
  137. package/src/stat-card/stat-card.tokens.json +3 -0
  138. package/src/status-indicator/status-indicator.css +28 -28
  139. package/src/stepper/stepper.css +58 -62
  140. package/src/switch/switch.css +86 -92
  141. package/src/table/table.css +310 -165
  142. package/src/table/table.tokens.json +6 -0
  143. package/src/table-of-contents/table-of-contents.css +51 -54
  144. package/src/tabs/tabs.css +330 -302
  145. package/src/tabs/tabs.tokens.json +8 -5
  146. package/src/tag/tag.css +79 -71
  147. package/src/tag/tag.tokens.json +9 -0
  148. package/src/tags-input/tags-input.css +145 -82
  149. package/src/tags-input/tags-input.tokens.json +7 -1
  150. package/src/text-field/text-field.css +132 -136
  151. package/src/text-field/text-field.tokens.json +1 -0
  152. package/src/textarea/textarea.css +31 -28
  153. package/src/textarea/textarea.tokens.json +1 -0
  154. package/src/time-field/time-field.css +72 -69
  155. package/src/time-field/time-field.tokens.json +1 -0
  156. package/src/time-picker/time-picker.css +56 -58
  157. package/src/time-range-picker/time-range-picker.css +126 -133
  158. package/src/timeline/timeline.css +254 -266
  159. package/src/timeline/timeline.tokens.json +5 -0
  160. package/src/toast/toast.css +89 -90
  161. package/src/toast/toast.tokens.json +5 -0
  162. package/src/toggle/toggle.css +62 -25
  163. package/src/toggle/toggle.tokens.json +8 -0
  164. package/src/toggle-group/toggle-group.css +106 -60
  165. package/src/toggle-group/toggle-group.tokens.json +10 -0
  166. package/src/toolbar/toolbar.css +30 -35
  167. package/src/tooltip/tooltip.css +26 -26
  168. package/src/top-navigation/top-navigation.css +243 -259
  169. package/src/tour/tour.css +51 -60
  170. package/src/transfer/transfer.css +160 -164
  171. package/src/tree/tree.css +103 -111
  172. package/src/typography/typography.css +40 -36
  173. package/src/typography/typography.tokens.json +1 -0
  174. package/src/upload/upload.css +224 -224
  175. package/src/visually-hidden/visually-hidden.css +1 -1
  176. package/src/wizard/wizard.css +185 -197
@@ -31,8 +31,8 @@
31
31
  * none of these, and states the same set for itself. They are declared once,
32
32
  * for both, rather than copied into a second block that drifts from the first.
33
33
  */
34
- [data-ui='upload'][data-part='root'],
35
- [data-ui='upload'][data-part='viewer'] {
34
+ [data-ui-upload][data-part-root],
35
+ [data-ui-upload][data-part-viewer] {
36
36
  /**
37
37
  * Type, glyph, control height and inner gap come from the control scales,
38
38
  * the only ones the theme restates per density, so an upload inside a dense
@@ -175,7 +175,7 @@
175
175
  }
176
176
 
177
177
  /* The family itself: the column the reader sees in the page. */
178
- [data-ui='upload'][data-part='root'] {
178
+ [data-ui-upload][data-part-root] {
179
179
  container-name: slotted-upload;
180
180
  container-type: inline-size;
181
181
  /**
@@ -193,7 +193,7 @@
193
193
  gap: var(--_section-gap);
194
194
  }
195
195
 
196
- [data-ui='upload'][data-size='sm'] {
196
+ [data-ui-upload][data-size='sm'] {
197
197
  --_font-size: var(--slotted-control-font-size-sm, 12px);
198
198
  --_glyph-size: var(--slotted-control-icon-size-sm, 14px);
199
199
  --_inner-size: var(--slotted-control-inner-size-sm, 22px);
@@ -202,7 +202,7 @@
202
202
  --_gap: var(--slotted-control-gap-sm, 6px);
203
203
  }
204
204
 
205
- [data-ui='upload'][data-size='lg'] {
205
+ [data-ui-upload][data-size='lg'] {
206
206
  --_font-size: var(--slotted-control-font-size-lg, 14px);
207
207
  --_glyph-size: var(--slotted-control-icon-size-lg, 18px);
208
208
  --_inner-size: var(--slotted-control-inner-size-lg, 28px);
@@ -217,13 +217,13 @@
217
217
  * label row, the description and the error slot for every control in this
218
218
  * library. They exist for the upload that stands on its own.
219
219
  */
220
- [data-ui='upload'] [data-part='label'] {
220
+ [data-ui-upload] [data-part-label] {
221
221
  color: var(--slotted-text);
222
222
  flex: none;
223
223
  font-weight: var(--slotted-upload-label-font-weight, var(--slotted-font-weight-medium, 500));
224
224
  }
225
225
 
226
- [data-ui='upload'] [data-part='description'] {
226
+ [data-ui-upload] [data-part-description] {
227
227
  color: var(--slotted-text-muted);
228
228
  flex: none;
229
229
  margin: 0;
@@ -237,7 +237,7 @@
237
237
  * reaches, and WCAG 2.2 SC 2.5.7 is discharged by its being there rather
238
238
  * than by the region pretending to be a control.
239
239
  */
240
- [data-ui='upload'] [data-part='dropzone'] {
240
+ [data-ui-upload] [data-part-dropzone] {
241
241
  --_zone-border-color: var(--_zone-edge);
242
242
  --_zone-surface: var(--_zone-ground);
243
243
 
@@ -264,7 +264,7 @@
264
264
  * the `dropzone` shape only. The `field` shape is one control's height and
265
265
  * has no room for a second mark beside the trigger's.
266
266
  */
267
- [data-ui='upload'] [data-part='dropzone'] > [data-ui='icon'] {
267
+ [data-ui-upload] [data-part-dropzone] > [data-ui-icon] {
268
268
  --slotted-icon-size: var(--_zone-glyph-size);
269
269
 
270
270
  color: var(--slotted-text-muted);
@@ -277,7 +277,7 @@
277
277
  * ratio against the page and against the ground it encloses, and the ground
278
278
  * alone would not.
279
279
  */
280
- [data-ui='upload'] [data-part='dropzone'][data-drop-target] {
280
+ [data-ui-upload] [data-part-dropzone][data-drop-target] {
281
281
  --_zone-border-color: var(--slotted-tone-accent-border);
282
282
  --_zone-surface: var(--slotted-tone-accent-surface);
283
283
  }
@@ -289,7 +289,7 @@
289
289
  * the name or the size — so this is painted for a refusal that is already
290
290
  * certain and never for one that is merely possible.
291
291
  */
292
- [data-ui='upload'] [data-part='dropzone'][data-drop-invalid] {
292
+ [data-ui-upload] [data-part-dropzone][data-drop-invalid] {
293
293
  --_zone-border-color: var(--slotted-tone-danger-border);
294
294
  --_zone-surface: var(--slotted-tone-danger-surface);
295
295
  }
@@ -308,12 +308,12 @@
308
308
  * OKLab L, above the 0.02 the theme holds every surface step to, and eight
309
309
  * by 0.062.
310
310
  */
311
- [data-ui='upload'] [data-part='dropzone'][data-browsable] {
311
+ [data-ui-upload] [data-part-dropzone][data-browsable] {
312
312
  cursor: pointer;
313
313
  }
314
314
 
315
- [data-ui='upload']:not([data-disabled])
316
- [data-part='dropzone'][data-browsable]:not([data-drop-target], [data-drop-invalid]):hover {
315
+ [data-ui-upload]:not([data-disabled])
316
+ [data-part-dropzone][data-browsable]:not([data-drop-target], [data-drop-invalid]):hover {
317
317
  --_zone-surface: color-mix(
318
318
  in oklab,
319
319
  var(--slotted-text) var(--slotted-upload-zone-state-layer-hover, 4%),
@@ -321,8 +321,8 @@
321
321
  );
322
322
  }
323
323
 
324
- [data-ui='upload']:not([data-disabled])
325
- [data-part='dropzone'][data-browsable]:not([data-drop-target], [data-drop-invalid]):active {
324
+ [data-ui-upload]:not([data-disabled])
325
+ [data-part-dropzone][data-browsable]:not([data-drop-target], [data-drop-invalid]):active {
326
326
  --_zone-surface: color-mix(
327
327
  in oklab,
328
328
  var(--slotted-text) var(--slotted-upload-zone-state-layer-active, 8%),
@@ -331,8 +331,8 @@
331
331
  }
332
332
 
333
333
  /* An invalid region keeps its danger edge under the pointer. */
334
- [data-ui='upload']:not([data-disabled], [data-invalid])
335
- [data-part='dropzone'][data-browsable]:not([data-drop-target], [data-drop-invalid]):is(
334
+ [data-ui-upload]:not([data-disabled], [data-invalid])
335
+ [data-part-dropzone][data-browsable]:not([data-drop-target], [data-drop-invalid]):is(
336
336
  :hover,
337
337
  :active
338
338
  ) {
@@ -344,24 +344,24 @@
344
344
  * hover over the region around it, and the two answering at once drew two
345
345
  * targets for one press.
346
346
  */
347
- [data-ui='upload']:not([data-disabled])
348
- [data-part='dropzone'][data-browsable]:not([data-drop-target], [data-drop-invalid]):has(
349
- [data-part='trigger']:hover
347
+ [data-ui-upload]:not([data-disabled])
348
+ [data-part-dropzone][data-browsable]:not([data-drop-target], [data-drop-invalid]):has(
349
+ [data-part-trigger]:hover
350
350
  ) {
351
351
  --_zone-border-color: var(--_zone-edge);
352
352
  --_zone-surface: var(--_zone-ground);
353
353
  }
354
354
 
355
- [data-ui='upload'][data-disabled][data-part='root'] {
355
+ [data-ui-upload][data-disabled][data-part-root] {
356
356
  --_zone-edge: var(--slotted-disabled-border);
357
357
  --_zone-ground: var(--slotted-disabled-background);
358
358
  }
359
359
 
360
- [data-ui='upload'][data-disabled] [data-part='dropzone'] {
360
+ [data-ui-upload][data-disabled] [data-part-dropzone] {
361
361
  color: var(--slotted-disabled-foreground);
362
362
  }
363
363
 
364
- [data-ui='upload'][data-invalid][data-part='root'] {
364
+ [data-ui-upload][data-invalid][data-part-root] {
365
365
  --_zone-edge: var(--slotted-tone-danger-border);
366
366
  }
367
367
 
@@ -372,7 +372,7 @@
372
372
  * family's contract, and what is wanted is one control-height box that opens
373
373
  * the picker natively.
374
374
  */
375
- [data-ui='upload'] [data-part='trigger'] {
375
+ [data-ui-upload] [data-part-trigger] {
376
376
  align-items: center;
377
377
  background-color: var(--slotted-upload-trigger-background, var(--slotted-surface));
378
378
  block-size: var(--_control-height);
@@ -403,11 +403,11 @@
403
403
  * in the `dropzone` shape the region already carries it, and two of the same
404
404
  * mark eighty pixels apart is one mark too many.
405
405
  */
406
- [data-ui='upload'] [data-part='trigger'] > [data-ui='icon'] {
406
+ [data-ui-upload] [data-part-trigger] > [data-ui-icon] {
407
407
  --slotted-icon-size: var(--_glyph-size);
408
408
  }
409
409
 
410
- [data-ui='upload']:not([data-disabled]) [data-part='trigger']:hover {
410
+ [data-ui-upload]:not([data-disabled]) [data-part-trigger]:hover {
411
411
  background-color: var(--slotted-tone-secondary-subtle-hover);
412
412
  }
413
413
 
@@ -415,12 +415,12 @@
415
415
  * The trigger is drawn as a control and presses like `button` does: the
416
416
  * ground takes the next step and the box settles by a hairline, at once.
417
417
  */
418
- [data-ui='upload']:not([data-disabled]) [data-part='trigger']:active {
418
+ [data-ui-upload]:not([data-disabled]) [data-part-trigger]:active {
419
419
  background-color: var(--slotted-tone-secondary-subtle-active);
420
420
  translate: 0 var(--slotted-border-width-thin, 1px);
421
421
  }
422
422
 
423
- [data-ui='upload'][data-disabled] [data-part='trigger'] {
423
+ [data-ui-upload][data-disabled] [data-part-trigger] {
424
424
  background-color: var(--slotted-disabled-background);
425
425
  border-color: var(--slotted-disabled-border);
426
426
  box-shadow: none;
@@ -432,12 +432,12 @@
432
432
  * The ring belongs to the trigger and the focus belongs to the input inside
433
433
  * it. A ring around a one-pixel input would be a ring around nothing.
434
434
  */
435
- [data-ui='upload'] [data-part='trigger']:has(:focus-visible) {
435
+ [data-ui-upload] [data-part-trigger]:has(:focus-visible) {
436
436
  outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
437
437
  outline-offset: var(--slotted-focus-ring-offset, 2px);
438
438
  }
439
439
 
440
- [data-ui='upload'][data-invalid] [data-part='trigger'] {
440
+ [data-ui-upload][data-invalid] [data-part-trigger] {
441
441
  --slotted-focus-ring-color: var(--slotted-focus-ring-color-invalid);
442
442
 
443
443
  border-color: var(--slotted-tone-danger-border);
@@ -458,7 +458,7 @@
458
458
  * stretching a transparent input across the region takes the drop away from
459
459
  * the region and makes the drag state unobservable.
460
460
  */
461
- [data-ui='upload'] [data-part='input'] {
461
+ [data-ui-upload] [data-part-input] {
462
462
  block-size: 1px;
463
463
  border: 0;
464
464
  clip-path: inset(50%);
@@ -477,7 +477,7 @@
477
477
  * draw on the element holding focus has to go: `tree` moved its ring and
478
478
  * forgot this, and a focused row carried two rings in two colours.
479
479
  */
480
- [data-ui='upload'] [data-part='input']:focus-visible {
480
+ [data-ui-upload] [data-part-input]:focus-visible {
481
481
  outline: none;
482
482
  }
483
483
 
@@ -488,7 +488,7 @@
488
488
  * drawn only when there is more than one file, because for a single file the
489
489
  * row already says all of it.
490
490
  */
491
- [data-ui='upload'] [data-part='summary'] {
491
+ [data-ui-upload] [data-part-summary] {
492
492
  align-items: center;
493
493
  color: var(--slotted-text-muted);
494
494
  display: flex;
@@ -497,7 +497,7 @@
497
497
  justify-content: space-between;
498
498
  }
499
499
 
500
- [data-ui='upload'] [data-part='clear'] {
500
+ [data-ui-upload] [data-part-clear] {
501
501
  appearance: none;
502
502
  flex: none;
503
503
  white-space: nowrap;
@@ -515,20 +515,20 @@
515
515
  var(--slotted-control-transition-easing);
516
516
  }
517
517
 
518
- [data-ui='upload'] [data-part='clear']:enabled:hover {
518
+ [data-ui-upload] [data-part-clear]:enabled:hover {
519
519
  background-color: var(--_state-hover);
520
520
  }
521
521
 
522
- [data-ui='upload'] [data-part='clear']:enabled:active {
522
+ [data-ui-upload] [data-part-clear]:enabled:active {
523
523
  background-color: var(--_state-active);
524
524
  }
525
525
 
526
- [data-ui='upload'] [data-part='clear']:disabled {
526
+ [data-ui-upload] [data-part-clear]:disabled {
527
527
  color: var(--slotted-disabled-foreground);
528
528
  cursor: default;
529
529
  }
530
530
 
531
- [data-ui='upload'] [data-part='clear']:focus-visible {
531
+ [data-ui-upload] [data-part-clear]:focus-visible {
532
532
  outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
533
533
  outline-offset: var(--slotted-focus-ring-offset, 2px);
534
534
  }
@@ -552,7 +552,7 @@
552
552
  * between two — which is what says there is more below without a shadow, a
553
553
  * gradient or a count.
554
554
  */
555
- [data-ui='upload'] [data-part='list'] {
555
+ [data-ui-upload] [data-part-list] {
556
556
  /** One row, from the parts a row is made of. Used twice below. */
557
557
  --_row-block-size: calc(
558
558
  max(var(--_preview-size), 2lh) + 2 * var(--_item-inset-block) + 2 * var(--_border-width) +
@@ -605,7 +605,7 @@
605
605
  * text with icons beside it, and only a failed one had a box; a file is a
606
606
  * thing the reader acts on, and it reads as one.
607
607
  */
608
- [data-ui='upload'] [data-part='item'] {
608
+ [data-ui-upload] [data-part-item] {
609
609
  align-items: center;
610
610
  /*
611
611
  * A row is never squeezed. Flex children shrink by default, so nine rows in
@@ -653,13 +653,13 @@
653
653
  * controlled `files`; the promise is in `docs/process/build-order.md`.
654
654
  */
655
655
  @starting-style {
656
- [data-ui='upload'] [data-part='item'] {
656
+ [data-ui-upload] [data-part-item] {
657
657
  opacity: 0;
658
658
  translate: 0 calc(-1 * var(--slotted-space-2, 0.25rem));
659
659
  }
660
660
  }
661
661
 
662
- [data-ui='upload'] [data-part='item'][data-status='success'] {
662
+ [data-ui-upload] [data-part-item][data-status='success'] {
663
663
  --_status-text: var(--slotted-tone-success-text);
664
664
  }
665
665
 
@@ -671,12 +671,12 @@
671
671
  * forced colours, where the line survives and a tint does not. ReUI draws
672
672
  * its `idle` attachment the same way (`c-attachment-5`).
673
673
  */
674
- [data-ui='upload'] [data-part='item'][data-status='ready'] {
674
+ [data-ui-upload] [data-part-item][data-status='ready'] {
675
675
  border-style: dashed;
676
676
  }
677
677
 
678
- [data-ui='upload'] [data-part='item'][data-status='paused'],
679
- [data-ui='upload'] [data-part='item'][data-status='stalled'] {
678
+ [data-ui-upload] [data-part-item][data-status='paused'],
679
+ [data-ui-upload] [data-part-item][data-status='stalled'] {
680
680
  --_status-text: var(--slotted-tone-warning-text);
681
681
  }
682
682
 
@@ -686,18 +686,18 @@
686
686
  * both need the reader to do something; a file the reader stopped themselves
687
687
  * does not, so it stays neutral and only its word changes.
688
688
  */
689
- [data-ui='upload'] [data-part='item'][data-status='rejected'],
690
- [data-ui='upload'] [data-part='item'][data-status='error'] {
689
+ [data-ui-upload] [data-part-item][data-status='rejected'],
690
+ [data-ui-upload] [data-part-item][data-status='error'] {
691
691
  --_status-text: var(--slotted-tone-danger-text);
692
692
  --_item-surface: var(--slotted-tone-danger-surface);
693
693
  --_item-border: var(--slotted-tone-danger-border);
694
694
  }
695
695
 
696
- [data-ui='upload'] [data-part='item'][data-status='canceled'] {
696
+ [data-ui-upload] [data-part-item][data-status='canceled'] {
697
697
  --_status-text: var(--slotted-text-muted);
698
698
  }
699
699
 
700
- [data-ui='upload'][data-disabled] [data-part='item'] {
700
+ [data-ui-upload][data-disabled] [data-part-item] {
701
701
  color: var(--slotted-disabled-foreground);
702
702
  }
703
703
 
@@ -722,7 +722,7 @@
722
722
  * tile. `packages/themes/test/default-theme.test.mjs` measures all
723
723
  * twenty-seven.
724
724
  */
725
- [data-ui='upload'] [data-part='preview'] {
725
+ [data-ui-upload] [data-part-preview] {
726
726
  align-items: center;
727
727
  background-color: var(--_kind-tile);
728
728
  block-size: var(--_preview-size);
@@ -736,46 +736,46 @@
736
736
  overflow: hidden;
737
737
  }
738
738
 
739
- [data-ui='upload'] [data-part='preview'] > img {
739
+ [data-ui-upload] [data-part-preview] > img {
740
740
  block-size: 100%;
741
741
  inline-size: 100%;
742
742
  object-fit: cover;
743
743
  }
744
744
 
745
745
  /* The kind's glyph, drawn by the binding when there is no picture to show. */
746
- [data-ui='upload'] [data-part='preview'] > [data-ui='icon'] {
746
+ [data-ui-upload] [data-part-preview] > [data-ui-icon] {
747
747
  --slotted-icon-size: var(--_glyph-size);
748
748
  }
749
749
 
750
- [data-ui='upload'] [data-part='preview'][data-kind='pdf'] {
750
+ [data-ui-upload] [data-part-preview][data-kind='pdf'] {
751
751
  --_kind-tile: var(--slotted-upload-kind-pdf);
752
752
  }
753
753
 
754
- [data-ui='upload'] [data-part='preview'][data-kind='document'] {
754
+ [data-ui-upload] [data-part-preview][data-kind='document'] {
755
755
  --_kind-tile: var(--slotted-upload-kind-document);
756
756
  }
757
757
 
758
- [data-ui='upload'] [data-part='preview'][data-kind='spreadsheet'] {
758
+ [data-ui-upload] [data-part-preview][data-kind='spreadsheet'] {
759
759
  --_kind-tile: var(--slotted-upload-kind-spreadsheet);
760
760
  }
761
761
 
762
- [data-ui='upload'] [data-part='preview'][data-kind='presentation'] {
762
+ [data-ui-upload] [data-part-preview][data-kind='presentation'] {
763
763
  --_kind-tile: var(--slotted-upload-kind-presentation);
764
764
  }
765
765
 
766
- [data-ui='upload'] [data-part='preview'][data-kind='image'] {
766
+ [data-ui-upload] [data-part-preview][data-kind='image'] {
767
767
  --_kind-tile: var(--slotted-upload-kind-image);
768
768
  }
769
769
 
770
- [data-ui='upload'] [data-part='preview'][data-kind='video'] {
770
+ [data-ui-upload] [data-part-preview][data-kind='video'] {
771
771
  --_kind-tile: var(--slotted-upload-kind-video);
772
772
  }
773
773
 
774
- [data-ui='upload'] [data-part='preview'][data-kind='audio'] {
774
+ [data-ui-upload] [data-part-preview][data-kind='audio'] {
775
775
  --_kind-tile: var(--slotted-upload-kind-audio);
776
776
  }
777
777
 
778
- [data-ui='upload'] [data-part='preview'][data-kind='archive'] {
778
+ [data-ui-upload] [data-part-preview][data-kind='archive'] {
779
779
  --_kind-tile: var(--slotted-upload-kind-archive);
780
780
  }
781
781
 
@@ -800,7 +800,7 @@
800
800
  * is what makes a long name truncate instead of pushing the controls off the
801
801
  * end.
802
802
  */
803
- [data-ui='upload'] [data-part='item'] > [data-part='body'] {
803
+ [data-ui-upload] [data-part-item] > [data-part-body] {
804
804
  display: flex;
805
805
  flex-direction: column;
806
806
  gap: var(--_line-gap);
@@ -817,7 +817,7 @@
817
817
  * `pdf.claim-form-2026-0914`. Found in the harness capture at `dir="rtl"`,
818
818
  * where nothing failed and the name was backwards.
819
819
  */
820
- [data-ui='upload'] [data-part='filename'] {
820
+ [data-ui-upload] [data-part-filename] {
821
821
  display: flex;
822
822
  /*
823
823
  * The name is the row's title and the detail line under it is at the same
@@ -841,7 +841,7 @@
841
841
  * Nothing about it looks like a control until the pointer is on it — a list
842
842
  * of nine underlined names is a list nobody can read.
843
843
  */
844
- [data-ui='upload'] button[data-part='filename'] {
844
+ [data-ui-upload] button[data-part-filename] {
845
845
  appearance: none;
846
846
  background: none;
847
847
  border: 0;
@@ -856,7 +856,7 @@
856
856
  transition: translate var(--slotted-duration-instant) var(--slotted-control-transition-easing);
857
857
  }
858
858
 
859
- [data-ui='upload'] button[data-part='filename']:enabled:hover {
859
+ [data-ui-upload] button[data-part-filename]:enabled:hover {
860
860
  text-decoration-line: underline;
861
861
  text-underline-offset: 0.2em;
862
862
  }
@@ -866,20 +866,20 @@
866
866
  * a press answers in place: the name settles by a hairline — the answer
867
867
  * `timeline` gives its group heading.
868
868
  */
869
- [data-ui='upload'] button[data-part='filename']:enabled:active {
869
+ [data-ui-upload] button[data-part-filename]:enabled:active {
870
870
  text-decoration-line: underline;
871
871
  text-underline-offset: 0.2em;
872
872
  translate: 0 var(--slotted-border-width-thin, 1px);
873
873
  }
874
874
 
875
- [data-ui='upload'] button[data-part='filename']:focus-visible {
875
+ [data-ui-upload] button[data-part-filename]:focus-visible {
876
876
  border-radius: var(--slotted-control-radius, 4px);
877
877
  outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
878
878
  outline-offset: var(--slotted-focus-ring-offset, 2px);
879
879
  }
880
880
 
881
881
  /* In a wall of pictures the picture is the thing the reader is pointing at. */
882
- [data-ui='upload'][data-layout='grid'] button[data-part='preview'] {
882
+ [data-ui-upload][data-layout='grid'] button[data-part-preview] {
883
883
  appearance: none;
884
884
  border: 0;
885
885
  cursor: pointer;
@@ -893,7 +893,7 @@
893
893
  * the file is. CSS cannot truncate in the middle; the split is made at the
894
894
  * last dot in the binding, and this is the half of the answer the sheet owes.
895
895
  */
896
- [data-ui='upload'] [data-part='name'] {
896
+ [data-ui-upload] [data-part-name] {
897
897
  flex: 0 1 auto;
898
898
  min-inline-size: 0;
899
899
  overflow: hidden;
@@ -901,12 +901,12 @@
901
901
  white-space: nowrap;
902
902
  }
903
903
 
904
- [data-ui='upload'] [data-part='extension'] {
904
+ [data-ui-upload] [data-part-extension] {
905
905
  flex: none;
906
906
  }
907
907
 
908
908
  /** The second line: the size, then the word for what is happening to it. */
909
- [data-ui='upload'] [data-part='detail'] {
909
+ [data-ui-upload] [data-part-detail] {
910
910
  align-items: baseline;
911
911
  color: var(--slotted-text-muted);
912
912
  display: flex;
@@ -916,7 +916,7 @@
916
916
  min-inline-size: 0;
917
917
  }
918
918
 
919
- [data-ui='upload'] [data-part='meta'] {
919
+ [data-ui-upload] [data-part-meta] {
920
920
  font-variant-numeric: tabular-nums;
921
921
  white-space: nowrap;
922
922
  }
@@ -925,7 +925,7 @@
925
925
  * The word, in the colour the status set. A status said in colour alone fails
926
926
  * WCAG 2.2 SC 1.4.1, which is why it is a word first and a colour second.
927
927
  */
928
- [data-ui='upload'] [data-part='status'] {
928
+ [data-ui-upload] [data-part-status] {
929
929
  color: var(--_status-text);
930
930
  font-weight: var(--slotted-upload-status-font-weight, var(--slotted-font-weight-medium, 500));
931
931
  min-inline-size: 0;
@@ -941,13 +941,13 @@
941
941
  * it left an orphaned middot at the start of the second line, which is what
942
942
  * the card at 720 pixels showed.
943
943
  */
944
- [data-ui='upload'] [data-part='meta']:has(+ [data-part='status'])::after {
944
+ [data-ui-upload] [data-part-meta]:has(+ [data-part-status])::after {
945
945
  color: var(--slotted-text-muted);
946
946
  content: ' ·';
947
947
  margin-inline-end: 0.4em;
948
948
  }
949
949
 
950
- [data-ui='upload'] [data-part='message'] {
950
+ [data-ui-upload] [data-part-message] {
951
951
  color: var(--_status-text);
952
952
  font-size: var(--slotted-font-size-xs, 0.75rem);
953
953
  line-height: var(--_leading);
@@ -962,7 +962,7 @@
962
962
  * answer to one question, drifting from the first the moment either is
963
963
  * retuned.
964
964
  */
965
- [data-ui='upload'] [data-part='progress'] {
965
+ [data-ui-upload] [data-part-progress] {
966
966
  display: block;
967
967
  inset-block-end: 0;
968
968
  inset-inline: 0;
@@ -989,20 +989,20 @@
989
989
  * is no column to keep and a row that offers one control no longer carries
990
990
  * two empty slots to prove it.
991
991
  */
992
- [data-ui='upload'] [data-part='actions'] {
992
+ [data-ui-upload] [data-part-actions] {
993
993
  display: inline-flex;
994
994
  gap: var(--slotted-space-1, 0.125rem);
995
995
  grid-area: actions;
996
996
  justify-content: flex-end;
997
997
  }
998
998
 
999
- [data-ui='upload'] [data-part='viewerExternal'],
1000
- [data-ui='upload'] [data-part='viewerClose'],
1001
- [data-ui='upload'] [data-part='start'],
1002
- [data-ui='upload'] [data-part='pause'],
1003
- [data-ui='upload'] [data-part='retry'],
1004
- [data-ui='upload'] [data-part='cancel'],
1005
- [data-ui='upload'] [data-part='remove'] {
999
+ [data-ui-upload] [data-part-viewerexternal],
1000
+ [data-ui-upload] [data-part-viewerclose],
1001
+ [data-ui-upload] [data-part-start],
1002
+ [data-ui-upload] [data-part-pause],
1003
+ [data-ui-upload] [data-part-retry],
1004
+ [data-ui-upload] [data-part-cancel],
1005
+ [data-ui-upload] [data-part-remove] {
1006
1006
  align-items: center;
1007
1007
  appearance: none;
1008
1008
  background-color: transparent;
@@ -1028,13 +1028,13 @@
1028
1028
  * pause, rotate-ccw, x and trash. A cross means *stop this* and a bin means
1029
1029
  * *take it away*, because the marks appear together on one row.
1030
1030
  */
1031
- [data-ui='upload'] [data-part='viewerExternal'] > [data-ui='icon'],
1032
- [data-ui='upload'] [data-part='viewerClose'] > [data-ui='icon'],
1033
- [data-ui='upload'] [data-part='start'] > [data-ui='icon'],
1034
- [data-ui='upload'] [data-part='pause'] > [data-ui='icon'],
1035
- [data-ui='upload'] [data-part='retry'] > [data-ui='icon'],
1036
- [data-ui='upload'] [data-part='cancel'] > [data-ui='icon'],
1037
- [data-ui='upload'] [data-part='remove'] > [data-ui='icon'] {
1031
+ [data-ui-upload] [data-part-viewerexternal] > [data-ui-icon],
1032
+ [data-ui-upload] [data-part-viewerclose] > [data-ui-icon],
1033
+ [data-ui-upload] [data-part-start] > [data-ui-icon],
1034
+ [data-ui-upload] [data-part-pause] > [data-ui-icon],
1035
+ [data-ui-upload] [data-part-retry] > [data-ui-icon],
1036
+ [data-ui-upload] [data-part-cancel] > [data-ui-icon],
1037
+ [data-ui-upload] [data-part-remove] > [data-ui-icon] {
1038
1038
  --slotted-icon-size: var(--_action-glyph-size);
1039
1039
  }
1040
1040
 
@@ -1047,67 +1047,67 @@
1047
1047
  * width and is 44 tall.
1048
1048
  */
1049
1049
  @media (pointer: coarse) {
1050
- [data-ui='upload']
1050
+ [data-ui-upload]
1051
1051
  :is(
1052
- [data-part='viewerExternal'],
1053
- [data-part='viewerClose'],
1054
- [data-part='start'],
1055
- [data-part='pause'],
1056
- [data-part='retry'],
1057
- [data-part='cancel'],
1058
- [data-part='remove']
1052
+ [data-part-viewerexternal],
1053
+ [data-part-viewerclose],
1054
+ [data-part-start],
1055
+ [data-part-pause],
1056
+ [data-part-retry],
1057
+ [data-part-cancel],
1058
+ [data-part-remove]
1059
1059
  ) {
1060
1060
  position: relative;
1061
1061
  }
1062
1062
 
1063
- [data-ui='upload']
1063
+ [data-ui-upload]
1064
1064
  :is(
1065
- [data-part='viewerExternal'],
1066
- [data-part='viewerClose'],
1067
- [data-part='start'],
1068
- [data-part='pause'],
1069
- [data-part='retry'],
1070
- [data-part='cancel'],
1071
- [data-part='remove']
1065
+ [data-part-viewerexternal],
1066
+ [data-part-viewerclose],
1067
+ [data-part-start],
1068
+ [data-part-pause],
1069
+ [data-part-retry],
1070
+ [data-part-cancel],
1071
+ [data-part-remove]
1072
1072
  )::after {
1073
1073
  content: '';
1074
1074
  inset: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
1075
1075
  position: absolute;
1076
1076
  }
1077
1077
 
1078
- [data-ui='upload']
1078
+ [data-ui-upload]
1079
1079
  :is(
1080
- [data-part='viewerExternal'],
1081
- [data-part='start'],
1082
- [data-part='pause'],
1083
- [data-part='retry'],
1084
- [data-part='cancel']
1080
+ [data-part-viewerexternal],
1081
+ [data-part-start],
1082
+ [data-part-pause],
1083
+ [data-part-retry],
1084
+ [data-part-cancel]
1085
1085
  ):has(
1086
1086
  + :is(
1087
- [data-part='viewerClose'],
1088
- [data-part='pause'],
1089
- [data-part='retry'],
1090
- [data-part='cancel'],
1091
- [data-part='remove']
1087
+ [data-part-viewerclose],
1088
+ [data-part-pause],
1089
+ [data-part-retry],
1090
+ [data-part-cancel],
1091
+ [data-part-remove]
1092
1092
  ):not([hidden])
1093
1093
  )::after {
1094
1094
  inset-inline-end: 0;
1095
1095
  }
1096
1096
 
1097
- [data-ui='upload']
1097
+ [data-ui-upload]
1098
1098
  :is(
1099
- [data-part='viewerExternal'],
1100
- [data-part='start'],
1101
- [data-part='pause'],
1102
- [data-part='retry'],
1103
- [data-part='cancel']
1099
+ [data-part-viewerexternal],
1100
+ [data-part-start],
1101
+ [data-part-pause],
1102
+ [data-part-retry],
1103
+ [data-part-cancel]
1104
1104
  ):not([hidden])
1105
1105
  + :is(
1106
- [data-part='viewerClose'],
1107
- [data-part='pause'],
1108
- [data-part='retry'],
1109
- [data-part='cancel'],
1110
- [data-part='remove']
1106
+ [data-part-viewerclose],
1107
+ [data-part-pause],
1108
+ [data-part-retry],
1109
+ [data-part-cancel],
1110
+ [data-part-remove]
1111
1111
  )::after {
1112
1112
  inset-inline-start: 0;
1113
1113
  }
@@ -1118,44 +1118,44 @@
1118
1118
  * and the reason it exists: a control the browser has already refused must
1119
1119
  * not answer a pointer.
1120
1120
  */
1121
- [data-ui='upload'] [data-part='viewerExternal']:enabled:hover,
1122
- [data-ui='upload'] [data-part='viewerClose']:enabled:hover,
1123
- [data-ui='upload'] [data-part='start']:enabled:hover,
1124
- [data-ui='upload'] [data-part='pause']:enabled:hover,
1125
- [data-ui='upload'] [data-part='retry']:enabled:hover,
1126
- [data-ui='upload'] [data-part='cancel']:enabled:hover,
1127
- [data-ui='upload'] [data-part='remove']:enabled:hover {
1121
+ [data-ui-upload] [data-part-viewerexternal]:enabled:hover,
1122
+ [data-ui-upload] [data-part-viewerclose]:enabled:hover,
1123
+ [data-ui-upload] [data-part-start]:enabled:hover,
1124
+ [data-ui-upload] [data-part-pause]:enabled:hover,
1125
+ [data-ui-upload] [data-part-retry]:enabled:hover,
1126
+ [data-ui-upload] [data-part-cancel]:enabled:hover,
1127
+ [data-ui-upload] [data-part-remove]:enabled:hover {
1128
1128
  background-color: var(--_state-hover);
1129
1129
  }
1130
1130
 
1131
- [data-ui='upload'] [data-part='viewerExternal']:enabled:active,
1132
- [data-ui='upload'] [data-part='viewerClose']:enabled:active,
1133
- [data-ui='upload'] [data-part='start']:enabled:active,
1134
- [data-ui='upload'] [data-part='pause']:enabled:active,
1135
- [data-ui='upload'] [data-part='retry']:enabled:active,
1136
- [data-ui='upload'] [data-part='cancel']:enabled:active,
1137
- [data-ui='upload'] [data-part='remove']:enabled:active {
1131
+ [data-ui-upload] [data-part-viewerexternal]:enabled:active,
1132
+ [data-ui-upload] [data-part-viewerclose]:enabled:active,
1133
+ [data-ui-upload] [data-part-start]:enabled:active,
1134
+ [data-ui-upload] [data-part-pause]:enabled:active,
1135
+ [data-ui-upload] [data-part-retry]:enabled:active,
1136
+ [data-ui-upload] [data-part-cancel]:enabled:active,
1137
+ [data-ui-upload] [data-part-remove]:enabled:active {
1138
1138
  background-color: var(--_state-active);
1139
1139
  }
1140
1140
 
1141
- [data-ui='upload'] [data-part='viewerExternal']:disabled,
1142
- [data-ui='upload'] [data-part='viewerClose']:disabled,
1143
- [data-ui='upload'] [data-part='start']:disabled,
1144
- [data-ui='upload'] [data-part='pause']:disabled,
1145
- [data-ui='upload'] [data-part='retry']:disabled,
1146
- [data-ui='upload'] [data-part='cancel']:disabled,
1147
- [data-ui='upload'] [data-part='remove']:disabled {
1141
+ [data-ui-upload] [data-part-viewerexternal]:disabled,
1142
+ [data-ui-upload] [data-part-viewerclose]:disabled,
1143
+ [data-ui-upload] [data-part-start]:disabled,
1144
+ [data-ui-upload] [data-part-pause]:disabled,
1145
+ [data-ui-upload] [data-part-retry]:disabled,
1146
+ [data-ui-upload] [data-part-cancel]:disabled,
1147
+ [data-ui-upload] [data-part-remove]:disabled {
1148
1148
  color: var(--slotted-disabled-foreground);
1149
1149
  cursor: default;
1150
1150
  }
1151
1151
 
1152
- [data-ui='upload'] [data-part='viewerExternal']:focus-visible,
1153
- [data-ui='upload'] [data-part='viewerClose']:focus-visible,
1154
- [data-ui='upload'] [data-part='start']:focus-visible,
1155
- [data-ui='upload'] [data-part='pause']:focus-visible,
1156
- [data-ui='upload'] [data-part='retry']:focus-visible,
1157
- [data-ui='upload'] [data-part='cancel']:focus-visible,
1158
- [data-ui='upload'] [data-part='remove']:focus-visible {
1152
+ [data-ui-upload] [data-part-viewerexternal]:focus-visible,
1153
+ [data-ui-upload] [data-part-viewerclose]:focus-visible,
1154
+ [data-ui-upload] [data-part-start]:focus-visible,
1155
+ [data-ui-upload] [data-part-pause]:focus-visible,
1156
+ [data-ui-upload] [data-part-retry]:focus-visible,
1157
+ [data-ui-upload] [data-part-cancel]:focus-visible,
1158
+ [data-ui-upload] [data-part-remove]:focus-visible {
1159
1159
  outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
1160
1160
  outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
1161
1161
  }
@@ -1172,7 +1172,7 @@
1172
1172
  * survives as the escape hatch inside the viewer, where a PDF is better read
1173
1173
  * in the browser's own full window.
1174
1174
  */
1175
- [data-ui='upload'][data-part='viewer'] {
1175
+ [data-ui-upload][data-part-viewer] {
1176
1176
  background-color: var(--slotted-surface);
1177
1177
  block-size: 100%;
1178
1178
  display: grid;
@@ -1189,7 +1189,7 @@
1189
1189
  inline-size: 100%;
1190
1190
  }
1191
1191
 
1192
- [data-ui='upload'] [data-part='viewerHeader'] {
1192
+ [data-ui-upload] [data-part-viewerheader] {
1193
1193
  align-items: center;
1194
1194
  border-block-end: var(--_border-width) solid var(--slotted-border-subtle);
1195
1195
  column-gap: var(--_gap);
@@ -1199,7 +1199,7 @@
1199
1199
  padding-inline: var(--slotted-space-6, 1rem);
1200
1200
  }
1201
1201
 
1202
- [data-ui='upload'] [data-part='viewerTitle'] {
1202
+ [data-ui-upload] [data-part-viewertitle] {
1203
1203
  font-size: var(--slotted-font-size-md, 0.875rem);
1204
1204
  line-height: var(--_leading);
1205
1205
  font-weight: var(--slotted-font-weight-semibold, 600);
@@ -1209,13 +1209,13 @@
1209
1209
  white-space: nowrap;
1210
1210
  }
1211
1211
 
1212
- [data-ui='upload'] [data-part='viewerMeta'] {
1212
+ [data-ui-upload] [data-part-viewermeta] {
1213
1213
  color: var(--slotted-text-muted);
1214
1214
  font-size: var(--slotted-font-size-xs, 0.75rem);
1215
1215
  line-height: var(--_leading);
1216
1216
  }
1217
1217
 
1218
- [data-ui='upload'] [data-part='viewerActions'] {
1218
+ [data-ui-upload] [data-part-vieweractions] {
1219
1219
  align-items: center;
1220
1220
  display: inline-flex;
1221
1221
  gap: var(--slotted-space-1, 0.125rem);
@@ -1226,7 +1226,7 @@
1226
1226
  * on it is the consumer's content and a photograph with a white border on a
1227
1227
  * white page has no edge at all.
1228
1228
  */
1229
- [data-ui='upload'] [data-part='viewerStage'] {
1229
+ [data-ui-upload] [data-part-viewerstage] {
1230
1230
  background-color: var(--slotted-surface-sunken);
1231
1231
  display: grid;
1232
1232
  min-block-size: 0;
@@ -1251,8 +1251,8 @@
1251
1251
  * a reader saw as an image running off the screen. `contain` is what keeps a
1252
1252
  * portrait scan and a wide dashcam frame both whole in the same box.
1253
1253
  */
1254
- [data-ui='upload'] [data-part='viewerStage'] > img,
1255
- [data-ui='upload'] [data-part='viewerStage'] > iframe {
1254
+ [data-ui-upload] [data-part-viewerstage] > img,
1255
+ [data-ui-upload] [data-part-viewerstage] > iframe {
1256
1256
  align-self: stretch;
1257
1257
  block-size: auto;
1258
1258
  inline-size: auto;
@@ -1261,7 +1261,7 @@
1261
1261
  min-inline-size: 0;
1262
1262
  }
1263
1263
 
1264
- [data-ui='upload'] [data-part='viewerStage'] > img {
1264
+ [data-ui-upload] [data-part-viewerstage] > img {
1265
1265
  object-fit: contain;
1266
1266
  }
1267
1267
 
@@ -1272,14 +1272,14 @@
1272
1272
  * no script. Both bindings state it; it is written here because a reader of
1273
1273
  * this file will ask why one frame differs from the other.
1274
1274
  */
1275
- [data-ui='upload'] [data-part='viewerStage'] > iframe {
1275
+ [data-ui-upload] [data-part-viewerstage] > iframe {
1276
1276
  background-color: var(--slotted-surface);
1277
1277
  border: 0;
1278
1278
  }
1279
1279
 
1280
1280
  /* Sized by the film rather than by the stage, and never past it. */
1281
- [data-ui='upload'] [data-part='viewerStage'] > video,
1282
- [data-ui='upload'] [data-part='viewerStage'] > audio {
1281
+ [data-ui-upload] [data-part-viewerstage] > video,
1282
+ [data-ui-upload] [data-part-viewerstage] > audio {
1283
1283
  max-block-size: 100%;
1284
1284
  max-inline-size: 100%;
1285
1285
  min-block-size: 0;
@@ -1292,12 +1292,12 @@
1292
1292
  * because a browser cannot draw them and drawing them needs a server or a
1293
1293
  * megabyte of engine — which is the honest answer rather than an empty box.
1294
1294
  */
1295
- [data-ui='upload'] [data-part='viewerStage'] > [data-part='preview'] {
1295
+ [data-ui-upload] [data-part-viewerstage] > [data-part-preview] {
1296
1296
  block-size: var(--slotted-upload-viewer-tile-size, 6rem);
1297
1297
  inline-size: var(--slotted-upload-viewer-tile-size, 6rem);
1298
1298
  }
1299
1299
 
1300
- [data-ui='upload'] [data-part='viewerStage'] > [data-part='preview'] > [data-ui='icon'] {
1300
+ [data-ui-upload] [data-part-viewerstage] > [data-part-preview] > [data-ui-icon] {
1301
1301
  --slotted-icon-size: calc(3 * var(--_glyph-size));
1302
1302
  }
1303
1303
 
@@ -1306,7 +1306,7 @@
1306
1306
  * the defaults provider holds, so an application translates it once; the name
1307
1307
  * and the way out are in the header, where they are for every other file.
1308
1308
  */
1309
- [data-ui='upload'] [data-part='viewerStage'] > p {
1309
+ [data-ui-upload] [data-part-viewerstage] > p {
1310
1310
  color: var(--slotted-text-muted);
1311
1311
  margin: 0;
1312
1312
  max-inline-size: 28ch;
@@ -1319,7 +1319,7 @@
1319
1319
  * different axes and sat diagonally apart; a column of two things centred is
1320
1320
  * one rule with one meaning.
1321
1321
  */
1322
- [data-ui='upload'] [data-part='viewerStage']:has(> [data-part='preview']) {
1322
+ [data-ui-upload] [data-part-viewerstage]:has(> [data-part-preview]) {
1323
1323
  align-items: center;
1324
1324
  display: flex;
1325
1325
  flex-direction: column;
@@ -1332,8 +1332,8 @@
1332
1332
  * the header, where the reader's pointer already is, and they are held off
1333
1333
  * the edge so a photograph that fills the stage is not covered at its corner.
1334
1334
  */
1335
- [data-ui='upload'] [data-part='viewerPrevious'],
1336
- [data-ui='upload'] [data-part='viewerNext'] {
1335
+ [data-ui-upload] [data-part-viewerprevious],
1336
+ [data-ui-upload] [data-part-viewernext] {
1337
1337
  align-items: center;
1338
1338
  appearance: none;
1339
1339
  background-color: color-mix(
@@ -1358,11 +1358,11 @@
1358
1358
  translate var(--slotted-duration-instant) var(--slotted-control-transition-easing);
1359
1359
  }
1360
1360
 
1361
- [data-ui='upload'] [data-part='viewerPrevious'] {
1361
+ [data-ui-upload] [data-part-viewerprevious] {
1362
1362
  inset-inline-start: var(--slotted-space-5, 0.75rem);
1363
1363
  }
1364
1364
 
1365
- [data-ui='upload'] [data-part='viewerNext'] {
1365
+ [data-ui-upload] [data-part-viewernext] {
1366
1366
  inset-inline-end: var(--slotted-space-5, 0.75rem);
1367
1367
  }
1368
1368
 
@@ -1372,12 +1372,12 @@
1372
1372
  * chevron rather than a pair. The binding marks both icons `directional`, so
1373
1373
  * they mirror where reading runs right to left.
1374
1374
  */
1375
- [data-ui='upload'] [data-part='viewerPrevious'] > [data-ui='icon'],
1376
- [data-ui='upload'] [data-part='viewerNext'] > [data-ui='icon'] {
1375
+ [data-ui-upload] [data-part-viewerprevious] > [data-ui-icon],
1376
+ [data-ui-upload] [data-part-viewernext] > [data-ui-icon] {
1377
1377
  --slotted-icon-size: var(--_glyph-size);
1378
1378
  }
1379
1379
 
1380
- [data-ui='upload'] [data-part='viewerPrevious'] > [data-ui='icon'] {
1380
+ [data-ui-upload] [data-part-viewerprevious] > [data-ui-icon] {
1381
1381
  rotate: 180deg;
1382
1382
  }
1383
1383
 
@@ -1387,8 +1387,8 @@
1387
1387
  * is mixed into the plate instead, which keeps it opaque over the photograph
1388
1388
  * and steps it by the amount every other control in the family steps.
1389
1389
  */
1390
- [data-ui='upload'] [data-part='viewerPrevious']:enabled:hover,
1391
- [data-ui='upload'] [data-part='viewerNext']:enabled:hover {
1390
+ [data-ui-upload] [data-part-viewerprevious]:enabled:hover,
1391
+ [data-ui-upload] [data-part-viewernext]:enabled:hover {
1392
1392
  background-color: color-mix(
1393
1393
  in oklab,
1394
1394
  currentcolor var(--slotted-upload-state-layer-hover, 8%),
@@ -1396,8 +1396,8 @@
1396
1396
  );
1397
1397
  }
1398
1398
 
1399
- [data-ui='upload'] [data-part='viewerPrevious']:enabled:active,
1400
- [data-ui='upload'] [data-part='viewerNext']:enabled:active {
1399
+ [data-ui-upload] [data-part-viewerprevious]:enabled:active,
1400
+ [data-ui-upload] [data-part-viewernext]:enabled:active {
1401
1401
  background-color: color-mix(
1402
1402
  in oklab,
1403
1403
  currentcolor var(--slotted-upload-state-layer-active, 14%),
@@ -1406,14 +1406,14 @@
1406
1406
  translate: 0 var(--slotted-border-width-thin, 1px);
1407
1407
  }
1408
1408
 
1409
- [data-ui='upload'] [data-part='viewerPrevious']:disabled,
1410
- [data-ui='upload'] [data-part='viewerNext']:disabled {
1409
+ [data-ui-upload] [data-part-viewerprevious]:disabled,
1410
+ [data-ui-upload] [data-part-viewernext]:disabled {
1411
1411
  color: var(--slotted-disabled-foreground);
1412
1412
  cursor: default;
1413
1413
  }
1414
1414
 
1415
- [data-ui='upload'] [data-part='viewerPrevious']:focus-visible,
1416
- [data-ui='upload'] [data-part='viewerNext']:focus-visible {
1415
+ [data-ui-upload] [data-part-viewerprevious]:focus-visible,
1416
+ [data-ui-upload] [data-part-viewernext]:focus-visible {
1417
1417
  outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
1418
1418
  outline-offset: var(--slotted-focus-ring-offset, 2px);
1419
1419
  }
@@ -1430,9 +1430,9 @@
1430
1430
  * is a third place the DOM is written and a scene that puts an upload in a
1431
1431
  * field has to look like the form does.
1432
1432
  */
1433
- [data-ui='field'] [data-ui='upload'] > [data-part='label'],
1434
- [data-ui='field'] [data-ui='upload'] > [data-part='description'],
1435
- [data-ui='field'] [data-ui='upload'] > [data-part='message'] {
1433
+ [data-ui-field] [data-ui-upload] > [data-part-label],
1434
+ [data-ui-field] [data-ui-upload] > [data-part-description],
1435
+ [data-ui-field] [data-ui-upload] > [data-part-message] {
1436
1436
  display: none;
1437
1437
  }
1438
1438
 
@@ -1442,7 +1442,7 @@
1442
1442
  * one step: the region, the summary and the list are one block rather than
1443
1443
  * three things with a paragraph's air between them.
1444
1444
  */
1445
- [data-ui='field'] [data-ui='upload'][data-part='root'] {
1445
+ [data-ui-field] [data-ui-upload][data-part-root] {
1446
1446
  --_section-gap: var(--slotted-upload-field-section-gap, var(--slotted-space-4, 0.5rem));
1447
1447
  }
1448
1448
 
@@ -1452,7 +1452,7 @@
1452
1452
  * is still a target; what it does not do is claim a box the size of a card
1453
1453
  * for an application that wanted a button.
1454
1454
  */
1455
- [data-ui='upload'][data-variant='button'] [data-part='trigger'] {
1455
+ [data-ui-upload][data-variant='button'] [data-part-trigger] {
1456
1456
  align-self: start;
1457
1457
  }
1458
1458
 
@@ -1470,12 +1470,12 @@
1470
1470
  * written as a border colour on the region, it held one colour through all
1471
1471
  * of them. `:where` keeps it below the invalid and disabled pair.
1472
1472
  */
1473
- [data-ui='upload'][data-variant='field']:where([data-part='root']) {
1473
+ [data-ui-upload][data-variant='field']:where([data-part-root]) {
1474
1474
  --_zone-edge: var(--slotted-control-border-color);
1475
1475
  --_zone-ground: var(--slotted-control-surface, Field);
1476
1476
  }
1477
1477
 
1478
- [data-ui='upload'][data-variant='field'] [data-part='dropzone'] {
1478
+ [data-ui-upload][data-variant='field'] [data-part-dropzone] {
1479
1479
  align-items: center;
1480
1480
  border-style: solid;
1481
1481
  border-width: var(--slotted-control-border-width, 1px);
@@ -1493,13 +1493,13 @@
1493
1493
  * controls move to the corner of the picture, where they are over the one
1494
1494
  * thing the reader is pointing at.
1495
1495
  */
1496
- [data-ui='upload'][data-layout='grid'] [data-part='list'] {
1496
+ [data-ui-upload][data-layout='grid'] [data-part-list] {
1497
1497
  display: grid;
1498
1498
  gap: var(--_gap);
1499
1499
  grid-template-columns: repeat(auto-fill, minmax(var(--slotted-upload-card-measure, 9rem), 1fr));
1500
1500
  }
1501
1501
 
1502
- [data-ui='upload'][data-layout='grid'] [data-part='item'] {
1502
+ [data-ui-upload][data-layout='grid'] [data-part-item] {
1503
1503
  /*
1504
1504
  * Cards in one row share its height, and the spare height of the shorter
1505
1505
  * ones goes under their content rather than between the picture and the
@@ -1523,7 +1523,7 @@
1523
1523
  * the height: 117.66 at 720 pixels, with every edge under it blurred. The
1524
1524
  * card is a container, so `cqi` is the width the picture fills.
1525
1525
  */
1526
- [data-ui='upload'][data-layout='grid'] [data-part='preview'] {
1526
+ [data-ui-upload][data-layout='grid'] [data-part-preview] {
1527
1527
  block-size: round(down, calc(100cqi * 3 / 4), 1px);
1528
1528
  inline-size: 100%;
1529
1529
  }
@@ -1546,7 +1546,7 @@
1546
1546
  * the frameless rest state R2 requires of them and the reader still gets one
1547
1547
  * legible plate.
1548
1548
  */
1549
- [data-ui='upload'][data-layout='grid'] [data-part='actions'] {
1549
+ [data-ui-upload][data-layout='grid'] [data-part-actions] {
1550
1550
  background-color: color-mix(
1551
1551
  in oklab,
1552
1552
  var(--slotted-surface) var(--slotted-upload-card-actions-opacity, 96%),
@@ -1568,7 +1568,7 @@
1568
1568
  * three letters than by the silhouette. It is drawn from the attribute the
1569
1569
  * binding already writes, so the label costs no element.
1570
1570
  */
1571
- [data-ui='upload'][data-layout='grid'] [data-part='preview']:not(:has(img))::after {
1571
+ [data-ui-upload][data-layout='grid'] [data-part-preview]:not(:has(img))::after {
1572
1572
  content: attr(data-extension);
1573
1573
  font-size: var(--slotted-font-size-sm, 0.8125rem);
1574
1574
  font-weight: var(--slotted-font-weight-semibold, 600);
@@ -1578,7 +1578,7 @@
1578
1578
  }
1579
1579
 
1580
1580
  /* A card's tile carries a mark the size of the card, not the size of a row. */
1581
- [data-ui='upload'][data-layout='grid'] [data-part='preview'] > [data-ui='icon'] {
1581
+ [data-ui-upload][data-layout='grid'] [data-part-preview] > [data-ui-icon] {
1582
1582
  --slotted-icon-size: calc(2 * var(--_glyph-size));
1583
1583
  }
1584
1584
 
@@ -1595,7 +1595,7 @@
1595
1595
  * words broke across two lines with the underline broken between them.
1596
1596
  */
1597
1597
  @container slotted-upload (max-width: 30rem) {
1598
- [data-ui='upload'] [data-part='summary'] {
1598
+ [data-ui-upload] [data-part-summary] {
1599
1599
  align-items: start;
1600
1600
  flex-direction: column;
1601
1601
  }
@@ -1608,7 +1608,7 @@
1608
1608
  * characters. The chip spans both rows, so the block it is centred on is
1609
1609
  * still the block it is about.
1610
1610
  */
1611
- [data-ui='upload'] [data-part='item'] {
1611
+ [data-ui-upload] [data-part-item] {
1612
1612
  grid-template-areas:
1613
1613
  'preview body'
1614
1614
  'preview actions'
@@ -1616,16 +1616,16 @@
1616
1616
  grid-template-columns: auto minmax(0, 1fr);
1617
1617
  }
1618
1618
 
1619
- [data-ui='upload'] [data-part='preview'] {
1619
+ [data-ui-upload] [data-part-preview] {
1620
1620
  align-self: start;
1621
1621
  }
1622
1622
 
1623
- [data-ui='upload'] [data-part='actions'] {
1623
+ [data-ui-upload] [data-part-actions] {
1624
1624
  justify-content: flex-start;
1625
1625
  margin-inline-start: calc(-1 * var(--slotted-space-2, 0.25rem));
1626
1626
  }
1627
1627
 
1628
- [data-ui='upload'] [data-part='dropzone'] {
1628
+ [data-ui-upload] [data-part-dropzone] {
1629
1629
  padding-block: var(--slotted-space-6, 1rem);
1630
1630
  }
1631
1631
  }
@@ -1640,8 +1640,8 @@
1640
1640
  * carries it there instead.
1641
1641
  */
1642
1642
  @media (forced-colors: active) {
1643
- [data-ui='upload'] [data-part='item'][data-status='rejected'],
1644
- [data-ui='upload'] [data-part='item'][data-status='error'] {
1643
+ [data-ui-upload] [data-part-item][data-status='rejected'],
1644
+ [data-ui-upload] [data-part-item][data-status='error'] {
1645
1645
  --_item-border: CanvasText;
1646
1646
  }
1647
1647
 
@@ -1651,12 +1651,12 @@
1651
1651
  * out of it — in the system's two colours rather than in nine. What kind a
1652
1652
  * file is, is then said by its shape, which is what survives this mode.
1653
1653
  */
1654
- [data-ui='upload'] [data-part='preview'] {
1654
+ [data-ui-upload] [data-part-preview] {
1655
1655
  border: var(--_border-width) solid ButtonBorder;
1656
1656
  }
1657
1657
 
1658
- [data-ui='upload'] [data-part='dropzone'][data-drop-target],
1659
- [data-ui='upload'] [data-part='dropzone'][data-drop-invalid] {
1658
+ [data-ui-upload] [data-part-dropzone][data-drop-target],
1659
+ [data-ui-upload] [data-part-dropzone][data-drop-invalid] {
1660
1660
  --_zone-border-color: Highlight;
1661
1661
  }
1662
1662
 
@@ -1666,18 +1666,18 @@
1666
1666
  * the reader could see. The system's own pair answers instead — the one
1667
1667
  * `alert` gives its dismiss.
1668
1668
  */
1669
- [data-ui='upload']
1669
+ [data-ui-upload]
1670
1670
  :is(
1671
- [data-part='clear'],
1672
- [data-part='viewerExternal'],
1673
- [data-part='viewerClose'],
1674
- [data-part='viewerPrevious'],
1675
- [data-part='viewerNext'],
1676
- [data-part='start'],
1677
- [data-part='pause'],
1678
- [data-part='retry'],
1679
- [data-part='cancel'],
1680
- [data-part='remove']
1671
+ [data-part-clear],
1672
+ [data-part-viewerexternal],
1673
+ [data-part-viewerclose],
1674
+ [data-part-viewerprevious],
1675
+ [data-part-viewernext],
1676
+ [data-part-start],
1677
+ [data-part-pause],
1678
+ [data-part-retry],
1679
+ [data-part-cancel],
1680
+ [data-part-remove]
1681
1681
  ):enabled:is(:hover, :active) {
1682
1682
  background-color: Highlight;
1683
1683
  color: HighlightText;
@@ -1690,14 +1690,14 @@
1690
1690
  * on the same box an invalid ring is double, which a valid one is not.
1691
1691
  */
1692
1692
  @media (forced-colors: active) {
1693
- [data-ui='upload'][data-invalid] [data-part='trigger'] {
1693
+ [data-ui-upload][data-invalid] [data-part-trigger] {
1694
1694
  outline: var(--_invalid-edge-width) solid CanvasText;
1695
1695
  outline-offset: calc(
1696
1696
  -1 * (var(--slotted-control-border-width, 1px) + var(--_invalid-edge-width))
1697
1697
  );
1698
1698
  }
1699
1699
 
1700
- [data-ui='upload'][data-invalid] [data-part='trigger']:has(:focus-visible) {
1700
+ [data-ui-upload][data-invalid] [data-part-trigger]:has(:focus-visible) {
1701
1701
  outline: calc(var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width)) double
1702
1702
  var(--slotted-focus-ring-color, Highlight);
1703
1703
  outline-offset: var(--slotted-focus-ring-offset, 2px);