@slotted/styles 0.1.0-beta.1 → 0.1.0-beta.11

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 (180) hide show
  1. package/package.json +1 -1
  2. package/src/accordion/accordion.css +10 -10
  3. package/src/action-bar/action-bar.css +35 -42
  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 +149 -68
  17. package/src/button/button.tokens.json +10 -0
  18. package/src/button-group/button-group.css +79 -74
  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 +103 -90
  36. package/src/command-palette/command-palette.tokens.json +1 -0
  37. package/src/container/container.css +24 -24
  38. package/src/context-menu/context-menu.css +8 -8
  39. package/src/currency-field/currency-field.css +210 -88
  40. package/src/currency-field/currency-field.tokens.json +13 -0
  41. package/src/dashboard-grid/dashboard-grid.css +148 -116
  42. package/src/data-grid/data-grid.css +535 -470
  43. package/src/data-grid/data-grid.tokens.json +4 -0
  44. package/src/data-list/data-list.css +81 -70
  45. package/src/data-list/data-list.tokens.json +2 -1
  46. package/src/date-field/date-field.css +55 -52
  47. package/src/date-field/date-field.tokens.json +1 -0
  48. package/src/date-picker/date-picker.css +40 -42
  49. package/src/date-range-picker/date-range-picker.css +114 -118
  50. package/src/datetime-field/datetime-field.css +78 -80
  51. package/src/datetime-field/datetime-field.tokens.json +1 -0
  52. package/src/datetime-picker/datetime-picker.css +61 -63
  53. package/src/datetime-range-picker/datetime-range-picker.css +149 -156
  54. package/src/description-list/description-list.css +61 -64
  55. package/src/detail-panel/detail-panel.css +86 -71
  56. package/src/detail-panel/detail-panel.tokens.json +2 -0
  57. package/src/dialog/dialog.css +372 -153
  58. package/src/dialog/dialog.tokens.json +6 -0
  59. package/src/divider/divider.css +18 -18
  60. package/src/drawer/drawer.css +205 -210
  61. package/src/drawer/drawer.tokens.json +1 -0
  62. package/src/entity-picker/entity-picker.css +238 -241
  63. package/src/entity-picker/entity-picker.tokens.json +1 -0
  64. package/src/event-calendar/event-calendar.css +343 -385
  65. package/src/field/field.css +74 -78
  66. package/src/field-group/field-group.css +22 -25
  67. package/src/filter-bar/filter-bar.css +193 -209
  68. package/src/form/form.css +34 -24
  69. package/src/form/form.tokens.json +1 -0
  70. package/src/fullscreen/fullscreen.css +24 -25
  71. package/src/grid/grid.css +28 -28
  72. package/src/highlight/highlight.css +6 -6
  73. package/src/hover-card/hover-card.css +6 -6
  74. package/src/icon/icon.css +19 -15
  75. package/src/icon/icon.tokens.json +1 -0
  76. package/src/image/image.css +39 -39
  77. package/src/import-export-center/import-export-center.css +135 -156
  78. package/src/inline/inline.css +27 -27
  79. package/src/inline-message/inline-message.css +52 -28
  80. package/src/inline-message/inline-message.tokens.json +4 -0
  81. package/src/kbd/kbd.css +30 -26
  82. package/src/link/link.css +15 -15
  83. package/src/list/list.css +44 -17
  84. package/src/list/list.tokens.json +4 -0
  85. package/src/list-item/list-item.css +80 -66
  86. package/src/list-item/list-item.tokens.json +7 -0
  87. package/src/listbox/listbox.css +56 -59
  88. package/src/loading-overlay/loading-overlay.css +75 -92
  89. package/src/markdown/markdown.css +17 -17
  90. package/src/menu/menu.css +83 -63
  91. package/src/menubar/menubar.css +13 -13
  92. package/src/message/message.css +182 -202
  93. package/src/message/message.tokens.json +5 -0
  94. package/src/message-scroller/message-scroller.css +41 -42
  95. package/src/multi-select/multi-select.css +152 -145
  96. package/src/multi-select/multi-select.tokens.json +1 -0
  97. package/src/navigation-menu/navigation-menu.css +167 -188
  98. package/src/notification-center/notification-center.css +140 -148
  99. package/src/notification-center/notification-center.tokens.json +3 -0
  100. package/src/number-field/number-field.css +84 -83
  101. package/src/number-field/number-field.tokens.json +1 -0
  102. package/src/otp-input/otp-input.css +67 -57
  103. package/src/otp-input/otp-input.tokens.json +1 -0
  104. package/src/page/page.css +39 -23
  105. package/src/page/page.tokens.json +1 -0
  106. package/src/page-header/page-header.css +323 -283
  107. package/src/page-header/page-header.tokens.json +5 -0
  108. package/src/pagination/pagination.css +68 -72
  109. package/src/popover/popover.css +40 -49
  110. package/src/progress-indicator/progress-indicator.css +177 -120
  111. package/src/progress-indicator/progress-indicator.tokens.json +1 -1
  112. package/src/prompt-composer/prompt-composer.css +221 -102
  113. package/src/prompt-composer/prompt-composer.tokens.json +15 -0
  114. package/src/prose/prose.css +71 -75
  115. package/src/radio-group/radio-group.css +98 -103
  116. package/src/rating/rating.css +136 -132
  117. package/src/rating/rating.tokens.json +1 -0
  118. package/src/result-state/result-state.css +74 -77
  119. package/src/runtime-properties.mjs +2 -0
  120. package/src/saved-views/saved-views.css +41 -47
  121. package/src/scroll-area/scroll-area.css +39 -32
  122. package/src/section/section.css +161 -41
  123. package/src/section/section.tokens.json +7 -2
  124. package/src/segmented-control/segmented-control.css +254 -97
  125. package/src/segmented-control/segmented-control.tokens.json +15 -11
  126. package/src/select/select.css +118 -117
  127. package/src/select/select.tokens.json +1 -0
  128. package/src/side-navigation/side-navigation.css +179 -182
  129. package/src/side-navigation/side-navigation.tokens.json +1 -0
  130. package/src/skeleton/skeleton.css +47 -48
  131. package/src/slider/slider.css +86 -88
  132. package/src/sparkline/sparkline.css +62 -40
  133. package/src/sparkline/sparkline.tokens.json +2 -0
  134. package/src/spinner/spinner.css +83 -180
  135. package/src/spinner/spinner.tokens.json +0 -1
  136. package/src/split-button/split-button.css +30 -31
  137. package/src/split-button/split-button.tokens.json +1 -0
  138. package/src/splitter/splitter.css +35 -35
  139. package/src/stack/stack.css +24 -24
  140. package/src/stat-card/stat-card.css +341 -224
  141. package/src/stat-card/stat-card.tokens.json +3 -0
  142. package/src/status-indicator/status-indicator.css +28 -28
  143. package/src/stepper/stepper.css +58 -62
  144. package/src/switch/switch.css +86 -92
  145. package/src/table/table.css +310 -165
  146. package/src/table/table.tokens.json +6 -0
  147. package/src/table-of-contents/table-of-contents.css +51 -54
  148. package/src/tabs/tabs.css +337 -302
  149. package/src/tabs/tabs.tokens.json +8 -5
  150. package/src/tag/tag.css +79 -71
  151. package/src/tag/tag.tokens.json +9 -0
  152. package/src/tags-input/tags-input.css +145 -82
  153. package/src/tags-input/tags-input.tokens.json +7 -1
  154. package/src/text-field/text-field.css +132 -136
  155. package/src/text-field/text-field.tokens.json +1 -0
  156. package/src/textarea/textarea.css +31 -28
  157. package/src/textarea/textarea.tokens.json +1 -0
  158. package/src/time-field/time-field.css +72 -69
  159. package/src/time-field/time-field.tokens.json +1 -0
  160. package/src/time-picker/time-picker.css +56 -58
  161. package/src/time-range-picker/time-range-picker.css +126 -133
  162. package/src/timeline/timeline.css +254 -266
  163. package/src/timeline/timeline.tokens.json +5 -0
  164. package/src/toast/toast.css +108 -90
  165. package/src/toast/toast.tokens.json +6 -0
  166. package/src/toggle/toggle.css +62 -25
  167. package/src/toggle/toggle.tokens.json +8 -0
  168. package/src/toggle-group/toggle-group.css +106 -60
  169. package/src/toggle-group/toggle-group.tokens.json +10 -0
  170. package/src/toolbar/toolbar.css +30 -35
  171. package/src/tooltip/tooltip.css +26 -26
  172. package/src/top-navigation/top-navigation.css +243 -259
  173. package/src/tour/tour.css +51 -60
  174. package/src/transfer/transfer.css +160 -164
  175. package/src/tree/tree.css +103 -111
  176. package/src/typography/typography.css +40 -36
  177. package/src/typography/typography.tokens.json +1 -0
  178. package/src/upload/upload.css +224 -224
  179. package/src/visually-hidden/visually-hidden.css +1 -1
  180. package/src/wizard/wizard.css +185 -197
@@ -16,7 +16,7 @@
16
16
  * indicator, the group and the filter row — is declared after the shared
17
17
  * set.
18
18
  */
19
- [data-ui='data-grid'][data-part='root'] {
19
+ [data-ui-data-grid][data-part-root] {
20
20
  /* Geometry. Every value is the control scale's, so one theme decision
21
21
  retunes the rows, the buttons and the fields together, and
22
22
  `@media (pointer: coarse)` grows all three at once. */
@@ -147,6 +147,13 @@
147
147
  var(--slotted-space-1, 0.125rem) * 2
148
148
  )
149
149
  );
150
+ /* The control scale as the theme states it, read here once: a body row
151
+ restates the scale for what its cells hold (below), and a property
152
+ cannot read its own inherited value. */
153
+ --_control-height-sm: var(--slotted-control-height-sm, 30px);
154
+ --_control-height-md: var(--slotted-control-height-md, 34px);
155
+ --_control-height-lg: var(--slotted-control-height-lg, 38px);
156
+ --_target-min: var(--slotted-target-min, 24px);
150
157
  /* Its glyph keeps two pixels of air inside the control's ground, so at
151
158
  dense — a 17-pixel control in a 25-pixel track — the ground reads as a
152
159
  button and not as a filled cell. */
@@ -183,7 +190,7 @@
183
190
  position: relative;
184
191
  }
185
192
 
