sherick-ui 2.8.0 → 2.10.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 (284) hide show
  1. package/README.md +32 -0
  2. package/dist/cjs/components/Accordion.cjs +14 -26
  3. package/dist/cjs/components/Accordion.cjs.map +1 -1
  4. package/dist/cjs/components/Alert.cjs +64 -19
  5. package/dist/cjs/components/Alert.cjs.map +1 -1
  6. package/dist/cjs/components/AlertDialog.cjs +5 -3
  7. package/dist/cjs/components/AlertDialog.cjs.map +1 -1
  8. package/dist/cjs/components/Avatar.cjs +12 -3
  9. package/dist/cjs/components/Avatar.cjs.map +1 -1
  10. package/dist/cjs/components/Badge.cjs +5 -3
  11. package/dist/cjs/components/Badge.cjs.map +1 -1
  12. package/dist/cjs/components/Breadcrumb.cjs +8 -4
  13. package/dist/cjs/components/Breadcrumb.cjs.map +1 -1
  14. package/dist/cjs/components/Button.cjs +11 -4
  15. package/dist/cjs/components/Button.cjs.map +1 -1
  16. package/dist/cjs/components/Calendar.cjs +39 -4
  17. package/dist/cjs/components/Calendar.cjs.map +1 -1
  18. package/dist/cjs/components/Card.cjs +16 -4
  19. package/dist/cjs/components/Card.cjs.map +1 -1
  20. package/dist/cjs/components/Checkbox.cjs +15 -3
  21. package/dist/cjs/components/Checkbox.cjs.map +1 -1
  22. package/dist/cjs/components/CheckboxGroup.cjs +3 -2
  23. package/dist/cjs/components/CheckboxGroup.cjs.map +1 -1
  24. package/dist/cjs/components/Chip.cjs +53 -43
  25. package/dist/cjs/components/Chip.cjs.map +1 -1
  26. package/dist/cjs/components/ChipGroup.cjs +17 -0
  27. package/dist/cjs/components/ChipGroup.cjs.map +1 -1
  28. package/dist/cjs/components/Collapsible.cjs +1 -1
  29. package/dist/cjs/components/Collapsible.cjs.map +1 -1
  30. package/dist/cjs/components/Combobox.cjs +59 -15
  31. package/dist/cjs/components/Combobox.cjs.map +1 -1
  32. package/dist/cjs/components/Command.cjs +11 -5
  33. package/dist/cjs/components/Command.cjs.map +1 -1
  34. package/dist/cjs/components/CommandPalette.cjs +5 -2
  35. package/dist/cjs/components/CommandPalette.cjs.map +1 -1
  36. package/dist/cjs/components/DatePicker.cjs +6 -3
  37. package/dist/cjs/components/DatePicker.cjs.map +1 -1
  38. package/dist/cjs/components/DateRangePicker.cjs +3 -2
  39. package/dist/cjs/components/DateRangePicker.cjs.map +1 -1
  40. package/dist/cjs/components/DateTimePicker.cjs +1 -1
  41. package/dist/cjs/components/DateTimePicker.cjs.map +1 -1
  42. package/dist/cjs/components/Dialog.cjs +10 -3
  43. package/dist/cjs/components/Dialog.cjs.map +1 -1
  44. package/dist/cjs/components/DialogContent.cjs +5 -3
  45. package/dist/cjs/components/DialogContent.cjs.map +1 -1
  46. package/dist/cjs/components/DialogDescription.cjs +5 -3
  47. package/dist/cjs/components/DialogDescription.cjs.map +1 -1
  48. package/dist/cjs/components/DialogFooter.cjs +3 -3
  49. package/dist/cjs/components/DialogFooter.cjs.map +1 -1
  50. package/dist/cjs/components/DialogHeader.cjs +5 -3
  51. package/dist/cjs/components/DialogHeader.cjs.map +1 -1
  52. package/dist/cjs/components/DialogSurface.cjs +37 -15
  53. package/dist/cjs/components/DialogSurface.cjs.map +1 -1
  54. package/dist/cjs/components/DismissButton.cjs +24 -0
  55. package/dist/cjs/components/DismissButton.cjs.map +1 -0
  56. package/dist/cjs/components/Divider.cjs +3 -1
  57. package/dist/cjs/components/Divider.cjs.map +1 -1
  58. package/dist/cjs/components/Drawer.cjs +28 -15
  59. package/dist/cjs/components/Drawer.cjs.map +1 -1
  60. package/dist/cjs/components/Field.cjs +47 -2
  61. package/dist/cjs/components/Field.cjs.map +1 -1
  62. package/dist/cjs/components/FieldLabel.cjs +20 -0
  63. package/dist/cjs/components/FieldLabel.cjs.map +1 -0
  64. package/dist/cjs/components/FileUpload.cjs +19 -9
  65. package/dist/cjs/components/FileUpload.cjs.map +1 -1
  66. package/dist/cjs/components/IconButton.cjs +28 -3
  67. package/dist/cjs/components/IconButton.cjs.map +1 -1
  68. package/dist/cjs/components/Input.cjs +14 -5
  69. package/dist/cjs/components/Input.cjs.map +1 -1
  70. package/dist/cjs/components/Menu.cjs +18 -4
  71. package/dist/cjs/components/Menu.cjs.map +1 -1
  72. package/dist/cjs/components/NavGroup.cjs +7 -1
  73. package/dist/cjs/components/NavGroup.cjs.map +1 -1
  74. package/dist/cjs/components/NavItem.cjs +28 -3
  75. package/dist/cjs/components/NavItem.cjs.map +1 -1
  76. package/dist/cjs/components/NumberField.cjs +7 -6
  77. package/dist/cjs/components/NumberField.cjs.map +1 -1
  78. package/dist/cjs/components/Pagination.cjs +45 -10
  79. package/dist/cjs/components/Pagination.cjs.map +1 -1
  80. package/dist/cjs/components/Popover.cjs +17 -3
  81. package/dist/cjs/components/Popover.cjs.map +1 -1
  82. package/dist/cjs/components/Progress.cjs +5 -3
  83. package/dist/cjs/components/Progress.cjs.map +1 -1
  84. package/dist/cjs/components/RadioGroup.cjs +3 -2
  85. package/dist/cjs/components/RadioGroup.cjs.map +1 -1
  86. package/dist/cjs/components/Search.cjs +35 -14
  87. package/dist/cjs/components/Search.cjs.map +1 -1
  88. package/dist/cjs/components/SegmentedControl.cjs +2 -1
  89. package/dist/cjs/components/SegmentedControl.cjs.map +1 -1
  90. package/dist/cjs/components/Select.cjs +14 -4
  91. package/dist/cjs/components/Select.cjs.map +1 -1
  92. package/dist/cjs/components/Skeleton.cjs +5 -3
  93. package/dist/cjs/components/Skeleton.cjs.map +1 -1
  94. package/dist/cjs/components/Slider.cjs +1 -1
  95. package/dist/cjs/components/Slider.cjs.map +1 -1
  96. package/dist/cjs/components/Spinner.cjs +25 -14
  97. package/dist/cjs/components/Spinner.cjs.map +1 -1
  98. package/dist/cjs/components/StatusMark.cjs +43 -0
  99. package/dist/cjs/components/StatusMark.cjs.map +1 -0
  100. package/dist/cjs/components/Stepper.cjs +9 -6
  101. package/dist/cjs/components/Stepper.cjs.map +1 -1
  102. package/dist/cjs/components/Switch.cjs +20 -1
  103. package/dist/cjs/components/Switch.cjs.map +1 -1
  104. package/dist/cjs/components/Table.cjs +15 -7
  105. package/dist/cjs/components/Table.cjs.map +1 -1
  106. package/dist/cjs/components/Tabs.cjs +10 -3
  107. package/dist/cjs/components/Tabs.cjs.map +1 -1
  108. package/dist/cjs/components/Textarea.cjs +8 -4
  109. package/dist/cjs/components/Textarea.cjs.map +1 -1
  110. package/dist/cjs/components/Toast.cjs +47 -34
  111. package/dist/cjs/components/Toast.cjs.map +1 -1
  112. package/dist/cjs/components/ToggleGroup.cjs +14 -3
  113. package/dist/cjs/components/ToggleGroup.cjs.map +1 -1
  114. package/dist/cjs/components/Tooltip.cjs +16 -2
  115. package/dist/cjs/components/Tooltip.cjs.map +1 -1
  116. package/dist/cjs/components/TreeView.cjs +8 -4
  117. package/dist/cjs/components/TreeView.cjs.map +1 -1
  118. package/dist/cjs/components/choice-row.cjs +1 -1
  119. package/dist/cjs/components/choice-row.cjs.map +1 -1
  120. package/dist/cjs/components/date-family.cjs +16 -2
  121. package/dist/cjs/components/date-family.cjs.map +1 -1
  122. package/dist/cjs/components/date-field.cjs +5 -3
  123. package/dist/cjs/components/date-field.cjs.map +1 -1
  124. package/dist/cjs/components/edge-fade.cjs +80 -0
  125. package/dist/cjs/components/edge-fade.cjs.map +1 -0
  126. package/dist/cjs/components/scroll-region.cjs +56 -0
  127. package/dist/cjs/components/scroll-region.cjs.map +1 -0
  128. package/dist/cjs/components/time-panel.cjs +2 -2
  129. package/dist/cjs/components/time-panel.cjs.map +1 -1
  130. package/dist/cjs/components/ui.common.cjs +179 -71
  131. package/dist/cjs/components/ui.common.cjs.map +1 -1
  132. package/dist/cjs/components/ui.motion.cjs +46 -15
  133. package/dist/cjs/components/ui.motion.cjs.map +1 -1
  134. package/dist/cjs/dev.cjs +9 -0
  135. package/dist/cjs/dev.cjs.map +1 -1
  136. package/dist/cjs/index.cjs +1 -0
  137. package/dist/cjs/index.cjs.map +1 -1
  138. package/dist/esm/components/Accordion.js +16 -28
  139. package/dist/esm/components/Accordion.js.map +1 -1
  140. package/dist/esm/components/Alert.js +66 -22
  141. package/dist/esm/components/Alert.js.map +1 -1
  142. package/dist/esm/components/AlertDialog.js +6 -4
  143. package/dist/esm/components/AlertDialog.js.map +1 -1
  144. package/dist/esm/components/Avatar.js +14 -5
  145. package/dist/esm/components/Avatar.js.map +1 -1
  146. package/dist/esm/components/Badge.js +6 -4
  147. package/dist/esm/components/Badge.js.map +1 -1
  148. package/dist/esm/components/Breadcrumb.js +9 -5
  149. package/dist/esm/components/Breadcrumb.js.map +1 -1
  150. package/dist/esm/components/Button.js +11 -4
  151. package/dist/esm/components/Button.js.map +1 -1
  152. package/dist/esm/components/Calendar.js +43 -8
  153. package/dist/esm/components/Calendar.js.map +1 -1
  154. package/dist/esm/components/Card.js +17 -5
  155. package/dist/esm/components/Card.js.map +1 -1
  156. package/dist/esm/components/Checkbox.js +17 -5
  157. package/dist/esm/components/Checkbox.js.map +1 -1
  158. package/dist/esm/components/CheckboxGroup.js +4 -3
  159. package/dist/esm/components/CheckboxGroup.js.map +1 -1
  160. package/dist/esm/components/Chip.js +56 -46
  161. package/dist/esm/components/Chip.js.map +1 -1
  162. package/dist/esm/components/ChipGroup.js +18 -1
  163. package/dist/esm/components/ChipGroup.js.map +1 -1
  164. package/dist/esm/components/CodeBlock.js +58 -28
  165. package/dist/esm/components/CodeBlock.js.map +1 -1
  166. package/dist/esm/components/Collapsible.js +2 -2
  167. package/dist/esm/components/Collapsible.js.map +1 -1
  168. package/dist/esm/components/Combobox.js +63 -19
  169. package/dist/esm/components/Combobox.js.map +1 -1
  170. package/dist/esm/components/Command.js +12 -6
  171. package/dist/esm/components/Command.js.map +1 -1
  172. package/dist/esm/components/CommandPalette.js +7 -4
  173. package/dist/esm/components/CommandPalette.js.map +1 -1
  174. package/dist/esm/components/DatePicker.js +7 -4
  175. package/dist/esm/components/DatePicker.js.map +1 -1
  176. package/dist/esm/components/DateRangePicker.js +4 -3
  177. package/dist/esm/components/DateRangePicker.js.map +1 -1
  178. package/dist/esm/components/DateTimePicker.js +2 -2
  179. package/dist/esm/components/DateTimePicker.js.map +1 -1
  180. package/dist/esm/components/Dialog.js +12 -6
  181. package/dist/esm/components/Dialog.js.map +1 -1
  182. package/dist/esm/components/DialogContent.js +6 -4
  183. package/dist/esm/components/DialogContent.js.map +1 -1
  184. package/dist/esm/components/DialogDescription.js +6 -4
  185. package/dist/esm/components/DialogDescription.js.map +1 -1
  186. package/dist/esm/components/DialogFooter.js +3 -3
  187. package/dist/esm/components/DialogFooter.js.map +1 -1
  188. package/dist/esm/components/DialogHeader.js +5 -3
  189. package/dist/esm/components/DialogHeader.js.map +1 -1
  190. package/dist/esm/components/DialogSurface.js +38 -17
  191. package/dist/esm/components/DialogSurface.js.map +1 -1
  192. package/dist/esm/components/DismissButton.js +20 -0
  193. package/dist/esm/components/DismissButton.js.map +1 -0
  194. package/dist/esm/components/Divider.js +3 -1
  195. package/dist/esm/components/Divider.js.map +1 -1
  196. package/dist/esm/components/Drawer.js +31 -18
  197. package/dist/esm/components/Drawer.js.map +1 -1
  198. package/dist/esm/components/Field.js +49 -6
  199. package/dist/esm/components/Field.js.map +1 -1
  200. package/dist/esm/components/FieldLabel.js +15 -0
  201. package/dist/esm/components/FieldLabel.js.map +1 -0
  202. package/dist/esm/components/FileUpload.js +23 -13
  203. package/dist/esm/components/FileUpload.js.map +1 -1
  204. package/dist/esm/components/IconButton.js +31 -6
  205. package/dist/esm/components/IconButton.js.map +1 -1
  206. package/dist/esm/components/Input.js +15 -6
  207. package/dist/esm/components/Input.js.map +1 -1
  208. package/dist/esm/components/Markdown.js +10 -7
  209. package/dist/esm/components/Markdown.js.map +1 -1
  210. package/dist/esm/components/Menu.js +20 -6
  211. package/dist/esm/components/Menu.js.map +1 -1
  212. package/dist/esm/components/NavGroup.js +9 -3
  213. package/dist/esm/components/NavGroup.js.map +1 -1
  214. package/dist/esm/components/NavItem.js +30 -6
  215. package/dist/esm/components/NavItem.js.map +1 -1
  216. package/dist/esm/components/NumberField.js +8 -7
  217. package/dist/esm/components/NumberField.js.map +1 -1
  218. package/dist/esm/components/Pagination.js +47 -12
  219. package/dist/esm/components/Pagination.js.map +1 -1
  220. package/dist/esm/components/Popover.js +18 -4
  221. package/dist/esm/components/Popover.js.map +1 -1
  222. package/dist/esm/components/Progress.js +6 -4
  223. package/dist/esm/components/Progress.js.map +1 -1
  224. package/dist/esm/components/RadioGroup.js +4 -3
  225. package/dist/esm/components/RadioGroup.js.map +1 -1
  226. package/dist/esm/components/Search.js +36 -15
  227. package/dist/esm/components/Search.js.map +1 -1
  228. package/dist/esm/components/SegmentedControl.js +2 -1
  229. package/dist/esm/components/SegmentedControl.js.map +1 -1
  230. package/dist/esm/components/Select.js +16 -6
  231. package/dist/esm/components/Select.js.map +1 -1
  232. package/dist/esm/components/Skeleton.js +5 -3
  233. package/dist/esm/components/Skeleton.js.map +1 -1
  234. package/dist/esm/components/Slider.js +2 -2
  235. package/dist/esm/components/Slider.js.map +1 -1
  236. package/dist/esm/components/Spinner.js +25 -14
  237. package/dist/esm/components/Spinner.js.map +1 -1
  238. package/dist/esm/components/StatusMark.js +38 -0
  239. package/dist/esm/components/StatusMark.js.map +1 -0
  240. package/dist/esm/components/Stepper.js +10 -7
  241. package/dist/esm/components/Stepper.js.map +1 -1
  242. package/dist/esm/components/Switch.js +21 -2
  243. package/dist/esm/components/Switch.js.map +1 -1
  244. package/dist/esm/components/Table.js +16 -8
  245. package/dist/esm/components/Table.js.map +1 -1
  246. package/dist/esm/components/Tabs.js +11 -4
  247. package/dist/esm/components/Tabs.js.map +1 -1
  248. package/dist/esm/components/Textarea.js +9 -5
  249. package/dist/esm/components/Textarea.js.map +1 -1
  250. package/dist/esm/components/Toast.js +49 -36
  251. package/dist/esm/components/Toast.js.map +1 -1
  252. package/dist/esm/components/ToggleGroup.js +16 -5
  253. package/dist/esm/components/ToggleGroup.js.map +1 -1
  254. package/dist/esm/components/Tooltip.js +17 -4
  255. package/dist/esm/components/Tooltip.js.map +1 -1
  256. package/dist/esm/components/TreeView.js +9 -5
  257. package/dist/esm/components/TreeView.js.map +1 -1
  258. package/dist/esm/components/choice-row.js +1 -1
  259. package/dist/esm/components/choice-row.js.map +1 -1
  260. package/dist/esm/components/date-family.js +15 -3
  261. package/dist/esm/components/date-family.js.map +1 -1
  262. package/dist/esm/components/date-field.js +6 -4
  263. package/dist/esm/components/date-field.js.map +1 -1
  264. package/dist/esm/components/edge-fade.js +77 -0
  265. package/dist/esm/components/edge-fade.js.map +1 -0
  266. package/dist/esm/components/scroll-region.js +52 -0
  267. package/dist/esm/components/scroll-region.js.map +1 -0
  268. package/dist/esm/components/time-panel.js +2 -2
  269. package/dist/esm/components/time-panel.js.map +1 -1
  270. package/dist/esm/components/ui.common.js +175 -73
  271. package/dist/esm/components/ui.common.js.map +1 -1
  272. package/dist/esm/components/ui.motion.js +44 -16
  273. package/dist/esm/components/ui.motion.js.map +1 -1
  274. package/dist/esm/content.js +1 -1
  275. package/dist/esm/dev.js +2 -2
  276. package/dist/esm/index.js +1 -1
  277. package/dist/styles.css +341 -209
  278. package/dist/theme.css +15 -12
  279. package/dist/types/content.d.ts +13 -3
  280. package/dist/types/dev.d.cts +79 -29
  281. package/dist/types/dev.d.ts +79 -29
  282. package/dist/types/index.d.cts +512 -154
  283. package/dist/types/index.d.ts +512 -154
  284. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { cx } from '../libs/utils.js';
