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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/package.json +276 -3
  4. package/src/accordion/accordion.css +96 -0
  5. package/src/accordion/accordion.tokens.json +14 -0
  6. package/src/action-bar/action-bar.css +455 -0
  7. package/src/action-bar/action-bar.tokens.json +50 -0
  8. package/src/action-sheet/action-sheet.css +462 -0
  9. package/src/action-sheet/action-sheet.tokens.json +59 -0
  10. package/src/alert/alert.css +764 -0
  11. package/src/alert/alert.tokens.json +77 -0
  12. package/src/app-shell/app-shell.css +1899 -0
  13. package/src/app-shell/app-shell.tokens.json +88 -0
  14. package/src/aspect-ratio/aspect-ratio.css +131 -0
  15. package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
  16. package/src/attachment/attachment.css +906 -0
  17. package/src/attachment/attachment.tokens.json +85 -0
  18. package/src/avatar/avatar.css +598 -0
  19. package/src/avatar/avatar.tokens.json +64 -0
  20. package/src/avatar-group/avatar-group.css +268 -0
  21. package/src/avatar-group/avatar-group.tokens.json +16 -0
  22. package/src/badge/badge.css +462 -0
  23. package/src/badge/badge.tokens.json +58 -0
  24. package/src/breadcrumb/breadcrumb.css +441 -0
  25. package/src/breadcrumb/breadcrumb.tokens.json +50 -0
  26. package/src/button/button.css +754 -0
  27. package/src/button/button.tokens.json +72 -0
  28. package/src/button-group/button-group.css +455 -0
  29. package/src/button-group/button-group.tokens.json +11 -0
  30. package/src/calendar/calendar.css +846 -0
  31. package/src/calendar/calendar.tokens.json +67 -0
  32. package/src/card/card.css +602 -0
  33. package/src/card/card.tokens.json +68 -0
  34. package/src/carousel/carousel.css +860 -0
  35. package/src/carousel/carousel.tokens.json +62 -0
  36. package/src/cascader/cascader.css +1320 -0
  37. package/src/cascader/cascader.tokens.json +103 -0
  38. package/src/chart/chart.css +1473 -0
  39. package/src/chart/chart.tokens.json +107 -0
  40. package/src/checkbox/checkbox.css +1011 -0
  41. package/src/checkbox/checkbox.tokens.json +102 -0
  42. package/src/checkbox-group/checkbox-group.css +70 -0
  43. package/src/checkbox-group/checkbox-group.tokens.json +6 -0
  44. package/src/code-block/code-block.css +555 -0
  45. package/src/code-block/code-block.tokens.json +69 -0
  46. package/src/collapsible/collapsible.css +546 -0
  47. package/src/collapsible/collapsible.tokens.json +55 -0
  48. package/src/color-picker/color-picker.css +607 -0
  49. package/src/color-picker/color-picker.tokens.json +58 -0
  50. package/src/column-manager/column-manager.css +452 -0
  51. package/src/column-manager/column-manager.tokens.json +43 -0
  52. package/src/combobox/combobox.css +1048 -0
  53. package/src/combobox/combobox.tokens.json +112 -0
  54. package/src/command-palette/command-palette.css +1000 -0
  55. package/src/command-palette/command-palette.tokens.json +75 -0
  56. package/src/container/container.css +198 -0
  57. package/src/container/container.tokens.json +18 -0
  58. package/src/context-menu/context-menu.css +104 -0
  59. package/src/context-menu/context-menu.tokens.json +11 -0
  60. package/src/currency-field/currency-field.css +787 -0
  61. package/src/currency-field/currency-field.tokens.json +80 -0
  62. package/src/dashboard-grid/dashboard-grid.css +748 -0
  63. package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
  64. package/src/data-grid/data-grid.css +2484 -0
  65. package/src/data-grid/data-grid.tokens.json +100 -0
  66. package/src/data-list/data-list.css +455 -0
  67. package/src/data-list/data-list.tokens.json +35 -0
  68. package/src/date-field/date-field.css +560 -0
  69. package/src/date-field/date-field.tokens.json +80 -0
  70. package/src/date-picker/date-picker.css +420 -0
  71. package/src/date-picker/date-picker.tokens.json +49 -0
  72. package/src/date-range-picker/date-range-picker.css +983 -0
  73. package/src/date-range-picker/date-range-picker.tokens.json +109 -0
  74. package/src/datetime-field/datetime-field.css +850 -0
  75. package/src/datetime-field/datetime-field.tokens.json +91 -0
  76. package/src/datetime-picker/datetime-picker.css +843 -0
  77. package/src/datetime-picker/datetime-picker.tokens.json +78 -0
  78. package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
  79. package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
  80. package/src/description-list/description-list.css +675 -0
  81. package/src/description-list/description-list.tokens.json +66 -0
  82. package/src/detail-panel/detail-panel.css +329 -0
  83. package/src/detail-panel/detail-panel.tokens.json +33 -0
  84. package/src/dialog/dialog.css +968 -0
  85. package/src/dialog/dialog.tokens.json +66 -0
  86. package/src/divider/divider.css +131 -0
  87. package/src/divider/divider.tokens.json +18 -0
  88. package/src/drawer/drawer.css +1303 -0
  89. package/src/drawer/drawer.tokens.json +75 -0
  90. package/src/entity-picker/entity-picker.css +1367 -0
  91. package/src/entity-picker/entity-picker.tokens.json +118 -0
  92. package/src/event-calendar/event-calendar.css +2148 -0
  93. package/src/event-calendar/event-calendar.tokens.json +87 -0
  94. package/src/field/field.css +707 -0
  95. package/src/field/field.tokens.json +58 -0
  96. package/src/field-group/field-group.css +226 -0
  97. package/src/field-group/field-group.tokens.json +33 -0
  98. package/src/filter-bar/filter-bar.css +1306 -0
  99. package/src/filter-bar/filter-bar.tokens.json +78 -0
  100. package/src/form/form.css +218 -0
  101. package/src/form/form.tokens.json +32 -0
  102. package/src/fullscreen/fullscreen.css +376 -0
  103. package/src/fullscreen/fullscreen.tokens.json +50 -0
  104. package/src/grid/grid.css +173 -0
  105. package/src/grid/grid.tokens.json +20 -0
  106. package/src/highlight/highlight.css +135 -0
  107. package/src/highlight/highlight.tokens.json +16 -0
  108. package/src/hover-card/hover-card.css +93 -0
  109. package/src/hover-card/hover-card.tokens.json +17 -0
  110. package/src/icon/icon.css +136 -0
  111. package/src/icon/icon.tokens.json +14 -0
  112. package/src/image/image.css +449 -0
  113. package/src/image/image.tokens.json +27 -0
  114. package/src/import-export-center/import-export-center.css +1175 -0
  115. package/src/import-export-center/import-export-center.tokens.json +84 -0
  116. package/src/inline/inline.css +149 -0
  117. package/src/inline/inline.tokens.json +14 -0
  118. package/src/inline-message/inline-message.css +396 -0
  119. package/src/inline-message/inline-message.tokens.json +19 -0
  120. package/src/kbd/kbd.css +490 -0
  121. package/src/kbd/kbd.tokens.json +40 -0
  122. package/src/link/link.css +237 -0
  123. package/src/link/link.tokens.json +25 -0
  124. package/src/list/list.css +240 -0
  125. package/src/list/list.tokens.json +42 -0
  126. package/src/list-item/list-item.css +937 -0
  127. package/src/list-item/list-item.tokens.json +114 -0
  128. package/src/listbox/listbox.css +674 -0
  129. package/src/listbox/listbox.tokens.json +72 -0
  130. package/src/loading-overlay/loading-overlay.css +730 -0
  131. package/src/loading-overlay/loading-overlay.tokens.json +48 -0
  132. package/src/markdown/markdown.css +168 -0
  133. package/src/markdown/markdown.tokens.json +18 -0
  134. package/src/menu/menu.css +817 -0
  135. package/src/menu/menu.tokens.json +78 -0
  136. package/src/menubar/menubar.css +170 -0
  137. package/src/menubar/menubar.tokens.json +32 -0
  138. package/src/message/message.css +1453 -0
  139. package/src/message/message.tokens.json +85 -0
  140. package/src/message-scroller/message-scroller.css +371 -0
  141. package/src/message-scroller/message-scroller.tokens.json +47 -0
  142. package/src/multi-select/multi-select.css +1427 -0
  143. package/src/multi-select/multi-select.tokens.json +114 -0
  144. package/src/navigation-menu/navigation-menu.css +1029 -0
  145. package/src/navigation-menu/navigation-menu.tokens.json +70 -0
  146. package/src/notification-center/notification-center.css +856 -0
  147. package/src/notification-center/notification-center.tokens.json +84 -0
  148. package/src/number-field/number-field.css +794 -0
  149. package/src/number-field/number-field.tokens.json +80 -0
  150. package/src/otp-input/otp-input.css +525 -0
  151. package/src/otp-input/otp-input.tokens.json +69 -0
  152. package/src/page/page.css +179 -0
  153. package/src/page/page.tokens.json +20 -0
  154. package/src/page-header/page-header.css +1181 -0
  155. package/src/page-header/page-header.tokens.json +71 -0
  156. package/src/pagination/pagination.css +500 -0
  157. package/src/pagination/pagination.tokens.json +56 -0
  158. package/src/popover/popover.css +526 -0
  159. package/src/popover/popover.tokens.json +60 -0
  160. package/src/progress-indicator/progress-indicator.css +1584 -0
  161. package/src/progress-indicator/progress-indicator.tokens.json +50 -0
  162. package/src/prompt-composer/prompt-composer.css +680 -0
  163. package/src/prompt-composer/prompt-composer.tokens.json +99 -0
  164. package/src/prose/prose.css +733 -0
  165. package/src/prose/prose.tokens.json +79 -0
  166. package/src/radio-group/radio-group.css +778 -0
  167. package/src/radio-group/radio-group.tokens.json +103 -0
  168. package/src/rating/rating.css +1071 -0
  169. package/src/rating/rating.tokens.json +88 -0
  170. package/src/result-state/result-state.css +980 -0
  171. package/src/result-state/result-state.tokens.json +63 -0
  172. package/src/runtime-properties.mjs +321 -0
  173. package/src/saved-views/saved-views.css +394 -0
  174. package/src/saved-views/saved-views.tokens.json +41 -0
  175. package/src/scroll-area/scroll-area.css +481 -0
  176. package/src/scroll-area/scroll-area.tokens.json +15 -0
  177. package/src/section/section.css +177 -0
  178. package/src/section/section.tokens.json +39 -0
  179. package/src/segmented-control/segmented-control.css +564 -0
  180. package/src/segmented-control/segmented-control.tokens.json +67 -0
  181. package/src/select/select.css +1593 -0
  182. package/src/select/select.tokens.json +110 -0
  183. package/src/side-navigation/side-navigation.css +1096 -0
  184. package/src/side-navigation/side-navigation.tokens.json +87 -0
  185. package/src/skeleton/skeleton.css +431 -0
  186. package/src/skeleton/skeleton.tokens.json +29 -0
  187. package/src/slider/slider.css +792 -0
  188. package/src/slider/slider.tokens.json +75 -0
  189. package/src/sparkline/sparkline.css +282 -0
  190. package/src/sparkline/sparkline.tokens.json +45 -0
  191. package/src/spinner/spinner.css +224 -0
  192. package/src/spinner/spinner.tokens.json +8 -0
  193. package/src/split-button/split-button.css +253 -0
  194. package/src/split-button/split-button.tokens.json +12 -0
  195. package/src/splitter/splitter.css +336 -0
  196. package/src/splitter/splitter.tokens.json +24 -0
  197. package/src/stack/stack.css +128 -0
  198. package/src/stack/stack.tokens.json +14 -0
  199. package/src/stat-card/stat-card.css +641 -0
  200. package/src/stat-card/stat-card.tokens.json +95 -0
  201. package/src/status-indicator/status-indicator.css +481 -0
  202. package/src/status-indicator/status-indicator.tokens.json +38 -0
  203. package/src/stepper/stepper.css +629 -0
  204. package/src/stepper/stepper.tokens.json +72 -0
  205. package/src/switch/switch.css +703 -0
  206. package/src/switch/switch.tokens.json +75 -0
  207. package/src/table/table.css +1482 -0
  208. package/src/table/table.tokens.json +69 -0
  209. package/src/table-of-contents/table-of-contents.css +533 -0
  210. package/src/table-of-contents/table-of-contents.tokens.json +53 -0
  211. package/src/tabs/tabs.css +998 -0
  212. package/src/tabs/tabs.tokens.json +82 -0
  213. package/src/tag/tag.css +768 -0
  214. package/src/tag/tag.tokens.json +85 -0
  215. package/src/tags-input/tags-input.css +757 -0
  216. package/src/tags-input/tags-input.tokens.json +84 -0
  217. package/src/text-field/text-field.css +900 -0
  218. package/src/text-field/text-field.tokens.json +87 -0
  219. package/src/textarea/textarea.css +365 -0
  220. package/src/textarea/textarea.tokens.json +59 -0
  221. package/src/time-field/time-field.css +719 -0
  222. package/src/time-field/time-field.tokens.json +86 -0
  223. package/src/time-picker/time-picker.css +665 -0
  224. package/src/time-picker/time-picker.tokens.json +66 -0
  225. package/src/time-range-picker/time-range-picker.css +1287 -0
  226. package/src/time-range-picker/time-range-picker.tokens.json +134 -0
  227. package/src/timeline/timeline.css +1596 -0
  228. package/src/timeline/timeline.tokens.json +96 -0
  229. package/src/toast/toast.css +943 -0
  230. package/src/toast/toast.tokens.json +90 -0
  231. package/src/toggle/toggle.css +290 -0
  232. package/src/toggle/toggle.tokens.json +54 -0
  233. package/src/toggle-group/toggle-group.css +463 -0
  234. package/src/toggle-group/toggle-group.tokens.json +54 -0
  235. package/src/toolbar/toolbar.css +434 -0
  236. package/src/toolbar/toolbar.tokens.json +49 -0
  237. package/src/tooltip/tooltip.css +368 -0
  238. package/src/tooltip/tooltip.tokens.json +39 -0
  239. package/src/top-navigation/top-navigation.css +1287 -0
  240. package/src/top-navigation/top-navigation.tokens.json +91 -0
  241. package/src/tour/tour.css +680 -0
  242. package/src/tour/tour.tokens.json +67 -0
  243. package/src/transfer/transfer.css +571 -0
  244. package/src/transfer/transfer.tokens.json +49 -0
  245. package/src/tree/tree.css +1000 -0
  246. package/src/tree/tree.tokens.json +80 -0
  247. package/src/typography/typography.css +211 -0
  248. package/src/typography/typography.tokens.json +31 -0
  249. package/src/upload/upload.css +1706 -0
  250. package/src/upload/upload.tokens.json +123 -0
  251. package/src/visually-hidden/visually-hidden.css +52 -0
  252. package/src/visually-hidden/visually-hidden.tokens.json +1 -0
  253. package/src/wizard/wizard.css +740 -0
  254. package/src/wizard/wizard.tokens.json +63 -0