186
- [data-ui='data-grid'][data-variant='framed'] {
193
+ [data-ui-data-grid][data-variant='framed'] {
187
194
  border: var(--_rule-width) solid var(--_rule);
188
195
  border-radius: var(--_radius);
189
196
  /* A box standing on the page takes the surface step, as table's frame does. */
@@ -199,12 +206,13 @@
199
206
  * Both axes. It is the window the virtualiser measures, so it takes the room
200
207
  * the frame leaves after the footer and scrolls what does not fit.
201
208
  */
202
- [data-ui='data-grid'] > [data-part='scroll'] {
203
- /* The container a detail row, a group row and the empty state measure
204
- their width against: each spans every column of a template that may
205
- be wider than the frame, and `100cqi` is what holds it to the frame. */
206
- container-name: slotted-data-grid;
207
- container-type: inline-size;
209
+ [data-ui-data-grid] > [data-part-scroll] {
210
+ /* No `container-type`. A detail row, a group row and the empty state are
211
+ held to the frame by `--slotted-data-grid-viewport`, the scroller's
212
+ width the binding measures. As a size container the scroller made the
213
+ browser recalculate and lay out everything inside it whenever a row
214
+ entered or left: 45 ms of layout per scroll step on a grid of 29 mounted
215
+ rows, against 3 ms without it. */
208
216
  flex: 1 1 auto;
209
217
  min-block-size: 0;
210
218
  overflow: auto;
@@ -223,7 +231,7 @@
223
231
  position: relative;
224
232
  }
225
233
 
226
- [data-ui='data-grid'][data-sticky-to='page'] > [data-part='scroll'] {
234
+ [data-ui-data-grid][data-sticky-to='page'] > [data-part-scroll] {
227
235
  overflow: visible;
228
236
  }
229
237
 
@@ -251,14 +259,14 @@
251
259
  other: a widget inside a cell may hold rows of its own — a multi-select's
252
260
  chips are a `row` of a grid pattern — and a descendant selector laid its
253
261
  chips out on this grid's column template. */
254
- [data-ui='data-grid']
255
- > [data-part='scroll']
262
+ [data-ui-data-grid]
263
+ > [data-part-scroll]
256
264
  > :is(
257
- [data-part='head'],
258
- [data-part='body'],
259
- [data-part='pinned-rows'],
260
- [data-part='summary'],
261
- [data-part='loader']
265
+ [data-part-head],
266
+ [data-part-body],
267
+ [data-part-pinned-rows],
268
+ [data-part-summary],
269
+ [data-part-loader]
262
270
  )
263
271
  > [role='row'] {
264
272
  box-sizing: border-box;
@@ -279,7 +287,7 @@
279
287
 
280
288
  /* The rules between rows are the rows' own: a row is a block box, unlike a
281
289
  table row, so its border runs the whole width, filler included. */
282
- [data-ui='data-grid'] [data-part='header-row'] {
290
+ [data-ui-data-grid] [data-part-header-row] {
283
291
  background-color: var(--_head-surface);
284
292
  border-block-end: var(--_rule-width) solid var(--_rule-strong);
285
293
  }
@@ -287,27 +295,27 @@
287
295
  /* A row of column groups stands above the row of names, and the rule
288
296
  between the two is the lighter one; the strong rule is the last header
289
297
  row's, over the values. */
290
- [data-ui='data-grid'] [data-part='header-row']:not(:last-of-type) {
298
+ [data-ui-data-grid] [data-part-header-row]:not(:last-of-type) {
291
299
  border-block-end-color: var(--_rule);
292
300
  }
293
301
 
294
- [data-ui='data-grid'][data-variant='plain'] [data-part='header-row'] {
302
+ [data-ui-data-grid][data-variant='plain'] [data-part-header-row] {
295
303
  background-color: transparent;
296
304
  }
297
305
 
298
- [data-ui='data-grid'] [data-part='filter-row'] {
306
+ [data-ui-data-grid] [data-part-filter-row] {
299
307
  background-color: var(--_band-surface);
300
308
  border-block-end: var(--_rule-width) solid var(--_rule);
301
309
  }
302
310
 
303
- [data-ui='data-grid']
304
- > [data-part='scroll']
311
+ [data-ui-data-grid]
312
+ > [data-part-scroll]
305
313
  > :is(
306
- [data-part='head'],
307
- [data-part='body'],
308
- [data-part='pinned-rows'],
309
- [data-part='summary'],
310
- [data-part='loader']
314
+ [data-part-head],
315
+ [data-part-body],
316
+ [data-part-pinned-rows],
317
+ [data-part-summary],
318
+ [data-part-loader]
311
319
  )
312
320
  > [role='row']
313
321
  > * {
@@ -318,14 +326,14 @@
318
326
  scroller's width with wider rows inside it is a box its own rows overflow,
319
327
  which the page audit reads as a defect and a reader never sees. Sized to
320
328
  the rows, the only thing that scrolls is the scroller. */
321
- [data-ui='data-grid']
322
- > [data-part='scroll']
329
+ [data-ui-data-grid]
330
+ > [data-part-scroll]
323
331
  > :is(
324
- [data-part='head'],
325
- [data-part='body'],
326
- [data-part='pinned-rows'],
327
- [data-part='summary'],
328
- [data-part='loader']
332
+ [data-part-head],
333
+ [data-part-body],
334
+ [data-part-pinned-rows],
335
+ [data-part-summary],
336
+ [data-part-loader]
329
337
  ) {
330
338
  inline-size: fit-content;
331
339
  min-inline-size: 100%;
@@ -342,23 +350,23 @@
342
350
  * `button` inside a `columnheader` would be a widget the cursor has to
343
351
  * enter.
344
352
  */
345
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='head'] {
353
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-head] {
346
354
  inset-block-start: var(--slotted-data-grid-sticky-offset, 0);
347
355
  position: sticky;
348
356
  z-index: calc(var(--slotted-z-index-sticky, 100) + 1);
349
357
  }
350
358
 
351
- [data-ui='data-grid']:not([data-sticky-header]) > [data-part='scroll'] > [data-part='head'] {
359
+ [data-ui-data-grid]:not([data-sticky-header]) > [data-part-scroll] > [data-part-head] {
352
360
  position: static;
353
361
  }
354
362
 
355
- [data-ui='data-grid'] [data-part='column-header'],
356
- [data-ui='data-grid'] [data-part='column-group'],
357
- [data-ui='data-grid']
358
- > [data-part='scroll']
359
- > [data-part='head']
363
+ [data-ui-data-grid] [data-part-column-header],
364
+ [data-ui-data-grid] [data-part-column-group],
365
+ [data-ui-data-grid]
366
+ > [data-part-scroll]
367
+ > [data-part-head]
360
368
  > [role='row']
361
- > [data-part='selection'] {
369
+ > [data-part-selection] {
362
370
  align-items: center;
363
371
  background-color: var(--_head-surface);
364
372
  box-sizing: border-box;
@@ -378,21 +386,21 @@
378
386
  transition: background-color var(--_transition);
379
387
  }
380
388
 
381
- [data-ui='data-grid'][data-variant='plain']
382
- :is([data-part='column-header'], [data-part='column-group']) {
389
+ [data-ui-data-grid][data-variant='plain']
390
+ :is([data-part-column-header], [data-part-column-group]) {
383
391
  background-color: transparent;
384
392
  }
385
393
 
386
394
  /* A group header is centred over the columns it spans and separated from
387
395
  the row of column names by the same rule that separates the names from
388
396
  the values, one step lighter. */
389
- [data-ui='data-grid'] [data-part='column-group'] {
397
+ [data-ui-data-grid] [data-part-column-group] {
390
398
  justify-content: center;
391
399
  }
392
400
 
393
401
  /* The name takes what is left and truncates: a column name is two or three
394
402
  words and its full text is the header's own accessible name. */
395
- [data-ui='data-grid'] [data-part='column-header'] > span:first-child {
403
+ [data-ui-data-grid] [data-part-column-header] > span:first-child {
396
404
  flex: 1 1 auto;
397
405
  min-inline-size: 0;
398
406
  overflow: hidden;
@@ -401,30 +409,30 @@
401
409
  }
402
410
 
403
411
  /* An aligned column keeps its name over its values. */
404
- [data-ui='data-grid'] [data-part='column-header'][data-align='center'] {
412
+ [data-ui-data-grid] [data-part-column-header][data-align='center'] {
405
413
  justify-content: center;
406
414
  }
407
415
 
408
- [data-ui='data-grid'] [data-part='column-header'][data-align='center'] > span:first-child {
416
+ [data-ui-data-grid] [data-part-column-header][data-align='center'] > span:first-child {
409
417
  flex: 0 1 auto;
410
418
  margin-inline-start: auto;
411
419
  }
412
420
 
413
- [data-ui='data-grid']
414
- [data-part='column-header']:is([data-align='end'], [data-numeric]:not([data-align]))
421
+ [data-ui-data-grid]
422
+ [data-part-column-header]:is([data-align='end'], [data-numeric]:not([data-align]))
415
423
  > span:first-child {
416
424
  text-align: end;
417
425
  }
418
426
 
419
427
  /* A sortable header is a control and takes the hand. */
420
- [data-ui='data-grid'] [data-part='column-header'][data-sortable] {
428
+ [data-ui-data-grid] [data-part-column-header][data-sortable] {
421
429
  cursor: pointer;
422
430
  }
423
431
 
424
432
  /* A header, a filter cell and a summary cell are controls, not prose: a
425
433
  Shift-press that appends a sort key must not also select its name. */
426
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='head'] > [role='row'] > *,
427
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='summary'] > [role='row'] > * {
434
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-head] > [role='row'] > *,
435
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-summary] > [role='row'] > * {
428
436
  user-select: none;
429
437
  }
430
438
 
@@ -432,12 +440,12 @@
432
440
  selection of the grid's own and not of text: the browser's selection is
433
441
  put out of the body for the two modes that press across cells. Ctrl+C
434
442
  copies the range; a grid with no selection keeps its text selectable. */
435
- [data-ui='data-grid']:is([data-selection='multiple'], [data-selection='range'])
436
- :is([data-part='body'], [data-part='pinned-rows']) {
443
+ [data-ui-data-grid]:is([data-selection='multiple'], [data-selection='range'])
444
+ :is([data-part-body], [data-part-pinned-rows]) {
437
445
  user-select: none;
438
446
  }
439
447
 
440
- [data-ui='data-grid'] [data-part='column-header'][data-sortable]:not([data-disabled]):hover {
448
+ [data-ui-data-grid] [data-part-column-header][data-sortable]:not([data-disabled]):hover {
441
449
  background-color: var(--_head-surface-hover);
442
450
  }
443
451
 
@@ -451,7 +459,7 @@
451
459
  * header can be sorted is the hand, the darker band and the menu it
452
460
  * reveals — the answer AG Grid gives.
453
461
  */
454
- [data-ui='data-grid'] [data-part='column-header'] > [data-part='sort'] {
462
+ [data-ui-data-grid] [data-part-column-header] > [data-part-sort] {
455
463
  --slotted-icon-size: var(--_icon-size);
456
464
  align-items: center;
457
465
  color: var(--_text);
@@ -463,29 +471,29 @@
463
471
  line-height: 1;
464
472
  }
465
473
 
466
- [data-ui='data-grid'] [data-part='column-header'] > [data-part='sort'] > [data-ui='icon'] {
474
+ [data-ui-data-grid] [data-part-column-header] > [data-part-sort] > [data-ui-icon] {
467
475
  transition: rotate var(--_transition);
468
476
  }
469
477
 
470
- [data-ui='data-grid'] [data-part='column-header'][data-sorted] > [data-part='sort'] {
478
+ [data-ui-data-grid] [data-part-column-header][data-sorted] > [data-part-sort] {
471
479
  display: inline-flex;
472
480
  }
473
481
 
474
- [data-ui='data-grid']
475
- [data-part='column-header'][data-sorted='ascending']
476
- > [data-part='sort']
477
- > [data-ui='icon'] {
482
+ [data-ui-data-grid]
483
+ [data-part-column-header][data-sorted='ascending']
484
+ > [data-part-sort]
485
+ > [data-ui-icon] {
478
486
  rotate: 180deg;
479
487
  }
480
488
 
481
489
  /* The index of a key past the first, drawn only then: `aria-sort` cannot say
482
490
  which key came first, and the number is what says it. */
483
- [data-ui='data-grid'] [data-part='column-header'] > [data-part='sort']::before {
491
+ [data-ui-data-grid] [data-part-column-header] > [data-part-sort]::before {
484
492
  content: attr(data-index);
485
493
  font-weight: var(--slotted-font-weight-medium, 500);
486
494
  }
487
495
 
488
- [data-ui='data-grid'] [data-part='column-header'] > [data-part='sort']:not([data-index])::before {
496
+ [data-ui-data-grid] [data-part-column-header] > [data-part-sort]:not([data-index])::before {
489
497
  content: none;
490
498
  }
491
499
 
@@ -505,7 +513,7 @@
505
513
  * filter row. Read on the first capture with both controls reserving room,
506
514
  * a 120-pixel column had 34 pixels left for its name.
507
515
  */
508
- [data-ui='data-grid'] [data-part='column-actions'] {
516
+ [data-ui-data-grid] [data-part-column-actions] {
509
517
  align-items: center;
510
518
  display: inline-flex;
511
519
  flex: none;
@@ -516,16 +524,16 @@
516
524
  margin-inline-start: auto;
517
525
  }
518
526
 
519
- [data-ui='data-grid'] [data-part='column-actions'] *:has([data-part='filter']) {
527
+ [data-ui-data-grid] [data-part-column-actions] *:has([data-part-filter]) {
520
528
  display: contents;
521
529
  }
522
530
 
523
- [data-ui='data-grid'] [data-part='column-help'],
524
- [data-ui='data-grid'] [data-part='column-menu'],
525
- [data-ui='data-grid'] [data-part='column-header'] [data-part='filter'],
526
- [data-ui='data-grid'] [data-part='expander'],
527
- [data-ui='data-grid'] [data-part='group-toggle'],
528
- [data-ui='data-grid'] [data-part='tree-toggle'] {
531
+ [data-ui-data-grid] [data-part-column-help],
532
+ [data-ui-data-grid] [data-part-column-menu],
533
+ [data-ui-data-grid] [data-part-column-header] [data-part-filter],
534
+ [data-ui-data-grid] [data-part-expander],
535
+ [data-ui-data-grid] [data-part-group-toggle],
536
+ [data-ui-data-grid] [data-part-tree-toggle] {
529
537
  /* The mark inside is the `Glyph` the binding draws, at the controls' own
530
538
  icon step rather than the box's. */
531
539
  --slotted-icon-size: var(--_control-icon);
@@ -547,44 +555,42 @@
547
555
  opacity var(--_transition);
548
556
  }
549
557
 
550
- [data-ui='data-grid'] [data-part='column-menu'] {
558
+ [data-ui-data-grid] [data-part-column-menu] {
551
559
  opacity: 0;
552
560
  }
553
561
 
554
- [data-ui='data-grid']
555
- [data-part='column-header']
556
- [data-part='filter']:not([data-filtered], [data-open]) {
562
+ [data-ui-data-grid]
563
+ [data-part-column-header]
564
+ [data-part-filter]:not([data-filtered], [data-open]) {
557
565
  display: none;
558
566
  }
559
567
 
560
- [data-ui='data-grid']
561
- [data-part='column-header']:not([data-disabled]):hover
562
- [data-part='column-menu'],
563
- [data-ui='data-grid'] [data-part='column-header']:focus-within [data-part='column-menu'],
564
- [data-ui='data-grid'] [data-part='column-header'][data-current] [data-part='column-menu'],
565
- [data-ui='data-grid'] [data-part='column-menu'][data-open] {
568
+ [data-ui-data-grid] [data-part-column-header]:not([data-disabled]):hover [data-part-column-menu],
569
+ [data-ui-data-grid] [data-part-column-header]:focus-within [data-part-column-menu],
570
+ [data-ui-data-grid] [data-part-column-header][data-current] [data-part-column-menu],
571
+ [data-ui-data-grid] [data-part-column-menu][data-open] {
566
572
  opacity: 1;
567
573
  }
568
574
 
569
- [data-ui='data-grid'] [data-part='column-help']:not(:disabled):hover,
570
- [data-ui='data-grid'] [data-part='column-help'][data-open],
571
- [data-ui='data-grid'] [data-part='column-menu']:not(:disabled):hover,
572
- [data-ui='data-grid'] [data-part='column-header'] [data-part='filter']:not(:disabled):hover,
573
- [data-ui='data-grid'] [data-part='group-toggle']:not(:disabled):hover {
575
+ [data-ui-data-grid] [data-part-column-help]:not(:disabled):hover,
576
+ [data-ui-data-grid] [data-part-column-help][data-open],
577
+ [data-ui-data-grid] [data-part-column-menu]:not(:disabled):hover,
578
+ [data-ui-data-grid] [data-part-column-header] [data-part-filter]:not(:disabled):hover,
579
+ [data-ui-data-grid] [data-part-group-toggle]:not(:disabled):hover {
574
580
  background-color: var(--_head-surface-hover);
575
581
  color: var(--_text);
576
582
  }
577
583
 
578
- [data-ui='data-grid'] [data-part='expander']:not(:disabled):hover {
584
+ [data-ui-data-grid] [data-part-expander]:not(:disabled):hover {
579
585
  background-color: var(--_hover);
580
586
  color: var(--_text);
581
587
  }
582
588
 
583
- [data-ui='data-grid'] [data-part='column-help']:focus-visible,
584
- [data-ui='data-grid'] [data-part='column-menu']:focus-visible,
585
- [data-ui='data-grid'] [data-part='column-header'] [data-part='filter']:focus-visible,
586
- [data-ui='data-grid'] [data-part='expander']:focus-visible,
587
- [data-ui='data-grid'] [data-part='group-toggle']:focus-visible {
589
+ [data-ui-data-grid] [data-part-column-help]:focus-visible,
590
+ [data-ui-data-grid] [data-part-column-menu]:focus-visible,
591
+ [data-ui-data-grid] [data-part-column-header] [data-part-filter]:focus-visible,
592
+ [data-ui-data-grid] [data-part-expander]:focus-visible,
593
+ [data-ui-data-grid] [data-part-group-toggle]:focus-visible {
588
594
  outline: var(--_ring-width) solid var(--slotted-focus-ring-color, Highlight);
589
595
  outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
590
596
  }
@@ -596,7 +602,7 @@
596
602
 
597
603
  /* The description is the header's `aria-describedby`: read, never drawn,
598
604
  and out of the header's flow so it asks for no room beside the name. */
599
- [data-ui='data-grid'] [data-part='column-description'] {
605
+ [data-ui-data-grid] [data-part-column-description] {
600
606
  block-size: 1px;
601
607
  border: 0;
602
608
  clip-path: inset(50%);
@@ -610,7 +616,7 @@
610
616
 
611
617
  /* The pop-in's column header names the pop-in for a reader: read, never
612
618
  drawn, and out of the row's flow so it takes no track of the template. */
613
- [data-ui='data-grid'] [data-part='popin-header'] {
619
+ [data-ui-data-grid] [data-part-popin-header] {
614
620
  block-size: 1px;
615
621
  border: 0;
616
622
  clip-path: inset(50%);
@@ -627,7 +633,7 @@
627
633
  is set as a caption over the items, in the muted ink, on the items' inset.
628
634
  The screen reader hears it once, through the menu's `aria-describedby`.
629
635
  The menu lays its items on a grid of tracks; the caption spans them all. */
630
- [data-ui='menu'] [data-part='column-menu-description'] {
636
+ [data-ui-menu] [data-part-column-menu-description] {
631
637
  grid-column: 1 / -1;
632
638
  border-block-end: var(--slotted-border-width-thin, 1px) solid
633
639
  var(--slotted-border-subtle, GrayText);
@@ -645,49 +651,47 @@
645
651
  glyph scale for this family: `table` takes the artwork from the consumer,
646
652
  and a control this family draws itself owes its glyph to the scale. */
647
653
 
648
- [data-ui='data-grid'] [data-part='column-header'] [data-part='filter'][data-filtered],
649
- [data-ui='data-grid'] [data-part='column-header'] [data-part='filter'][data-open] {
654
+ [data-ui-data-grid] [data-part-column-header] [data-part-filter][data-filtered],
655
+ [data-ui-data-grid] [data-part-column-header] [data-part-filter][data-open] {
650
656
  color: var(--slotted-tone-accent-text, CanvasText);
651
657
  }
652
658
 
653
- [data-ui='data-grid']
654
- [data-part='column-header']
655
- [data-part='filter'][data-filtered]:not(:disabled):hover {
659
+ [data-ui-data-grid]
660
+ [data-part-column-header]
661
+ [data-part-filter][data-filtered]:not(:disabled):hover {
656
662
  background-color: var(--slotted-tone-accent-surface, Canvas);
657
663
  }
658
664
 
659
665
  /* The expander and the group toggle are the `chevron-right` `Glyph` the
660
666
  binding draws, turned a quarter turn when open and mirrored in a
661
667
  right-to-left document. */
662
- [data-ui='data-grid'] [data-part='expander'] > [data-ui='icon'],
663
- [data-ui='data-grid'] [data-part='group-toggle'] > [data-ui='icon'],
664
- [data-ui='data-grid'] button[data-part='tree-toggle'] > [data-ui='icon'] {
668
+ [data-ui-data-grid] [data-part-expander] > [data-ui-icon],
669
+ [data-ui-data-grid] [data-part-group-toggle] > [data-ui-icon],
670
+ [data-ui-data-grid] button[data-part-tree-toggle] > [data-ui-icon] {
665
671
  transition: rotate var(--_transition);
666
672
  }
667
673
 
668
- [data-ui='data-grid'] [data-part='expander'][aria-expanded='true'] > [data-ui='icon'],
669
- [data-ui='data-grid'] button[data-part='tree-toggle'][aria-expanded='true'] > [data-ui='icon'],
670
- [data-ui='data-grid']
671
- [data-part='group-row'][aria-expanded='true']
672
- [data-part='group-toggle']
673
- > [data-ui='icon'] {
674
+ [data-ui-data-grid] [data-part-expander][aria-expanded='true'] > [data-ui-icon],
675
+ [data-ui-data-grid] button[data-part-tree-toggle][aria-expanded='true'] > [data-ui-icon],
676
+ [data-ui-data-grid]
677
+ [data-part-group-row][aria-expanded='true']
678
+ [data-part-group-toggle]
679
+ > [data-ui-icon] {
674
680
  rotate: 90deg;
675
681
  }
676
682
 
677
- [data-ui='data-grid']:dir(rtl) [data-part='expander'] > [data-ui='icon'],
678
- [data-ui='data-grid']:dir(rtl) [data-part='group-toggle'] > [data-ui='icon'],
679
- [data-ui='data-grid']:dir(rtl) button[data-part='tree-toggle'] > [data-ui='icon'] {
683
+ [data-ui-data-grid]:dir(rtl) [data-part-expander] > [data-ui-icon],
684
+ [data-ui-data-grid]:dir(rtl) [data-part-group-toggle] > [data-ui-icon],
685
+ [data-ui-data-grid]:dir(rtl) button[data-part-tree-toggle] > [data-ui-icon] {
680
686
  rotate: 180deg;
681
687
  }
682
688
 
683
- [data-ui='data-grid']:dir(rtl) [data-part='expander'][aria-expanded='true'] > [data-ui='icon'],
684
- [data-ui='data-grid']:dir(rtl)
685
- button[data-part='tree-toggle'][aria-expanded='true']
686
- > [data-ui='icon'],
687
- [data-ui='data-grid']:dir(rtl)
688
- [data-part='group-row'][aria-expanded='true']
689
- [data-part='group-toggle']
690
- > [data-ui='icon'] {
689
+ [data-ui-data-grid]:dir(rtl) [data-part-expander][aria-expanded='true'] > [data-ui-icon],
690
+ [data-ui-data-grid]:dir(rtl) button[data-part-tree-toggle][aria-expanded='true'] > [data-ui-icon],
691
+ [data-ui-data-grid]:dir(rtl)
692
+ [data-part-group-row][aria-expanded='true']
693
+ [data-part-group-toggle]
694
+ > [data-ui-icon] {
691
695
  rotate: 90deg;
692
696
  }
693
697
 
@@ -700,26 +704,26 @@
700
704
  * horizontal arrows there open and close. A row waiting for its children
701
705
  * turns the chevron into the loader's ring.
702
706
  */
703
- [data-ui='data-grid'] [data-part='cell'][data-tree],
704
- [data-ui='data-grid'] [data-part='row-header'][data-tree] {
707
+ [data-ui-data-grid] [data-part-cell][data-tree],
708
+ [data-ui-data-grid] [data-part-row-header][data-tree] {
705
709
  gap: var(--slotted-space-1, 0.125rem);
706
710
  padding-inline-start: calc(
707
711
  var(--_pad-inline) + var(--_indent) * (var(--slotted-data-grid-level, 1) - 1)
708
712
  );
709
713
  }
710
714
 
711
- [data-ui='data-grid'] [data-part='tree-toggle'][data-empty] {
715
+ [data-ui-data-grid] [data-part-tree-toggle][data-empty] {
712
716
  /* The room, and nothing in it. */
713
717
  cursor: default;
714
718
  }
715
719
 
716
- [data-ui='data-grid'] button[data-part='tree-toggle']:not(:disabled):hover {
720
+ [data-ui-data-grid] button[data-part-tree-toggle]:not(:disabled):hover {
717
721
  background-color: var(--_hover);
718
722
  color: var(--_text);
719
723
  }
720
724
 
721
725
  /* The binding draws the loader's ring in place of the chevron. */
722
- [data-ui='data-grid'] button[data-part='tree-toggle'][data-loading] > [data-ui='icon'] {
726
+ [data-ui-data-grid] button[data-part-tree-toggle][data-loading] > [data-ui-icon] {
723
727
  animation: slotted-data-grid-turn var(--slotted-duration-loop) linear infinite;
724
728
  rotate: 0deg;
725
729
  }
@@ -739,12 +743,12 @@
739
743
  * width and the reader hears why nothing moves. A row on its way is
740
744
  * dimmed, as a column is.
741
745
  */
742
- [data-ui='data-grid'] [data-part='cell'][data-kind='drag'] {
746
+ [data-ui-data-grid] [data-part-cell][data-kind='drag'] {
743
747
  justify-content: center;
744
748
  padding-inline: 0;
745
749
  }
746
750
 
747
- [data-ui='data-grid'] [data-part='row-handle'] {
751
+ [data-ui-data-grid] [data-part-row-handle] {
748
752
  /* The grip is the `Glyph` the binding draws, at the controls' icon step. */
749
753
  --slotted-icon-size: var(--_control-icon);
750
754
  align-items: center;
@@ -766,21 +770,21 @@
766
770
  opacity var(--_transition);
767
771
  }
768
772
 
769
- [data-ui='data-grid'] [data-part='row-handle']:not([data-disabled]):hover {
773
+ [data-ui-data-grid] [data-part-row-handle]:not([data-disabled]):hover {
770
774
  background-color: var(--_hover);
771
775
  color: var(--_text);
772
776
  }
773
777
 
774
- [data-ui='data-grid'] [data-part='row-handle'][data-disabled] {
778
+ [data-ui-data-grid] [data-part-row-handle][data-disabled] {
775
779
  cursor: default;
776
780
  opacity: 0.5;
777
781
  }
778
782
 
779
- [data-ui='data-grid'] [data-part='row'][data-dragging] {
783
+ [data-ui-data-grid] [data-part-row][data-dragging] {
780
784
  opacity: 0.5;
781
785
  }
782
786
 
783
- [data-ui='data-grid'] [data-part='row'][data-dragging] [data-part='row-handle'] {
787
+ [data-ui-data-grid] [data-part-row][data-dragging] [data-part-row-handle] {
784
788
  cursor: grabbing;
785
789
  }
786
790
 
@@ -794,7 +798,7 @@
794
798
  * resizes from the header cell itself, and a focusable handle inside a
795
799
  * composite widget would be a second tab stop.
796
800
  */
797
- [data-ui='data-grid'] [data-part='resizer'] {
801
+ [data-ui-data-grid] [data-part-resizer] {
798
802
  cursor: col-resize;
799
803
  inline-size: var(--slotted-target-min, 24px);
800
804
  inset-block: 0;
@@ -808,16 +812,17 @@
808
812
 
809
813
  /* The last column's handle stays inside the row: half a target hanging
810
814
  past the last cell was twelve pixels of overflow on a row nothing could
811
- scroll to. */
812
- [data-ui='data-grid']
813
- [data-part='header-row']
814
- > [data-part='column-header']:last-child
815
- > [data-part='resizer'] {
815
+ scroll to. The last column header, not the row's last child: the pop-in
816
+ header follows it when columns yield to the frame. */
817
+ [data-ui-data-grid]
818
+ [data-part-header-row]
819
+ > [data-part-column-header]:not(:has(~ [data-part-column-header]))
820
+ > [data-part-resizer] {
816
821
  inline-size: calc(var(--slotted-target-min, 24px) / 2);
817
822
  inset-inline-end: 0;
818
823
  }
819
824
 
820
- [data-ui='data-grid'] [data-part='resizer']::after {
825
+ [data-ui-data-grid] [data-part-resizer]::after {
821
826
  background-color: transparent;
822
827
  block-size: 100%;
823
828
  content: '';
@@ -827,15 +832,39 @@
827
832
  transition: background-color var(--_transition);
828
833
  }
829
834
 
830
- [data-ui='data-grid'] [data-part='resizer']:not([data-disabled]):hover::after {
835
+ [data-ui-data-grid] [data-part-resizer]:not([data-disabled]):hover::after {
831
836
  background-color: var(--_rule-strong);
832
837
  }
833
838
 
834
- [data-ui='data-grid'] [data-part='resizer'][data-resizing]::after,
835
- [data-ui='data-grid'] [data-part='column-header'][data-resizing] > [data-part='resizer']::after {
839
+ [data-ui-data-grid] [data-part-resizer][data-resizing]::after,
840
+ [data-ui-data-grid] [data-part-column-header][data-resizing] > [data-part-resizer]::after {
836
841
  background-color: var(--_cursor);
837
842
  }
838
843
 
844
+ /**
845
+ * Under `resizeMode="deferred"` the drag moves this line and nothing else:
846
+ * it stands on the column's edge, spans the scroller's visible height and
847
+ * slides by `translate`, which lays nothing out; the width is applied once,
848
+ * on release.
849
+ */
850
+ [data-ui-data-grid] [data-part-resizer] > [data-part-resize-guide] {
851
+ background-color: var(
852
+ --slotted-data-grid-resize-guide-color,
853
+ var(--slotted-focus-ring-color, Highlight)
854
+ );
855
+ inline-size: var(
856
+ --slotted-data-grid-resize-guide-width,
857
+ var(--slotted-border-width-thick, 2px)
858
+ );
859
+ inset-block-start: 0;
860
+ inset-inline-start: calc(
861
+ 50% - var(--slotted-data-grid-resize-guide-width, var(--slotted-border-width-thick, 2px)) / 2
862
+ );
863
+ pointer-events: none;
864
+ position: absolute;
865
+ z-index: 2;
866
+ }
867
+
839
868
  /**
840
869
  * ── Reordering ─────────────────────────────────────────────────────────
841
870
  *
@@ -843,15 +872,15 @@
843
872
  * colour between two columns, positioned by the binding through
844
873
  * `--slotted-data-grid-drop-offset` from the scroller's start edge.
845
874
  */
846
- [data-ui='data-grid'] [data-part='column-header'][data-dragging] {
875
+ [data-ui-data-grid] [data-part-column-header][data-dragging] {
847
876
  opacity: 0.5;
848
877
  }
849
878
 
850
- [data-ui='data-grid'] [data-part='column-header'][data-drop-target] {
879
+ [data-ui-data-grid] [data-part-column-header][data-drop-target] {
851
880
  background-color: var(--_head-surface-hover);
852
881
  }
853
882
 
854
- [data-ui='data-grid'] [data-part='drop-indicator'] {
883
+ [data-ui-data-grid] [data-part-drop-indicator] {
855
884
  background-color: var(--_cursor);
856
885
  /* Absolute in the scroller: its box is the content's, so the line is
857
886
  moved down by the scrolled distance to span the viewport. */
@@ -868,9 +897,9 @@
868
897
 
869
898
  /* The same line for a row on its way: horizontal, in the gap the drop
870
899
  lands in, as wide as the viewport and moved by the sideways scroll. */
871
- [data-ui='data-grid'] [data-part='drop-indicator'][data-axis='row'] {
900
+ [data-ui-data-grid] [data-part-drop-indicator][data-axis='row'] {
872
901
  block-size: var(--slotted-border-width-thick, 2px);
873
- inline-size: 100cqi;
902
+ inline-size: var(--slotted-data-grid-viewport, 100%);
874
903
  inset-block-start: calc(
875
904
  var(--slotted-data-grid-drop-offset, 0px) - var(--slotted-border-width-thick, 2px) / 2
876
905
  );
@@ -886,7 +915,7 @@
886
915
  * head. It is a row of the grid — `role="row"`, one `gridcell` per column —
887
916
  * so the cursor walks it.
888
917
  */
889
- [data-ui='data-grid'] [data-part='filter-row'] > [data-part='filter-cell'] {
918
+ [data-ui-data-grid] [data-part-filter-row] > [data-part-filter-cell] {
890
919
  /* The control inside draws no ring of its own: the cell draws the trace
891
920
  around the whole of it while anything inside has the focus, so a field
892
921
  in the row and the cell it fills are not two rings. The accent edge a
@@ -906,7 +935,7 @@
906
935
  position: relative;
907
936
  }
908
937
 
909
- [data-ui='data-grid'] [data-part='filter-row'] > [data-part='filter-cell']:focus-within {
938
+ [data-ui-data-grid] [data-part-filter-row] > [data-part-filter-cell]:focus-within {
910
939
  box-shadow: none;
911
940
  outline: var(--_ring-width) solid var(--slotted-focus-ring-color, Highlight);
912
941
  outline-offset: calc(var(--_ring-width) * -1);
@@ -923,11 +952,8 @@
923
952
  named there, and `A > :is(host > B)` asks B to be A's child and the
924
953
  host's at once. `data-grid.styles.test.mjs` holds the rule for every
925
954
  hosted part. */
926
- [data-ui='data-grid'] [data-part='filter-cell'] > [data-part='filter-operand'],
927
- [data-ui='data-grid']
928
- [data-part='filter-cell']
929
- > :not([data-part])
930
- > [data-part='filter-operand'] {
955
+ [data-ui-data-grid] [data-part-filter-cell] > [data-part-filter-operand],
956
+ [data-ui-data-grid] [data-part-filter-cell] > :not([data-part]) > [data-part-filter-operand] {
931
957
  align-items: center;
932
958
  display: flex;
933
959
  flex: 1 1 auto;
@@ -944,15 +970,15 @@
944
970
  /* The plain control inside takes what the trace leaves of the row's
945
971
  height and a short inset after the operator, the rule every cell
946
972
  holding a plain control applies. */
947
- [data-ui='data-grid']
948
- [data-part='filter-cell']
949
- [data-part='filter-operand']
950
- > [data-part='root'][data-variant='plain'],
951
- [data-ui='data-grid']
952
- [data-part='filter-cell']
953
- [data-part='filter-operand']
973
+ [data-ui-data-grid]
974
+ [data-part-filter-cell]
975
+ [data-part-filter-operand]
976
+ > [data-part-root][data-variant='plain'],
977
+ [data-ui-data-grid]
978
+ [data-part-filter-cell]
979
+ [data-part-filter-operand]
954
980
  > :not([data-part])
955
- > [data-part='root'][data-variant='plain'] {
981
+ > [data-part-root][data-variant='plain'] {
956
982
  --slotted-control-padding-inline-sm: var(--slotted-space-3, 0.375rem);
957
983
  --slotted-control-height-sm: calc(var(--_head-block) - var(--_ring-width) * 2);
958
984
 
@@ -963,34 +989,34 @@
963
989
  /* Both fields of a numeric `between` share the line, a dash between them;
964
990
  a date, a time or a date-time `between` is one range picker and carries
965
991
  no `data-range`. */
966
- [data-ui='data-grid']
967
- [data-part='filter-cell']
968
- [data-part='filter-operand'][data-range]
969
- > [data-part='root'],
970
- [data-ui='data-grid']
971
- [data-part='filter-cell']
972
- [data-part='filter-operand'][data-range]
992
+ [data-ui-data-grid]
993
+ [data-part-filter-cell]
994
+ [data-part-filter-operand][data-range]
995
+ > [data-part-root],
996
+ [data-ui-data-grid]
997
+ [data-part-filter-cell]
998
+ [data-part-filter-operand][data-range]
973
999
  > :not([data-part])
974
- > [data-part='root'] {
1000
+ > [data-part-root] {
975
1001
  flex: 1 1 0;
976
1002
  inline-size: 0;
977
1003
  }
978
1004
 
979
- [data-ui='data-grid'] [data-part='filter-cell'] [data-part='filter-operand'][data-range]::before {
1005
+ [data-ui-data-grid] [data-part-filter-cell] [data-part-filter-operand][data-range]::before {
980
1006
  color: var(--_muted);
981
1007
  content: '–';
982
1008
  order: 2;
983
1009
  }
984
1010
 
985
- [data-ui='data-grid']
986
- [data-part='filter-cell']
987
- [data-part='filter-operand'][data-range]
988
- > [data-part='root']:last-child,
989
- [data-ui='data-grid']
990
- [data-part='filter-cell']
991
- [data-part='filter-operand'][data-range]
1011
+ [data-ui-data-grid]
1012
+ [data-part-filter-cell]
1013
+ [data-part-filter-operand][data-range]
1014
+ > [data-part-root]:last-child,
1015
+ [data-ui-data-grid]
1016
+ [data-part-filter-cell]
1017
+ [data-part-filter-operand][data-range]
992
1018
  > :not([data-part]):last-child
993
- > [data-part='root'] {
1019
+ > [data-part-root] {
994
1020
  order: 3;
995
1021
  }
996
1022
 
@@ -999,7 +1025,7 @@
999
1025
  * square target the height of the inner control; it opens a `menu` naming
1000
1026
  * every operator in full, and its accessible name is the operator in full.
1001
1027
  */
1002
- [data-ui='data-grid'] [data-part='filter-cell'] [data-part='filter-operator'] {
1028
+ [data-ui-data-grid] [data-part-filter-cell] [data-part-filter-operator] {
1003
1029
  display: inline-flex;
1004
1030
  flex: none;
1005
1031
  /* One space step off the cell's edge: glued to it, the symbol read as
@@ -1007,7 +1033,7 @@
1007
1033
  padding-inline-start: var(--slotted-space-3, 0.375rem);
1008
1034
  }
1009
1035
 
1010
- [data-ui='data-grid'] [data-part='filter-cell'] [data-part='filter-operator'] > button {
1036
+ [data-ui-data-grid] [data-part-filter-cell] [data-part-filter-operator] > button {
1011
1037
  align-items: center;
1012
1038
  background-color: transparent;
1013
1039
  block-size: var(--slotted-control-inner-size-sm, 22px);
@@ -1028,26 +1054,20 @@
1028
1054
  color var(--_transition);
1029
1055
  }
1030
1056
 
1031
- [data-ui='data-grid']
1032
- [data-part='filter-cell']
1033
- [data-part='filter-operator']
1057
+ [data-ui-data-grid]
1058
+ [data-part-filter-cell]
1059
+ [data-part-filter-operator]
1034
1060
  > button:not(:disabled):hover {
1035
1061
  background-color: var(--_head-surface-hover);
1036
1062
  color: var(--_text);
1037
1063
  }
1038
1064
 
1039
- [data-ui='data-grid']
1040
- [data-part='filter-cell']
1041
- [data-part='filter-operator']
1042
- > button:focus-visible {
1065
+ [data-ui-data-grid] [data-part-filter-cell] [data-part-filter-operator] > button:focus-visible {
1043
1066
  outline: var(--_ring-width) solid var(--slotted-focus-ring-color, Highlight);
1044
1067
  outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
1045
1068
  }
1046
1069
 
1047
- [data-ui='data-grid']
1048
- [data-part='filter-cell'][data-filtered]
1049
- [data-part='filter-operator']
1050
- > button {
1070
+ [data-ui-data-grid] [data-part-filter-cell][data-filtered] [data-part-filter-operator] > button {
1051
1071
  color: var(--slotted-tone-accent-text, CanvasText);
1052
1072
  }
1053
1073
 
@@ -1069,7 +1089,7 @@
1069
1089
  binding draws it inside a host element of its own (`display: contents`),
1070
1090
  and a child combinator here left that popover at sixteen rem with the
1071
1091
  panel standing out of it. */
1072
- [data-ui='popover']:has(> [data-part='content'] [data-ui='data-grid'][data-part='filter-panel']) {
1092
+ [data-ui-popover]:has(> [data-part-content] [data-ui-data-grid][data-part-filter-panel]) {
1073
1093
  --slotted-popover-measure-sm: calc(
1074
1094
  var(--slotted-data-grid-filter-panel-size, 24rem) + 2 *
1075
1095
  (var(--slotted-popover-gap, 0.5rem) + var(--slotted-border-width-thin, 1px))
@@ -1079,14 +1099,14 @@
1079
1099
  /* A date's `between` is two dates in one frame and a date-time's two
1080
1100
  date-times: the panel widens for the kinds whose operand is long, so the
1081
1101
  range is read whole rather than clipped. */
1082
- [data-ui='popover']:has(
1083
- > [data-part='content'] [data-ui='data-grid'][data-part='filter-panel'][data-kind='date']
1102
+ [data-ui-popover]:has(
1103
+ > [data-part-content] [data-ui-data-grid][data-part-filter-panel][data-kind='date']
1084
1104
  ) {
1085
1105
  --slotted-data-grid-filter-panel-size: var(--slotted-data-grid-filter-panel-size-date, 28rem);
1086
1106
  }
1087
1107
 
1088
- [data-ui='popover']:has(
1089
- > [data-part='content'] [data-ui='data-grid'][data-part='filter-panel'][data-kind='datetime']
1108
+ [data-ui-popover]:has(
1109
+ > [data-part-content] [data-ui-data-grid][data-part-filter-panel][data-kind='datetime']
1090
1110
  ) {
1091
1111
  --slotted-data-grid-filter-panel-size: var(
1092
1112
  --slotted-data-grid-filter-panel-size-datetime,
@@ -1094,7 +1114,7 @@
1094
1114
  );
1095
1115
  }
1096
1116
 
1097
- [data-ui='data-grid'][data-part='filter-panel'] {
1117
+ [data-ui-data-grid][data-part-filter-panel] {
1098
1118
  --_operator-size: var(--slotted-data-grid-filter-operator-size, 7rem);
1099
1119
  --_panel-gap: var(--slotted-space-3, 0.375rem);
1100
1120
 
@@ -1119,7 +1139,7 @@
1119
1139
  var(--slotted-popover-padding-inline-sm, var(--slotted-space-5, 0.75rem));
1120
1140
  }
1121
1141
 
1122
- [data-ui='data-grid'][data-part='filter-panel'] > [data-part='filter-condition'] {
1142
+ [data-ui-data-grid][data-part-filter-panel] > [data-part-filter-condition] {
1123
1143
  align-items: center;
1124
1144
  display: grid;
1125
1145
  gap: var(--_panel-gap);
@@ -1129,22 +1149,22 @@
1129
1149
 
1130
1150
  /* The first condition has no join: its operator starts in the second
1131
1151
  column. A set filter has one condition and no join at all. */
1132
- [data-ui='data-grid'][data-part='filter-panel']
1133
- > [data-part='filter-condition']:first-child
1134
- > [data-part='filter-operator'] {
1152
+ [data-ui-data-grid][data-part-filter-panel]
1153
+ > [data-part-filter-condition]:first-child
1154
+ > [data-part-filter-operator] {
1135
1155
  grid-column: 2;
1136
1156
  }
1137
1157
 
1138
- [data-ui='data-grid'][data-part='filter-panel'] [data-part='filter-join'] {
1158
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-join] {
1139
1159
  grid-column: 1;
1140
1160
  }
1141
1161
 
1142
- [data-ui='data-grid'][data-part='filter-panel'] [data-part='filter-operator'] {
1162
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-operator] {
1143
1163
  grid-column: 2;
1144
1164
  min-inline-size: 0;
1145
1165
  }
1146
1166
 
1147
- [data-ui='data-grid'][data-part='filter-panel'] [data-part='filter-operand'] {
1167
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-operand] {
1148
1168
  align-items: center;
1149
1169
  display: flex;
1150
1170
  gap: var(--_panel-gap);
@@ -1154,46 +1174,44 @@
1154
1174
 
1155
1175
  /* An operator taking no operand leaves the operand column empty rather than
1156
1176
  drawing a disabled field. */
1157
- [data-ui='data-grid'][data-part='filter-panel']
1158
- [data-part='filter-condition'][data-operands='0']
1159
- > [data-part='filter-operand'] {
1177
+ [data-ui-data-grid][data-part-filter-panel]
1178
+ [data-part-filter-condition][data-operands='0']
1179
+ > [data-part-filter-operand] {
1160
1180
  display: none;
1161
1181
  }
1162
1182
 
1163
1183
  /* Both operands of a `between` stand on the line with a dash between them:
1164
1184
  the pair is one thought and one line says so. */
1165
- [data-ui='data-grid'][data-part='filter-panel'] [data-part='filter-operand'][data-range] > * {
1185
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-operand][data-range] > * {
1166
1186
  flex: 1 1 0;
1167
1187
  inline-size: 0;
1168
1188
  min-inline-size: 0;
1169
1189
  }
1170
1190
 
1171
- [data-ui='data-grid'][data-part='filter-panel'] [data-part='filter-operand'][data-range]::before {
1191
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-operand][data-range]::before {
1172
1192
  color: var(--slotted-text-muted);
1173
1193
  content: '–';
1174
1194
  order: 1;
1175
1195
  }
1176
1196
 
1177
- [data-ui='data-grid'][data-part='filter-panel']
1178
- [data-part='filter-operand'][data-range]
1179
- > :last-child {
1197
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-operand][data-range] > :last-child {
1180
1198
  order: 2;
1181
1199
  }
1182
1200
 
1183
- [data-ui='data-grid'][data-part='filter-panel'] [data-part='filter-operand'] > [data-part='root'],
1184
- [data-ui='data-grid'][data-part='filter-panel']
1185
- [data-part='filter-operand']
1201
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-operand] > [data-part-root],
1202
+ [data-ui-data-grid][data-part-filter-panel]
1203
+ [data-part-filter-operand]
1186
1204
  > :not([data-part])
1187
- > [data-part='root'] {
1205
+ > [data-part-root] {
1188
1206
  flex: 1 1 auto;
1189
1207
  min-inline-size: 0;
1190
1208
  }
1191
1209
 
1192
- [data-ui='data-grid'][data-part='filter-panel'] [data-part='filter-operand'] [data-part='input'] {
1210
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-operand] [data-part-input] {
1193
1211
  min-inline-size: 0;
1194
1212
  }
1195
1213
 
1196
- [data-ui='data-grid'][data-part='filter-panel'] [data-part='filter-actions'] {
1214
+ [data-ui-data-grid][data-part-filter-panel] [data-part-filter-actions] {
1197
1215
  display: flex;
1198
1216
  gap: var(--_panel-gap);
1199
1217
  grid-column: 1 / -1;
@@ -1204,8 +1222,10 @@
1204
1222
  /**
1205
1223
  * ── Rows and cells ─────────────────────────────────────────────────────
1206
1224
  */
1207
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='body'] {
1225
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-body] {
1208
1226
  box-sizing: border-box;
1227
+ /* The containing block of the veil a busy grid lays over its rows. */
1228
+ position: relative;
1209
1229
  /* The virtual window: the body is as tall as every row and its padding is
1210
1230
  the offset of the first mounted one, so the mounted rows stand where the
1211
1231
  unmounted ones would. No transform, so a pinned column's `sticky`
@@ -1214,7 +1234,7 @@
1214
1234
  padding-block-start: var(--slotted-data-grid-window-start, 0);
1215
1235
  }
1216
1236
 
1217
- [data-ui='data-grid'] [data-part='row'] {
1237
+ [data-ui-data-grid] [data-part-row] {
1218
1238
  background-color: var(--_surface);
1219
1239
  transition: background-color var(--_transition);
1220
1240
  }
@@ -1234,28 +1254,28 @@
1234
1254
  * content grows a `minmax(row, cap)` track to the cap — read on the content
1235
1255
  * scene, every auto row was four rows tall, one line of text in each.
1236
1256
  */
1237
- [data-ui='data-grid'][data-rows='fixed']
1238
- > [data-part='scroll']
1239
- > :is([data-part='body'], [data-part='pinned-rows'])
1240
- > [data-part='row'] {
1257
+ [data-ui-data-grid][data-rows='fixed']
1258
+ > [data-part-scroll]
1259
+ > :is([data-part-body], [data-part-pinned-rows])
1260
+ > [data-part-row] {
1241
1261
  block-size: var(--_row-block);
1242
1262
  grid-auto-rows: var(--_track);
1243
1263
  }
1244
1264
 
1245
- [data-ui='data-grid'][data-rows='auto']
1246
- > [data-part='scroll']
1247
- > :is([data-part='body'], [data-part='pinned-rows'])
1248
- > [data-part='row'] {
1265
+ [data-ui-data-grid][data-rows='auto']
1266
+ > [data-part-scroll]
1267
+ > :is([data-part-body], [data-part-pinned-rows])
1268
+ > [data-part-row] {
1249
1269
  grid-auto-rows: minmax(var(--_track), auto);
1250
1270
  }
1251
1271
 
1252
1272
  /* A value taller than the cap is clipped at it, on the block axis only: a
1253
1273
  pinned cell's edge shadow is drawn past its inline end. The pop-in is not
1254
1274
  a value of the row and has no cap. */
1255
- [data-ui='data-grid'][data-rows='auto']
1256
- :is([data-part='body'], [data-part='pinned-rows'])
1257
- > [data-part='row']
1258
- > :is([role='gridcell'], [role='rowheader']):not([data-part='popin']) {
1275
+ [data-ui-data-grid][data-rows='auto']
1276
+ :is([data-part-body], [data-part-pinned-rows])
1277
+ > [data-part-row]
1278
+ > :is([role='gridcell'], [role='rowheader']):not([data-part-popin]) {
1259
1279
  max-block-size: var(--_row-max-block);
1260
1280
  overflow-y: clip;
1261
1281
  }
@@ -1263,37 +1283,56 @@
1263
1283
  /* A row that grows to its text aligns its cells to the top: a one-line
1264
1284
  value centred beside a four-line one floats in the middle of nothing,
1265
1285
  and the eye reads a row from its first line. Fixed rows stay centred. */
1266
- [data-ui='data-grid'][data-rows='auto']
1267
- :is([data-part='body'], [data-part='pinned-rows'])
1268
- > [data-part='row']
1286
+ [data-ui-data-grid][data-rows='auto']
1287
+ :is([data-part-body], [data-part-pinned-rows])
1288
+ > [data-part-row]
1269
1289
  > [role='gridcell'],
1270
- [data-ui='data-grid'][data-rows='auto']
1271
- :is([data-part='body'], [data-part='pinned-rows'])
1272
- > [data-part='row']
1290
+ [data-ui-data-grid][data-rows='auto']
1291
+ :is([data-part-body], [data-part-pinned-rows])
1292
+ > [data-part-row]
1273
1293
  > [role='rowheader'] {
1274
1294
  align-items: start;
1275
1295
  }
1276
1296
 
1277
- [data-ui='data-grid']:is([data-variant='ruled'], [data-variant='framed'])
1278
- > [data-part='scroll']
1279
- > :is([data-part='body'], [data-part='pinned-rows']) {
1297
+ [data-ui-data-grid]:is([data-variant='ruled'], [data-variant='framed'])
1298
+ > [data-part-scroll]
1299
+ > :is([data-part-body], [data-part-pinned-rows]) {
1280
1300
  --_track: calc(var(--_row-block) - var(--_rule-width));
1281
1301
  }
1282
1302
 
1283
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='head'] > [role='row'],
1284
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='summary'] > [role='row'],
1285
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='loader'] > [role='row'] {
1303
+ /**
1304
+ * A control a cell renderer draws — a `Button`, an `IconButton`, a `Select` —
1305
+ * stands inside the cursor's trace: the row restates the control scale as
1306
+ * the track less the ring and one space step on each side, so a hovered
1307
+ * ground never covers the trace, at every density. The restatement is on
1308
+ * the row and not on each cell, so a row of eight cells computes it once.
1309
+ * A cell in edit states its own, the track less the ring.
1310
+ */
1311
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-body] > [data-part-row],
1312
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-pinned-rows] > [data-part-row] {
1313
+ --_cell-control: calc(
1314
+ var(--_track) - var(--_ring-width) * 2 - var(--slotted-space-1, 0.125rem) * 2
1315
+ );
1316
+ --slotted-control-height-sm: min(var(--_control-height-sm), var(--_cell-control));
1317
+ --slotted-control-height-md: min(var(--_control-height-md), var(--_cell-control));
1318
+ --slotted-control-height-lg: min(var(--_control-height-lg), var(--_cell-control));
1319
+ --slotted-target-min: min(var(--_target-min), var(--_cell-control));
1320
+ }
1321
+
1322
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-head] > [role='row'],
1323
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-summary] > [role='row'],
1324
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-loader] > [role='row'] {
1286
1325
  grid-auto-rows: minmax(var(--_head-block), auto);
1287
1326
  }
1288
1327
 
1289
- [data-ui='data-grid'] [data-part='cell'],
1290
- [data-ui='data-grid'] [data-part='row-header'],
1291
- [data-ui='data-grid'] [data-part='summary-cell'],
1292
- [data-ui='data-grid']
1293
- > [data-part='scroll']
1294
- > :is([data-part='body'], [data-part='pinned-rows'])
1328
+ [data-ui-data-grid] [data-part-cell],
1329
+ [data-ui-data-grid] [data-part-row-header],
1330
+ [data-ui-data-grid] [data-part-summary-cell],
1331
+ [data-ui-data-grid]
1332
+ > [data-part-scroll]
1333
+ > :is([data-part-body], [data-part-pinned-rows])
1295
1334
  > [role='row']
1296
- > [data-part='selection'] {
1335
+ > [data-part-selection] {
1297
1336
  align-items: center;
1298
1337
  box-sizing: border-box;
1299
1338
  display: flex;
@@ -1305,7 +1344,7 @@
1305
1344
 
1306
1345
  /* Every cell but a pinned one is a containing block, for the range edges
1307
1346
  and the invalid mark; a pinned cell is already positioned by `sticky`. */
1308
- [data-ui='data-grid'] [data-part='cell']:not([data-pinned]) {
1347
+ [data-ui-data-grid] [data-part-cell]:not([data-pinned]) {
1309
1348
  position: relative;
1310
1349
  }
1311
1350
 
@@ -1313,9 +1352,9 @@
1313
1352
  keeps its own direction: an identifier, an email or a price in a
1314
1353
  right-to-left document is left-to-right text, and read in `dir="rtl"`
1315
1354
  "Bloom & Co." had its full stop moved to the front. */
1316
- [data-ui='data-grid'] [data-part='cell'] > span:not([data-ui], [data-part]),
1317
- [data-ui='data-grid'] [data-part='row-header'] > span:not([data-ui], [data-part]),
1318
- [data-ui='data-grid'] [data-part='summary-cell'] > span:not([data-ui], [data-part]) {
1355
+ [data-ui-data-grid] [data-part-cell] > span:not([data-ui], [data-part]),
1356
+ [data-ui-data-grid] [data-part-row-header] > span:not([data-ui], [data-part]),
1357
+ [data-ui-data-grid] [data-part-summary-cell] > span:not([data-ui], [data-part]) {
1319
1358
  flex: 1 1 auto;
1320
1359
  min-inline-size: 0;
1321
1360
  unicode-bidi: plaintext;
@@ -1324,35 +1363,35 @@
1324
1363
  /* A family drawn in a cell by a renderer — a badge, a tag — keeps its own
1325
1364
  size: read on the status column, a badge filled the cell's whole width
1326
1365
  because it was a span standing where the value stands. */
1327
- [data-ui='data-grid'] [data-part='cell'] > [data-ui]:not([data-part]) {
1366
+ [data-ui-data-grid] [data-part-cell] > [data-ui]:not([data-part]) {
1328
1367
  flex: 0 0 auto;
1329
1368
  max-inline-size: 100%;
1330
1369
  }
1331
1370
 
1332
1371
  /* A row header names the record and carries one step of weight. */
1333
- [data-ui='data-grid'] [data-part='row-header'] {
1372
+ [data-ui-data-grid] [data-part-row-header] {
1334
1373
  font-weight: var(--slotted-font-weight-medium, 500);
1335
1374
  }
1336
1375
 
1337
1376
  /* The rule between two rows, on the row; the last gives its rule up so a
1338
1377
  ruled grid does not end in a line with nothing under it. */
1339
- [data-ui='data-grid']:is([data-variant='ruled'], [data-variant='framed'])
1340
- :is([data-part='body'], [data-part='pinned-rows'])
1378
+ [data-ui-data-grid]:is([data-variant='ruled'], [data-variant='framed'])
1379
+ :is([data-part-body], [data-part-pinned-rows])
1341
1380
  > [role='row'] {
1342
1381
  border-block-end: var(--_rule-width) solid var(--_rule);
1343
1382
  }
1344
1383
 
1345
- [data-ui='data-grid']:is([data-variant='ruled'], [data-variant='framed'])
1346
- :is([data-part='body'], [data-part='pinned-rows'])
1384
+ [data-ui-data-grid]:is([data-variant='ruled'], [data-variant='framed'])
1385
+ :is([data-part-body], [data-part-pinned-rows])
1347
1386
  > [role='row']:last-child {
1348
1387
  border-block-end-color: transparent;
1349
1388
  }
1350
1389
 
1351
1390
  /* The stripe, declared before every state. */
1352
- [data-ui='data-grid'][data-striped]
1353
- > [data-part='scroll']
1354
- > :is([data-part='body'], [data-part='pinned-rows'])
1355
- > [data-part='row']:nth-child(even) {
1391
+ [data-ui-data-grid][data-striped]
1392
+ > [data-part-scroll]
1393
+ > :is([data-part-body], [data-part-pinned-rows])
1394
+ > [data-part-row]:nth-child(even) {
1356
1395
  background-color: var(--_stripe);
1357
1396
  }
1358
1397
 
@@ -1361,28 +1400,28 @@
1361
1400
  *
1362
1401
  * In the order `STATE_PRECEDENCE` declares them, weakest last.
1363
1402
  */
1364
- [data-ui='data-grid']
1365
- > [data-part='scroll']
1366
- > :is([data-part='body'], [data-part='pinned-rows'])
1367
- > [data-part='row']:not([data-disabled]):hover {
1403
+ [data-ui-data-grid]
1404
+ > [data-part-scroll]
1405
+ > :is([data-part-body], [data-part-pinned-rows])
1406
+ > [data-part-row]:not([data-disabled]):hover {
1368
1407
  background-color: var(--_hover);
1369
1408
  }
1370
1409
 
1371
- [data-ui='data-grid']
1372
- > [data-part='scroll']
1373
- > :is([data-part='body'], [data-part='pinned-rows'])
1374
- > [data-part='row'][data-selected] {
1410
+ [data-ui-data-grid]
1411
+ > [data-part-scroll]
1412
+ > :is([data-part-body], [data-part-pinned-rows])
1413
+ > [data-part-row][data-selected] {
1375
1414
  background-color: var(--_selected);
1376
1415
  color: var(--_selected-text);
1377
1416
  }
1378
1417
 
1379
- [data-ui='data-grid']
1380
- :is([data-part='body'], [data-part='pinned-rows'])
1381
- > [data-part='row'][data-selected]:not([data-disabled]):hover {
1418
+ [data-ui-data-grid]
1419
+ :is([data-part-body], [data-part-pinned-rows])
1420
+ > [data-part-row][data-selected]:not([data-disabled]):hover {
1382
1421
  background-color: var(--_selected-hover);
1383
1422
  }
1384
1423
 
1385
- [data-ui='data-grid'] [data-part='row'][data-disabled] {
1424
+ [data-ui-data-grid] [data-part-row][data-disabled] {
1386
1425
  color: var(--slotted-disabled-foreground, GrayText);
1387
1426
  }
1388
1427
 
@@ -1395,9 +1434,9 @@
1395
1434
  * cell has no margin for an outer ring and the row below would cover it.
1396
1435
  * A cell in edit draws nothing: its control draws the inner ring.
1397
1436
  */
1398
- [data-ui='data-grid'] [role='gridcell'][data-current]:not([data-editing]),
1399
- [data-ui='data-grid'] [role='rowheader'][data-current]:not([data-editing]),
1400
- [data-ui='data-grid'] [role='columnheader'][data-current] {
1437
+ [data-ui-data-grid] [role='gridcell'][data-current]:not([data-editing]),
1438
+ [data-ui-data-grid] [role='rowheader'][data-current]:not([data-editing]),
1439
+ [data-ui-data-grid] [role='columnheader'][data-current] {
1401
1440
  /* An inset shadow rather than an outline: an outline is a focus ring by
1402
1441
  the library's rule and is drawn in the ring colour whole; this is the
1403
1442
  place the reader left, at rest. */
@@ -1407,9 +1446,9 @@
1407
1446
  /* The grid's own cells, the children of its rows: a chip in a multi-select
1408
1447
  is a `gridcell` too, of the grid pattern the chips row is, and must keep
1409
1448
  its own ring rather than take this one. */
1410
- [data-ui='data-grid'] [role='row'] > [role='gridcell']:focus-visible:not([data-editing]),
1411
- [data-ui='data-grid'] [role='row'] > [role='rowheader']:focus-visible:not([data-editing]),
1412
- [data-ui='data-grid'] [role='row'] > [role='columnheader']:focus-visible {
1449
+ [data-ui-data-grid] [role='row'] > [role='gridcell']:focus-visible:not([data-editing]),
1450
+ [data-ui-data-grid] [role='row'] > [role='rowheader']:focus-visible:not([data-editing]),
1451
+ [data-ui-data-grid] [role='row'] > [role='columnheader']:focus-visible {
1413
1452
  box-shadow: none;
1414
1453
  outline: var(--_ring-width) solid var(--slotted-focus-ring-color, Highlight);
1415
1454
  outline-offset: calc(var(--_ring-width) * -1);
@@ -1419,8 +1458,8 @@
1419
1458
  draws none, so there are not two. A cell in edit and a filter cell are
1420
1459
  the other way round — the control inside is silenced and the cell draws
1421
1460
  the trace — so they are left out. */
1422
- [data-ui='data-grid']
1423
- [role='gridcell'][data-current]:not([data-editing], [data-part='filter-cell']):focus-within:not(
1461
+ [data-ui-data-grid]
1462
+ [role='gridcell'][data-current]:not([data-editing], [data-part-filter-cell]):focus-within:not(
1424
1463
  :focus
1425
1464
  ) {
1426
1465
  outline: none;
@@ -1435,11 +1474,11 @@
1435
1474
  * pseudo-element rather than a border, because the cell's own bottom border
1436
1475
  * is the rule between rows.
1437
1476
  */
1438
- [data-ui='data-grid'] [data-part='cell'][data-in-range] {
1477
+ [data-ui-data-grid] [data-part-cell][data-in-range] {
1439
1478
  background-color: var(--_range);
1440
1479
  }
1441
1480
 
1442
- [data-ui='data-grid'] [data-part='cell'][data-range-edge]::before {
1481
+ [data-ui-data-grid] [data-part-cell][data-range-edge]::before {
1443
1482
  border: 0 solid var(--_cursor);
1444
1483
  content: '';
1445
1484
  /* Past the cell's own bottom border, so a vertical edge runs unbroken
@@ -1449,22 +1488,22 @@
1449
1488
  position: absolute;
1450
1489
  }
1451
1490
 
1452
- [data-ui='data-grid'] [data-part='cell'][data-range-edge~='top']::before {
1491
+ [data-ui-data-grid] [data-part-cell][data-range-edge~='top']::before {
1453
1492
  border-block-start-width: var(--_ring-width);
1454
1493
  }
1455
1494
 
1456
1495
  /* The bottom edge ends at the cell: run past it, over the row's rule, it
1457
1496
  read one pixel thicker than the other three. */
1458
- [data-ui='data-grid'] [data-part='cell'][data-range-edge~='bottom']::before {
1497
+ [data-ui-data-grid] [data-part-cell][data-range-edge~='bottom']::before {
1459
1498
  border-block-end-width: var(--_ring-width);
1460
1499
  inset-block-end: 0;
1461
1500
  }
1462
1501
 
1463
- [data-ui='data-grid'] [data-part='cell'][data-range-edge~='start']::before {
1502
+ [data-ui-data-grid] [data-part-cell][data-range-edge~='start']::before {
1464
1503
  border-inline-start-width: var(--_ring-width);
1465
1504
  }
1466
1505
 
1467
- [data-ui='data-grid'] [data-part='cell'][data-range-edge~='end']::before {
1506
+ [data-ui-data-grid] [data-part-cell][data-range-edge~='end']::before {
1468
1507
  border-inline-end-width: var(--_ring-width);
1469
1508
  }
1470
1509
 
@@ -1476,7 +1515,7 @@
1476
1515
  * The control is the row's height, so a row in edit is as tall as one that
1477
1516
  * is not.
1478
1517
  */
1479
- [data-ui='data-grid'] [data-part='cell'][data-editing] {
1518
+ [data-ui-data-grid] [data-part-cell][data-editing] {
1480
1519
  --slotted-control-padding-inline-sm: var(--_pad-inline);
1481
1520
  --slotted-control-padding-inline-md: var(--_pad-inline);
1482
1521
  --slotted-control-padding-inline-lg: var(--_pad-inline);
@@ -1507,7 +1546,7 @@
1507
1546
  padding: 0;
1508
1547
  }
1509
1548
 
1510
- [data-ui='data-grid'] [data-part='cell'][data-editing][data-current] {
1549
+ [data-ui-data-grid] [data-part-cell][data-editing][data-current] {
1511
1550
  box-shadow: none;
1512
1551
  outline: var(--_ring-width) solid var(--slotted-focus-ring-color, Highlight);
1513
1552
  outline-offset: calc(var(--_ring-width) * -1);
@@ -1517,7 +1556,7 @@
1517
1556
  does — by pointing the ring at the invalid step: `invalid` does not erase
1518
1557
  focus. The descendants' ring width is already zero, so the token moves
1519
1558
  only this cell's own trace. */
1520
- [data-ui='data-grid'] [data-part='cell'][data-editing][data-invalid] {
1559
+ [data-ui-data-grid] [data-part-cell][data-editing][data-invalid] {
1521
1560
  --slotted-focus-ring-color: var(--slotted-focus-ring-color-invalid);
1522
1561
  /* Width as well as colour (WCAG 1.4.1): in `high-contrast` the invalid ring
1523
1562
  is the valid ring's black, and the corner mark is withdrawn while the
@@ -1532,11 +1571,11 @@
1532
1571
 
1533
1572
  /* The editor of a numeric column keeps the digits at the end, where the
1534
1573
  read value stood. */
1535
- [data-ui='data-grid'] [data-numeric][data-editing] [data-part='input'] {
1574
+ [data-ui-data-grid] [data-numeric][data-editing] [data-part-input] {
1536
1575
  text-align: end;
1537
1576
  }
1538
1577
 
1539
- [data-ui='data-grid'] [data-part='cell'] > [data-part='editor'] {
1578
+ [data-ui-data-grid] [data-part-cell] > [data-part-editor] {
1540
1579
  display: flex;
1541
1580
  flex: 1 1 auto;
1542
1581
  /* Inside the cell's trace, at every density. */
@@ -1544,12 +1583,8 @@
1544
1583
  min-inline-size: 0;
1545
1584
  }
1546
1585
 
1547
- [data-ui='data-grid'] [data-part='cell'] > [data-part='editor'] > [data-part='root'],
1548
- [data-ui='data-grid']
1549
- [data-part='cell']
1550
- > [data-part='editor']
1551
- > :not([data-part])
1552
- > [data-part='root'] {
1586
+ [data-ui-data-grid] [data-part-cell] > [data-part-editor] > [data-part-root],
1587
+ [data-ui-data-grid] [data-part-cell] > [data-part-editor] > :not([data-part]) > [data-part-root] {
1553
1588
  flex: 1 1 auto;
1554
1589
  min-inline-size: 0;
1555
1590
  }
@@ -1563,13 +1598,13 @@
1563
1598
  * outside the motion scale; under reduced motion the ground stays flat and
1564
1599
  * leaves when the mark does.
1565
1600
  */
1566
- [data-ui='data-grid'] [data-part='cell'][data-changed='a'] {
1601
+ [data-ui-data-grid] [data-part-cell][data-changed='a'] {
1567
1602
  animation: slotted-data-grid-changed-a
1568
1603
  var(--slotted-data-grid-changed-duration, var(--slotted-duration-long))
1569
1604
  var(--slotted-easing-standard, ease-out) forwards;
1570
1605
  }
1571
1606
 
1572
- [data-ui='data-grid'] [data-part='cell'][data-changed='b'] {
1607
+ [data-ui-data-grid] [data-part-cell][data-changed='b'] {
1573
1608
  animation: slotted-data-grid-changed-b
1574
1609
  var(--slotted-data-grid-changed-duration, var(--slotted-duration-long))
1575
1610
  var(--slotted-easing-standard, ease-out) forwards;
@@ -1600,12 +1635,12 @@
1600
1635
  }
1601
1636
 
1602
1637
  @media (prefers-reduced-motion: reduce) {
1603
- [data-ui='data-grid'] [data-part='cell'][data-changed] {
1638
+ [data-ui-data-grid] [data-part-cell][data-changed] {
1604
1639
  animation: none;
1605
1640
  background-color: var(--_changed);
1606
1641
  }
1607
1642
 
1608
- [data-ui='data-grid'] button[data-part='tree-toggle'][data-loading] > [data-ui='icon'] {
1643
+ [data-ui-data-grid] button[data-part-tree-toggle][data-loading] > [data-ui-icon] {
1609
1644
  animation: none;
1610
1645
  }
1611
1646
  }
@@ -1613,7 +1648,7 @@
1613
1648
  /* A cell whose draft failed, or whose value changed under the reader. The
1614
1649
  mark is a corner in the danger ink, and the message is the control's own
1615
1650
  `aria-errormessage`; the cell keeps the draft. */
1616
- [data-ui='data-grid'] [data-part='cell'][data-invalid]:not([data-editing])::after {
1651
+ [data-ui-data-grid] [data-part-cell][data-invalid]:not([data-editing])::after {
1617
1652
  border-block-start: var(--slotted-space-3, 0.375rem) solid var(--slotted-tone-danger-border);
1618
1653
  border-inline-start: var(--slotted-space-3, 0.375rem) solid transparent;
1619
1654
  content: '';
@@ -1626,39 +1661,39 @@
1626
1661
  }
1627
1662
 
1628
1663
  /* A cell whose commit is pending dims its value; nothing moves. */
1629
- [data-ui='data-grid'] [data-part='cell'][data-loading] {
1664
+ [data-ui-data-grid] [data-part-cell][data-loading] {
1630
1665
  color: var(--_muted);
1631
1666
  }
1632
1667
 
1633
1668
  /* A cell that does not edit in a grid that does: no mark, no hand. It is a
1634
1669
  fact the reader hears, not one the eye needs. */
1635
- [data-ui='data-grid'] [data-part='cell'][data-readonly] {
1670
+ [data-ui-data-grid] [data-part-cell][data-readonly] {
1636
1671
  cursor: default;
1637
1672
  }
1638
1673
 
1639
1674
  /**
1640
1675
  * ── Alignment, numerals and the text treatment ─────────────────────────
1641
1676
  */
1642
- [data-ui='data-grid'] [data-align='start'] {
1677
+ [data-ui-data-grid] [data-align='start'] {
1643
1678
  justify-content: start;
1644
1679
  text-align: start;
1645
1680
  }
1646
1681
 
1647
- [data-ui='data-grid'] [data-align='center'] {
1682
+ [data-ui-data-grid] [data-align='center'] {
1648
1683
  justify-content: center;
1649
1684
  text-align: center;
1650
1685
  }
1651
1686
 
1652
- [data-ui='data-grid'] [data-align='end'] {
1687
+ [data-ui-data-grid] [data-align='end'] {
1653
1688
  justify-content: end;
1654
1689
  text-align: end;
1655
1690
  }
1656
1691
 
1657
- [data-ui='data-grid'] [data-numeric] {
1692
+ [data-ui-data-grid] [data-numeric] {
1658
1693
  font-variant-numeric: tabular-nums;
1659
1694
  }
1660
1695
 
1661
- [data-ui='data-grid'] [data-numeric]:not([data-align]) {
1696
+ [data-ui-data-grid] [data-numeric]:not([data-align]) {
1662
1697
  justify-content: end;
1663
1698
  text-align: end;
1664
1699
  }
@@ -1668,7 +1703,7 @@
1668
1703
  is the span with no part of its own — in a tree column the toggle comes
1669
1704
  first, and a rule on `:first-child` left "Barcelona" drawn over the next
1670
1705
  column once the column was narrower than the name. */
1671
- [data-ui='data-grid'] [data-text='truncate'] > span:not([data-ui], [data-part]) {
1706
+ [data-ui-data-grid] [data-text='truncate'] > span:not([data-ui], [data-part]) {
1672
1707
  overflow: hidden;
1673
1708
  text-overflow: ellipsis;
1674
1709
  white-space: nowrap;
@@ -1677,12 +1712,12 @@
1677
1712
  /* A value that is never broken is clipped at its cell rather than drawn over
1678
1713
  the next one: a grid's columns are its layout, and a value crossing one is
1679
1714
  a value in the wrong column. */
1680
- [data-ui='data-grid'] [data-text='nowrap'] > span:not([data-ui], [data-part]) {
1715
+ [data-ui-data-grid] [data-text='nowrap'] > span:not([data-ui], [data-part]) {
1681
1716
  overflow: hidden;
1682
1717
  white-space: nowrap;
1683
1718
  }
1684
1719
 
1685
- [data-ui='data-grid'] [data-text='wrap'] > span:not([data-ui], [data-part]) {
1720
+ [data-ui-data-grid] [data-text='wrap'] > span:not([data-ui], [data-part]) {
1686
1721
  overflow-wrap: anywhere;
1687
1722
  }
1688
1723
 
@@ -1696,14 +1731,14 @@
1696
1731
  * the rules rather than as a border, for the reason `table` records: two
1697
1732
  * borders of one box are mitred at the corner.
1698
1733
  */
1699
- [data-ui='data-grid'] [data-pinned='start'] {
1734
+ [data-ui-data-grid] [data-pinned='start'] {
1700
1735
  background-color: inherit;
1701
1736
  inset-inline-start: var(--slotted-data-grid-pin-offset, 0);
1702
1737
  position: sticky;
1703
1738
  z-index: var(--slotted-z-index-sticky, 100);
1704
1739
  }
1705
1740
 
1706
- [data-ui='data-grid'] [data-pinned='end'] {
1741
+ [data-ui-data-grid] [data-pinned='end'] {
1707
1742
  background-color: inherit;
1708
1743
  inset-inline-end: var(--slotted-data-grid-pin-offset, 0);
1709
1744
  position: sticky;
@@ -1711,7 +1746,7 @@
1711
1746
  }
1712
1747
 
1713
1748
  /* The corner: a header cell that is also pinned takes the step above both. */
1714
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='head'] [data-pinned] {
1749
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-head] [data-pinned] {
1715
1750
  background-color: var(--_head-surface);
1716
1751
  z-index: calc(var(--slotted-z-index-sticky, 100) + 2);
1717
1752
  }
@@ -1719,33 +1754,30 @@
1719
1754
  /* A plain header has no band: a pinned header cell takes the page's ground,
1720
1755
  opaque over the names sliding under it, and not the band it would be the
1721
1756
  only piece of — read on the pop-in scene, a grey block behind one name. */
1722
- [data-ui='data-grid'][data-variant='plain']
1723
- > [data-part='scroll']
1724
- > [data-part='head']
1725
- [data-pinned],
1726
- [data-ui='data-grid'][data-variant='plain']
1727
- > [data-part='scroll']
1728
- > [data-part='head']
1757
+ [data-ui-data-grid][data-variant='plain'] > [data-part-scroll] > [data-part-head] [data-pinned],
1758
+ [data-ui-data-grid][data-variant='plain']
1759
+ > [data-part-scroll]
1760
+ > [data-part-head]
1729
1761
  > [role='row']
1730
- > [data-part='selection'] {
1762
+ > [data-part-selection] {
1731
1763
  background-color: var(--_surface);
1732
1764
  }
1733
1765
 
1734
- [data-ui='data-grid'] [data-part='filter-row'] > [data-pinned] {
1766
+ [data-ui-data-grid] [data-part-filter-row] > [data-pinned] {
1735
1767
  background-color: var(--_band-surface);
1736
1768
  }
1737
1769
 
1738
- [data-ui='data-grid']
1739
- > [data-part='scroll']
1740
- > :is([data-part='body'], [data-part='pinned-rows'])
1741
- > [data-part='row'][data-selected]
1770
+ [data-ui-data-grid]
1771
+ > [data-part-scroll]
1772
+ > :is([data-part-body], [data-part-pinned-rows])
1773
+ > [data-part-row][data-selected]
1742
1774
  > [data-pinned] {
1743
1775
  background-color: var(--_selected);
1744
1776
  }
1745
1777
 
1746
1778
  /* The last pinned cell of each zone draws the edge: the same hairline as
1747
1779
  the rules between rows, and no more. */
1748
- [data-ui='data-grid'] [data-pinned][data-pin-edge]::after {
1780
+ [data-ui-data-grid] [data-pinned][data-pin-edge]::after {
1749
1781
  background-color: var(--_rule);
1750
1782
  content: '';
1751
1783
  inline-size: var(--_rule-width);
@@ -1756,19 +1788,19 @@
1756
1788
  z-index: 1;
1757
1789
  }
1758
1790
 
1759
- [data-ui='data-grid']
1760
- > [data-part='scroll']
1761
- > :is([data-part='body'], [data-part='pinned-rows'])
1791
+ [data-ui-data-grid]
1792
+ > [data-part-scroll]
1793
+ > :is([data-part-body], [data-part-pinned-rows])
1762
1794
  > [role='row']:last-child
1763
1795
  > [data-pin-edge]::after {
1764
1796
  inset-block-end: 0;
1765
1797
  }
1766
1798
 
1767
- [data-ui='data-grid'] [data-pinned='start'][data-pin-edge]::after {
1799
+ [data-ui-data-grid] [data-pinned='start'][data-pin-edge]::after {
1768
1800
  inset-inline-end: 0;
1769
1801
  }
1770
1802
 
1771
- [data-ui='data-grid'] [data-pinned='end'][data-pin-edge]::after {
1803
+ [data-ui-data-grid] [data-pinned='end'][data-pin-edge]::after {
1772
1804
  inset-inline-start: 0;
1773
1805
  }
1774
1806
 
@@ -1776,7 +1808,7 @@
1776
1808
  run down the body: it stood as a stub beside each values' line. At rest
1777
1809
  a grid with a pop-in draws no edge; the shadow below still marks what
1778
1810
  slides under a zone. */
1779
- [data-ui='data-grid'][data-popin] [data-pinned][data-pin-edge]::after {
1811
+ [data-ui-data-grid][data-popin] [data-pinned][data-pin-edge]::after {
1780
1812
  background-color: transparent;
1781
1813
  }
1782
1814
 
@@ -1786,11 +1818,11 @@
1786
1818
  mid-word is not always there to be seen. A shadow and not a stronger
1787
1819
  line: read on the pinning scene, a dark rule down the body read as a
1788
1820
  frame inside the frame. */
1789
- [data-ui='data-grid']
1790
- [data-part='scroll'][data-overflowing]:not([data-at-start])
1821
+ [data-ui-data-grid]
1822
+ [data-part-scroll][data-overflowing]:not([data-at-start])
1791
1823
  [data-pinned='start'][data-pin-edge]::after,
1792
- [data-ui='data-grid']
1793
- [data-part='scroll'][data-overflowing]:not([data-at-end])
1824
+ [data-ui-data-grid]
1825
+ [data-part-scroll][data-overflowing]:not([data-at-end])
1794
1826
  [data-pinned='end'][data-pin-edge]::after {
1795
1827
  /* The colour is the gradient's alone: with the hairline's colour still
1796
1828
  under the widened box, the shadow read as a solid grey band. */
@@ -1798,8 +1830,8 @@
1798
1830
  inline-size: calc(var(--_rule-width) + var(--_edge-shadow-size));
1799
1831
  }
1800
1832
 
1801
- [data-ui='data-grid']
1802
- [data-part='scroll'][data-overflowing]:not([data-at-start])
1833
+ [data-ui-data-grid]
1834
+ [data-part-scroll][data-overflowing]:not([data-at-start])
1803
1835
  [data-pinned='start'][data-pin-edge]::after {
1804
1836
  background-image: linear-gradient(
1805
1837
  to right,
@@ -1810,8 +1842,8 @@
1810
1842
  inset-inline-end: calc(var(--_edge-shadow-size) * -1);
1811
1843
  }
1812
1844
 
1813
- [data-ui='data-grid']
1814
- [data-part='scroll'][data-overflowing]:not([data-at-end])
1845
+ [data-ui-data-grid]
1846
+ [data-part-scroll][data-overflowing]:not([data-at-end])
1815
1847
  [data-pinned='end'][data-pin-edge]::after {
1816
1848
  background-image: linear-gradient(
1817
1849
  to left,
@@ -1822,8 +1854,8 @@
1822
1854
  inset-inline-start: calc(var(--_edge-shadow-size) * -1);
1823
1855
  }
1824
1856
 
1825
- [data-ui='data-grid']:dir(rtl)
1826
- [data-part='scroll'][data-overflowing]:not([data-at-start])
1857
+ [data-ui-data-grid]:dir(rtl)
1858
+ [data-part-scroll][data-overflowing]:not([data-at-start])
1827
1859
  [data-pinned='start'][data-pin-edge]::after {
1828
1860
  background-image: linear-gradient(
1829
1861
  to left,
@@ -1833,8 +1865,8 @@
1833
1865
  );
1834
1866
  }
1835
1867
 
1836
- [data-ui='data-grid']:dir(rtl)
1837
- [data-part='scroll'][data-overflowing]:not([data-at-end])
1868
+ [data-ui-data-grid]:dir(rtl)
1869
+ [data-part-scroll][data-overflowing]:not([data-at-end])
1838
1870
  [data-pinned='end'][data-pin-edge]::after {
1839
1871
  background-image: linear-gradient(
1840
1872
  to right,
@@ -1850,7 +1882,7 @@
1850
1882
  * The cell is the family's and the control is `checkbox`'s. The width is
1851
1883
  * stated so a column pinned beside it has a length to state.
1852
1884
  */
1853
- [data-ui='data-grid'] [role='row'] > [data-part='selection'] {
1885
+ [data-ui-data-grid] [role='row'] > [data-part-selection] {
1854
1886
  --slotted-selection-halo-opacity: 0;
1855
1887
 
1856
1888
  justify-content: center;
@@ -1865,7 +1897,7 @@
1865
1897
  * X both pin it with the first pinned column; here it is pinned always, so a
1866
1898
  * consumer never has to say it.
1867
1899
  */
1868
- [data-ui='data-grid'] [role='row'] > [data-part='selection'] {
1900
+ [data-ui-data-grid] [role='row'] > [data-part-selection] {
1869
1901
  background-color: inherit;
1870
1902
  inset-inline-start: 0;
1871
1903
  position: sticky;
@@ -1875,25 +1907,25 @@
1875
1907
  /* Restated for the head's chooser, whose header rule above made it
1876
1908
  `relative` at a higher specificity: read scrolled, the select-all left
1877
1909
  with the columns while every row's chooser stayed. */
1878
- [data-ui='data-grid']
1879
- > [data-part='scroll']
1880
- > [data-part='head']
1910
+ [data-ui-data-grid]
1911
+ > [data-part-scroll]
1912
+ > [data-part-head]
1881
1913
  > [role='row']
1882
- > [data-part='selection'] {
1914
+ > [data-part-selection] {
1883
1915
  background-color: var(--_head-surface);
1884
1916
  inset-inline-start: 0;
1885
1917
  position: sticky;
1886
1918
  z-index: calc(var(--slotted-z-index-sticky, 100) + 2);
1887
1919
  }
1888
1920
 
1889
- [data-ui='data-grid']
1890
- :is([data-part='body'], [data-part='pinned-rows'])
1891
- > [data-part='row'][data-selected]
1892
- > [data-part='selection'] {
1921
+ [data-ui-data-grid]
1922
+ :is([data-part-body], [data-part-pinned-rows])
1923
+ > [data-part-row][data-selected]
1924
+ > [data-part-selection] {
1893
1925
  background-color: var(--_selected);
1894
1926
  }
1895
1927
 
1896
- [data-ui='data-grid'] [role='row'] > [data-part='selection'] > [data-ui='checkbox'] {
1928
+ [data-ui-data-grid] [role='row'] > [data-part-selection] > [data-ui-checkbox] {
1897
1929
  block-size: var(--_line);
1898
1930
  }
1899
1931
 
@@ -1901,7 +1933,7 @@
1901
1933
  it rather than the stylesheet asking every cell what it holds: `:has()`
1902
1934
  on every cell of a windowed body is a question asked a thousand times per
1903
1935
  style pass. */
1904
- [data-ui='data-grid'] [data-part='cell'][data-kind='expander'] {
1936
+ [data-ui-data-grid] [data-part-cell][data-kind='expander'] {
1905
1937
  justify-content: center;
1906
1938
  padding-inline: 0;
1907
1939
  }
@@ -1912,11 +1944,11 @@
1912
1944
  * One cell spanning every column, on the sunken ground, with the record's
1913
1945
  * own inset so what is inside reads as belonging to the row above.
1914
1946
  */
1915
- [data-ui='data-grid'] [data-part='detail'] {
1947
+ [data-ui-data-grid] [data-part-detail] {
1916
1948
  background-color: var(--slotted-surface-sunken, Canvas);
1917
1949
  }
1918
1950
 
1919
- [data-ui='data-grid'] [data-part='detail'] > * {
1951
+ [data-ui-data-grid] [data-part-detail] > * {
1920
1952
  background-color: var(--slotted-surface-sunken, Canvas);
1921
1953
  box-sizing: border-box;
1922
1954
  grid-column: 1 / -1;
@@ -1926,7 +1958,7 @@
1926
1958
  the consumer's own layout and not a column. */
1927
1959
  position: sticky;
1928
1960
  inset-inline-start: 0;
1929
- max-inline-size: 100cqi;
1961
+ max-inline-size: var(--slotted-data-grid-viewport, 100%);
1930
1962
  }
1931
1963
 
1932
1964
  /**
@@ -1946,28 +1978,28 @@
1946
1978
  */
1947
1979
  /* The values' line is the density's row, grown to its content; the
1948
1980
  pop-in's line is as tall as its fields. */
1949
- [data-ui='data-grid'][data-popin]
1950
- > [data-part='scroll']
1951
- > :is([data-part='body'], [data-part='pinned-rows'])
1952
- > [data-part='row'] {
1981
+ [data-ui-data-grid][data-popin]
1982
+ > [data-part-scroll]
1983
+ > :is([data-part-body], [data-part-pinned-rows])
1984
+ > [data-part-row] {
1953
1985
  grid-template-rows: minmax(var(--_track), auto) auto;
1954
1986
  }
1955
1987
 
1956
- [data-ui='data-grid'][data-popin] > [data-part='scroll'] > [data-part='summary'] > [role='row'] {
1988
+ [data-ui-data-grid][data-popin] > [data-part-scroll] > [data-part-summary] > [role='row'] {
1957
1989
  grid-template-rows: minmax(var(--_head-block), auto) auto;
1958
1990
  }
1959
1991
 
1960
1992
  /* The chooser, the expander, the values and the actions stand on the
1961
1993
  values' line centred, as in a fixed row: the line is the row's own
1962
1994
  height, and a wrapped value is the only thing that grows it. */
1963
- [data-ui='data-grid'][data-popin]
1964
- :is([data-part='body'], [data-part='pinned-rows'])
1965
- > [data-part='row']
1966
- > :is([role='gridcell'], [role='rowheader']):not([data-part='popin']) {
1995
+ [data-ui-data-grid][data-popin]
1996
+ :is([data-part-body], [data-part-pinned-rows])
1997
+ > [data-part-row]
1998
+ > :is([role='gridcell'], [role='rowheader']):not([data-part-popin]) {
1967
1999
  align-items: center;
1968
2000
  }
1969
2001
 
1970
- [data-ui='data-grid'] [data-part='popin'] {
2002
+ [data-ui-data-grid] [data-part-popin] {
1971
2003
  align-content: start;
1972
2004
  box-sizing: border-box;
1973
2005
  column-gap: var(--slotted-space-4, 0.5rem);
@@ -1976,7 +2008,7 @@
1976
2008
  grid-row: 2;
1977
2009
  grid-template-columns: repeat(auto-fill, minmax(min(9rem, 100%), 1fr));
1978
2010
  inset-inline-start: 0;
1979
- max-inline-size: 100cqi;
2011
+ max-inline-size: var(--slotted-data-grid-viewport, 100%);
1980
2012
  min-inline-size: 0;
1981
2013
  padding-block: 0 var(--_pad-block);
1982
2014
  padding-inline: calc(var(--slotted-data-grid-leading, 0px) + var(--_pad-inline))
@@ -1990,15 +2022,13 @@
1990
2022
  indent: with the chooser and the expander, 88 of 360 pixels left one
1991
2023
  column of fields where the row's whole width holds two. The fields start
1992
2024
  at the row's own padding, under the chooser. */
1993
- @container slotted-data-grid (width < 600px) {
1994
- [data-ui='data-grid'] [data-part='popin'] {
1995
- padding-inline-start: var(--_pad-inline);
1996
- }
2025
+ [data-ui-data-grid][data-narrow] [data-part-popin] {
2026
+ padding-inline-start: var(--_pad-inline);
1997
2027
  }
1998
2028
 
1999
2029
  /* The label above the value, as a form reads, so a narrow field keeps the
2000
2030
  value's whole width. */
2001
- [data-ui='data-grid'] [data-part='popin-field'] {
2031
+ [data-ui-data-grid] [data-part-popin-field] {
2002
2032
  display: flex;
2003
2033
  flex-direction: column;
2004
2034
  min-inline-size: 0;
@@ -2007,7 +2037,7 @@
2007
2037
  /* Room for one column of fields only (two need 2 × 9rem and the gap): the
2008
2038
  label goes beside its value, so each field takes one line instead of two. */
2009
2039
  @container slotted-data-grid-popin (width < 19rem) {
2010
- [data-ui='data-grid'] [data-part='popin-field'] {
2040
+ [data-ui-data-grid] [data-part-popin-field] {
2011
2041
  align-items: baseline;
2012
2042
  column-gap: var(--slotted-space-3, 0.375rem);
2013
2043
  display: grid;
@@ -2015,7 +2045,7 @@
2015
2045
  }
2016
2046
  }
2017
2047
 
2018
- [data-ui='data-grid'] [data-part='popin-label'] {
2048
+ [data-ui-data-grid] [data-part-popin-label] {
2019
2049
  color: var(--_muted);
2020
2050
  font-size: var(--slotted-font-size-xs, 0.75rem);
2021
2051
  font-weight: var(--slotted-font-weight-regular, 400);
@@ -2026,7 +2056,7 @@
2026
2056
  field under a label at its start reads as the next field's. One line tall
2027
2057
  when empty, so an empty value keeps its place under its label, as the
2028
2058
  empty cell keeps its row. */
2029
- [data-ui='data-grid'] [data-part='popin-value'] {
2059
+ [data-ui-data-grid] [data-part-popin-value] {
2030
2060
  align-items: center;
2031
2061
  display: flex;
2032
2062
  gap: var(--_gap);
@@ -2042,8 +2072,8 @@
2042
2072
  aligns its lines to the grid's start, under its label: read in `rtl`, a
2043
2073
  company name set by its own direction ran from the far edge of the field,
2044
2074
  and `match-parent` did not move it. */
2045
- [data-ui='data-grid'] [data-part='popin-value'][data-text] > span:not([data-ui], [data-part]),
2046
- [data-ui='data-grid'] [data-part='popin-value'] > span:not([data-ui], [data-part]) {
2075
+ [data-ui-data-grid] [data-part-popin-value][data-text] > span:not([data-ui], [data-part]),
2076
+ [data-ui-data-grid] [data-part-popin-value] > span:not([data-ui], [data-part]) {
2047
2077
  flex: 0 1 auto;
2048
2078
  min-inline-size: 0;
2049
2079
  overflow: visible;
@@ -2055,11 +2085,11 @@
2055
2085
  }
2056
2086
 
2057
2087
  /* Physical, because `start` under `plaintext` is the value's own start. */
2058
- [data-ui='data-grid']:dir(rtl) [data-part='popin-value'] > span:not([data-ui], [data-part]) {
2088
+ [data-ui-data-grid]:dir(rtl) [data-part-popin-value] > span:not([data-ui], [data-part]) {
2059
2089
  text-align: right;
2060
2090
  }
2061
2091
 
2062
- [data-ui='data-grid'] [data-part='popin-value'] > [data-ui]:not([data-part]) {
2092
+ [data-ui-data-grid] [data-part-popin-value] > [data-ui]:not([data-part]) {
2063
2093
  flex: 0 0 auto;
2064
2094
  max-inline-size: 100%;
2065
2095
  }
@@ -2071,13 +2101,13 @@
2071
2101
  * indented by its level. The ground is the band at 4%, and the text is
2072
2102
  * semibold, so a reader scanning for a group finds it without reading.
2073
2103
  */
2074
- [data-ui='data-grid'] [data-part='group-row'] {
2104
+ [data-ui-data-grid] [data-part-group-row] {
2075
2105
  background-color: var(--_band-surface);
2076
2106
  color: var(--_text);
2077
2107
  font-weight: var(--slotted-font-weight-semibold, 600);
2078
2108
  }
2079
2109
 
2080
- [data-ui='data-grid'] [data-part='group-row'] > [role='gridcell'] {
2110
+ [data-ui-data-grid] [data-part-group-row] > [role='gridcell'] {
2081
2111
  align-items: center;
2082
2112
  box-sizing: border-box;
2083
2113
  display: flex;
@@ -2090,7 +2120,7 @@
2090
2120
 
2091
2121
  /* The first cell of a group row spans to the first aggregate, indented by
2092
2122
  its level; the aggregates stand in their own columns. */
2093
- [data-ui='data-grid'] [data-part='group-row'] > [role='gridcell']:first-child {
2123
+ [data-ui-data-grid] [data-part-group-row] > [role='gridcell']:first-child {
2094
2124
  padding-inline-start: calc(
2095
2125
  var(--_pad-inline) + var(--_indent) * (var(--slotted-data-grid-level, 1) - 1)
2096
2126
  );
@@ -2098,25 +2128,25 @@
2098
2128
  inset-inline-start: 0;
2099
2129
  }
2100
2130
 
2101
- [data-ui='data-grid'] [data-part='group-row'] > [role='gridcell']:first-child > span {
2131
+ [data-ui-data-grid] [data-part-group-row] > [role='gridcell']:first-child > span {
2102
2132
  overflow: hidden;
2103
2133
  text-overflow: ellipsis;
2104
2134
  white-space: nowrap;
2105
2135
  }
2106
2136
 
2107
2137
  /* The count, one step lighter than the value. */
2108
- [data-ui='data-grid'] [data-part='group-row'] [data-count] {
2138
+ [data-ui-data-grid] [data-part-group-row] [data-count] {
2109
2139
  color: var(--_muted);
2110
2140
  font-weight: var(--slotted-font-weight-regular, 400);
2111
2141
  }
2112
2142
 
2113
- [data-ui='data-grid'] [data-part='group-row'] [data-aggregate] {
2143
+ [data-ui-data-grid] [data-part-group-row] [data-aggregate] {
2114
2144
  color: var(--_muted);
2115
2145
  font-variant-numeric: tabular-nums;
2116
2146
  font-weight: var(--slotted-font-weight-medium, 500);
2117
2147
  }
2118
2148
 
2119
- [data-ui='data-grid'] [data-part='group-toggle'] {
2149
+ [data-ui-data-grid] [data-part-group-toggle] {
2120
2150
  margin-block: calc((var(--_line) - var(--slotted-target-min, 24px)) / 2);
2121
2151
  margin-inline-start: calc(var(--slotted-space-2, 0.25rem) * -1);
2122
2152
  }
@@ -2127,13 +2157,13 @@
2127
2157
  * The aggregates of the whole query, pinned to the end of the scroller, on
2128
2158
  * the band with a strong rule above — the header of the other end.
2129
2159
  */
2130
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='summary'] {
2160
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-summary] {
2131
2161
  inset-block-end: var(--slotted-data-grid-sticky-offset-end, 0);
2132
2162
  position: sticky;
2133
2163
  z-index: calc(var(--slotted-z-index-sticky, 100) + 1);
2134
2164
  }
2135
2165
 
2136
- [data-ui='data-grid']:not([data-sticky-header]) > [data-part='scroll'] > [data-part='summary'] {
2166
+ [data-ui-data-grid]:not([data-sticky-header]) > [data-part-scroll] > [data-part-summary] {
2137
2167
  position: static;
2138
2168
  }
2139
2169
 
@@ -2145,20 +2175,20 @@
2145
2175
  * surface so the body scrolls under it, with a rule on the side it faces
2146
2176
  * the body. Their rows are the body's rows.
2147
2177
  */
2148
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='pinned-rows'] {
2178
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-pinned-rows] {
2149
2179
  background-color: var(--_surface);
2150
2180
  position: sticky;
2151
2181
  z-index: calc(var(--slotted-z-index-sticky, 100) + 1);
2152
2182
  }
2153
2183
 
2154
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='pinned-rows'][data-edge='top'] {
2184
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-pinned-rows][data-edge='top'] {
2155
2185
  border-block-end: var(--_rule-width) solid var(--_rule-strong);
2156
2186
  inset-block-start: calc(
2157
2187
  var(--slotted-data-grid-sticky-offset, 0px) + var(--slotted-data-grid-pinned-top-offset, 0px)
2158
2188
  );
2159
2189
  }
2160
2190
 
2161
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='pinned-rows'][data-edge='bottom'] {
2191
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-pinned-rows][data-edge='bottom'] {
2162
2192
  border-block-start: var(--_rule-width) solid var(--_rule-strong);
2163
2193
  inset-block-end: calc(
2164
2194
  var(--slotted-data-grid-sticky-offset-end, 0px) +
@@ -2166,36 +2196,34 @@
2166
2196
  );
2167
2197
  }
2168
2198
 
2169
- [data-ui='data-grid']:not([data-sticky-header])
2170
- > [data-part='scroll']
2171
- > [data-part='pinned-rows'] {
2199
+ [data-ui-data-grid]:not([data-sticky-header]) > [data-part-scroll] > [data-part-pinned-rows] {
2172
2200
  position: static;
2173
2201
  }
2174
2202
 
2175
2203
  /* A pinned cell inside a held row stands over the row's own ground. */
2176
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='pinned-rows'] [data-pinned] {
2204
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-pinned-rows] [data-pinned] {
2177
2205
  background-color: var(--_surface);
2178
2206
  }
2179
2207
 
2180
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='summary'] > [role='row'] {
2208
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-summary] > [role='row'] {
2181
2209
  background-color: var(--_head-surface);
2182
2210
  border-block-start: var(--_rule-width) solid var(--_rule-strong);
2183
2211
  }
2184
2212
 
2185
- [data-ui='data-grid'] [data-part='summary-cell'] {
2213
+ [data-ui-data-grid] [data-part-summary-cell] {
2186
2214
  background-color: var(--_head-surface);
2187
2215
  font-weight: var(--slotted-font-weight-semibold, 600);
2188
2216
  min-block-size: var(--_head-block);
2189
2217
  }
2190
2218
 
2191
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='summary'] [data-pinned] {
2219
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-summary] [data-pinned] {
2192
2220
  background-color: var(--_head-surface);
2193
2221
  z-index: calc(var(--slotted-z-index-sticky, 100) + 2);
2194
2222
  }
2195
2223
 
2196
2224
  /* The label of an aggregate — "Total", "Average" — one step lighter than
2197
2225
  the number beside it. */
2198
- [data-ui='data-grid'] [data-part='summary-cell'] [data-label] {
2226
+ [data-ui-data-grid] [data-part-summary-cell] [data-label] {
2199
2227
  color: var(--_muted);
2200
2228
  font-weight: var(--slotted-font-weight-regular, 400);
2201
2229
  margin-inline-end: var(--slotted-space-2, 0.25rem);
@@ -2211,7 +2239,7 @@
2211
2239
  /* Scoped to the cell's own child: `result-state` in the empty part has an
2212
2240
  `actions` part of the same name, and a rule naming the part alone hid
2213
2241
  its buttons. */
2214
- [data-ui='data-grid'] [data-part='cell'] > [data-part='actions'] {
2242
+ [data-ui-data-grid] [data-part-cell] > [data-part-actions] {
2215
2243
  align-items: center;
2216
2244
  /* One line tall, whatever stands inside: the buttons are taller than the
2217
2245
  line and overflow it evenly, so the row is still measured by its text
@@ -2231,7 +2259,7 @@
2231
2259
  * scene, two of them stood five pixels proud of the row on both sides and
2232
2260
  * grew its track. The consumer keeps the behaviour and the artwork.
2233
2261
  */
2234
- [data-ui='data-grid'] [data-part='cell'] > [data-part='actions'] > button {
2262
+ [data-ui-data-grid] [data-part-cell] > [data-part-actions] > button {
2235
2263
  align-items: center;
2236
2264
  background-color: transparent;
2237
2265
  block-size: var(--_control);
@@ -2249,42 +2277,42 @@
2249
2277
  color var(--_transition);
2250
2278
  }
2251
2279
 
2252
- [data-ui='data-grid'] [data-part='cell'] > [data-part='actions'] > button :is(svg, img) {
2280
+ [data-ui-data-grid] [data-part-cell] > [data-part-actions] > button :is(svg, img) {
2253
2281
  block-size: var(--_control-icon);
2254
2282
  inline-size: var(--_control-icon);
2255
2283
  }
2256
2284
 
2257
- [data-ui='data-grid'] [data-part='cell'] > [data-part='actions'] > button:not(:disabled):hover {
2285
+ [data-ui-data-grid] [data-part-cell] > [data-part-actions] > button:not(:disabled):hover {
2258
2286
  background-color: color-mix(in oklab, var(--slotted-text, CanvasText) 7%, transparent);
2259
2287
  color: var(--_text);
2260
2288
  }
2261
2289
 
2262
- [data-ui='data-grid'] [data-part='cell'] > [data-part='actions'] > button:focus-visible {
2290
+ [data-ui-data-grid] [data-part-cell] > [data-part-actions] > button:focus-visible {
2263
2291
  outline: var(--_ring-width) solid var(--slotted-focus-ring-color, Highlight);
2264
2292
  outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
2265
2293
  }
2266
2294
 
2267
- [data-ui='data-grid']
2268
- [data-part='row']:not([data-disabled]):hover
2269
- [data-part='cell']
2270
- > [data-part='actions'],
2271
- [data-ui='data-grid'] [data-part='row']:focus-within [data-part='cell'] > [data-part='actions'],
2272
- [data-ui='data-grid'] [data-part='row'][data-current] [data-part='cell'] > [data-part='actions'],
2273
- [data-ui='data-grid'] [data-part='row'][data-editing] [data-part='cell'] > [data-part='actions'] {
2295
+ [data-ui-data-grid]
2296
+ [data-part-row]:not([data-disabled]):hover
2297
+ [data-part-cell]
2298
+ > [data-part-actions],
2299
+ [data-ui-data-grid] [data-part-row]:focus-within [data-part-cell] > [data-part-actions],
2300
+ [data-ui-data-grid] [data-part-row][data-current] [data-part-cell] > [data-part-actions],
2301
+ [data-ui-data-grid] [data-part-row][data-editing] [data-part-cell] > [data-part-actions] {
2274
2302
  opacity: 1;
2275
2303
  }
2276
2304
 
2277
2305
  @media (pointer: coarse) {
2278
- [data-ui='data-grid'] [data-part='cell'] > [data-part='actions'],
2279
- [data-ui='data-grid'] [data-part='column-menu'],
2280
- [data-ui='data-grid'] [data-part='column-header'] [data-part='filter'] {
2306
+ [data-ui-data-grid] [data-part-cell] > [data-part-actions],
2307
+ [data-ui-data-grid] [data-part-column-menu],
2308
+ [data-ui-data-grid] [data-part-column-header] [data-part-filter] {
2281
2309
  opacity: 1;
2282
2310
  }
2283
2311
 
2284
2312
  /* The row grew to the comfortable target through the control scale; the
2285
2313
  family's own controls grow with it, to the row less the cursor's ring.
2286
2314
  A 24-pixel button in a 44-pixel row is a target a thumb misses. */
2287
- [data-ui='data-grid'][data-part='root'] {
2315
+ [data-ui-data-grid][data-part-root] {
2288
2316
  --_control: min(
2289
2317
  var(--slotted-target-comfortable, 44px),
2290
2318
  calc(min(var(--_row-block), var(--_head-block)) - var(--_ring-width) * 2)
@@ -2297,13 +2325,13 @@
2297
2325
  shows round it; the box reaches the full target by a padding the ground
2298
2326
  does not paint, and gives it back as a negative margin, so no row, no
2299
2327
  header and no column name moves. Neighbours overlap by the gap. */
2300
- [data-ui='data-grid'] [data-part='column-help'],
2301
- [data-ui='data-grid'] [data-part='column-menu'],
2302
- [data-ui='data-grid'] [data-part='column-header'] [data-part='filter'],
2303
- [data-ui='data-grid'] [data-part='expander'],
2304
- [data-ui='data-grid'] [data-part='group-toggle'],
2305
- [data-ui='data-grid'] [data-part='tree-toggle'],
2306
- [data-ui='data-grid'] [data-part='row-handle'] {
2328
+ [data-ui-data-grid] [data-part-column-help],
2329
+ [data-ui-data-grid] [data-part-column-menu],
2330
+ [data-ui-data-grid] [data-part-column-header] [data-part-filter],
2331
+ [data-ui-data-grid] [data-part-expander],
2332
+ [data-ui-data-grid] [data-part-group-toggle],
2333
+ [data-ui-data-grid] [data-part-tree-toggle],
2334
+ [data-ui-data-grid] [data-part-row-handle] {
2307
2335
  background-clip: content-box;
2308
2336
  box-sizing: content-box;
2309
2337
  margin: calc(var(--_reach) * -1);
@@ -2314,7 +2342,7 @@
2314
2342
  /**
2315
2343
  * ── Empty, and loading ─────────────────────────────────────────────────
2316
2344
  */
2317
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='empty'] {
2345
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-empty] {
2318
2346
  align-items: center;
2319
2347
  /* The padding stands inside the viewport's width. Without it the box was
2320
2348
  its own padding wider than the frame, and a grid whose columns all fit
@@ -2325,7 +2353,7 @@
2325
2353
  stands in the middle of what the reader sees whatever the columns'
2326
2354
  width and however far the grid is scrolled sideways: laid out over the
2327
2355
  columns, the middle of a wide template was off screen. */
2328
- inline-size: 100cqi;
2356
+ inline-size: var(--slotted-data-grid-viewport, 100%);
2329
2357
  inset-inline-start: 0;
2330
2358
  justify-content: center;
2331
2359
  min-block-size: calc(var(--_row-block) * 6);
@@ -2333,7 +2361,7 @@
2333
2361
  position: sticky;
2334
2362
  }
2335
2363
 
2336
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='loader'] > [data-part='row'] > * {
2364
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-loader] > [data-part-row] > * {
2337
2365
  align-items: center;
2338
2366
  box-sizing: border-box;
2339
2367
  display: flex;
@@ -2348,12 +2376,25 @@
2348
2376
  padding-inline: var(--_pad-inline);
2349
2377
  }
2350
2378
 
2351
- [data-ui='data-grid'][aria-busy='true'] > [data-part='scroll'] > [data-part='body'] {
2379
+ [data-ui-data-grid][aria-busy='true'] > [data-part-scroll] > [data-part-body] {
2352
2380
  opacity: 0.55;
2353
- pointer-events: none;
2354
2381
  transition: opacity var(--_transition);
2355
2382
  }
2356
2383
 
2384
+ /**
2385
+ * The rows refuse a press while they are read again through a veil over
2386
+ * them, not through `pointer-events: none` on the body: the property is
2387
+ * inherited, and toggling it restyled every cell — 8 ms of a 70-row grid's
2388
+ * 9 ms. The veil is one box; the body's opacity makes it a stacking context,
2389
+ * so the veil's layer is above the pinned cells and below nothing outside.
2390
+ */
2391
+ [data-ui-data-grid][aria-busy='true'] > [data-part-scroll] > [data-part-body]::after {
2392
+ content: '';
2393
+ inset: 0;
2394
+ position: absolute;
2395
+ z-index: calc(var(--slotted-z-index-sticky, 100) + 4);
2396
+ }
2397
+
2357
2398
  /**
2358
2399
  * ── The footer ─────────────────────────────────────────────────────────
2359
2400
  *
@@ -2365,7 +2406,7 @@
2365
2406
  * its own content to the end: `pagination` is an inline-size container and
2366
2407
  * contributes no intrinsic width, so it cannot be sized by its content.
2367
2408
  */
2368
- [data-ui='data-grid'] > [data-part='footer'] {
2409
+ [data-ui-data-grid] > [data-part-footer] {
2369
2410
  align-items: center;
2370
2411
  border-block-start: var(--_rule-width) solid var(--_rule);
2371
2412
  box-sizing: border-box;
@@ -2380,14 +2421,14 @@
2380
2421
  padding-inline: var(--_pad-inline);
2381
2422
  }
2382
2423
 
2383
- [data-ui='data-grid'] > [data-part='footer'] > :last-child {
2424
+ [data-ui-data-grid] > [data-part-footer] > :last-child {
2384
2425
  display: flex;
2385
2426
  flex: 1 1 auto;
2386
2427
  justify-content: flex-end;
2387
2428
  min-inline-size: 0;
2388
2429
  }
2389
2430
 
2390
- [data-ui='data-grid'] > [data-part='footer'] [data-range] {
2431
+ [data-ui-data-grid] > [data-part-footer] [data-range] {
2391
2432
  color: var(--_muted);
2392
2433
  flex: none;
2393
2434
  font-variant-numeric: tabular-nums;
@@ -2398,21 +2439,26 @@
2398
2439
  * ── Scheme and platform ────────────────────────────────────────────────
2399
2440
  */
2400
2441
  @media (forced-colors: active) {
2401
- [data-ui='data-grid'] [role='gridcell'][data-current],
2402
- [data-ui='data-grid'] [role='columnheader'][data-current] {
2442
+ [data-ui-data-grid] [data-part-resizer] > [data-part-resize-guide] {
2443
+ background-color: Highlight;
2444
+ forced-color-adjust: none;
2445
+ }
2446
+
2447
+ [data-ui-data-grid] [role='gridcell'][data-current],
2448
+ [data-ui-data-grid] [role='columnheader'][data-current] {
2403
2449
  box-shadow: inset 0 0 0 var(--_ring-width) Highlight;
2404
2450
  }
2405
2451
 
2406
- [data-ui='data-grid'] [data-part='cell'][data-in-range] {
2452
+ [data-ui-data-grid] [data-part-cell][data-in-range] {
2407
2453
  background-color: Highlight;
2408
2454
  color: HighlightText;
2409
2455
  }
2410
2456
 
2411
- [data-ui='data-grid'] [data-part='drop-indicator'] {
2457
+ [data-ui-data-grid] [data-part-drop-indicator] {
2412
2458
  background-color: Highlight;
2413
2459
  }
2414
2460
 
2415
- [data-ui='data-grid'] [data-part='cell'][data-changed] {
2461
+ [data-ui-data-grid] [data-part-cell][data-changed] {
2416
2462
  animation: none;
2417
2463
  background-color: Highlight;
2418
2464
  color: HighlightText;
@@ -2420,7 +2466,7 @@
2420
2466
 
2421
2467
  /* The resizer's line is a painted background, which the adjustment
2422
2468
  would otherwise replace, leaving the target with no line to show. */
2423
- [data-ui='data-grid'] [data-part='resizer']::after {
2469
+ [data-ui-data-grid] [data-part-resizer]::after {
2424
2470
  forced-color-adjust: none;
2425
2471
  }
2426
2472
  }
@@ -2435,50 +2481,69 @@
2435
2481
  * consumer who prints ten thousand turns the window off first.
2436
2482
  */
2437
2483
  @media print {
2438
- [data-ui='data-grid'][data-part='root'] {
2484
+ [data-ui-data-grid][data-part-root] {
2439
2485
  block-size: auto;
2440
2486
  break-inside: auto;
2441
2487
  }
2442
2488
 
2443
- [data-ui='data-grid'] > [data-part='scroll'] {
2489
+ [data-ui-data-grid] > [data-part-scroll] {
2444
2490
  overflow: visible;
2445
2491
  }
2446
2492
 
2447
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='head'],
2448
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='summary'],
2449
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='empty'],
2450
- [data-ui='data-grid'] > [data-part='scroll'] > [data-part='pinned-rows'],
2451
- [data-ui='data-grid'] [data-pinned] {
2493
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-head],
2494
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-summary],
2495
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-empty],
2496
+ [data-ui-data-grid] > [data-part-scroll] > [data-part-pinned-rows],
2497
+ [data-ui-data-grid] [data-pinned] {
2452
2498
  position: static;
2453
2499
  }
2454
2500
 
2455
- [data-ui='data-grid'] [data-pinned] {
2501
+ [data-ui-data-grid] [data-pinned] {
2456
2502
  box-shadow: none;
2457
2503
  }
2458
2504
 
2459
- [data-ui='data-grid'] [data-part='column-actions'],
2460
- [data-ui='data-grid'] [data-part='row-handle'],
2461
- [data-ui='data-grid'] [data-part='resizer'],
2462
- [data-ui='data-grid'] [data-part='drop-indicator'],
2463
- [data-ui='data-grid'] [data-part='loader'] {
2505
+ [data-ui-data-grid] [data-part-column-actions],
2506
+ [data-ui-data-grid] [data-part-row-handle],
2507
+ [data-ui-data-grid] [data-part-resizer],
2508
+ [data-ui-data-grid] [data-part-drop-indicator],
2509
+ [data-ui-data-grid] [data-part-loader] {
2464
2510
  display: none;
2465
2511
  }
2466
2512
 
2467
- [data-ui='data-grid'] [role='gridcell'][data-current],
2468
- [data-ui='data-grid'] [role='rowheader'][data-current],
2469
- [data-ui='data-grid'] [role='columnheader'][data-current] {
2513
+ [data-ui-data-grid] [role='gridcell'][data-current],
2514
+ [data-ui-data-grid] [role='rowheader'][data-current],
2515
+ [data-ui-data-grid] [role='columnheader'][data-current] {
2470
2516
  box-shadow: none;
2471
2517
  }
2472
2518
 
2473
- [data-ui='data-grid'] :is([data-part='body'], [data-part='pinned-rows']) > [data-part='row'] {
2519
+ [data-ui-data-grid] :is([data-part-body], [data-part-pinned-rows]) > [data-part-row] {
2474
2520
  break-inside: avoid;
2475
2521
  }
2476
2522
 
2477
- [data-ui='data-grid']
2478
- > [data-part='scroll']
2479
- > :is([data-part='body'], [data-part='pinned-rows'])
2480
- > [data-part='row'] {
2523
+ [data-ui-data-grid]
2524
+ > [data-part-scroll]
2525
+ > :is([data-part-body], [data-part-pinned-rows])
2526
+ > [data-part-row] {
2481
2527
  --_hover: transparent;
2482
2528
  }
2483
2529
  }
2484
2530
  }
2531
+
2532
+ /**
2533
+ * The row window's offset and the body's whole height, written on the body
2534
+ * by script on every scroll step and read only by the body. Unregistered,
2535
+ * each one inherited into every row and cell, and a scroll step restyled the
2536
+ * whole window: 41 ms of style recalculation per step on 29 mounted rows.
2537
+ * Registered without inheritance and without a type, a body the grid does not
2538
+ * window still takes the fallback of `var()`. Outside the layer, because
2539
+ * `@property` is a registration, not a rule a cascade layer holds.
2540
+ */
2541
+ @property --slotted-data-grid-window-start {
2542
+ syntax: '*';
2543
+ inherits: false;
2544
+ }
2545
+
2546
+ @property --slotted-data-grid-window-total {
2547
+ syntax: '*';
2548
+ inherits: false;
2549
+ }