2
- import { motionRim, motionFeedback, motionStateLayer, motionRowLayer, motionDisclose } from './ui.motion.js';
2
+ import { motionStateLayer, motionRim, motionFeedback, motionRowLayer, motionDisclose } from './ui.motion.js';
3
3
 
4
4
  /* Sherick UI design primitives
5
5
  ==========================================================================
@@ -9,16 +9,18 @@ import { motionRim, motionFeedback, motionStateLayer, motionRowLayer, motionDisc
9
9
 
10
10
  material what a surface is made of (canvas, matte, control, acrylic)
11
11
  elevation how far it sits off the page (flat, raised, floating, control, recessed)
12
- shape its corner role (control, prominent, surface, expressive, pill, circle)
12
+ shape its corner role (mark, row, control, prominent, surface, sheet, expressive, pill, circle)
13
13
  edge the hairline between stacked parts (row, header, rule)
14
14
  state how it responds (rest, hover, pressed, selected, disabled, focus)
15
- stateLayer the composited hover/press overlay (quiet, tonal, filled, track, activeRow)
15
+ stateLayer the composited hover/press overlay (quiet, tonal, filled, track, mark, activeRow, fieldPart)
16
16
  disclosure one expandable region and its row (trigger, panel)
17
17
  tone its color role (text, soft, tonal, selected, strong)
18
18
  text the readable emphasis ladder (high, medium)
19
- density how tightly it is packed (compact, normal, prominent, target)
19
+ type the recurring kinds of copy (control, label, body, supporting, caption, title, heading, numeric)
20
+ density how tightly it is packed (compact, normal, prominent, target, part)
21
+ iconStroke the one rendered stroke of a glyph (glyph, mark)
20
22
  overlay floating shells (menu, tooltip, popup, toast, sheet, dialog)
21
- focusRing the one focus language (focusRing, focusRingInset, focusRingHeld, focusRingWithin, groupFocusRing)
23
+ focusRing the one focus language (focusRing, focusRingInset, focusRingHeld, focusRingWithin, groupFocusRing)
22
24
 
23
25
  Temporal behavior is deliberately not here: `ui.motion.ts` owns every transition,
24
26
  duration, curve and reduced-motion rule, and a recipe below names one of its recipes
@@ -64,8 +66,10 @@ import { motionRim, motionFeedback, motionStateLayer, motionRowLayer, motionDisc
64
66
  trigger and an editable combobox field end up identical in every state: neither looks ringed at
65
67
  rest, both look ringed the moment either is used, and both lose it together. `groupFocusRing`
66
68
  draws it from the wrapping control instead of the track it contains. */