@@ -0,0 +1,680 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── A message being written ─────────────────────────────────────────────
4
+ *
5
+ * A form around a textarea, with a band above it for what the message
6
+ * carries — attachments, a quoted reply, a context chip — and a band below
7
+ * it for what the message is sent with — a model, a tool, the send itself.
8
+ * The root paints the border, the ground, the lift and the ring; the
9
+ * textarea inside gives up all four and keeps the value, the caret and the
10
+ * selection (docs/history/designs/2026-09-30-prompt-composer-design.md § 3).
11
+ *
12
+ * Three variants. `raised` is the chat composer: a surface lifted off the
13
+ * page, round buttons, a corner derived from them. `outline` and `subtle`
14
+ * are the composer inside a form — a comment, a reply — and keep the
15
+ * geometry of a one-line control.
16
+ */
17
+ [data-ui='prompt-composer'][data-part='root'] {
18
+ --_font-size: var(--slotted-control-font-size-md, 13px);
19
+ --_height: var(--slotted-control-height-md, 34px);
20
+ --_icon-size: var(--slotted-control-icon-size-md, 16px);
21
+ --_inner-size: var(--slotted-control-inner-size-md, 24px);
22
+ --_rows: var(--slotted-prompt-composer-rows, 1);
23
+ --_max-rows: var(--slotted-prompt-composer-max-rows, 8);
24
+ /**
25
+ * The box of every button in a band. In a form it is the inside of a
26
+ * control of this step, the height a key or a chip takes in a field; the
27
+ * chat composer adds a step of air, because its buttons are the only
28
+ * targets on a surface meant for a thumb.
29
+ */
30
+ --_button: var(--_inner-size);
31
+ /**
32
+ * The air around the buttons in both bands: the air a button has inside
33
+ * a control of this step, so a band in a form holds its buttons the way a
34
+ * one-line field does.
35
+ */
36
+ --_inset: max(
37
+ 0px,
38
+ calc((var(--_height) - 2 * var(--slotted-control-border-width, 1px) - var(--_inner-size)) / 2)
39
+ );
40
+ /**
41
+ * The value starts on the vertical line the ink of the first button in a
42
+ * band starts on — the glyph, not its box — so the paperclip below and the
43
+ * first letter above stand on one edge. Measured, the old control padding
44
+ * put the text five pixels inside the paperclip at `md`.
45
+ */
46
+ --_padding-inline: calc(var(--_inset) + (var(--_button) - var(--_icon-size)) / 2);
47
+ /* One row of the composer in a form is one row of a text field. */
48
+ --_padding-block: max(0px, calc((var(--_height) - 1lh) / 2));
49
+ --_radius: var(--slotted-prompt-composer-radius, var(--slotted-radius-lg, 8px));
50
+ /* A button's corner in a form is the frame's corner less the air around
51
+ it, so the two shapes are concentric. */
52
+ --_action-radius: max(var(--slotted-radius-xs, 2px), calc(var(--_radius) - var(--_inset)));
53
+ --_lift: var(--slotted-prompt-composer-shadow, var(--slotted-control-shadow, none));
54
+ --_lift-focus: var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
55
+ var(--slotted-focus-ring-color, Highlight);
56
+
57
+ background-color: var(
58
+ --slotted-prompt-composer-background,
59
+ var(--slotted-control-surface, Field)
60
+ );
61
+ border: var(--slotted-control-border-width, 1px) solid
62
+ var(--slotted-prompt-composer-border-color, var(--slotted-control-border-color, ButtonBorder));
63
+ border-radius: var(--_radius);
64
+ box-shadow: var(--_lift);
65
+ box-sizing: border-box;
66
+ color: var(--slotted-prompt-composer-color, var(--slotted-text, CanvasText));
67
+ /* The whole frame is where the caret goes: a press on its padding lands in
68
+ the textarea through the binding, and the cursor says so. */
69
+ cursor: text;
70
+ display: flex;
71
+ flex-direction: column;
72
+ font-family: var(--slotted-control-font-family, system-ui, sans-serif);
73
+ font-size: var(--_font-size);
74
+ inline-size: 100%;
75
+ line-height: var(--slotted-prompt-composer-line-height, var(--slotted-line-height-md, 1.5));
76
+ margin: 0;
77
+ min-inline-size: 0;
78
+ transition:
79
+ background-color var(--slotted-duration-medium) var(--slotted-easing-standard),
80
+ border-color var(--slotted-duration-medium) var(--slotted-easing-standard),
81
+ box-shadow var(--slotted-duration-medium) var(--slotted-easing-standard),
82
+ outline-color var(--slotted-duration-medium) var(--slotted-easing-standard);
83
+ }
84
+
85
+ [data-ui='prompt-composer'][data-part='root'][data-size='sm'] {
86
+ --_font-size: var(--slotted-control-font-size-sm, 12px);
87
+ --_height: var(--slotted-control-height-sm, 30px);
88
+ --_icon-size: var(--slotted-control-icon-size-sm, 14px);
89
+ --_inner-size: var(--slotted-control-inner-size-sm, 22px);
90
+ }
91
+
92
+ [data-ui='prompt-composer'][data-part='root'][data-size='lg'] {
93
+ --_font-size: var(--slotted-control-font-size-lg, 14px);
94
+ --_height: var(--slotted-control-height-lg, 38px);
95
+ --_icon-size: var(--slotted-control-icon-size-lg, 18px);
96
+ --_inner-size: var(--slotted-control-inner-size-lg, 28px);
97
+ }
98
+
99
+ /**
100
+ * ── The chat composer ──────────────────────────────────────────────────
101
+ *
102
+ * A surface, not a field: lifted by the theme's middle shadow at rest and
103
+ * its large one while the reader writes, with a step of the space scale
104
+ * around the buttons and a step more above the first line.
105
+ *
106
+ * The corner is derived rather than chosen. Every button in the bands is
107
+ * round, and a round button inset by `--_inset` sits concentric with the
108
+ * frame only when the frame's radius is the button's radius plus that air:
109
+ * 14 + 8 = 22 at `md`. The theme's radius scale stops at 8, which is a
110
+ * card's corner, and a card's corner around a round send draws two curves
111
+ * that do not agree.
112
+ */
113
+ [data-ui='prompt-composer'][data-part='root'][data-variant='raised'] {
114
+ --_button: calc(var(--_inner-size) + var(--slotted-space-2, 0.25rem));
115
+ --_inset: var(--slotted-space-4, 0.5rem);
116
+ --_padding-block: calc(var(--_inset) + var(--slotted-space-2, 0.25rem));
117
+ --_radius: var(--slotted-prompt-composer-radius, calc(var(--_button) / 2 + var(--_inset)));
118
+ --_action-radius: var(--slotted-radius-full, 9999px);
119
+ --_lift: var(--slotted-prompt-composer-raised-shadow, var(--slotted-shadow-md, none));
120
+ --_lift-focus: var(
121
+ --slotted-prompt-composer-raised-focus-shadow,
122
+ var(--slotted-shadow-lg, none)
123
+ );
124
+ }
125
+
126
+ [data-ui='prompt-composer'][data-part='root'][data-variant='subtle'] {
127
+ background-color: var(
128
+ --slotted-prompt-composer-subtle-background,
129
+ var(--slotted-surface-sunken, Canvas)
130
+ );
131
+ border-color: var(
132
+ --slotted-prompt-composer-subtle-border-color,
133
+ var(--slotted-border-subtle, ButtonBorder)
134
+ );
135
+ }
136
+
137
+ /* ── The value ─────────────────────────────────────────────────────────
138
+ *
139
+ * Grows with what is written, from `rows` lines to `maxRows`, then scrolls:
140
+ * `field-sizing: content`, the mechanism `textarea` already uses, so no
141
+ * script measures a line. The band below stays where the reader's thumb
142
+ * expects it.
143
+ */
144
+ [data-ui='prompt-composer'] > [data-part='input'] {
145
+ appearance: none;
146
+ background: transparent;
147
+ border: 0;
148
+ box-sizing: border-box;
149
+ caret-color: var(--slotted-prompt-composer-caret-color, var(--slotted-tone-accent-solid, auto));
150
+ color: inherit;
151
+ display: block;
152
+ field-sizing: content;
153
+ font: inherit;
154
+ inline-size: 100%;
155
+ line-height: inherit;
156
+ margin: 0;
157
+ max-block-size: calc(var(--_max-rows) * 1lh + 2 * var(--_padding-block));
158
+ min-block-size: calc(var(--_rows) * 1lh + 2 * var(--_padding-block));
159
+ /* The frame draws the ring for it, so two rings never nest. */
160
+ outline: none;
161
+ overflow-wrap: anywhere;
162
+ overflow-y: auto;
163
+ padding-block: var(--_padding-block);
164
+ padding-inline: var(--_padding-inline);
165
+ resize: none;
166
+ scrollbar-color: var(--slotted-border-strong, GrayText) transparent;
167
+ scrollbar-width: thin;
168
+ /* A message mixes languages, and each paragraph takes the direction of
169
+ its own first strong character: a Portuguese question in an Arabic
170
+ interface ends in its own question mark, not at the other margin. */
171
+ unicode-bidi: plaintext;
172
+ }
173
+
174
+ [data-ui='prompt-composer'] > [data-part='input']::placeholder {
175
+ color: var(--slotted-prompt-composer-placeholder-color, var(--slotted-text-muted, GrayText));
176
+ }
177
+
178
+ [data-ui='prompt-composer'] > [data-part='input']::selection {
179
+ background-color: var(
180
+ --slotted-prompt-composer-selection-background,
181
+ var(--slotted-tone-accent-surface, Highlight)
182
+ );
183
+ }
184
+
185
+ /* A band above the value gives it back the block padding it already has. */
186
+ [data-ui='prompt-composer'] > [data-part='header'] + [data-part='input'] {
187
+ padding-block-start: var(--_inset);
188
+ }
189
+
190
+ /* The band below sits on the last line: the value keeps its own air above
191
+ the text and hands the air below it to the band's inset. */
192
+ [data-ui='prompt-composer'][data-variant='raised']
193
+ > [data-part='input']:has(+ [data-part='footer']) {
194
+ padding-block-end: var(--slotted-space-2, 0.25rem);
195
+ }
196
+
197
+ /* ── The two bands ─────────────────────────────────────────────────────
198
+ *
199
+ * Each band is a row of what the consumer put in it, inset by `--_inset`.
200
+ * The header wraps — a message can carry six attachments — and the footer
201
+ * does not: the send stays on the line, and a narrow composer gives up the
202
+ * space between the tools first.
203
+ */
204
+ [data-ui='prompt-composer'] > :is([data-part='header'], [data-part='footer']) {
205
+ --slotted-icon-size: var(--_icon-size);
206
+ --slotted-control-inner-size: var(--_button);
207
+
208
+ align-items: center;
209
+ display: flex;
210
+ gap: var(--slotted-space-2, 0.25rem);
211
+ min-inline-size: 0;
212
+ padding: var(--_inset);
213
+ }
214
+
215
+ [data-ui='prompt-composer'] > [data-part='header'] {
216
+ flex-wrap: wrap;
217
+ padding-block-end: 0;
218
+ }
219
+
220
+ /* A strip of attachments is the width the band has and scrolls inside it;
221
+ a flex item otherwise keeps its content's width and crosses the frame. */
222
+ [data-ui='prompt-composer'] > [data-part='header'] > * {
223
+ max-inline-size: 100%;
224
+ min-inline-size: 0;
225
+ }
226
+
227
+ [data-ui='prompt-composer'] > [data-part='footer'] {
228
+ flex-wrap: nowrap;
229
+ padding-block-start: 0;
230
+ }
231
+
232
+ /* ── Buttons in the bands ───────────────────────────────────────────────
233
+ *
234
+ * `action` is the consumer's, `attach` the family's: both are R2 inner
235
+ * controls — no frame, no ground at rest, one step of ground for hover and
236
+ * one for press, and the ink never moves. Square when named by aria-label,
237
+ * padded when named by their own words, the rule `text-field` set; round
238
+ * in the chat composer, a pill when they carry words.
239
+ */
240
+ [data-ui='prompt-composer']
241
+ > :is([data-part='header'], [data-part='footer'])
242
+ > :is([data-part='action'], [data-part='attach']) {
243
+ align-items: center;
244
+ appearance: none;
245
+ background-color: transparent;
246
+ block-size: var(--_button);
247
+ border: 0;
248
+ border-radius: var(--_action-radius);
249
+ box-sizing: border-box;
250
+ color: var(--slotted-prompt-composer-action-color, var(--slotted-text-muted, GrayText));
251
+ cursor: pointer;
252
+ display: inline-flex;
253
+ flex: 0 0 auto;
254
+ font: inherit;
255
+ gap: var(--slotted-space-2, 0.25rem);
256
+ justify-content: center;
257
+ line-height: 1;
258
+ min-inline-size: var(--_button);
259
+ padding: 0;
260
+ position: relative;
261
+ touch-action: manipulation;
262
+ transition: background-color var(--slotted-control-transition-duration)
263
+ var(--slotted-control-transition-easing);
264
+ unicode-bidi: plaintext;
265
+ white-space: nowrap;
266
+ -webkit-tap-highlight-color: transparent;
267
+ }
268
+
269
+ [data-ui='prompt-composer']
270
+ > :is([data-part='header'], [data-part='footer'])
271
+ > [data-part='action']:not([aria-label], [aria-labelledby]) {
272
+ color: var(--slotted-prompt-composer-action-label-color, var(--slotted-text, CanvasText));
273
+ font-weight: var(--slotted-font-weight-medium, 500);
274
+ padding-inline: var(--slotted-space-3, 0.375rem);
275
+ }
276
+
277
+ /**
278
+ * Words and a mark in one button — a country code over its chevron, a model
279
+ * name, a notation. The mark is centred on the band the letters occupy, not
280
+ * on the line box: the line box keeps room under the baseline for
281
+ * descenders, so a box centred in it sits low beside the letters — every
282
+ * chevron in these buttons did. The rule is the briefing's (_A mark beside a
283
+ * line of text is aligned to the text_), here in a grid: items share the
284
+ * baseline, the mark's synthesized baseline is its bottom edge, a negative
285
+ * start margin takes back the height it would add above the letters, and a
286
+ * translate puts its centre at `(1cap + 1ex) / 4` above the baseline — the
287
+ * midpoint of the capitals' and the lowercase letters' own centres.
288
+ */
289
+ [data-ui='prompt-composer']
290
+ > :is([data-part='header'], [data-part='footer'])
291
+ > [data-part='action']:not([aria-label], [aria-labelledby]) {
292
+ align-content: center;
293
+ align-items: baseline;
294
+ display: inline-grid;
295
+ grid-auto-flow: column;
296
+ justify-content: center;
297
+ }
298
+
299
+ [data-ui='prompt-composer']
300
+ > :is([data-part='header'], [data-part='footer'])
301
+ > [data-part='action']:not([aria-label], [aria-labelledby])
302
+ > [data-ui='icon'] {
303
+ margin-block-start: calc((1cap + 1ex) / 4 - var(--_icon-size) / 2);
304
+ translate: 0 calc(var(--_icon-size) / 2 - (1cap + 1ex) / 4);
305
+ }
306
+
307
+ /* A pill carries its words a step further from its round ends. */
308
+ [data-ui='prompt-composer'][data-variant='raised']
309
+ > :is([data-part='header'], [data-part='footer'])
310
+ > [data-part='action']:not([aria-label], [aria-labelledby]) {
311
+ padding-inline: var(--slotted-space-4, 0.5rem);
312
+ }
313
+
314
+ /* The target, recovered outside the paint: 24 pixels on a mouse, 44 on a
315
+ finger, and never across the edge two buttons share. */
316
+ [data-ui='prompt-composer']
317
+ > :is([data-part='header'], [data-part='footer'])
318
+ > :is([data-part='action'], [data-part='attach'], [data-part='submit'])::after {
319
+ content: '';
320
+ inset: min(0px, calc((100% - var(--slotted-target-min, 24px)) / 2));
321
+ position: absolute;
322
+ }
323
+
324
+ @media (pointer: coarse) {
325
+ [data-ui='prompt-composer']
326
+ > :is([data-part='header'], [data-part='footer'])
327
+ > :is([data-part='action'], [data-part='attach'], [data-part='submit'])::after {
328
+ inset: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
329
+ }
330
+
331
+ [data-ui='prompt-composer']
332
+ > :is([data-part='header'], [data-part='footer'])
333
+ > :is([data-part='action'], [data-part='attach']):has(+ *)::after {
334
+ inset-inline-end: 0;
335
+ }
336
+
337
+ [data-ui='prompt-composer']
338
+ > :is([data-part='header'], [data-part='footer'])
339
+ > *
340
+ + :is([data-part='action'], [data-part='attach'], [data-part='submit'])::after {
341
+ inset-inline-start: 0;
342
+ }
343
+ }
344
+
345
+ [data-ui='prompt-composer']
346
+ > :is([data-part='header'], [data-part='footer'])
347
+ > :is([data-part='action'], [data-part='attach']):hover:not(:disabled, [aria-expanded='true']) {
348
+ background-color: var(
349
+ --slotted-prompt-composer-action-hover-background,
350
+ var(--slotted-tone-secondary-subtle-hover)
351
+ );
352
+ }
353
+
354
+ [data-ui='prompt-composer']
355
+ > :is([data-part='header'], [data-part='footer'])
356
+ > :is([data-part='action'], [data-part='attach']):is(:active, [aria-expanded='true']):not(
357
+ :disabled
358
+ ) {
359
+ background-color: var(
360
+ --slotted-prompt-composer-action-active-background,
361
+ var(--slotted-tone-secondary-subtle-active)
362
+ );
363
+ }
364
+
365
+ [data-ui='prompt-composer']
366
+ > :is([data-part='header'], [data-part='footer'])
367
+ > :is([data-part='action'], [data-part='attach']):disabled {
368
+ color: var(--slotted-disabled-foreground);
369
+ cursor: not-allowed;
370
+ }
371
+
372
+ /* ── Send, stop, retry ──────────────────────────────────────────────────
373
+ *
374
+ * The one solid thing in the frame, and round: the command the whole
375
+ * control exists for, in the accent the theme gives a primary action. It
376
+ * holds the end of the footer by an automatic margin rather than a spacer.
377
+ * The mark and the ring share one grid cell, so the stop square stands in
378
+ * the middle of the ring that says an answer is still arriving.
379
+ */
380
+ [data-ui='prompt-composer'] > [data-part='footer'] > [data-part='submit'] {
381
+ /* Alone, the ring is the glyph's size and stands where the arrow stood;
382
+ around the stop square it grows to the disc (below). */
383
+ --slotted-spinner-size: var(--_icon-size);
384
+
385
+ align-items: center;
386
+ appearance: none;
387
+ background-color: var(
388
+ --slotted-prompt-composer-submit-background,
389
+ var(--slotted-tone-accent-solid, Highlight)
390
+ );
391
+ block-size: var(--_button);
392
+ border: 0;
393
+ border-radius: var(--slotted-radius-full, 9999px);
394
+ color: var(
395
+ --slotted-prompt-composer-submit-color,
396
+ var(--slotted-tone-accent-on-solid, HighlightText)
397
+ );
398
+ cursor: pointer;
399
+ display: inline-grid;
400
+ flex: 0 0 auto;
401
+ inline-size: var(--_button);
402
+ justify-items: center;
403
+ margin-inline-start: auto;
404
+ padding: 0;
405
+ position: relative;
406
+ touch-action: manipulation;
407
+ transition:
408
+ background-color var(--slotted-control-transition-duration)
409
+ var(--slotted-control-transition-easing),
410
+ color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing),
411
+ scale var(--slotted-duration-short) var(--slotted-easing-standard);
412
+ -webkit-tap-highlight-color: transparent;
413
+ }
414
+
415
+ [data-ui='prompt-composer'] > [data-part='footer'] > [data-part='submit'] > * {
416
+ grid-area: 1 / 1;
417
+ }
418
+
419
+ /* Named by its own word — Comentar, Publicar — the send is a padded pill at
420
+ the same height; named by aria-label it is the round mark. */
421
+ [data-ui='prompt-composer']
422
+ > [data-part='footer']
423
+ > [data-part='submit']:not([aria-label], [aria-labelledby]) {
424
+ border-radius: var(--_action-radius);
425
+ font: inherit;
426
+ font-weight: var(--slotted-font-weight-medium, 500);
427
+ inline-size: auto;
428
+ line-height: 1;
429
+ padding-inline: var(--slotted-space-5, 0.75rem);
430
+ }
431
+
432
+ [data-ui='prompt-composer'] > [data-part='footer'] > [data-part='submit']:hover:not(:disabled) {
433
+ background-color: var(
434
+ --slotted-prompt-composer-submit-hover-background,
435
+ var(--slotted-tone-accent-solid-hover, Highlight)
436
+ );
437
+ }
438
+
439
+ /**
440
+ * Press settles the round mark to nine tenths, a movement the eye reads as
441
+ * the button going in; the ground darkens a further step. A padded send
442
+ * holds its words, so it takes the ground alone (R7).
443
+ */
444
+ [data-ui='prompt-composer'] > [data-part='footer'] > [data-part='submit']:active:not(:disabled) {
445
+ background-color: var(
446
+ --slotted-prompt-composer-submit-active-background,
447
+ var(--slotted-tone-accent-solid-active, Highlight)
448
+ );
449
+ }
450
+
451
+ [data-ui='prompt-composer']
452
+ > [data-part='footer']
453
+ > [data-part='submit']:is([aria-label], [aria-labelledby]):active:not(:disabled) {
454
+ scale: 0.9;
455
+ }
456
+
457
+ /**
458
+ * The arrow leans a pixel in the direction it sends while the pointer is
459
+ * over it: a hint of the movement the press will start, and nothing else
460
+ * in the frame moves.
461
+ */
462
+ [data-ui='prompt-composer']
463
+ > [data-part='footer']
464
+ > [data-part='submit']
465
+ > [data-ui='icon']:has([data-glyph='arrow-up']) {
466
+ transition: translate var(--slotted-duration-short) var(--slotted-easing-standard);
467
+ }
468
+
469
+ [data-ui='prompt-composer']
470
+ > [data-part='footer']
471
+ > [data-part='submit']:hover:not(:disabled)
472
+ > [data-ui='icon']:has([data-glyph='arrow-up']) {
473
+ translate: 0 calc(var(--slotted-border-width-thin, 1px) * -1);
474
+ }
475
+
476
+ /* Nothing to send: a quiet disc in the disabled ground, the arrow still
477
+ legible, so the reader sees where the send will be before it wakes. */
478
+ [data-ui='prompt-composer'] > [data-part='footer'] > [data-part='submit']:disabled {
479
+ background-color: var(
480
+ --slotted-prompt-composer-submit-disabled-background,
481
+ var(--slotted-disabled-background)
482
+ );
483
+ color: var(--slotted-disabled-foreground);
484
+ cursor: not-allowed;
485
+ }
486
+
487
+ /* While the request travels the button is busy, not unavailable: the ring
488
+ stands where the arrow stood and the ground keeps the accent. */
489
+ [data-ui='prompt-composer'][data-status='submitted']
490
+ > [data-part='footer']
491
+ > [data-part='submit'] {
492
+ background-color: var(
493
+ --slotted-prompt-composer-submit-background,
494
+ var(--slotted-tone-accent-solid, Highlight)
495
+ );
496
+ color: var(
497
+ --slotted-prompt-composer-submit-color,
498
+ var(--slotted-tone-accent-on-solid, HighlightText)
499
+ );
500
+ cursor: progress;
501
+ }
502
+
503
+ /* The ring around the stop square is drawn inside the disc, a stroke in
504
+ from its edge, so the disc keeps its outline. */
505
+ [data-ui='prompt-composer'][data-status='streaming']
506
+ > [data-part='footer']
507
+ > [data-part='submit'] {
508
+ --slotted-spinner-size: calc(var(--_button) - 2 * var(--slotted-space-1, 2px));
509
+ --slotted-icon-size: calc(var(--_icon-size) * 3 / 4);
510
+ }
511
+
512
+ /**
513
+ * The mark swaps — an arrow to send, a square to stop, a turn to retry — as
514
+ * a new element, and it arrives rather than replaces: from four fifths and
515
+ * transparent, on the entering curve. The old mark is gone in the same
516
+ * frame.
517
+ */
518
+ [data-ui='prompt-composer']
519
+ > [data-part='footer']
520
+ > [data-part='submit']
521
+ > :is([data-ui='icon'], [data-ui='spinner']) {
522
+ transition:
523
+ opacity var(--slotted-duration-short) var(--slotted-easing-enter),
524
+ scale var(--slotted-duration-short) var(--slotted-easing-enter),
525
+ translate var(--slotted-duration-short) var(--slotted-easing-standard);
526
+ }
527
+
528
+ @starting-style {
529
+ [data-ui='prompt-composer']
530
+ > [data-part='footer']
531
+ > [data-part='submit']
532
+ > :is([data-ui='icon'], [data-ui='spinner']) {
533
+ opacity: 0;
534
+ scale: 0.8;
535
+ }
536
+ }
537
+
538
+ /* The ghost buttons draw their ring inside their own box, the way every
539
+ inner control does: four pixels from the frame, an outward ring would
540
+ land on the frame's edge. The solid send keeps it outside, where the
541
+ ring stands against the frame's ground rather than against the accent. */
542
+ [data-ui='prompt-composer']
543
+ > :is([data-part='header'], [data-part='footer'])
544
+ > :is([data-part='action'], [data-part='attach']):focus-visible {
545
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
546
+ outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
547
+ }
548
+
549
+ [data-ui='prompt-composer'] > [data-part='footer'] > [data-part='submit']:focus-visible {
550
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
551
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
552
+ }
553
+
554
+ /* ── States of the frame ─────────────────────────────────────────────── */
555
+
556
+ [data-ui='prompt-composer'][data-part='root']:hover:not([data-disabled]):not([data-readonly]):not(
557
+ [data-invalid]
558
+ ):not([data-drop-target]) {
559
+ border-color: var(
560
+ --slotted-prompt-composer-hover-border-color,
561
+ var(--slotted-tone-accent-border)
562
+ );
563
+ }
564
+
565
+ /**
566
+ * Writing lifts the surface: the ring the theme draws for focus, and the
567
+ * shadow one step deeper — in a form the resting lift recoloured in the
568
+ * ring's ink, the rule every framed control follows; in the chat composer
569
+ * the theme's large shadow, because a surface that is being written on
570
+ * comes forward.
571
+ */
572
+ [data-ui='prompt-composer'][data-part='root']:has(> [data-part='input']:focus-visible) {
573
+ box-shadow: var(--_lift-focus);
574
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
575
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
576
+ }
577
+
578
+ /**
579
+ * Files held over the frame. The frame answers in the accent — a wash of
580
+ * its surface, and a dashed edge drawn inside it at half the bands' inset,
581
+ * concentric with the corner — so the reader sees where the drop will land
582
+ * before letting go, the picture `upload`'s drop zone gives the same
583
+ * moment. The dashed edge is a pseudo-element rather than an outline: the
584
+ * outline is the focus ring's, and the two can be on at once.
585
+ */
586
+ [data-ui='prompt-composer'][data-part='root'] {
587
+ position: relative;
588
+ }
589
+
590
+ [data-ui='prompt-composer'][data-part='root']::before {
591
+ /* Unthemed, the dashed edge disappears rather than shouting in a system
592
+ colour; the wash and the frame's edge still say where the drop lands. */
593
+ border: var(--slotted-border-width-medium, 1.5px) dashed
594
+ var(
595
+ --slotted-prompt-composer-drop-border-color,
596
+ var(--slotted-tone-accent-border, transparent)
597
+ );
598
+ border-radius: max(var(--slotted-radius-xs, 2px), calc(var(--_radius) - var(--_inset) / 2));
599
+ content: '';
600
+ /* Half the bands' air: between the frame and the buttons, crossing
601
+ neither. */
602
+ inset: calc(var(--_inset) / 2 - var(--slotted-control-border-width, 1px));
603
+ opacity: 0;
604
+ pointer-events: none;
605
+ position: absolute;
606
+ transition: opacity var(--slotted-duration-short) var(--slotted-easing-exit);
607
+ }
608
+
609
+ [data-ui='prompt-composer'][data-part='root'][data-drop-target]::before {
610
+ opacity: 1;
611
+ transition-timing-function: var(--slotted-easing-enter);
612
+ }
613
+
614
+ [data-ui='prompt-composer'][data-part='root'][data-drop-target] {
615
+ background-color: var(
616
+ --slotted-prompt-composer-drop-background,
617
+ var(--slotted-tone-accent-surface, Canvas)
618
+ );
619
+ border-color: var(
620
+ --slotted-prompt-composer-drop-border-color,
621
+ var(--slotted-tone-accent-border, Highlight)
622
+ );
623
+ }
624
+
625
+ [data-ui='prompt-composer'][data-part='root'][data-invalid] {
626
+ --slotted-focus-ring-color: var(
627
+ --slotted-prompt-composer-invalid-focus-ring-color,
628
+ var(--slotted-focus-ring-color-invalid, Highlight)
629
+ );
630
+ --_invalid-edge-width: var(
631
+ --slotted-prompt-composer-invalid-edge-width,
632
+ var(--slotted-control-invalid-edge-width, 1px)
633
+ );
634
+
635
+ border-color: var(
636
+ --slotted-prompt-composer-invalid-border-color,
637
+ var(--slotted-tone-danger-border)
638
+ );
639
+ }
640
+
641
+ /*
642
+ * Width as well as colour (WCAG 1.4.1), the edge `text-field` draws: in
643
+ * `high-contrast` the danger border is the resting edge's black. It is a
644
+ * border on a box laid over the frame's padding box rather than a shadow on
645
+ * the frame, so the frame keeps its own elevation at rest and under focus —
646
+ * the large one in `raised` — and forced colours, which remove shadows, keep
647
+ * a border. Nothing moves: the box is out of flow.
648
+ */
649
+ [data-ui='prompt-composer'][data-part='root'][data-invalid]::after {
650
+ border: var(--_invalid-edge-width) solid
651
+ var(--slotted-prompt-composer-invalid-border-color, var(--slotted-tone-danger-border));
652
+ border-radius: max(0px, calc(var(--_radius) - var(--slotted-control-border-width, 1px)));
653
+ content: '';
654
+ inset: 0;
655
+ pointer-events: none;
656
+ position: absolute;
657
+ }
658
+
659
+ [data-ui='prompt-composer'][data-part='root'][data-readonly] {
660
+ background-color: var(
661
+ --slotted-prompt-composer-readonly-background,
662
+ var(--slotted-tone-secondary-subtle-hover)
663
+ );
664
+ cursor: default;
665
+ }
666
+
667
+ [data-ui='prompt-composer'][data-part='root'][data-disabled] {
668
+ background-color: var(
669
+ --slotted-prompt-composer-disabled-background,
670
+ var(--slotted-disabled-background)
671
+ );
672
+ border-color: var(
673
+ --slotted-prompt-composer-disabled-border-color,
674
+ var(--slotted-disabled-border)
675
+ );
676
+ box-shadow: none;
677
+ color: var(--slotted-prompt-composer-disabled-color, var(--slotted-disabled-foreground));
678
+ cursor: not-allowed;
679
+ }
680
+ }