@slotted/styles 0.0.0-stage → 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/package.json +276 -3
  4. package/src/accordion/accordion.css +96 -0
  5. package/src/accordion/accordion.tokens.json +14 -0
  6. package/src/action-bar/action-bar.css +455 -0
  7. package/src/action-bar/action-bar.tokens.json +50 -0
  8. package/src/action-sheet/action-sheet.css +462 -0
  9. package/src/action-sheet/action-sheet.tokens.json +59 -0
  10. package/src/alert/alert.css +764 -0
  11. package/src/alert/alert.tokens.json +77 -0
  12. package/src/app-shell/app-shell.css +1899 -0
  13. package/src/app-shell/app-shell.tokens.json +88 -0
  14. package/src/aspect-ratio/aspect-ratio.css +131 -0
  15. package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
  16. package/src/attachment/attachment.css +906 -0
  17. package/src/attachment/attachment.tokens.json +85 -0
  18. package/src/avatar/avatar.css +598 -0
  19. package/src/avatar/avatar.tokens.json +64 -0
  20. package/src/avatar-group/avatar-group.css +268 -0
  21. package/src/avatar-group/avatar-group.tokens.json +16 -0
  22. package/src/badge/badge.css +462 -0
  23. package/src/badge/badge.tokens.json +58 -0
  24. package/src/breadcrumb/breadcrumb.css +441 -0
  25. package/src/breadcrumb/breadcrumb.tokens.json +50 -0
  26. package/src/button/button.css +754 -0
  27. package/src/button/button.tokens.json +72 -0
  28. package/src/button-group/button-group.css +455 -0
  29. package/src/button-group/button-group.tokens.json +11 -0
  30. package/src/calendar/calendar.css +846 -0
  31. package/src/calendar/calendar.tokens.json +67 -0
  32. package/src/card/card.css +602 -0
  33. package/src/card/card.tokens.json +68 -0
  34. package/src/carousel/carousel.css +860 -0
  35. package/src/carousel/carousel.tokens.json +62 -0
  36. package/src/cascader/cascader.css +1320 -0
  37. package/src/cascader/cascader.tokens.json +103 -0
  38. package/src/chart/chart.css +1473 -0
  39. package/src/chart/chart.tokens.json +107 -0
  40. package/src/checkbox/checkbox.css +1011 -0
  41. package/src/checkbox/checkbox.tokens.json +102 -0
  42. package/src/checkbox-group/checkbox-group.css +70 -0
  43. package/src/checkbox-group/checkbox-group.tokens.json +6 -0
  44. package/src/code-block/code-block.css +555 -0
  45. package/src/code-block/code-block.tokens.json +69 -0
  46. package/src/collapsible/collapsible.css +546 -0
  47. package/src/collapsible/collapsible.tokens.json +55 -0
  48. package/src/color-picker/color-picker.css +607 -0
  49. package/src/color-picker/color-picker.tokens.json +58 -0
  50. package/src/column-manager/column-manager.css +452 -0
  51. package/src/column-manager/column-manager.tokens.json +43 -0
  52. package/src/combobox/combobox.css +1048 -0
  53. package/src/combobox/combobox.tokens.json +112 -0
  54. package/src/command-palette/command-palette.css +1000 -0
  55. package/src/command-palette/command-palette.tokens.json +75 -0
  56. package/src/container/container.css +198 -0
  57. package/src/container/container.tokens.json +18 -0
  58. package/src/context-menu/context-menu.css +104 -0
  59. package/src/context-menu/context-menu.tokens.json +11 -0
  60. package/src/currency-field/currency-field.css +787 -0
  61. package/src/currency-field/currency-field.tokens.json +80 -0
  62. package/src/dashboard-grid/dashboard-grid.css +748 -0
  63. package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
  64. package/src/data-grid/data-grid.css +2484 -0
  65. package/src/data-grid/data-grid.tokens.json +100 -0
  66. package/src/data-list/data-list.css +455 -0
  67. package/src/data-list/data-list.tokens.json +35 -0
  68. package/src/date-field/date-field.css +560 -0
  69. package/src/date-field/date-field.tokens.json +80 -0
  70. package/src/date-picker/date-picker.css +420 -0
  71. package/src/date-picker/date-picker.tokens.json +49 -0
  72. package/src/date-range-picker/date-range-picker.css +983 -0
  73. package/src/date-range-picker/date-range-picker.tokens.json +109 -0
  74. package/src/datetime-field/datetime-field.css +850 -0
  75. package/src/datetime-field/datetime-field.tokens.json +91 -0
  76. package/src/datetime-picker/datetime-picker.css +843 -0
  77. package/src/datetime-picker/datetime-picker.tokens.json +78 -0
  78. package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
  79. package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
  80. package/src/description-list/description-list.css +675 -0
  81. package/src/description-list/description-list.tokens.json +66 -0
  82. package/src/detail-panel/detail-panel.css +329 -0
  83. package/src/detail-panel/detail-panel.tokens.json +33 -0
  84. package/src/dialog/dialog.css +968 -0
  85. package/src/dialog/dialog.tokens.json +66 -0
  86. package/src/divider/divider.css +131 -0
  87. package/src/divider/divider.tokens.json +18 -0
  88. package/src/drawer/drawer.css +1303 -0
  89. package/src/drawer/drawer.tokens.json +75 -0
  90. package/src/entity-picker/entity-picker.css +1367 -0
  91. package/src/entity-picker/entity-picker.tokens.json +118 -0
  92. package/src/event-calendar/event-calendar.css +2148 -0
  93. package/src/event-calendar/event-calendar.tokens.json +87 -0
  94. package/src/field/field.css +707 -0
  95. package/src/field/field.tokens.json +58 -0
  96. package/src/field-group/field-group.css +226 -0
  97. package/src/field-group/field-group.tokens.json +33 -0
  98. package/src/filter-bar/filter-bar.css +1306 -0
  99. package/src/filter-bar/filter-bar.tokens.json +78 -0
  100. package/src/form/form.css +218 -0
  101. package/src/form/form.tokens.json +32 -0
  102. package/src/fullscreen/fullscreen.css +376 -0
  103. package/src/fullscreen/fullscreen.tokens.json +50 -0
  104. package/src/grid/grid.css +173 -0
  105. package/src/grid/grid.tokens.json +20 -0
  106. package/src/highlight/highlight.css +135 -0
  107. package/src/highlight/highlight.tokens.json +16 -0
  108. package/src/hover-card/hover-card.css +93 -0
  109. package/src/hover-card/hover-card.tokens.json +17 -0
  110. package/src/icon/icon.css +136 -0
  111. package/src/icon/icon.tokens.json +14 -0
  112. package/src/image/image.css +449 -0
  113. package/src/image/image.tokens.json +27 -0
  114. package/src/import-export-center/import-export-center.css +1175 -0
  115. package/src/import-export-center/import-export-center.tokens.json +84 -0
  116. package/src/inline/inline.css +149 -0
  117. package/src/inline/inline.tokens.json +14 -0
  118. package/src/inline-message/inline-message.css +396 -0
  119. package/src/inline-message/inline-message.tokens.json +19 -0
  120. package/src/kbd/kbd.css +490 -0
  121. package/src/kbd/kbd.tokens.json +40 -0
  122. package/src/link/link.css +237 -0
  123. package/src/link/link.tokens.json +25 -0
  124. package/src/list/list.css +240 -0
  125. package/src/list/list.tokens.json +42 -0
  126. package/src/list-item/list-item.css +937 -0
  127. package/src/list-item/list-item.tokens.json +114 -0
  128. package/src/listbox/listbox.css +674 -0
  129. package/src/listbox/listbox.tokens.json +72 -0
  130. package/src/loading-overlay/loading-overlay.css +730 -0
  131. package/src/loading-overlay/loading-overlay.tokens.json +48 -0
  132. package/src/markdown/markdown.css +168 -0
  133. package/src/markdown/markdown.tokens.json +18 -0
  134. package/src/menu/menu.css +817 -0
  135. package/src/menu/menu.tokens.json +78 -0
  136. package/src/menubar/menubar.css +170 -0
  137. package/src/menubar/menubar.tokens.json +32 -0
  138. package/src/message/message.css +1453 -0
  139. package/src/message/message.tokens.json +85 -0
  140. package/src/message-scroller/message-scroller.css +371 -0
  141. package/src/message-scroller/message-scroller.tokens.json +47 -0
  142. package/src/multi-select/multi-select.css +1427 -0
  143. package/src/multi-select/multi-select.tokens.json +114 -0
  144. package/src/navigation-menu/navigation-menu.css +1029 -0
  145. package/src/navigation-menu/navigation-menu.tokens.json +70 -0
  146. package/src/notification-center/notification-center.css +856 -0
  147. package/src/notification-center/notification-center.tokens.json +84 -0
  148. package/src/number-field/number-field.css +794 -0
  149. package/src/number-field/number-field.tokens.json +80 -0
  150. package/src/otp-input/otp-input.css +525 -0
  151. package/src/otp-input/otp-input.tokens.json +69 -0
  152. package/src/page/page.css +179 -0
  153. package/src/page/page.tokens.json +20 -0
  154. package/src/page-header/page-header.css +1181 -0
  155. package/src/page-header/page-header.tokens.json +71 -0
  156. package/src/pagination/pagination.css +500 -0
  157. package/src/pagination/pagination.tokens.json +56 -0
  158. package/src/popover/popover.css +526 -0
  159. package/src/popover/popover.tokens.json +60 -0
  160. package/src/progress-indicator/progress-indicator.css +1584 -0
  161. package/src/progress-indicator/progress-indicator.tokens.json +50 -0
  162. package/src/prompt-composer/prompt-composer.css +680 -0
  163. package/src/prompt-composer/prompt-composer.tokens.json +99 -0
  164. package/src/prose/prose.css +733 -0
  165. package/src/prose/prose.tokens.json +79 -0
  166. package/src/radio-group/radio-group.css +778 -0
  167. package/src/radio-group/radio-group.tokens.json +103 -0
  168. package/src/rating/rating.css +1071 -0
  169. package/src/rating/rating.tokens.json +88 -0
  170. package/src/result-state/result-state.css +980 -0
  171. package/src/result-state/result-state.tokens.json +63 -0
  172. package/src/runtime-properties.mjs +321 -0
  173. package/src/saved-views/saved-views.css +394 -0
  174. package/src/saved-views/saved-views.tokens.json +41 -0
  175. package/src/scroll-area/scroll-area.css +481 -0
  176. package/src/scroll-area/scroll-area.tokens.json +15 -0
  177. package/src/section/section.css +177 -0
  178. package/src/section/section.tokens.json +39 -0
  179. package/src/segmented-control/segmented-control.css +564 -0
  180. package/src/segmented-control/segmented-control.tokens.json +67 -0
  181. package/src/select/select.css +1593 -0
  182. package/src/select/select.tokens.json +110 -0
  183. package/src/side-navigation/side-navigation.css +1096 -0
  184. package/src/side-navigation/side-navigation.tokens.json +87 -0
  185. package/src/skeleton/skeleton.css +431 -0
  186. package/src/skeleton/skeleton.tokens.json +29 -0
  187. package/src/slider/slider.css +792 -0
  188. package/src/slider/slider.tokens.json +75 -0
  189. package/src/sparkline/sparkline.css +282 -0
  190. package/src/sparkline/sparkline.tokens.json +45 -0
  191. package/src/spinner/spinner.css +224 -0
  192. package/src/spinner/spinner.tokens.json +8 -0
  193. package/src/split-button/split-button.css +253 -0
  194. package/src/split-button/split-button.tokens.json +12 -0
  195. package/src/splitter/splitter.css +336 -0
  196. package/src/splitter/splitter.tokens.json +24 -0
  197. package/src/stack/stack.css +128 -0
  198. package/src/stack/stack.tokens.json +14 -0
  199. package/src/stat-card/stat-card.css +641 -0
  200. package/src/stat-card/stat-card.tokens.json +95 -0
  201. package/src/status-indicator/status-indicator.css +481 -0
  202. package/src/status-indicator/status-indicator.tokens.json +38 -0
  203. package/src/stepper/stepper.css +629 -0
  204. package/src/stepper/stepper.tokens.json +72 -0
  205. package/src/switch/switch.css +703 -0
  206. package/src/switch/switch.tokens.json +75 -0
  207. package/src/table/table.css +1482 -0
  208. package/src/table/table.tokens.json +69 -0
  209. package/src/table-of-contents/table-of-contents.css +533 -0
  210. package/src/table-of-contents/table-of-contents.tokens.json +53 -0
  211. package/src/tabs/tabs.css +998 -0
  212. package/src/tabs/tabs.tokens.json +82 -0
  213. package/src/tag/tag.css +768 -0
  214. package/src/tag/tag.tokens.json +85 -0
  215. package/src/tags-input/tags-input.css +757 -0
  216. package/src/tags-input/tags-input.tokens.json +84 -0
  217. package/src/text-field/text-field.css +900 -0
  218. package/src/text-field/text-field.tokens.json +87 -0
  219. package/src/textarea/textarea.css +365 -0
  220. package/src/textarea/textarea.tokens.json +59 -0
  221. package/src/time-field/time-field.css +719 -0
  222. package/src/time-field/time-field.tokens.json +86 -0
  223. package/src/time-picker/time-picker.css +665 -0
  224. package/src/time-picker/time-picker.tokens.json +66 -0
  225. package/src/time-range-picker/time-range-picker.css +1287 -0
  226. package/src/time-range-picker/time-range-picker.tokens.json +134 -0
  227. package/src/timeline/timeline.css +1596 -0
  228. package/src/timeline/timeline.tokens.json +96 -0
  229. package/src/toast/toast.css +943 -0
  230. package/src/toast/toast.tokens.json +90 -0
  231. package/src/toggle/toggle.css +290 -0
  232. package/src/toggle/toggle.tokens.json +54 -0
  233. package/src/toggle-group/toggle-group.css +463 -0
  234. package/src/toggle-group/toggle-group.tokens.json +54 -0
  235. package/src/toolbar/toolbar.css +434 -0
  236. package/src/toolbar/toolbar.tokens.json +49 -0
  237. package/src/tooltip/tooltip.css +368 -0
  238. package/src/tooltip/tooltip.tokens.json +39 -0
  239. package/src/top-navigation/top-navigation.css +1287 -0
  240. package/src/top-navigation/top-navigation.tokens.json +91 -0
  241. package/src/tour/tour.css +680 -0
  242. package/src/tour/tour.tokens.json +67 -0
  243. package/src/transfer/transfer.css +571 -0
  244. package/src/transfer/transfer.tokens.json +49 -0
  245. package/src/tree/tree.css +1000 -0
  246. package/src/tree/tree.tokens.json +80 -0
  247. package/src/typography/typography.css +211 -0
  248. package/src/typography/typography.tokens.json +31 -0
  249. package/src/upload/upload.css +1706 -0
  250. package/src/upload/upload.tokens.json +123 -0
  251. package/src/visually-hidden/visually-hidden.css +52 -0
  252. package/src/visually-hidden/visually-hidden.tokens.json +1 -0
  253. package/src/wizard/wizard.css +740 -0
  254. package/src/wizard/wizard.tokens.json +63 -0