67
- const focusRing = "focus:outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-sherick-focus focus-visible:outline-offset-[3px]";
68
- const focusRingInset = "focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-sherick-focus";
69
+ const focusRing = "focus:[outline-style:none] focus-visible:outline focus-visible:outline-2 focus-visible:outline-sherick-focus focus-visible:outline-offset-[3px]";
70
+ /* The inset ring is a box shadow, and forced colors removes every box shadow, so the same 2px ring
71
+ is drawn there as an inset outline instead, which the platform paints in a system colour. */
72
+ const focusRingInset = "focus:[outline-style:none] focus-visible:[outline-style:none] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-sherick-focus forced-colors:focus-visible:outline forced-colors:focus-visible:outline-2 forced-colors:focus-visible:outline-offset-[-2px]";
69
73
  /* A focus owner that also contains a subtree paints the inset ring on its direct row only. */
70
74
  const parentFocusRingInset = "[:focus-visible>&]:ring-2 [:focus-visible>&]:ring-inset [:focus-visible>&]:ring-sherick-focus";
71
75
  /* The ring of a value control that is itself the focusable element: it wears it whenever it
@@ -73,7 +77,7 @@ const parentFocusRingInset = "[:focus-visible>&]:ring-2 [:focus-visible>&]:ring-
73
77
  hands the DOM focus to its list while that list is open, so the ring follows the control's
74
78
  engagement rather than the focus — which is exactly what a native `select` shows, and the only
75
79
  focus indication the field has left once the list has taken over. */
76
- const focusRingHeld = "focus:outline-none focus:outline focus:outline-2 focus:outline-sherick-focus focus:outline-offset-[3px] data-[popup-open]:outline data-[popup-open]:outline-2 data-[popup-open]:outline-sherick-focus data-[popup-open]:outline-offset-[3px]";
80
+ const focusRingHeld = "focus:outline focus:outline-2 focus:outline-sherick-focus focus:outline-offset-[3px] data-[popup-open]:outline data-[popup-open]:outline-2 data-[popup-open]:outline-sherick-focus data-[popup-open]:outline-offset-[3px]";
77
81
  /* The same ring for a value control whose focus lives in a borderless input inside it. It follows
78
82
  **visible** focus rather than any focus, which is what makes a field and a slider differ for
79
83
  the platform's reasons instead of by local say-so: a text field is `:focus-visible` whenever it
@@ -103,10 +107,16 @@ const groupFocusRing = "group-focus-visible:outline group-focus-visible:outline-
103
107
  A passive surface is flat unless its anatomy is sunk by design: a well, a groove and
104
108
  a code well are `recessed` while they sit there, and `flat` is the default for
105
109
  everything else passive. A flat control never gains depth by being pressed. */
110
+ /* Forced colors removes shadows and tones, so a shell that separates from the page by depth alone
111
+ loses its boundary. Every shell that carries elevation draws its own system-coloured outline
112
+ there: `outline` is drawn in CanvasText by the platform and `outline-offset` pulls it onto the
113
+ border box, so it traces the object's own corner. The outline has no width in normal colors, so
114
+ it costs nothing on screen; `forced-colors:` is the only place it appears. */
115
+ const forcedBoundary = "forced-colors:outline forced-colors:outline-1 forced-colors:outline-offset-[-1px]";
106
116
  const elevation = {
107
117
  flat: "shadow-sherick-flat",
108
- raised: "shadow-sherick-raised",
109
- floating: "shadow-sherick-floating",
118
+ raised: /* @__PURE__ */ cx("shadow-sherick-raised", forcedBoundary),
119
+ floating: /* @__PURE__ */ cx("shadow-sherick-floating", forcedBoundary),
110
120
  control: "shadow-sherick-control",
111
121
  recessed: "shadow-sherick-recessed",
112
122
  /* One rung further down: the depth a small selection mark sinks to while it is held. A mark
@@ -125,8 +135,8 @@ const recessedTop = "shadow-sherick-recessed-top";
125
135
  an almost-button beside a real one. Nested roles stay concentric: an inner corner is the outer
126
136
  corner minus the inset between them (a 16px track around a 12px indicator at 4px, a 20px list
127
137
  sheet around 12px options at 8px).
128
- - control: ordinary controls and dense data regions — fields, rows, options,
129
- chips, tables.
138
+ - control: ordinary containers and dense data regions — fields, alerts, tables, segment
139
+ tracks and full-width option rows. Chips and badges are capsules (`pill`).
130
140
  - mark: a compact square selection mark — a 20px checkbox box. `control` is a role
131
141
  for objects the size of a field; its radius exceeds the half-extent of a
132
142
  20px square, so a mark needs a step of its own — a corner under a third of
@@ -210,7 +220,7 @@ const edge = {
210
220
  directional border class at the call site (`border-t`, `border-l`). */
211
221
  rule: edgeTone.rule,
212
222
  };
213
- const effectiveDisabled = "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-45 disabled:cursor-not-allowed disabled:opacity-45";
223
+ const effectiveDisabled = "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-45 aria-disabled:cursor-not-allowed aria-disabled:opacity-45 disabled:cursor-not-allowed disabled:opacity-45";
214
224
  /* Interaction states:
215
225
  rest the material, at whatever elevation its anatomy calls for
216
226
  hover one tonality step, never a change in depth or a new border
@@ -227,19 +237,26 @@ const state = {
227
237
  it belongs with the tactile intent in `ui.motion.ts`. */
228
238
  recess: "active:shadow-sherick-recessed",
229
239
  /* The disabled step for a control whose disabled state is a Sherick prop. */
230
- disabled: "cursor-not-allowed opacity-45",
240
+ disabled: "cursor-not-allowed opacity-45 aria-disabled:cursor-not-allowed aria-disabled:opacity-45",
241
+ /* A control that is busy is still working for the reader, so it is not dimmed: it keeps its full
242
+ strength and its cursor says work is happening. It stays focusable, and it takes no hover layer
243
+ and no press (`motionTactile` and the state layers withhold both on `aria-busy`). A busy
244
+ control is marked with `aria-busy="true"`, which is what Button and IconButton already carry. */
245
+ busy: "aria-busy:cursor-progress aria-busy:opacity-100",
231
246
  /* The same step, keyed on the primitive's own markers rather than on a Sherick prop: Base marks
232
247
  an effectively disabled control — including one disabled by the field around it — with
233
- `data-disabled`, and a part that disables itself at a bound carries `disabled` as well. */
248
+ `data-disabled`, and a part that disables itself at a bound carries `disabled` as well. A
249
+ control that stays focusable while disabled sets `aria-disabled="true"` instead, and it dims
250
+ exactly once, on the same step. */
234
251
  effectiveDisabled,
235
252
  /* A row whose control is disabled by any means — its own option, its group, or the field around
236
253
  it — dims from the control's own marker rather than from a Sherick prop. */
237
- disabledRow: "has-[[data-disabled]]:cursor-not-allowed has-[[data-disabled]]:opacity-45",
254
+ disabledRow: "has-[[data-disabled]]:cursor-not-allowed has-[[data-disabled]]:opacity-45 has-[[aria-disabled=true]]:cursor-not-allowed has-[[aria-disabled=true]]:opacity-45",
238
255
  /* A control nested inside a disabled composite. The composite already applied the opacity step,
239
256
  and a second one would dim the field unevenly; this carries only the disabled cursor. */
240
257
  disabledDescendant: "cursor-not-allowed",
241
258
  /* A part dims independently at a bound, but never a second time inside a disabled field. */
242
- disabledPart: /* @__PURE__ */ cx(effectiveDisabled, "group-data-[disabled]/field:opacity-100"),
259
+ disabledPart: /* @__PURE__ */ cx(effectiveDisabled, "group-data-[disabled]/field:opacity-100 group-data-[disabled]/field:aria-disabled:opacity-100"),
243
260
  /* A part the pointer is engaging — the handle of a value control. It sits matte and settled at
244
261
  rest and takes its accent, a little larger, while the pointer is on it. Drag covers the case
245
262
  where the pointer has been captured and left the control. */