@@ -0,0 +1,1000 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * A search that executes. The reader opens it by a shortcut or a trigger,
4
+ * types, and the list answers with commands and destinations in the order
5
+ * the ranker put them; Enter runs the current one.
6
+ *
7
+ * ┌─ root ─ the panel ─────────────────────────────────────────────────┐
8
+ * │ ┌─ header ───────────────────────────────────────────────────────┐ │
9
+ * │ │ search│busy pages ▸ page › page input (combobox) clear │ │
10
+ * │ └────────────────────────────────────────────────────────────────┘ │
11
+ * │ ┌─ list ─ role="listbox" ─ scrolls ──────────────────────────────┐ │
12
+ * │ │ group ▸ group-label │ │
13
+ * │ │ item ▸ icon │ label ▸ match │ meta │ shortcut │ arrow │ │
14
+ * │ │ description │ │
15
+ * │ │ separator · placeholder · empty │ │
16
+ * │ └────────────────────────────────────────────────────────────────┘ │
17
+ * │ status (live region, visually hidden) │
18
+ * │ ┌─ footer ─ hint ▸ kbd word · hint ▸ kbd word ────────────────────┐ │
19
+ * └────────────────────────────────────────────────────────────────────┘
20
+ *
21
+ * ── What this sheet does not draw ───────────────────────────────────
22
+ *
23
+ * The layer, the scrim, the motion of arriving and leaving, the focus
24
+ * containment and the Escape that closes are `dialog`'s: the panel stands
25
+ * inside a dialog whose surface is `plain`, and `identity.test.mjs` keeps
26
+ * this sheet off `[data-ui='dialog']`. The keys in an item's shortcut and in
27
+ * the footer's hints are `kbd`'s, worn as `data-ui='kbd'` under this family's
28
+ * own `shortcut` and `hint` parts, so every selector on those two parts is a
29
+ * child selector and never reaches the caps inside them. The mark on the
30
+ * run a query found is `highlight`'s, the ring while loading is `spinner`'s
31
+ * and the three bars are `skeleton`'s, exactly as `combobox` composes them.
32
+ *
33
+ * ── The panel draws itself ───────────────────────────────────────────
34
+ *
35
+ * `dialog`'s `plain` surface hands over the paint and keeps the mechanism,
36
+ * which is what this family needs: a palette is not a dialog with a title
37
+ * and a footer of buttons, it is a field over a list, and the two rows meet
38
+ * at a rule rather than at a header. The same root, drawn where the consumer
39
+ * wrote it under `presentation="inline"`, is the surface inside a popover —
40
+ * the filtered menu `menu` refused — and there the panel's own edge is the
41
+ * only edge it has.
42
+ *
43
+ * ── Why the list is a grid and the item a subgrid ────────────────────
44
+ *
45
+ * `menu`'s reasons, and `menu`'s columns plus two: the mark, the words, the
46
+ * meta, the shortcut and the arrow. A long translated label gives way in
47
+ * column two and never pushes a shortcut off the surface, and the shortcut
48
+ * column is as wide as the widest binding in the list, so `⌘K` and
49
+ * `Ctrl+Shift+P` end on one line. No `column-gap`, for the reason `menu`
50
+ * gives: a gap is drawn between two tracks even when the first is empty.
51
+ *
52
+ * ── Density ─────────────────────────────────────────────────────────
53
+ *
54
+ * A row is a control and reads control geometry: height, inset, type, glyph
55
+ * and gap. The header is one step up from the row — a field the reader is
56
+ * typing into is the thing the palette is about — and the footer one step
57
+ * down. Only the panel's own radius and the list's inset come off the space
58
+ * and radius scales.
59
+ */
60
+ [data-ui='command-palette'] {
61
+ --_surface: var(--slotted-command-palette-surface, var(--slotted-surface-raised, #ffffff));
62
+ --_text: var(--slotted-command-palette-text, var(--slotted-text, #0f172a));
63
+ --_muted: var(--slotted-command-palette-text-muted, var(--slotted-text-muted, #5b6b7f));
64
+ --_border-color: var(
65
+ --slotted-command-palette-border-color,
66
+ var(--slotted-border-subtle, #e2e8f0)
67
+ );
68
+ --_border-width: var(--slotted-border-width-thin, 1px);
69
+ --_radius: var(--slotted-command-palette-radius, var(--slotted-radius-lg, 8px));
70
+ --_shadow: var(--slotted-command-palette-shadow, var(--slotted-shadow-lg));
71
+
72
+ /* The current row: the accent ground under an accent ring, `combobox`'s
73
+ pair. Nothing on this surface holds focus — DOM focus is on the input —
74
+ so the ring is what says where the reader is. */
75
+ --_highlight: var(--slotted-command-palette-highlight, var(--slotted-tone-accent-surface));
76
+ --_highlight-ring: var(
77
+ --slotted-command-palette-highlight-ring,
78
+ var(--slotted-tone-accent-border)
79
+ );
80
+ --_hover: var(--slotted-command-palette-hover, var(--slotted-tone-secondary-subtle-hover));
81
+ --_active: var(--slotted-command-palette-active, var(--slotted-tone-secondary-subtle-active));
82
+
83
+ /* The row, at the family's size step; the header one step up. */
84
+ --_item-height: var(--slotted-control-height-md, 34px);
85
+ --_item-inset: var(--slotted-control-padding-inline-md, 13px);
86
+ --_item-radius: var(--slotted-command-palette-item-radius, var(--slotted-control-radius));
87
+ --_font-size: var(--slotted-control-font-size-md, 13px);
88
+ --_secondary-font-size: var(--slotted-control-font-size-sm, 12px);
89
+ --_icon-size: var(--slotted-control-icon-size-md, 16px);
90
+ --_column-gap: var(--slotted-control-gap-md, 8px);
91
+ --_header-height: var(--slotted-control-height-lg, 38px);
92
+ --_header-font-size: var(--slotted-control-font-size-lg, 14px);
93
+ --_header-icon-size: var(--slotted-control-icon-size-lg, 18px);
94
+ --_header-inset: var(--slotted-control-padding-inline-lg, 16px);
95
+ --_chip-size: var(--slotted-control-inner-size-md, 24px);
96
+ --_list-inset: var(--slotted-command-palette-list-padding, var(--slotted-space-2, 0.25rem));
97
+
98
+ /**
99
+ * How tall the list may grow before it scrolls. A literal with the reason
100
+ * `--slotted-dialog-measure` carries one: a height nothing in the scales
101
+ * holds, and the one number a product retunes when its palette lives in a
102
+ * short viewport. Ten rows at `md`, comfortable.
103
+ */
104
+ --_list-max: var(--slotted-command-palette-list-max-block-size, 22rem);
105
+
106
+ background: var(--_surface);
107
+ border: var(--_border-width) solid var(--_border-color);
108
+ border-radius: var(--_radius);
109
+ box-shadow: var(--_shadow);
110
+ box-sizing: border-box;
111
+ color: var(--_text);
112
+ /* The two elements a container query needs: this one is queried, and the
113
+ rows inside are what it restyles. The panel changes no track of its own. */
114
+ container-name: command-palette;
115
+ container-type: inline-size;
116
+ /**
117
+ * What the panel is worth to a parent that shrink-wraps it. Inline-size
118
+ * containment takes the panel's contents out of its intrinsic size, so
119
+ * inside a popover — which is as wide as its widest child — the panel
120
+ * measured two pixels: its two borders, around nothing. This is the width
121
+ * the panel asks for when nothing outside it says; where the parent is a
122
+ * block, `inline-size: 100%` below is what it takes. A literal, with the
123
+ * reason `--slotted-dialog-measure` carries one.
124
+ */
125
+ contain-intrinsic-inline-size: var(--slotted-command-palette-measure, 22rem);
126
+ display: grid;
127
+ font-family: var(--slotted-font-family-sans);
128
+ font-size: var(--_font-size);
129
+ grid-template-rows: auto minmax(0, 1fr) auto auto;
130
+ inline-size: 100%;
131
+ line-height: var(--slotted-line-height-md, 1.5);
132
+ /* The rows meet the rounded corner and are cut by it, as `table`'s framed
133
+ variant cuts its rows: a scrolled list otherwise draws square corners
134
+ inside a rounded panel. */
135
+ overflow: clip;
136
+ }
137
+
138
+ /* ── Size ─────────────────────────────────────────────────────────────── */
139
+
140
+ [data-ui='command-palette'][data-size='sm'] {
141
+ --_item-height: var(--slotted-control-height-sm, 30px);
142
+ --_item-inset: var(--slotted-control-padding-inline-sm, 10px);
143
+ --_font-size: var(--slotted-control-font-size-sm, 12px);
144
+ --_icon-size: var(--slotted-control-icon-size-sm, 14px);
145
+ --_column-gap: var(--slotted-control-gap-sm, 6px);
146
+ --_header-height: var(--slotted-control-height-md, 34px);
147
+ --_header-font-size: var(--slotted-control-font-size-md, 13px);
148
+ --_header-icon-size: var(--slotted-control-icon-size-md, 16px);
149
+ --_header-inset: var(--slotted-control-padding-inline-md, 13px);
150
+ --_chip-size: var(--slotted-control-inner-size-sm, 22px);
151
+ }
152
+
153
+ [data-ui='command-palette'][data-size='lg'] {
154
+ --_item-height: var(--slotted-control-height-lg, 38px);
155
+ --_item-inset: var(--slotted-control-padding-inline-lg, 16px);
156
+ --_font-size: var(--slotted-control-font-size-lg, 14px);
157
+ --_icon-size: var(--slotted-control-icon-size-lg, 18px);
158
+ --_column-gap: var(--slotted-control-gap-lg, 8px);
159
+ /* Nothing in control geometry stands above `lg`, so the header takes its
160
+ type from the text scale and its air from the space scale instead. */
161
+ --_header-height: calc(var(--slotted-control-height-lg, 38px) + var(--slotted-space-4, 0.5rem));
162
+ --_header-font-size: var(--slotted-font-size-lg, 1rem);
163
+ --_header-icon-size: var(--slotted-control-inner-size-sm, 22px);
164
+ --_chip-size: var(--slotted-control-inner-size-lg, 28px);
165
+ }
166
+
167
+ /* ── The header ───────────────────────────────────────────────────────── */
168
+
169
+ /**
170
+ * One row: the mark, the trail, the field, the clear. The field is `plain`
171
+ * in the sense `plain-variant.test.mjs` gives the word — its box belongs to
172
+ * something else — so it draws no edge and no ground of its own, and the
173
+ * rule under the header is the one line between the field and the list.
174
+ */
175
+ [data-ui='command-palette'] > [data-part='header'] {
176
+ align-items: center;
177
+ border-block-end: var(--_border-width) solid var(--_border-color);
178
+ box-sizing: border-box;
179
+ display: flex;
180
+ gap: var(--_column-gap);
181
+ min-block-size: var(--_header-height);
182
+ padding-inline: var(--_header-inset);
183
+ /* The containing block of the ring drawn under it, below. */
184
+ position: relative;
185
+ }
186
+
187
+ /**
188
+ * The ring under the field, and why it is not around it. The field is the
189
+ * only thing focused for the whole of the interaction, and a box around the
190
+ * top row of a panel that is itself a box says the wrong thing. The ring is
191
+ * drawn as a band the ring's own width along the header's bottom edge, in
192
+ * the theme's ring colour, and it appears only when the keyboard put focus
193
+ * there — which, for a palette opened with ⌘K, is every time. The band is
194
+ * a bottom edge: `state-rail.test.mjs` (R1) refuses a state rail on the
195
+ * start or the top edge, and this is neither.
196
+ */
197
+ [data-ui='command-palette']
198
+ > [data-part='header']:has(> [data-part='input']:focus-visible)::after {
199
+ background-color: var(--slotted-focus-ring-color, currentColor);
200
+ block-size: var(--slotted-focus-ring-width, 2px);
201
+ content: '';
202
+ inset-block-end: calc(-1 * var(--_border-width));
203
+ inset-inline: 0;
204
+ pointer-events: none;
205
+ position: absolute;
206
+ }
207
+
208
+ [data-ui='command-palette'] :is([data-part='search'], [data-part='busy']) {
209
+ color: var(--_muted);
210
+ flex: none;
211
+ }
212
+
213
+ /**
214
+ * The mark that says what the field is: the binding's `search` glyph, its
215
+ * icon box at the header's icon size so it sits on the field's line; a
216
+ * character is never an icon.
217
+ */
218
+ [data-ui='command-palette'] [data-part='search'] {
219
+ --slotted-icon-size: var(--_header-icon-size);
220
+
221
+ display: flex;
222
+ }
223
+
224
+ /**
225
+ * The ring while an answer is travelling, where the mark stood. The arc is
226
+ * `spinner/spinner.css`'s, worn as `data-ui='spinner'` beside this family's
227
+ * part, and this family only says where it stands and how big it is.
228
+ */
229
+ [data-ui='command-palette'] [data-part='busy'] {
230
+ --slotted-spinner-size: var(--_header-icon-size);
231
+ }
232
+
233
+ /* ── The trail ────────────────────────────────────────────────────────── */
234
+
235
+ /**
236
+ * The pages the reader has opened, oldest first, as chips before the field.
237
+ * Each is a control that returns to its page; the last one is where the
238
+ * reader is and reads as the field's own prefix.
239
+ */
240
+ [data-ui='command-palette'] [data-part='pages'] {
241
+ align-items: center;
242
+ display: flex;
243
+ flex: none;
244
+ gap: var(--slotted-space-2, 0.25rem);
245
+ list-style: none;
246
+ margin: 0;
247
+ max-inline-size: 50%;
248
+ min-inline-size: 0;
249
+ padding: 0;
250
+ }
251
+
252
+ [data-ui='command-palette'] [data-part='pages'] > li {
253
+ display: contents;
254
+ }
255
+
256
+ [data-ui='command-palette'] [data-part='page'] {
257
+ align-items: center;
258
+ appearance: none;
259
+ background-color: var(--slotted-command-palette-page-surface, var(--_hover));
260
+ block-size: var(--_chip-size);
261
+ border: 0;
262
+ border-radius: var(--slotted-radius-sm, 4px);
263
+ box-sizing: border-box;
264
+ color: var(--_muted);
265
+ cursor: pointer;
266
+ display: inline-flex;
267
+ flex: 0 1 auto;
268
+ font: inherit;
269
+ font-size: var(--_secondary-font-size);
270
+ font-weight: var(--slotted-font-weight-medium, 500);
271
+ line-height: 1;
272
+ max-inline-size: 100%;
273
+ min-inline-size: 0;
274
+ padding-block: 0;
275
+ padding-inline: var(--slotted-space-4, 0.5rem);
276
+ /* The containing block of the hit area below. */
277
+ position: relative;
278
+ touch-action: manipulation;
279
+ transition:
280
+ background-color var(--slotted-control-transition-duration, var(--slotted-duration-short))
281
+ var(--slotted-control-transition-easing, var(--slotted-easing-standard)),
282
+ color var(--slotted-control-transition-duration, var(--slotted-duration-short))
283
+ var(--slotted-control-transition-easing, var(--slotted-easing-standard));
284
+ white-space: nowrap;
285
+ }
286
+
287
+ [data-ui='command-palette'] [data-part='page'] > span {
288
+ overflow: hidden;
289
+ text-overflow: ellipsis;
290
+ }
291
+
292
+ /* A chip inside the header is shorter than the target minimum at every
293
+ density; the hit area is recovered outside its paint. */
294
+ [data-ui='command-palette'] [data-part='page']::after {
295
+ content: '';
296
+ inset: min(0px, calc((100% - var(--slotted-target-min, 24px)) / 2));
297
+ position: absolute;
298
+ }
299
+
300
+ [data-ui='command-palette'] [data-part='page']:not(:disabled):hover {
301
+ background-color: var(--_active);
302
+ color: var(--_text);
303
+ }
304
+
305
+ [data-ui='command-palette'] [data-part='page']:not(:disabled):active {
306
+ background-color: var(--_active);
307
+ }
308
+
309
+ /* Drawn one width inside the chip, as a chip in a scrolling row draws it:
310
+ the header clips at its padding edge and a ring at the theme's offset
311
+ would lose its outer half. */
312
+ [data-ui='command-palette'] [data-part='page']:focus-visible {
313
+ outline: var(--slotted-focus-ring-width, 2px) solid
314
+ var(--slotted-focus-ring-color, currentColor);
315
+ outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
316
+ }
317
+
318
+ /**
319
+ * The chevron between two pages: the binding's `chevron-right` glyph before
320
+ * every page but the first, in a `directional` icon box that mirrors in a
321
+ * right-to-left document so the trail reads in the direction the reader
322
+ * reads.
323
+ */
324
+ [data-ui='command-palette'] [data-part='pages'] > li > [data-ui='icon'] {
325
+ --slotted-icon-size: var(--_icon-size);
326
+
327
+ color: var(--_muted);
328
+ opacity: 0.7;
329
+ }
330
+
331
+ /* ── The field ────────────────────────────────────────────────────────── */
332
+
333
+ [data-ui='command-palette'] [data-part='input'] {
334
+ appearance: none;
335
+ background: transparent;
336
+ block-size: 100%;
337
+ border: 0;
338
+ box-sizing: border-box;
339
+ color: var(--_text);
340
+ flex: 1 1 auto;
341
+ font-family: inherit;
342
+ font-size: var(--_header-font-size);
343
+ line-height: inherit;
344
+ margin: 0;
345
+ min-block-size: var(--_header-height);
346
+ min-inline-size: 0;
347
+ /* The ring is the header's, drawn above; the browser's own goes. */
348
+ outline: none;
349
+ padding: 0;
350
+ }
351
+
352
+ [data-ui='command-palette'] [data-part='input']::placeholder {
353
+ color: var(--_muted);
354
+ opacity: 1;
355
+ }
356
+
357
+ /**
358
+ * A hint longer than the field fades out at the field's end rather than
359
+ * ending mid-glyph: a phone's field holds a third of the words. A fade and
360
+ * not `text-overflow: ellipsis`, which Chromium does not draw on a
361
+ * placeholder whose input the user agent clips (`overflow: clip`), focused
362
+ * or not — measured on the Nexora palette at 390 pixels. Only while the
363
+ * placeholder shows: what the reader types is never faded under the caret.
364
+ */
365
+ [data-ui='command-palette'] [data-part='input']:placeholder-shown {
366
+ mask-image: linear-gradient(
367
+ to right,
368
+ #000 calc(100% - var(--slotted-command-palette-placeholder-fade, 2em)),
369
+ transparent
370
+ );
371
+ }
372
+
373
+ /* The browser's own clear and its search decoration, which the family
374
+ draws itself so the two schemes and the three densities agree. */
375
+ [data-ui='command-palette'] [data-part='input']::-webkit-search-cancel-button,
376
+ [data-ui='command-palette'] [data-part='input']::-webkit-search-decoration {
377
+ appearance: none;
378
+ }
379
+
380
+ /**
381
+ * The clear, an inner control: `min(glyph + a step of air a side, the inner
382
+ * size at the family's step)`, never a control height, as
383
+ * `inner-control.test.mjs` holds every clear to. Out of the tab sequence,
384
+ * because Escape already clears and a second stop before the list is a
385
+ * stop nobody asked for.
386
+ */
387
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='clear'] {
388
+ --_clear-size: min(
389
+ calc(var(--_icon-size) + 2 * var(--slotted-space-2, 0.25rem)),
390
+ var(--slotted-control-inner-size-md, 24px)
391
+ );
392
+
393
+ align-items: center;
394
+ appearance: none;
395
+ background-color: transparent;
396
+ block-size: var(--_clear-size);
397
+ border: 0;
398
+ border-radius: var(--slotted-control-radius, 4px);
399
+ color: var(--_muted);
400
+ cursor: pointer;
401
+ display: inline-flex;
402
+ flex: none;
403
+ inline-size: var(--_clear-size);
404
+ justify-content: center;
405
+ padding: 0;
406
+ position: relative;
407
+ touch-action: manipulation;
408
+ transition:
409
+ background-color var(--slotted-control-transition-duration, var(--slotted-duration-short))
410
+ var(--slotted-control-transition-easing, var(--slotted-easing-standard)),
411
+ color var(--slotted-control-transition-duration, var(--slotted-duration-short))
412
+ var(--slotted-control-transition-easing, var(--slotted-easing-standard));
413
+ }
414
+
415
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='clear']::after {
416
+ content: '';
417
+ inset: min(0px, calc((100% - var(--slotted-target-min, 24px)) / 2));
418
+ position: absolute;
419
+ }
420
+
421
+ /* On a finger the target is the comfortable size in both axes and the box
422
+ is the one a mouse sees: the ground and the focus ring stay square, and
423
+ the hit area above grows to 44 pixels around them. It does not reach
424
+ across the close control after it. */
425
+ @media (pointer: coarse) {
426
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='clear']::after {
427
+ inset: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
428
+ }
429
+
430
+ [data-ui='command-palette']
431
+ > [data-part='header']
432
+ > [data-part='clear']:has(+ [data-part='close'])::after {
433
+ inset-inline-end: 0;
434
+ }
435
+ }
436
+
437
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='clear']:not(:disabled):hover {
438
+ background-color: var(--_hover);
439
+ color: var(--_text);
440
+ }
441
+
442
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='clear']:not(:disabled):active {
443
+ background-color: var(--_active);
444
+ }
445
+
446
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='clear']:focus-visible {
447
+ outline: var(--slotted-focus-ring-width, 2px) solid
448
+ var(--slotted-focus-ring-color, currentColor);
449
+ outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
450
+ }
451
+
452
+ /* Present in the DOM whenever the family renders it, drawn only with a
453
+ query: a clear beside an empty field is a control with nothing to do. */
454
+ [data-ui='command-palette']:not([data-query]) > [data-part='header'] > [data-part='clear'] {
455
+ display: none;
456
+ }
457
+
458
+ /**
459
+ * The way out where the scrim is not. The dialog closes on Escape and on
460
+ * the scrim; a palette that has taken the whole screen has no scrim to
461
+ * press, and a touch screen has no Escape, so a reader who opened it by
462
+ * mistake had nothing to press but a command. A word, not a cross: a ✕
463
+ * beside a search field reads as clear, which is what `clear` already is.
464
+ * Drawn only under the dialog's own full-screen query, below.
465
+ */
466
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='close'] {
467
+ align-items: center;
468
+ appearance: none;
469
+ background-color: transparent;
470
+ block-size: var(--slotted-control-height-sm, 30px);
471
+ border: 0;
472
+ border-radius: var(--slotted-control-radius, 4px);
473
+ color: var(--slotted-tone-accent-text, LinkText);
474
+ cursor: pointer;
475
+ display: none;
476
+ flex: none;
477
+ font: inherit;
478
+ font-size: var(--_font-size);
479
+ font-weight: var(--slotted-font-weight-medium, 500);
480
+ padding-block: 0;
481
+ padding-inline: var(--slotted-space-3, 0.375rem);
482
+ touch-action: manipulation;
483
+ white-space: nowrap;
484
+ }
485
+
486
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='close']:not(:disabled):hover {
487
+ background-color: var(--_hover);
488
+ }
489
+
490
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='close']:not(:disabled):active {
491
+ background-color: var(--_active);
492
+ }
493
+
494
+ [data-ui='command-palette'] > [data-part='header'] > [data-part='close']:focus-visible {
495
+ outline: var(--slotted-focus-ring-width, 2px) solid
496
+ var(--slotted-focus-ring-color, currentColor);
497
+ outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
498
+ }
499
+
500
+ /* ── The list ─────────────────────────────────────────────────────────── */
501
+
502
+ /**
503
+ * Five columns, bounded, scrolling. `overscroll-behavior` keeps the page —
504
+ * or the popover — still once the list has scrolled to its end.
505
+ */
506
+ [data-ui='command-palette'] > [data-part='list'] {
507
+ box-sizing: border-box;
508
+ display: grid;
509
+ grid-template-columns: auto minmax(0, 1fr) auto auto auto;
510
+ align-content: start;
511
+ max-block-size: var(--_list-max);
512
+ outline: none;
513
+ overflow-y: auto;
514
+ overscroll-behavior: contain;
515
+ padding-block: var(--_list-inset);
516
+ padding-inline: var(--_list-inset);
517
+ scroll-padding-block: var(--_list-inset);
518
+ }
519
+
520
+ [data-ui='command-palette'] > [data-part='list'][data-loading] {
521
+ cursor: progress;
522
+ }
523
+
524
+ /* ── Groups ───────────────────────────────────────────────────────────── */
525
+
526
+ [data-ui='command-palette'] [data-part='group'] {
527
+ display: grid;
528
+ grid-column: 1 / -1;
529
+ grid-template-columns: subgrid;
530
+ }
531
+
532
+ [data-ui='command-palette'] [data-part='group-label'] {
533
+ color: var(--_muted);
534
+ font-size: var(--_secondary-font-size);
535
+ font-weight: var(--slotted-font-weight-semibold, 600);
536
+ grid-column: 1 / -1;
537
+ line-height: var(--slotted-line-height-sm, 1.45);
538
+ padding-block: var(--slotted-space-2, 0.25rem);
539
+ padding-inline: var(--_item-inset);
540
+ }
541
+
542
+ /* ── Items ────────────────────────────────────────────────────────────── */
543
+
544
+ /**
545
+ * A `div` — or an `a`, for an item with a destination — carrying
546
+ * `role="option"`. Not a button: the option is never focused, the input is,
547
+ * and a button that is never focused is a button lying about what it is.
548
+ * `min-block-size` rather than a height, because an item with a description
549
+ * is two lines tall and still has to clear the target minimum.
550
+ */
551
+ [data-ui='command-palette'] [data-part='item'] {
552
+ align-content: center;
553
+ border-radius: var(--_item-radius);
554
+ box-sizing: border-box;
555
+ color: inherit;
556
+ cursor: pointer;
557
+ display: grid;
558
+ grid-column: 1 / -1;
559
+ grid-template-columns: subgrid;
560
+ /* The line box every cell inherits, for the reason `menu` states it once:
561
+ `1lh` on a mark resolves against the mark's own line height. */
562
+ line-height: var(--slotted-line-height-md, 1.5);
563
+ min-block-size: var(--_item-height);
564
+ padding-block: var(--slotted-space-2, 0.25rem);
565
+ padding-inline: var(--_item-inset);
566
+ /* No gap between the label and the line under it: each line box already
567
+ carries its own leading, and a gap on top of two leadings read as a
568
+ command and a footnote rather than as one row. */
569
+ row-gap: 0;
570
+ text-decoration: none;
571
+ user-select: none;
572
+ transition:
573
+ background-color var(--slotted-control-transition-duration, var(--slotted-duration-short))
574
+ var(--slotted-control-transition-easing, var(--slotted-easing-standard)),
575
+ color var(--slotted-control-transition-duration, var(--slotted-duration-short))
576
+ var(--slotted-control-transition-easing, var(--slotted-easing-standard));
577
+ }
578
+
579
+ /**
580
+ * The pointer over a row that is not the current one: a wash, and nothing
581
+ * more. The current row is stronger, below, and it is the one the keyboard
582
+ * moves; the two are told apart so a reader who arrowed to one row while the
583
+ * pointer rests on another reads exactly one cursor.
584
+ */
585
+ [data-ui='command-palette'] [data-part='item']:not([data-disabled]):not([data-current]):hover {
586
+ background-color: var(--_hover);
587
+ }
588
+
589
+ [data-ui='command-palette'] [data-part='item']:not([data-disabled]):not([data-current]):active {
590
+ background-color: var(--_active);
591
+ }
592
+
593
+ /**
594
+ * The current row: the accent ground under an inset accent ring. An inset
595
+ * shadow rather than an outline, so it follows the row's own radius and
596
+ * never overflows the list's rounded edge. It does not transition — a change
597
+ * of row is a reading, not a movement, and a transition lags behind a reader
598
+ * holding ArrowDown.
599
+ */
600
+ [data-ui='command-palette'] [data-part='item'][data-current] {
601
+ background-color: var(--_highlight);
602
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px) var(--_highlight-ring);
603
+ transition: none;
604
+ }
605
+
606
+ [data-ui='command-palette'] [data-part='item'][data-current]:not([data-disabled]):active {
607
+ background-color: var(--_active);
608
+ }
609
+
610
+ /**
611
+ * Disabled: legible rather than faded, announced, kept in place, never
612
+ * current — `moveIndex` skips it and the pointer does not highlight it. The
613
+ * hand goes, because there is nothing to press.
614
+ */
615
+ [data-ui='command-palette'] [data-part='item'][data-disabled] {
616
+ color: var(--slotted-disabled-foreground, #64748b);
617
+ cursor: not-allowed;
618
+ }
619
+
620
+ /* A handler that has not answered yet: the cursor says so, and the ring
621
+ `spinner` draws stands in the last column, where the arrow of a page
622
+ item stands, sized to the row's own glyph. */
623
+ [data-ui='command-palette'] [data-part='item'][data-loading] {
624
+ cursor: progress;
625
+ }
626
+
627
+ [data-ui='command-palette'] [data-part='item'] > [data-part='busy'] {
628
+ --slotted-spinner-size: var(--_icon-size);
629
+
630
+ color: var(--_muted);
631
+ grid-column: 5;
632
+ justify-self: end;
633
+ margin-inline-start: var(--_column-gap);
634
+ }
635
+
636
+ /* ── The cells ────────────────────────────────────────────────────────── */
637
+
638
+ /**
639
+ * Column one. The mark's box exists whether or not a mark is drawn, so a
640
+ * list where the third item has an icon and the fourth does not still lines
641
+ * its labels up. It holds an element of the consumer's own, centred; the
642
+ * stylesheet paints no mark into it.
643
+ *
644
+ * The box sizes what it holds: an icon box reads `--slotted-icon-size` from
645
+ * its container, and a bare glyph host such as `ng-icon` — which sizes
646
+ * itself at `1em` — reads the font-size the child rule below gives it.
647
+ * Nothing placed here is drawn at the row's type size. The font-size is on
648
+ * the child and not on the box, because the box's `1lh` reads the item's
649
+ * line box.
650
+ */
651
+ [data-ui='command-palette'] [data-part='icon'] {
652
+ --slotted-icon-size: var(--_icon-size);
653
+
654
+ align-items: center;
655
+ block-size: 1lh;
656
+ display: flex;
657
+ grid-column: 1;
658
+ grid-row: 1;
659
+ inline-size: var(--_icon-size);
660
+ justify-content: center;
661
+ justify-self: center;
662
+ /* One step more than the control gap. A consumer's icon fills its box to
663
+ the edge — a Lucide glyph drawn at sixteen pixels has ink at fifteen —
664
+ and at the control gap the mark touched the first letter of the label. */
665
+ margin-inline-end: calc(var(--_column-gap) + var(--slotted-space-2, 0.25rem));
666
+ }
667
+
668
+ [data-ui='command-palette'] [data-part='icon']:not(:empty) > * {
669
+ block-size: var(--_icon-size);
670
+ font-size: var(--_icon-size);
671
+ inline-size: var(--_icon-size);
672
+ }
673
+
674
+ /**
675
+ * Column two, and the only column that gives way. One line, cut with an
676
+ * ellipsis: a palette is scanned, and a command that wraps onto three lines
677
+ * is three rows pretending to be one. The whole text is on the item's
678
+ * `title` and reachable by the reader, so nothing leaves the DOM.
679
+ */
680
+ [data-ui='command-palette'] [data-part='label'] {
681
+ grid-column: 2;
682
+ grid-row: 1;
683
+ min-inline-size: 0;
684
+ overflow: hidden;
685
+ text-overflow: ellipsis;
686
+ white-space: nowrap;
687
+ }
688
+
689
+ [data-ui='command-palette'] [data-part='description'] {
690
+ color: var(--_muted);
691
+ font-size: var(--_secondary-font-size);
692
+ grid-column: 2;
693
+ grid-row: 2;
694
+ line-height: var(--slotted-line-height-xs, 1.4);
695
+ min-inline-size: 0;
696
+ overflow: hidden;
697
+ text-overflow: ellipsis;
698
+ white-space: nowrap;
699
+ }
700
+
701
+ [data-ui='command-palette'] [data-part='item'][data-disabled] > [data-part='description'] {
702
+ color: inherit;
703
+ }
704
+
705
+ /* Column three: a word at the end — "Recent", the kind of thing this is. */
706
+ /**
707
+ * The three cells at the end of the row span both of its rows and sit on the
708
+ * row's centre. Placed on the first row alone, a keycap taller than the
709
+ * label's line box stretched that row, and the description under it dropped
710
+ * by the difference — a gap that opened only on rows with a binding.
711
+ */
712
+ [data-ui='command-palette']
713
+ [data-part='item']
714
+ > :is([data-part='meta'], [data-part='shortcut'], [data-part='arrow'], [data-part='busy']) {
715
+ align-self: center;
716
+ grid-row: 1 / -1;
717
+ }
718
+
719
+ [data-ui='command-palette'] [data-part='meta'] {
720
+ color: var(--_muted);
721
+ font-size: var(--_secondary-font-size);
722
+ grid-column: 3;
723
+ justify-self: end;
724
+ margin-inline-start: var(--slotted-space-6, 1rem);
725
+ white-space: nowrap;
726
+ }
727
+
728
+ /* A word on a row with no binding takes the binding's column too, so it
729
+ ends where the bindings on the rows around it end rather than a column
730
+ short of them. */
731
+ [data-ui='command-palette']
732
+ [data-part='item']:not(:has(> [data-part='shortcut']))
733
+ > [data-part='meta'] {
734
+ grid-column: 3 / 5;
735
+ }
736
+
737
+ /**
738
+ * Column four. The caps inside are `kbd`'s, in its `plain` variant, and this
739
+ * rule places the column and states its ink; every selector stops at the
740
+ * part and never reaches the caps.
741
+ */
742
+ [data-ui='command-palette'] [data-part='item'] > [data-part='shortcut'] {
743
+ align-items: center;
744
+ color: var(--_muted);
745
+ display: inline-flex;
746
+ /**
747
+ * The caps read this size (`kbd` at `inherit`), and it is under the
748
+ * secondary type by a tenth: a keycap carries its own inset and edge, so
749
+ * at the secondary size it stood as tall as the label's line and read as
750
+ * a second label; a tenth under, it reads as an annotation of the row.
751
+ * A proportion of a scale value is geometry, as avatar's initials are.
752
+ */
753
+ font-size: calc(var(--_secondary-font-size) * 0.9);
754
+ grid-column: 4;
755
+ justify-self: end;
756
+ margin-inline-start: var(--slotted-space-6, 1rem);
757
+ white-space: nowrap;
758
+ }
759
+
760
+ [data-ui='command-palette']
761
+ [data-part='item'][data-disabled]
762
+ > :is([data-part='meta'], [data-part='shortcut']) {
763
+ color: inherit;
764
+ }
765
+
766
+ /**
767
+ * Column five: the mark that says an item opens a page, as `menu` draws the
768
+ * mark that says an item opens a submenu. The binding's `chevron-right`
769
+ * glyph in a `directional` icon box, which mirrors in a right-to-left
770
+ * document; the column is one line box tall and centres it.
771
+ */
772
+ [data-ui='command-palette'] [data-part='arrow'] {
773
+ --slotted-icon-size: var(--_icon-size);
774
+
775
+ align-items: center;
776
+ block-size: 1lh;
777
+ display: flex;
778
+ grid-column: 5;
779
+ inline-size: var(--_icon-size);
780
+ justify-self: end;
781
+ margin-inline-start: var(--_column-gap);
782
+ opacity: 0.7;
783
+ }
784
+
785
+ /* ── Separator, empty, status, placeholder ────────────────────────────── */
786
+
787
+ /**
788
+ * A child of the list and nothing deeper: `kbd` names the `+` and the `then`
789
+ * between two caps `separator` as well, and a descendant selector here
790
+ * painted them as one-pixel rules — the bar over the word, and the word
791
+ * itself pushed out of a box one pixel tall.
792
+ */
793
+ [data-ui='command-palette'] > [data-part='list'] [data-part='separator']:not([data-separator]) {
794
+ background-color: var(--slotted-command-palette-separator-color, var(--_border-color));
795
+ block-size: var(--_border-width);
796
+ border: 0;
797
+ grid-column: 1 / -1;
798
+ margin-block: var(--slotted-space-2, 0.25rem);
799
+ margin-inline: 0;
800
+ }
801
+
802
+ [data-ui='command-palette'] [data-part='empty'] {
803
+ color: var(--_muted);
804
+ grid-column: 1 / -1;
805
+ padding-block: var(--slotted-space-8, 1.5rem);
806
+ padding-inline: var(--_item-inset);
807
+ text-align: center;
808
+ unicode-bidi: plaintext;
809
+ }
810
+
811
+ /**
812
+ * The live region. It is read, never seen: the count is on the screen in the
813
+ * list itself, and a sentence under the list saying "12 results" would say
814
+ * what the reader is looking at. The clip is the visually-hidden idiom, kept
815
+ * in the DOM so `role="status"` has something to announce from.
816
+ */
817
+ [data-ui='command-palette'] > [data-part='status'] {
818
+ block-size: 1px;
819
+ clip-path: inset(50%);
820
+ inline-size: 1px;
821
+ margin: -1px;
822
+ overflow: hidden;
823
+ position: absolute;
824
+ white-space: nowrap;
825
+ }
826
+
827
+ /**
828
+ * The wait, as the shape of the list that is coming: three rows the height
829
+ * of an item, `combobox`'s decision for `combobox`'s reasons. The bars are
830
+ * `skeleton/skeleton.css`'s; this family places them.
831
+ */
832
+ [data-ui='command-palette'] [data-part='placeholder'] {
833
+ display: grid;
834
+ grid-column: 1 / -1;
835
+ padding-block: var(--slotted-space-2, 0.25rem);
836
+ padding-inline: var(--_item-inset);
837
+ }
838
+
839
+ [data-ui='command-palette'] [data-part='placeholder'] > * {
840
+ align-items: center;
841
+ display: flex;
842
+ min-block-size: var(--_item-height);
843
+ }
844
+
845
+ [data-ui='command-palette'] [data-part='placeholder'] > :nth-child(2) [data-ui='skeleton'] {
846
+ inline-size: 78%;
847
+ }
848
+
849
+ [data-ui='command-palette'] [data-part='placeholder'] > :nth-child(3) [data-ui='skeleton'] {
850
+ inline-size: 56%;
851
+ }
852
+
853
+ /* ── The footer ───────────────────────────────────────────────────────── */
854
+
855
+ /**
856
+ * The keys the palette answers, on a sunken row under a rule. The caps are
857
+ * `kbd`'s in its `plain` variant at the small step; the words beside them
858
+ * are this family's, one step quieter than the list.
859
+ */
860
+ [data-ui='command-palette'] > [data-part='footer'] {
861
+ align-items: center;
862
+ background: var(
863
+ --slotted-command-palette-footer-surface,
864
+ var(--slotted-surface-sunken, #f8fafd)
865
+ );
866
+ border-block-start: var(--_border-width) solid var(--_border-color);
867
+ box-sizing: border-box;
868
+ color: var(--_muted);
869
+ display: flex;
870
+ flex-wrap: wrap;
871
+ font-size: var(--slotted-font-size-xs, 0.75rem);
872
+ gap: var(--slotted-space-6, 1rem);
873
+ line-height: var(--slotted-line-height-xs, 1.4);
874
+ min-block-size: var(--slotted-control-height-sm, 30px);
875
+ padding-block: var(--slotted-space-2, 0.25rem);
876
+ padding-inline: var(--_header-inset);
877
+ }
878
+
879
+ [data-ui='command-palette'] > [data-part='footer'] > [data-part='hint'] {
880
+ align-items: center;
881
+ display: inline-flex;
882
+ /* The caps read the footer's own size through `kbd` at `inherit`, a tenth
883
+ under it, for the reason the row's caps are. */
884
+ font-size: calc(var(--slotted-font-size-xs, 0.75rem) * 0.9);
885
+ gap: var(--slotted-space-3, 0.375rem);
886
+ white-space: nowrap;
887
+ }
888
+
889
+ /**
890
+ * The word beside the caps, at the footer's own size on a line box of its
891
+ * own height: centred on the caps' box it sat a pixel and a half low,
892
+ * because a line box of 1.4 is centred on its leading and not on its
893
+ * letters. `line-height: 1` centres the em box, which is where the word is.
894
+ */
895
+ [data-ui='command-palette'] > [data-part='footer'] > [data-part='hint'] > span:not([data-ui]) {
896
+ font-size: var(--slotted-font-size-xs, 0.75rem);
897
+ line-height: 1;
898
+ }
899
+
900
+ /* ── Narrow ───────────────────────────────────────────────────────────── */
901
+
902
+ /**
903
+ * Below three hundred and sixty pixels the words column has the row to itself: the
904
+ * description and the meta go, the shortcut stays, and the trail keeps to a
905
+ * third of the header so the field is never squeezed to nothing.
906
+ */
907
+ @container command-palette (max-width: 360px) {
908
+ [data-ui='command-palette'] :is([data-part='description'], [data-part='meta']) {
909
+ display: none;
910
+ }
911
+
912
+ [data-ui='command-palette'] [data-part='pages'] {
913
+ max-inline-size: 33%;
914
+ }
915
+
916
+ [data-ui='command-palette'] > [data-part='footer'] {
917
+ gap: var(--slotted-space-4, 0.5rem);
918
+ }
919
+ }
920
+
921
+ /**
922
+ * The dialog took the layer. Under `fullScreen="narrow"` the dialog family
923
+ * removes its own radius, margins and measure below thirty rems of its
924
+ * container, and its `plain` surface has no edge of its own to remove — the
925
+ * edge is this panel's. The panel is asked the same question the dialog
926
+ * asked, of the dialog's own named container, so the two answer together:
927
+ * the corner, the side edges and the lift go, and the list takes the rest
928
+ * of the screen. Written here rather than on `[data-ui='dialog']` because
929
+ * `identity.test.mjs` keeps this sheet off another family's identifier;
930
+ * the container name and the breakpoint are the dialog's, recorded in
931
+ * `dialog.css` beside its own query.
932
+ */
933
+ @container slotted-dialog (max-inline-size: 30rem) {
934
+ [data-ui='command-palette'][data-presentation='dialog'] {
935
+ --_list-max: none;
936
+
937
+ border-inline: 0;
938
+ border-radius: 0;
939
+ box-shadow: none;
940
+ /* The whole layer, stated against the layer itself. A `plain` panel is
941
+ not bounded by the dialog — that is the cost the dialog family writes
942
+ beside the variant — so a percentage height here resolved against a
943
+ track the list had already grown, and the footer left the screen.
944
+ The layer is the nearest positioned ancestor, and its four edges are
945
+ where a full-screen palette ends. */
946
+ inset: 0;
947
+ position: absolute;
948
+ }
949
+
950
+ /* No scrim to press: the word that closes stands at the end of the field. */
951
+ [data-ui='command-palette'][data-presentation='dialog']
952
+ > [data-part='header']
953
+ > [data-part='close'] {
954
+ display: inline-flex;
955
+ }
956
+ }
957
+
958
+ /**
959
+ * A legend for keys the reader has none of. Where the primary input is a
960
+ * touch screen the footer's hints — arrows, Enter, Escape — name nothing
961
+ * the reader can press; the list is scrolled and the rows are tapped.
962
+ */
963
+ @media (hover: none) and (pointer: coarse) {
964
+ [data-ui='command-palette'] > [data-part='footer'] {
965
+ display: none;
966
+ }
967
+ }
968
+
969
+ /* ── Forced colours ───────────────────────────────────────────────────── */
970
+
971
+ /**
972
+ * The one thing the theme cannot reach: every tone surface becomes `Canvas`
973
+ * under forced colours, so the current row's ground — this family's cursor,
974
+ * not decoration — would disappear.
975
+ */
976
+ @media (forced-colors: active) {
977
+ [data-ui='command-palette'] [data-part='item'][data-current] {
978
+ background-color: Highlight;
979
+ color: HighlightText;
980
+ forced-color-adjust: none;
981
+ }
982
+
983
+ [data-ui='command-palette'] [data-part='item'][data-disabled][data-current] {
984
+ background-color: Highlight;
985
+ color: GrayText;
986
+ }
987
+
988
+ /*
989
+ * The focus bar under the field is painted with a background, and forced
990
+ * colours replace a background that is not one of the system's own
991
+ * colours. `forced-color-adjust: none` keeps its `currentColor` fallback,
992
+ * the host's ink the system has already forced. The glyphs are `Glyph`
993
+ * elements drawn in `currentColor` and need nothing here.
994
+ */
995
+ [data-ui='command-palette']
996
+ > [data-part='header']:has(> [data-part='input']:focus-visible)::after {
997
+ forced-color-adjust: none;
998
+ }
999
+ }
1000
+ }