@@ -248,13 +265,17 @@ const state = {
248
265
  enabled: "cursor-pointer",
249
266
  /* A text field: the normal text cursor, never a pointer. */
250
267
  text: "cursor-text",
268
+ /* A muted label that is also a quiet target: it rests at `text.medium` and rises to `text.high` on
269
+ hover and on keyboard focus, with no state layer. A dismiss glyph or a secondary link takes it,
270
+ so the response is the ink itself rather than a tint behind it. Hover is a pointer response
271
+ (§11), so a touch screen only ever sees the focus step. */
272
+ quietInk: "text-sherick-ink-muted hover:text-sherick-ink focus-visible:text-sherick-ink",
251
273
  /* Quiet scan feedback for non-interactive data rows: tonality only. */
252
274
  rowHover: "hover:bg-sherick-ink/[0.05]",
253
- /* The matte field family — one tonality ladder, four triggers, no rims. A field
254
- steps its surface up once on hover and once more while it is engaged; a
255
- composite field focuses its outer surface while the input inside stays
256
- borderless; an expanded control holds the engaged step while its popup is
257
- open. Tonality carries the state, so no border appears and disappears. */
275
+ /* The field family — one tray, one deeper step, no visible rims. Hover and engagement share the
276
+ deep step; a composite field engages its outer surface while the input inside stays borderless;
277
+ an expanded control holds the engaged step while its popup is open. Tonality and the focus ring
278
+ carry the state, so no border appears and disappears. */
258
279
  /* A field is a tray in the `surface-high` tone, so it reads as a quiet recess in light and a
259
280
  quiet step up in dark. It draws no line: its label and content identify it (see `rim`), so the
260
281
  tray is laid at full strength to say "something goes here" on a card and on the page alike.
@@ -312,29 +333,29 @@ const stateLayerBase = /* @__PURE__ */ cx("before:pointer-events-none before:abs
312
333
  a suffix, because the stylesheet compiler reads class names as literal text: a name that only
313
334
  exists once the recipe is evaluated compiles to no rule at all, and the step silently disappears.
314
335
  Interpolating one of these consts is safe — the name is still written here in full. */
315
- const hoverQuiet = "[&:not([data-disabled]):not(:disabled)]:hover:before:opacity-[0.05]";
316
- const hoverTonal = "[&:not([data-disabled]):not(:disabled)]:hover:before:opacity-[0.09]";
317
- const hoverFilled = "[&:not([data-disabled]):not(:disabled)]:hover:before:opacity-[0.18]";
318
- const hoverTrack = "group-[:not([data-disabled]):not(:disabled)]:hover:before:opacity-[0.18]";
319
- const pressQuiet = "[&:not([data-disabled]):not(:disabled)]:active:before:opacity-[0.09]";
320
- const pressTonal = "[&:not([data-disabled]):not(:disabled)]:active:before:opacity-[0.15]";
336
+ const hoverQuiet = "[&:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:hover:before:opacity-[0.05]";
337
+ const hoverTonal = "[&:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:hover:before:opacity-[0.09]";
338
+ const hoverFilled = "[&:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:hover:before:opacity-[0.18]";
339
+ const hoverTrack = "group-[:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:hover:before:opacity-[0.18]";
340
+ const pressQuiet = "[&:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:active:before:opacity-[0.09]";
341
+ const pressTonal = "[&:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:active:before:opacity-[0.15]";
321
342
  /* A neutral fill's label is ink, so a 15% ink veil turns the whole control a flat grey while it is
322
343
  held — and the recess and the compression already say "pressed". The neutral press is lighter;
323
344
  coloured fills keep the stronger step their labels were measured through. */
324
- const pressTonalNeutral = "[&:not([data-disabled]):not(:disabled)]:active:before:opacity-[0.12]";
325
- const pressFilled = "[&:not([data-disabled]):not(:disabled)]:active:before:opacity-[0.26]";
326
- const pressTrack = "group-[:not([data-disabled]):not(:disabled)]:active:before:opacity-[0.26]";
345
+ const pressTonalNeutral = "[&:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:active:before:opacity-[0.12]";
346
+ const pressFilled = "[&:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:active:before:opacity-[0.26]";
347
+ const pressTrack = "group-[:not([data-disabled]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled)]:active:before:opacity-[0.26]";
327
348
  /* A selection mark answers hover with the light tonal step: it is a 20px glyph beside its own
328
349
  label, and the track's step would turn an empty well into a grey disc. Its press is depth, not
329
350
  a heavier veil — `selectable.markSurface` sinks the well — so the layer only holds its hover
330
351
  step while the pointer is down. A read-only mark accepts no change and advertises none.
331
352
  The pseudo-class sits *inside* the group selector: written after it, as `…]:hover:`, it would
332
353
  match the mark's own 20px box rather than the control and the row around it. */
333
- const hoverMark = "group-[:not([data-disabled]):not([data-readonly]):not(:disabled):hover]:before:opacity-[0.09]";
354
+ const hoverMark = "[@media(hover:hover)_and_(pointer:fine)]:group-[:not([data-disabled]):not([data-readonly]):not([aria-disabled=true]):not(:disabled):hover]:before:opacity-[0.09]";
334
355
  /* A labelled control surface paints its state on a row that owns the pointer area while the
335
356
  actual disabled marker belongs to a descendant control. Gate the same quiet response on that
336
357
  descendant so a disabled or read-only choice does not advertise a press it cannot accept. */
337
- const stateLayerQuietComposite = /* @__PURE__ */ cx("relative", stateLayerBase, "before:rounded-[inherit] before:bg-current", "[&:not([data-disabled]):not([data-readonly]):not(:disabled):not(:has([data-disabled])):not(:has([data-readonly]))]:hover:before:opacity-[0.05]", "[&:not([data-disabled]):not([data-readonly]):not(:disabled):not(:has([data-disabled])):not(:has([data-readonly]))]:active:before:opacity-[0.09]");
358
+ const stateLayerQuietComposite = /* @__PURE__ */ cx("relative", stateLayerBase, "before:rounded-[inherit] before:bg-current", "[&:not([data-disabled]):not([data-readonly]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled):not(:has([data-disabled])):not(:has([data-readonly]))]:hover:before:opacity-[0.05]", "[&:not([data-disabled]):not([data-readonly]):not([aria-disabled=true]):not([aria-busy=true]):not(:disabled):not(:has([data-disabled])):not(:has([data-readonly]))]:active:before:opacity-[0.09]");
338
359
  const stateLayer = {
339
360
  /* Quiet surfaces — ghost controls, navigation rows, menu options. */
340
361
  quiet: /* @__PURE__ */ cx("relative", stateLayerBase, "before:rounded-[inherit] before:bg-current", hoverQuiet, pressQuiet),
@@ -395,8 +416,8 @@ const hitArea = "relative after:pointer-events-auto after:absolute after:inset-[
395
416
  takes the mid-emphasis tone, which inverts with the theme and separates in
396
417
  both.
397
418
  - acrylic: a translucent sheet lit from above, for surfaces that float above
398
- the application. The gradient, fill, blur and saturation are part of
399
- the material. A gradient arrives as a typed image arbitrary value
419
+ the application. The gradient and fill are part of the material; it carries
420
+ no backdrop filter (see `acrylic` below). A gradient arrives as a typed image arbitrary value
400
421
  rather than through the colour scale, because `tailwind-merge`
401
422
  collapses two background utilities into one and would silently drop
402
423
  either the fill or the gradient. Each one is written out literally, so
@@ -410,13 +431,13 @@ const hitArea = "relative after:pointer-events-auto after:absolute after:inset-[
410
431
  - acrylicHero: the large-overlay sheet, for a surface that owns the viewport. It is
411
432
  markedly more opaque and calmer than the smaller sheets: it has to
412
433
  read first as a physical surface and only secondarily as glass, so the
413
- scrim behind it does the separating, the blur only defocuses, and the
434
+ scrim behind it does the separating, and the
414
435
  gradient is a restrained top-to-bottom light rather than a frosted
415
436
  haze. Its tone is a subtle step above the canvas in every theme —
416
437
  in dark mode a small step above the canvas rather than a light grey
417
438
  sheet — which is how it separates without leaning on its shadow, and
418
439
  `--sui-overlay-fill` tunes how much of the sheet is its own tone rather
419
- than the defocused page — a large overlay leans on that, not on blur. */
440
+ than the page behind it — a large overlay leans on that, not on blur. */
420
441
  const material = {
421
442
  canvas: "bg-sherick-canvas text-sherick-ink",
422
443
  matteQuiet: "bg-sherick-surface/[0.42] text-sherick-ink",
@@ -432,9 +453,13 @@ const material = {
432
453
  already — so the error form is the same rule, in the tone the field is in. */
433
454
  controlError: "bg-sherick-danger-soft text-sherick-ink placeholder:text-sherick-danger",
434
455
  handle: "bg-sherick-ink-muted text-sherick-canvas",
435
- acrylic: "bg-sherick-surface-float/[var(--sui-glass-fill)] bg-[image:var(--sui-glass-gradient)] text-sherick-ink backdrop-blur-[var(--sui-glass-blur)] backdrop-saturate-[var(--sui-glass-saturation)] backdrop-brightness-[var(--sui-glass-brightness)]",
436
- acrylicDense: "bg-sherick-surface-float/[var(--sui-glass-dense-fill)] bg-[image:var(--sui-glass-gradient-dense)] text-sherick-ink backdrop-blur-[var(--sui-glass-dense-blur)] backdrop-saturate-[var(--sui-glass-dense-saturation)] backdrop-brightness-[var(--sui-glass-dense-brightness)]",
437
- acrylicHero: "bg-sherick-surface-overlay/[var(--sui-overlay-fill)] bg-[image:var(--sui-glass-hero-gradient)] text-sherick-ink backdrop-blur-[var(--sui-glass-hero-blur)] backdrop-saturate-[var(--sui-glass-hero-saturation)] backdrop-brightness-[var(--sui-glass-hero-brightness)]",
456
+ /* The glass carries no backdrop filter. Every presence recipe animates the popup node itself, and a
457
+ backdrop filter on an animated node re-blurs the page on each frame (DL §12). The fill is 0.98 to
458
+ 0.99 opaque, so the blur showed only one or two percent of what lay behind; the plane's scrim keeps
459
+ the blur where it is static. */
460
+ acrylic: "bg-sherick-surface-float/[var(--sui-glass-fill)] bg-[image:var(--sui-glass-gradient)] text-sherick-ink",
461
+ acrylicDense: "bg-sherick-surface-float/[var(--sui-glass-dense-fill)] bg-[image:var(--sui-glass-gradient-dense)] text-sherick-ink",
462
+ acrylicHero: "bg-sherick-surface-overlay/[var(--sui-overlay-fill)] bg-[image:var(--sui-glass-hero-gradient)] text-sherick-ink",
438
463
  };
439
464
  /* Dark neutral behind native video, including poster loading and letterboxing. */
440
465
  const mediaCanvas = "bg-sherick-media";
@@ -444,9 +469,17 @@ const matteInset = "bg-sherick-surface-high/[0.35] text-sherick-ink";
444
469
  where the role owns it, one weight. A component still owns copy that only it renders; these are
445
470
  the roles that recur across families and have to agree wherever they appear:
446
471
  - control: the type step of a control, owned through `density` below.
472
+ - label: the name above a control — a field's label, a progress label, a column header. It is
473
+ the medium weight of the compact step, so a label leads the value beneath it without
474
+ being as large as it.
475
+ - body: a sentence or a paragraph set inside a component — an alert, a toast's description, a
476
+ dialog's description and content, an open disclosure panel. Long-form Markdown keeps
477
+ its own reading rhythm; this is the rhythm of copy *in* an interface.
447
478
  - supporting: a field's description, hint and error, and the secondary line under a row's label.
448
479
  - caption: compact labels — a badge, a tooltip, a group label, a calendar weekday.
449
- - title: the heading of a compact surface — a popover, a toast, a command palette.
480
+ - title: the heading of a compact surface — a card, a popover, a toast, a command palette. It
481
+ is one step above the 15px control text it usually sits over, so a heading reads as a
482
+ heading by size and not by weight alone.
450
483
  - heading: the title of a surface that owns the viewport — a dialog, an alert dialog, a drawer.
451
484
  - numeric: figures that are compared down a column or updated in place.
452
485
  Every size lands on a whole-pixel line box, so stacked rows keep one rhythm. */
@@ -456,11 +489,18 @@ const type = {
456
489
  normal: "text-[0.9375rem] leading-[1.375rem]",
457
490
  prominent: "text-lg",
458
491
  },
459
- supporting: "text-[0.8125rem] leading-5",
460
- caption: "text-xs leading-4",
461
- title: "text-[0.9375rem] leading-[1.375rem] font-semibold tracking-[-0.011em]",
462
- heading: "text-xl leading-7 font-semibold tracking-[-0.02em]",
463
- numeric: "tabular-nums",
492
+ label: "text-sm leading-5 font-medium",
493
+ /* Wrapping copy keeps its line breaks even: `text-pretty` stops a sentence ending on one word,
494
+ and a heading balances its own lines (`text-balance`). Both are CSS `text-wrap`, so no line is
495
+ forced and a short string is unchanged. */
496
+ body: "text-sm leading-6 text-pretty",
497
+ supporting: "text-[0.8125rem] leading-5 text-pretty",
498
+ caption: "text-xs leading-4 text-pretty",
499
+ title: "text-base leading-6 font-semibold tracking-[-0.011em] text-balance",
500
+ heading: "text-xl leading-7 font-semibold tracking-[-0.02em] text-balance",
501
+ /* Figures carry their own size: a table cell, a stepper value or a time reading is 14px tabular
502
+ copy wherever it sits, so a site composes this role and does not write its own `text-sm`. */
503
+ numeric: "text-sm leading-5 tabular-nums",
464
504
  };
465
505
  /* Density — three control steps plus the accessible hit target.
466
506
  Density owns height and the type step, so controls of one density share a
@@ -497,6 +537,19 @@ const iconSlot = {
497
537
  normal: "inline-flex size-5 shrink-0 items-center justify-center [&>svg]:size-5",
498
538
  prominent: "inline-flex size-6 shrink-0 items-center justify-center [&>svg]:size-6",
499
539
  };
540
+ /* Icon stroke — the one rendered weight of a library glyph. The artwork is drawn on a 24-unit grid,
541
+ so a stroke written in the artwork's own units renders thinner at 16px and thicker at 24px: the
542
+ same set read 1.0px in a dismiss and 1.75px in a tick. A glyph the library draws holds its stroke
543
+ in screen pixels instead, so a 14px chevron and a 20px close mark have one weight, close to the
544
+ stem of the medium label beside them. A selection mark — the tick or minus inside a filled
545
+ checkbox — is the one deliberately heavier glyph: it sits on the strong accent and has to read as
546
+ the mark itself, not as a hairline drawn on it.
547
+ Apply it to the `svg` a component renders. It is not applied to artwork a consumer hands into a
548
+ slot: that artwork's weight is the consumer's choice. */
549
+ const iconStroke = {
550
+ glyph: "[&_*]:[vector-effect:non-scaling-stroke] [&_*]:[stroke-width:1.5px]",
551
+ mark: "[&_*]:[vector-effect:non-scaling-stroke] [&_*]:[stroke-width:1.75px]",
552
+ };
500
553
  /* Stacking level — where anything that floats sits relative to the application.
501
554
 
502
555
  One interaction level, deliberately. Base UI nests a popup's portal *inside* the portal of the surface it
@@ -523,7 +576,10 @@ const stacking = {
523
576
  alert dialog separate from the page identically. */
524
577
  const overlay = {
525
578
  /* The plane behind a surface that owns the viewport. */
526
- scrim: /* @__PURE__ */ cx("fixed inset-0", stacking.float, "bg-sherick-scrim/[0.30] backdrop-blur-[var(--sui-scrim-blur)]"),
579
+ scrim: /* @__PURE__ */ cx("fixed inset-0", stacking.float, "backdrop-blur-[var(--sui-scrim-blur)] [@media(pointer:coarse)]:[backdrop-filter:none]",
580
+ /* The tint is the plane's `::before`, so `motionPresenceScrim` can fade it without animating the
581
+ node that carries the blur. */
582
+ "before:absolute before:inset-0 before:content-[''] before:bg-sherick-scrim/[0.30]"),
527
583
  /* An anchored surface with room to breathe: a selection list (Select, Combobox) or
528
584
  structured content (Popover). It grows out of its trigger and carries the softer
529
585
  surface corner, because what it holds is read rather than scanned.
@@ -579,6 +635,14 @@ const detail = {
579
635
  /** The same tone as a block, for a gutter or a rail with thickness. */
580
636
  fill: "bg-sherick-detail",
581
637
  };
638
+ /* The gap between a heading and the supporting line beneath it. It is applied to the supporting
639
+ line, never to the heading, and it is the only such gap: a header takes no paired padding on its
640
+ own edges. A title-role surface (a card, a popover, a toast, a command palette) takes 4px; a
641
+ dialog or drawer heading, which is the larger `heading` role, takes 8px. */
642
+ const headingRhythm = {
643
+ title: "mt-1",
644
+ heading: "mt-2",
645
+ };
582
646
  /* A list surface — the sheet a collection of rows sits in, and the two row densities it can
583
647
  hold. Select, Combobox and Menu all compose these, so an option and a command are the same
584
648
  object at two densities instead of three independent designs.
@@ -601,6 +665,9 @@ const detail = {
601
665
  performed", never "cannot be found". */
602
666
  const list = {
603
667
  sheet: "max-w-[var(--available-width)] max-h-[var(--available-height)] overflow-y-auto",
668
+ /* The leading mark of a command row: the 14px command text takes the compact slot, so the mark is
669
+ 16px and sits in the same box every command's icon does. */
670
+ commandIcon: iconSlot.compact,
604
671
  /* A row in a selection list: one line, read one at a time and chosen.
605
672
  The row carries two separate things that both have to be visible. Its *navigation highlight*
606
673
  is the state layer — one tone shared with the pointer, because a row under the pointer and a
@@ -612,19 +679,22 @@ const list = {
612
679
  both, a selected row keeps its selection tint under the ring, and a disabled-but-navigable
613
680
  row still shows where the navigation is while saying it cannot be used. The ring is inset
614
681
  because the row lives inside the sheet it belongs to, as a segment does in its track. */
615
- option: /* @__PURE__ */ cx("flex w-full items-center justify-between gap-4 px-4 py-3 text-start outline-none", type.control.normal, shape.control, motionFeedback, focusRingInset, text.high, stateLayer.quiet, stateLayer.activeRow, motionRowLayer, state.effectiveDisabled),
682
+ /* The option's start inset is the field's: a sheet's 8px inset plus the row's 12px puts every
683
+ option label on the same 20px edge as the value in the trigger that opened it, so the list
684
+ reads as the field opening rather than a second surface beside it. */
685
+ option: /* @__PURE__ */ cx("flex w-full items-center justify-between gap-4 px-3 py-3 text-start [outline-style:none]", type.control.normal, shape.control, motionFeedback, focusRingInset, text.high, stateLayer.quiet, stateLayer.activeRow, motionRowLayer, state.effectiveDisabled),
616
686
  /* The heading of a group of options — a category above the channels filed under it. It is a
617
687
  caption, not a row: it takes no state layer, no highlight and no focus, because the reader never
618
688
  lands on it; the primitive names the group from it, so a screen reader hears the category as it
619
689
  enters the group. Its inline padding is the option's, so a heading and the labels beneath it
620
690
  share one start edge, and the space above it is what separates one group from the last: a
621
691
  group inside a sheet is grouped by spacing and a type role, never by a rule or a nested card. */
622
- groupLabel: /* @__PURE__ */ cx("px-4 pb-1 pt-3 font-medium", type.caption, text.medium),
692
+ groupLabel: /* @__PURE__ */ cx("px-3 pb-1 pt-3 font-medium", type.caption, text.medium),
623
693
  /* The same object at the density a list of short actions wants, where the row is scanned
624
694
  rather than read and the list is a control rather than a page. `shape.row` keeps the
625
695
  command's corner proportional to its own height, so its highlight nests in the tighter
626
696
  sheet the menu is. */
627
- command: /* @__PURE__ */ cx("flex w-full items-center gap-3 px-3 py-2 text-start outline-none", type.control.compact, shape.row, motionFeedback, focusRingInset, text.high, stateLayer.quiet, stateLayer.activeRow, motionRowLayer, state.effectiveDisabled),
697
+ command: /* @__PURE__ */ cx("flex w-full items-center gap-3 px-3 py-2 text-start [outline-style:none]", type.control.compact, shape.row, motionFeedback, focusRingInset, text.high, stateLayer.quiet, stateLayer.activeRow, motionRowLayer, state.effectiveDisabled),
628
698
  };
629
699
  /* A disclosure — one row that opens the region beneath it. An item in an `Accordion` and a
630
700
  standalone `Collapsible` are the same object: a stacked row, and the in-flow panel its
@@ -633,13 +703,22 @@ const list = {
633
703
  component maps its own primitive's panel variable onto, because the measured geometry is
634
704
  anatomy and only the interpolation is temporal. */
635
705
  const disclosure = {
636
- /* The row: a full-width row in a stacked group, activated like a selectable row. Its own focus
706
+ /* The chevron of a disclosure row. The row's label is 15px, so the mark takes the normal slot
707
+ (20px); the row owns the affordance, so the chevron follows the whole row rather than the first
708
+ line of a wrapping label (§17). */
709
+ chevron: iconSlot.normal,
710
+ /* The row: a full-width row in a stacked group, activated like a selectable row. It hangs its 16px
711
+ inset past both edges of its column (§17), so its label and chevron share the edges of the content
712
+ beside it and only the fill reaches into the surface's padding. The panel hangs by the same amount,
713
+ so the label still shares an edge with the panel copy beneath it. Its own focus
637
714
  indicator is the shared inset ring, because an offset one drawn outside the row would land on
638
715
  the divider or the panel beside it rather than around the row it belongs to — which is the same
639
716
  reason a segment inside a track takes the inset form. The chevron the component puts in the
640
717
  row is the disclosure's own affordance and turns in place under `motionOrient`. */
641
- trigger: /* @__PURE__ */ cx("group [overflow-wrap:anywhere]", list.option, state.enabled),
642
- panel: /* @__PURE__ */ cx("h-[var(--sui-disclose-height)] overflow-hidden text-sm leading-7 [overflow-wrap:anywhere]", text.medium, motionDisclose),
718
+ trigger: /* @__PURE__ */ cx("group -mx-4 flex w-[calc(100%+2rem)] items-center justify-between gap-4 px-4 py-3 text-start [outline-style:none] [overflow-wrap:anywhere]", type.control.normal, shape.control, motionFeedback, focusRingInset, text.high, stateLayer.quiet, stateLayer.activeRow, motionRowLayer, state.effectiveDisabled, state.enabled),
719
+ /* The panel hangs with the row and pads its copy back in, so its clip leaves the 16px a field's
720
+ focus ring inside it needs. */
721
+ panel: /* @__PURE__ */ cx("-mx-4 h-[var(--sui-disclose-height)] overflow-hidden [overflow-wrap:anywhere]", type.body, text.medium, motionDisclose),
643
722
  };
644
723
  /* Tone hierarchy — the color roles a surface can take, in rising strength:
645
724
  text foreground only, for quiet rows and links.
@@ -702,11 +781,17 @@ const tone = {
702
781
  success: "group-data-[checked]:bg-sherick-success group-data-[checked]:text-sherick-on-success",
703
782
  },
704
783
  };
705
- /* Current location — where the reader is, as opposed to a value they chose. A navigation row, the
706
- current page of a pagination and any other `aria-current` destination hold the role's soft
707
- container, full ink and a touch of weight, and stay flat: depth and the stronger selected step
708
- belong to held values (`tone.selected` with `elevation.control`). */
709
- const currentDestination = "bg-sherick-primary-soft text-sherick-ink font-medium";
784
+ /* Current location — where the reader is, as opposed to a value they chose. Both forms stay flat:
785
+ depth belongs to held values (`tone.selected` with `elevation.control`).
786
+ - row: a navigation row on a sheet — the role's soft container, full ink and a touch of weight.
787
+ - inTrack: a destination inside a recessed track, or the mark of a track's current stage — a
788
+ pagination's current page, a Stepper's current step. The soft step is the groove's own
789
+ lightness (1.00:1 in light), so there the fill steps up to `selected` and the label
790
+ takes the accent: the label, not the fill, says "you are here". */
791
+ const currentDestination = {
792
+ row: "bg-sherick-primary-soft text-sherick-ink font-medium",
793
+ inTrack: "bg-sherick-primary-selected text-sherick-primary font-semibold",
794
+ };
710
795
  /* Selectable surface — the recessed surface of a control that fills once it is selected: a
711
796
  switch track, a checkbox box, a radio circle, a slider groove. Selection is keyed on the
712
797
  primitive's own `data-checked` / `data-indeterminate`, so an uncontrolled control is styled
@@ -725,15 +810,12 @@ const puck = "bg-sherick-puck";
725
810
  /* A choice row — an opt-in `surface` row in a RadioGroup or CheckboxGroup — rests on the
726
811
  `matteHigh` tray, so every choice in the group reads as a target before any is chosen; it stays
727
812
  light enough that the empty mark's rim still clears 3:1 against it. The row that holds the
728
- selection takes the role's *soft* surface and the accent **selection rim**, and stays flat. The
729
- soft surface is lighter than the resting tray, so the tint alone would make the chosen row the
730
- quieter of the two; the rim is what says "this one". It is the row's selection mark, not an
731
- outline drawn to separate a surface, and it belongs to the selected state only. Like an empty
732
- mark's rim it is an overlay rather than a border, so the fill and the hover layer reach the row's
733
- real edge, and it is transparent rather than absent at rest, so forced colors keeps every row's
734
- outline. The selected step and a lift turned a whole card into an accent block, which outshouted
735
- the priority action on the same view. */
736
- const selectableRowSurface = /* @__PURE__ */ cx("has-[[data-checked]]:bg-sherick-primary-soft has-[[data-checked]]:text-sherick-ink", "after:pointer-events-none after:absolute after:inset-0 after:box-border after:rounded-[inherit] after:border-[1.5px] after:border-transparent after:content-['']", "has-[[data-checked]]:after:border-sherick-primary", motionRim);
813
+ selection takes the role's *soft* surface and stays flat. The mark it houses is what says "this
814
+ one": an accent rim around the row repeated it and made the chosen row the loudest object on a
815
+ quiet form, and the selected step and a lift turned a whole card into an accent block. The
816
+ transparent overlay stays, so forced colors keeps every row's outline, and the fill and the hover
817
+ layer still reach the row's real edge. */
818
+ const selectableRowSurface = /* @__PURE__ */ cx("has-[[data-checked]]:bg-sherick-primary-soft has-[[data-checked]]:text-sherick-ink", "after:pointer-events-none after:absolute after:inset-0 after:box-border after:rounded-[inherit] after:border-[1.5px] after:border-transparent after:content-['']");
737
819
  /* Supporting copy inside such a row — a choice's description. `text.medium` clears 4.5:1 on the
738
820
  soft step at rest (5.7:1 light, 6.2:1 dark), but the row's press layer composites toward the label
739
821
  and takes that margin away, so while the row holds the selection its supporting line takes full
@@ -749,7 +831,7 @@ const selectable = {
749
831
  does. While the wrapping control is held it sinks to the `well`: the floor darkens and the
750
832
  boundary stays exactly where it was, which is how a mark that must not move under the pointer
751
833
  answers a press. */
752
- markSurface: /* @__PURE__ */ cx("relative", elevation.recessed, "group-[:not([data-disabled]):not([data-readonly]):not(:disabled):active]:shadow-sherick-well", motionFeedback),
834
+ markSurface: /* @__PURE__ */ cx("relative", elevation.recessed, "group-[:not([data-disabled]):not([data-readonly]):not([aria-disabled=true]):not(:disabled):active]:shadow-sherick-well", motionFeedback),
753
835
  /* The resting fill a *groove* holds — a segmented control's track, a tab list — and nothing more.
754
836
  A groove that holds labelled segments is identified by those segments, exactly as a tab list is
755
837
  identified by its labels, so it takes no boundary of its own. */
@@ -765,7 +847,7 @@ const selectable = {
765
847
  recess all reach the mark's real edge: a border would leave a 1.5px frame of untinted fill
766
848
  around a hovered selected box. Hover steps the rim to the mid-emphasis tone — darker in light
767
849
  mode, lighter in dark — which is a visible answer on a 20px mark where a tint alone is not. */
768
- mark: /* @__PURE__ */ cx(markWellFill, text.medium, "after:pointer-events-none after:absolute after:inset-0 after:box-border after:rounded-[inherit] after:border-[1.5px] after:content-['']", "after:border-sherick-rim", "group-[:not([data-disabled]):not([data-readonly]):not(:disabled):hover]:after:border-sherick-ink-muted", motionRim),
850
+ mark: /* @__PURE__ */ cx(markWellFill, text.medium, "after:pointer-events-none after:absolute after:inset-0 after:box-border after:rounded-[inherit] after:border-[1.5px] after:content-['']", "after:border-sherick-rim", "[@media(hover:hover)_and_(pointer:fine)]:group-[:not([data-disabled]):not([data-readonly]):not(:disabled):hover]:after:border-sherick-ink-muted", motionRim),
769
851
  /* A selected mark is the strong accent, edge to edge, and it settles flat: it is identified by
770
852
  its fill and its glyph, and the rim fades out as the fill arrives. The rim fades by opacity
771
853
  rather than by colour, so forced colors cannot repaint a transparent rim as a visible one. */
@@ -813,6 +895,11 @@ const recipeAlphas = {
813
895
  neutralSoft: fillAlpha(tone.soft.secondary, "tint.neutralSoft"),
814
896
  neutralRest: fillAlpha(tone.tonal.secondary, "tint.neutralRest"),
815
897
  },
898
+ /* The code well is the `matteHigh` step over the card that holds it, so the contract reads its
899
+ alpha from the same recipe the CodeBlock renders. */
900
+ code: {
901
+ well: fillAlpha(material.matteHigh, "code.well"),
902
+ },
816
903
  field: {
817
904
  quiet: fillAlpha(material.matteQuiet, "field.quiet"),
818
905
  card: fillAlpha(material.matte, "field.card"),
@@ -826,13 +913,28 @@ const recipeAlphas = {
826
913
  };
827
914
  /* A labelled field is a shrinkable column. Its explanatory copy wraps, including identifiers;
828
915
  the input itself keeps its native single-line scrolling behavior. */
829
- const fieldLayout = "flex min-w-0 w-full flex-col [overflow-wrap:anywhere]";
916
+ const fieldLayout = "flex min-w-0 w-full flex-col gap-2 [overflow-wrap:anywhere] [&>label+p]:-mt-1";
830
917
  /* The messages under a field: its description or hint, and its error. One role for every field in
831
918
  the family, so a hint reads the same under a text field, a date range and a file chooser. */
919
+ /* The label above a field: the `label` role at full ink, with the one gap every field family keeps
920
+ between its name and its control. */
921
+ const fieldLabel = /* @__PURE__ */ cx(type.label, text.high);
922
+ /* The field column owns the gap between its parts (`fieldLayout`), so a label, a control and a
923
+ message are each eight pixels from the next, and a label that is followed straight by its
924
+ description takes four through the layout's sibling rule. No part carries its own margin. */
832
925
  const fieldMessage = {
833
- description: /* @__PURE__ */ cx("mt-2", type.supporting, text.medium),
834
- error: /* @__PURE__ */ cx("mt-2", type.supporting, tone.text.danger),
926
+ description: /* @__PURE__ */ cx(type.supporting, text.medium),
927
+ error: /* @__PURE__ */ cx(type.supporting, tone.text.danger),
928
+ };
929
+ /* The code well — the quiet recess a code block's lines sit in. It is the canvas showing through the
930
+ block's own matte shell, so a well reads as sunk into the block on a card and on the page alike. */
931
+ const codeWell = material.matteHigh;
932
+ /* Rich-text accents — content-level emphasis in rendered prose, not structural edges: a quote's rule
933
+ on its start edge, and a link's underline at rest and under the pointer. */
934
+ const richText = {
935
+ quoteRule: "border-sherick-primary/[0.45]",
936
+ linkUnderline: "decoration-sherick-primary/[0.35] hover:decoration-sherick-primary",
835
937
  };
836
938
 
837
- export { currentDestination, density, detail, disclosure, edge, edgeTone, elevation, fieldLayout, fieldMessage, focusRing, focusRingDrag, focusRingHeld, focusRingInset, focusRingWithin, groupFocusRing, hitArea, iconSlot, list, material, matteInset, mediaCanvas, overlay, parentFocusRingInset, puck, recessedTop, recipeAlphas, rim, selectable, selectableRowSupporting, selectableRowSurface, shape, stacking, state, stateLayer, stateLayerQuietComposite, text, tone, type };
939
+ export { codeWell, currentDestination, density, detail, disclosure, edge, edgeTone, elevation, fieldLabel, fieldLayout, fieldMessage, focusRing, focusRingDrag, focusRingHeld, focusRingInset, focusRingWithin, forcedBoundary, groupFocusRing, headingRhythm, hitArea, iconSlot, iconStroke, list, material, matteInset, mediaCanvas, overlay, parentFocusRingInset, puck, recessedTop, recipeAlphas, richText, rim, selectable, selectableRowSupporting, selectableRowSurface, shape, stacking, state, stateLayer, stateLayerQuietComposite, text, tone, type };
838
940
  //# sourceMappingURL=ui.common.js.map