@kerfjs/ui 5.0.0-beta.97 → 5.0.0-beta.99

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 (416) hide show
  1. package/README.md +42 -1
  2. package/ai/application-ui-diagnostic-ids-v1.json +1 -0
  3. package/ai/component-catalog.json +487 -66
  4. package/ai/component-catalog.schema.json +1 -1
  5. package/ai/component-composition-rules.json +22 -2
  6. package/ai/component-composition.json +360 -33
  7. package/ai/component-composition.schema.json +1 -1
  8. package/ai/components/README.md +18 -17
  9. package/ai/components/anchored-surface.md +13 -0
  10. package/ai/components/application-tabs.md +1 -1
  11. package/ai/components/chip.md +9 -5
  12. package/ai/components/choice-chips.md +15 -8
  13. package/ai/components/collapsible-panel.md +3 -2
  14. package/ai/components/composer.md +83 -0
  15. package/ai/components/content-item.md +2 -2
  16. package/ai/components/corner-status.md +1 -1
  17. package/ai/components/document-baseline.md +3 -3
  18. package/ai/components/foundation.md +2 -2
  19. package/ai/components/layout.md +1 -1
  20. package/ai/components/list-action-row.md +5 -1
  21. package/ai/components/list-item.md +5 -1
  22. package/ai/components/list.md +19 -3
  23. package/ai/components/nav-stack.md +11 -2
  24. package/ai/components/pane.md +13 -4
  25. package/ai/components/popup-menu.md +4 -4
  26. package/ai/components/recipe-app-shell.md +3 -3
  27. package/ai/components/recipe-collapsible-sidebar.md +3 -3
  28. package/ai/components/recipe-compact-toolbar.md +1 -1
  29. package/ai/components/recipe-composer-form.md +3 -3
  30. package/ai/components/recipe-list-detail-dialog.md +2 -2
  31. package/ai/components/recipe-list-workspace-states.md +3 -3
  32. package/ai/components/recipe-loading-inspector.md +1 -1
  33. package/ai/components/recipe-navigation-sidebar.md +3 -3
  34. package/ai/components/recipe-navigation-stack.md +3 -3
  35. package/ai/components/recipe-workspace-header.md +3 -3
  36. package/ai/components/resize.md +2 -2
  37. package/ai/components/split-view.md +4 -2
  38. package/ai/components/sunken-panel.md +2 -2
  39. package/ai/components/surface-scaffold.md +15 -3
  40. package/ai/components/tab-bar.md +1 -0
  41. package/ai/components/tab-navigator.md +4 -0
  42. package/ai/components/toolbar-control-group.md +2 -0
  43. package/ai/components/toolbar-text.md +1 -0
  44. package/ai/components/toolbar.md +1 -0
  45. package/ai/components/workbench.md +1 -0
  46. package/ai/public-api-signatures-v1.md +504 -80
  47. package/ai/skill.md +41 -14
  48. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  49. package/analyzer/component-ownership.mjs +1 -1
  50. package/analyzer/index.mjs +41 -14
  51. package/dist/anchored-surface.d.ts +30 -2
  52. package/dist/anchored-surface.js +1 -1
  53. package/dist/app-tab.js +1 -1
  54. package/dist/browser/composer.js +4 -0
  55. package/dist/catalog-resources.d.ts +3 -2
  56. package/dist/catalog-resources.js +4 -4
  57. package/dist/catalog-resources.js.map +1 -1
  58. package/dist/catalog.d.ts +39 -8
  59. package/dist/catalog.js +55 -32
  60. package/dist/catalog.js.map +1 -1
  61. package/dist/chip.d.ts +41 -9
  62. package/dist/chip.js +1 -1
  63. package/dist/choice-chips.d.ts +40 -16
  64. package/dist/choice-chips.js +1 -1
  65. package/dist/chunk-34U4ANDJ.js +119 -0
  66. package/dist/chunk-34U4ANDJ.js.map +1 -0
  67. package/dist/{chunk-36TL6BCR.js → chunk-3GLYIIFR.js} +34 -6
  68. package/dist/chunk-3GLYIIFR.js.map +1 -0
  69. package/dist/{chunk-HWY4BSLS.js → chunk-3VXDSIBJ.js} +2 -2
  70. package/dist/{chunk-HWY4BSLS.js.map → chunk-3VXDSIBJ.js.map} +1 -1
  71. package/dist/chunk-3WYREXW4.js +120 -0
  72. package/dist/chunk-3WYREXW4.js.map +1 -0
  73. package/dist/chunk-AV7CPAPT.js +82 -0
  74. package/dist/chunk-AV7CPAPT.js.map +1 -0
  75. package/dist/{chunk-XK4E225T.js → chunk-B53PS2LE.js} +2 -2
  76. package/dist/{chunk-XK4E225T.js.map → chunk-B53PS2LE.js.map} +1 -1
  77. package/dist/{chunk-R42D2BAO.js → chunk-CA7LNX3J.js} +2 -2
  78. package/dist/{chunk-R42D2BAO.js.map → chunk-CA7LNX3J.js.map} +1 -1
  79. package/dist/{chunk-AYHC62OZ.js → chunk-CMETHPKR.js} +26 -29
  80. package/dist/chunk-CMETHPKR.js.map +1 -0
  81. package/dist/{chunk-Y43B6DS3.js → chunk-CVD5IZGB.js} +2 -2
  82. package/dist/{chunk-Y43B6DS3.js.map → chunk-CVD5IZGB.js.map} +1 -1
  83. package/dist/{chunk-6STQXRT4.js → chunk-CXZXHZTR.js} +121 -12
  84. package/dist/chunk-CXZXHZTR.js.map +1 -0
  85. package/dist/{chunk-GZE2XVKC.js → chunk-DZJ4GBSP.js} +3 -3
  86. package/dist/{chunk-GZE2XVKC.js.map → chunk-DZJ4GBSP.js.map} +1 -1
  87. package/dist/chunk-ELCMSQNJ.js +49 -0
  88. package/dist/chunk-ELCMSQNJ.js.map +1 -0
  89. package/dist/{chunk-P74VXMB6.js → chunk-EOO6PYGF.js} +7 -14
  90. package/dist/chunk-EOO6PYGF.js.map +1 -0
  91. package/dist/{chunk-PRG4CL3Q.js → chunk-FR76ZJQC.js} +21 -19
  92. package/dist/chunk-FR76ZJQC.js.map +1 -0
  93. package/dist/{chunk-QQ3TTWFH.js → chunk-G3J7JDP6.js} +1 -1
  94. package/dist/{chunk-QQ3TTWFH.js.map → chunk-G3J7JDP6.js.map} +1 -1
  95. package/dist/{chunk-IGTWXPTN.js → chunk-HGV7J4T6.js} +3 -3
  96. package/dist/{chunk-IGTWXPTN.js.map → chunk-HGV7J4T6.js.map} +1 -1
  97. package/dist/{chunk-YWQGSUF2.js → chunk-HLDRH23D.js} +3 -3
  98. package/dist/{chunk-YWQGSUF2.js.map → chunk-HLDRH23D.js.map} +1 -1
  99. package/dist/{chunk-PBT3CPPY.js → chunk-HQZYKJ56.js} +24 -4
  100. package/dist/chunk-HQZYKJ56.js.map +1 -0
  101. package/dist/{chunk-V6W56V3N.js → chunk-HZPHCSCS.js} +16 -3
  102. package/dist/chunk-HZPHCSCS.js.map +1 -0
  103. package/dist/{chunk-GJYQ27C2.js → chunk-INI4WDWC.js} +8 -1
  104. package/dist/chunk-INI4WDWC.js.map +1 -0
  105. package/dist/{chunk-U657IHFB.js → chunk-IQSRHXZR.js} +10 -4
  106. package/dist/chunk-IQSRHXZR.js.map +1 -0
  107. package/dist/{chunk-KQDU7Z7P.js → chunk-K4AT3V3J.js} +2 -1
  108. package/dist/chunk-K4AT3V3J.js.map +1 -0
  109. package/dist/{chunk-QIAPOWHH.js → chunk-KCS6NJ3O.js} +2 -2
  110. package/dist/{chunk-QIAPOWHH.js.map → chunk-KCS6NJ3O.js.map} +1 -1
  111. package/dist/{chunk-UKKRPP56.js → chunk-LOSRXZAH.js} +2 -2
  112. package/dist/{chunk-UKKRPP56.js.map → chunk-LOSRXZAH.js.map} +1 -1
  113. package/dist/{chunk-ROZLJULF.js → chunk-MF6ZUUJZ.js} +8 -3
  114. package/dist/chunk-MF6ZUUJZ.js.map +1 -0
  115. package/dist/{chunk-6IVNMC6R.js → chunk-MHMWQ7RB.js} +2 -2
  116. package/dist/{chunk-6IVNMC6R.js.map → chunk-MHMWQ7RB.js.map} +1 -1
  117. package/dist/{chunk-JYD7G4RG.js → chunk-PIVY32AE.js} +15 -5
  118. package/dist/chunk-PIVY32AE.js.map +1 -0
  119. package/dist/{chunk-BU23Z5HZ.js → chunk-PYBBYSZ3.js} +13 -18
  120. package/dist/chunk-PYBBYSZ3.js.map +1 -0
  121. package/dist/chunk-QDSZTQXL.js +28 -0
  122. package/dist/chunk-QDSZTQXL.js.map +1 -0
  123. package/dist/{chunk-YXOMI7ES.js → chunk-QIG4IGUP.js} +2 -2
  124. package/dist/{chunk-YXOMI7ES.js.map → chunk-QIG4IGUP.js.map} +1 -1
  125. package/dist/{chunk-6BRRUPJY.js → chunk-QROYYGWU.js} +3 -3
  126. package/dist/chunk-QROYYGWU.js.map +1 -0
  127. package/dist/{chunk-FOQK4F3L.js → chunk-RHD7RKGI.js} +28 -7
  128. package/dist/chunk-RHD7RKGI.js.map +1 -0
  129. package/dist/{chunk-BBU2SPRE.js → chunk-T4WJ5VGP.js} +4 -4
  130. package/dist/{chunk-BBU2SPRE.js.map → chunk-T4WJ5VGP.js.map} +1 -1
  131. package/dist/{chunk-6NOLL5KG.js → chunk-TGLUDQP2.js} +3 -3
  132. package/dist/{chunk-6NOLL5KG.js.map → chunk-TGLUDQP2.js.map} +1 -1
  133. package/dist/{chunk-HO6FU3G7.js → chunk-TLMMFQWM.js} +4 -4
  134. package/dist/{chunk-HO6FU3G7.js.map → chunk-TLMMFQWM.js.map} +1 -1
  135. package/dist/chunk-UMKV7YVQ.js +20 -0
  136. package/dist/chunk-UMKV7YVQ.js.map +1 -0
  137. package/dist/{chunk-M2NRCFRO.js → chunk-VFYO3UGZ.js} +2 -2
  138. package/dist/{chunk-M2NRCFRO.js.map → chunk-VFYO3UGZ.js.map} +1 -1
  139. package/dist/{chunk-YOKEL75M.js → chunk-WVS6CUCT.js} +2 -2
  140. package/dist/{chunk-YOKEL75M.js.map → chunk-WVS6CUCT.js.map} +1 -1
  141. package/dist/{chunk-MN3POJFN.js → chunk-YMUIQRWK.js} +2 -2
  142. package/dist/{chunk-MN3POJFN.js.map → chunk-YMUIQRWK.js.map} +1 -1
  143. package/dist/{chunk-Y3LC7JQO.js → chunk-YOA5W5ZH.js} +2 -2
  144. package/dist/{chunk-Y3LC7JQO.js.map → chunk-YOA5W5ZH.js.map} +1 -1
  145. package/dist/{chunk-44A6LP54.js → chunk-YQ2AC4E2.js} +2 -2
  146. package/dist/{chunk-44A6LP54.js.map → chunk-YQ2AC4E2.js.map} +1 -1
  147. package/dist/chunk-ZNROKDSZ.js +54 -0
  148. package/dist/chunk-ZNROKDSZ.js.map +1 -0
  149. package/dist/collapsible-panel.d.ts +3 -2
  150. package/dist/collapsible-panel.js +4 -3
  151. package/dist/collapsible-panel.js.map +1 -1
  152. package/dist/composer.d.ts +62 -0
  153. package/dist/composer.js +5 -0
  154. package/dist/composer.js.map +1 -0
  155. package/dist/corner-status.d.ts +1 -1
  156. package/dist/corner-status.js +1 -1
  157. package/dist/css-values.d.ts +9 -1
  158. package/dist/css-values.js +1 -1
  159. package/dist/disclosure-arrow.js +1 -1
  160. package/dist/empty-state.js +1 -1
  161. package/dist/grid.js +1 -1
  162. package/dist/icon-button.js +1 -1
  163. package/dist/icon-toggle-button.js +1 -1
  164. package/dist/index.d.ts +10 -5
  165. package/dist/index.js +40 -37
  166. package/dist/list-action-row.d.ts +10 -2
  167. package/dist/list-action-row.js +1 -1
  168. package/dist/list-header.js +1 -1
  169. package/dist/list-icon-tile-B8dr97OW.d.ts +18 -0
  170. package/dist/list-item.d.ts +10 -3
  171. package/dist/list-item.js +1 -1
  172. package/dist/list.d.ts +36 -4
  173. package/dist/list.js +1 -1
  174. package/dist/loading-spinner.js +1 -1
  175. package/dist/lucide-icon.js +1 -1
  176. package/dist/{nav-stack-BvSKY448.d.ts → nav-stack-VXTumzKa.d.ts} +53 -4
  177. package/dist/nav-stack.d.ts +3 -2
  178. package/dist/nav-stack.js +2 -1
  179. package/dist/pane.d.ts +40 -3
  180. package/dist/pane.js +1 -1
  181. package/dist/{panel-toolbar-CL9tYOkh.d.ts → panel-toolbar-vg6Ir5Dy.d.ts} +6 -1
  182. package/dist/popup-menu-register.d.ts +2 -1
  183. package/dist/popup-menu-register.js +97 -22
  184. package/dist/popup-menu-register.js.map +1 -1
  185. package/dist/popup-menu.js +1 -1
  186. package/dist/row.js +1 -1
  187. package/dist/scroll-clearance-BikHljTc.d.ts +14 -0
  188. package/dist/select-register.js +11 -0
  189. package/dist/select-register.js.map +1 -1
  190. package/dist/select.js +1 -1
  191. package/dist/skeleton.js +1 -1
  192. package/dist/spacer.js +1 -1
  193. package/dist/split-button.js +1 -1
  194. package/dist/split-view.d.ts +7 -5
  195. package/dist/split-view.js +6 -3
  196. package/dist/split-view.js.map +1 -1
  197. package/dist/state-banner.d.ts +6 -1
  198. package/dist/state-banner.js +1 -1
  199. package/dist/styles/anchored-surface.css +27 -1
  200. package/dist/styles/catalog/components/catalog-example-stack.css +5 -0
  201. package/dist/styles/catalog/components/catalog-example.css +33 -0
  202. package/dist/styles/catalog/components/catalog-stage.css +7 -0
  203. package/dist/styles/chip.css +70 -0
  204. package/dist/styles/components/actions/popup-menu/popup-menu.css +21 -4
  205. package/dist/styles/components/actions/toolbar/toolbar.css +19 -0
  206. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +75 -1
  207. package/dist/styles/components/actions/toolbar-text/toolbar-text.css +75 -0
  208. package/dist/styles/components/collections/list/list.css +77 -7
  209. package/dist/styles/components/collections/list-action-row/list-action-row.css +177 -22
  210. package/dist/styles/components/collections/list-item/list-item.css +158 -11
  211. package/dist/styles/components/feedback/anchored-surface/anchored-surface.css +27 -1
  212. package/dist/styles/components/feedback/chip/chip.css +70 -0
  213. package/dist/styles/components/feedback/state-banner/state-banner.css +24 -13
  214. package/dist/styles/components/forms/composer/composer.css +100 -0
  215. package/dist/styles/components/forms/select/select.css +1 -0
  216. package/dist/styles/components/forms/token-search-field/token-search-field.css +13 -2
  217. package/dist/styles/components/layout/pane/pane.css +81 -2
  218. package/dist/styles/components/navigation/nav-stack/nav-stack.css +84 -0
  219. package/dist/styles/components/navigation/tab-bar/tab-bar.css +15 -4
  220. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +79 -4
  221. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +195 -0
  222. package/dist/styles/composer.css +100 -0
  223. package/dist/styles/foundation.css +66 -0
  224. package/dist/styles/list-action-row.css +177 -22
  225. package/dist/styles/list-item.css +158 -11
  226. package/dist/styles/list.css +77 -7
  227. package/dist/styles/nav-stack.css +84 -0
  228. package/dist/styles/pane.css +81 -2
  229. package/dist/styles/popup-menu.css +21 -4
  230. package/dist/styles/select.css +1 -0
  231. package/dist/styles/state-banner.css +24 -13
  232. package/dist/styles/styles.css +1 -0
  233. package/dist/styles/surface-scaffold.css +195 -0
  234. package/dist/styles/tab-bar.css +15 -4
  235. package/dist/styles/tab-navigator.css +79 -4
  236. package/dist/styles/token-search-field.css +13 -2
  237. package/dist/styles/toolbar-control-group.css +75 -1
  238. package/dist/styles/toolbar-text.css +75 -0
  239. package/dist/styles/toolbar.css +19 -0
  240. package/dist/styles/webawesome.css +18 -0
  241. package/dist/surface-scaffold-register.d.ts +6 -1
  242. package/dist/surface-scaffold-register.js +89 -3
  243. package/dist/surface-scaffold-register.js.map +1 -1
  244. package/dist/surface-scaffold.d.ts +66 -7
  245. package/dist/surface-scaffold.js +1 -1
  246. package/dist/tab-navigator.d.ts +23 -2
  247. package/dist/tab-navigator.js +2 -0
  248. package/dist/tab-navigator.js.map +1 -1
  249. package/dist/token-search-field.d.ts +1 -1
  250. package/dist/token-search-field.js +1 -1
  251. package/dist/{token-search-model-DTcTXWMS.d.ts → token-search-model-aYR0YAei.d.ts} +32 -2
  252. package/dist/token-search-model.d.ts +1 -1
  253. package/dist/toolbar-control-group.js +1 -1
  254. package/dist/toolbar-text.js +1 -1
  255. package/dist/toolbar.d.ts +1 -0
  256. package/dist/value-table.js +1 -1
  257. package/dist/wire-catalog.d.ts +3 -2
  258. package/dist/wire-catalog.js +2 -2
  259. package/dist/wire-composers.d.ts +16 -0
  260. package/dist/wire-composers.js +3 -0
  261. package/dist/wire-composers.js.map +1 -0
  262. package/dist/wire-list-focus-scroll.d.ts +16 -0
  263. package/dist/wire-list-focus-scroll.js +3 -0
  264. package/dist/wire-list-focus-scroll.js.map +1 -0
  265. package/dist/wire-nav-stack.js +135 -0
  266. package/dist/wire-nav-stack.js.map +1 -1
  267. package/dist/wire-scroll-dividers.d.ts +9 -0
  268. package/dist/wire-scroll-dividers.js +1 -1
  269. package/dist/wire-tab-bars.js +1 -1
  270. package/dist/wire-tab-navigator.d.ts +3 -1
  271. package/dist/wire-tab-navigator.js +133 -1
  272. package/dist/wire-tab-navigator.js.map +1 -1
  273. package/dist/wire-token-search-fields.d.ts +1 -1
  274. package/dist/wire-token-search-fields.js +1 -1
  275. package/dist/workbench.d.ts +8 -3
  276. package/dist/workbench.js +2 -1
  277. package/docs/accessibility.md +132 -3
  278. package/docs/anchored-surface.md +46 -4
  279. package/docs/app-layouts.md +23 -2
  280. package/docs/apple-hig.md +1 -0
  281. package/docs/catalog.md +61 -9
  282. package/docs/collapsible-panel.md +9 -6
  283. package/docs/component-contract.md +46 -13
  284. package/docs/component-selection.md +147 -20
  285. package/docs/composer.md +143 -0
  286. package/docs/design/templates/choice-chips/multiple-dark.svg +1 -0
  287. package/docs/design/templates/choice-chips/multiple.svg +1 -0
  288. package/docs/design/templates/choice-chips-dark.svg +1 -1
  289. package/docs/design/templates/choice-chips.svg +1 -1
  290. package/docs/design/templates/composer/chat-dark.svg +1 -0
  291. package/docs/design/templates/composer/chat.svg +1 -0
  292. package/docs/design/templates/composer/prompt-dark.svg +1 -0
  293. package/docs/design/templates/composer/prompt.svg +1 -0
  294. package/docs/design/templates/composer-dark.svg +1 -0
  295. package/docs/design/templates/composer.svg +1 -0
  296. package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
  297. package/docs/design/templates/empty-state/filtered.svg +1 -1
  298. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  299. package/docs/design/templates/empty-state/with-action.svg +1 -1
  300. package/docs/design/templates/empty-state-dark.svg +1 -1
  301. package/docs/design/templates/empty-state.svg +1 -1
  302. package/docs/design/templates/list/compact-dark.svg +1 -1
  303. package/docs/design/templates/list/compact.svg +1 -1
  304. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  305. package/docs/design/templates/list-action-row/default.svg +1 -1
  306. package/docs/design/templates/list-action-row/icon-tile-dark.svg +1 -0
  307. package/docs/design/templates/list-action-row/icon-tile.svg +1 -0
  308. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  309. package/docs/design/templates/list-action-row/selected.svg +1 -1
  310. package/docs/design/templates/list-action-row/trailing-menu-dark.svg +1 -1
  311. package/docs/design/templates/list-action-row/trailing-menu.svg +1 -1
  312. package/docs/design/templates/list-action-row-dark.svg +1 -1
  313. package/docs/design/templates/list-action-row.svg +1 -1
  314. package/docs/design/templates/list-dark.svg +1 -1
  315. package/docs/design/templates/list-header/size-l-dark.svg +1 -1
  316. package/docs/design/templates/list-header/size-l.svg +1 -1
  317. package/docs/design/templates/list-header/size-m-dark.svg +1 -1
  318. package/docs/design/templates/list-header/size-m.svg +1 -1
  319. package/docs/design/templates/list-header/size-xl-dark.svg +1 -1
  320. package/docs/design/templates/list-header/size-xl.svg +1 -1
  321. package/docs/design/templates/list-header-dark.svg +1 -1
  322. package/docs/design/templates/list-header.svg +1 -1
  323. package/docs/design/templates/list-item/icon-tile-dark.svg +1 -0
  324. package/docs/design/templates/list-item/icon-tile.svg +1 -0
  325. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  326. package/docs/design/templates/list-item/selected.svg +1 -1
  327. package/docs/design/templates/list-item-dark.svg +1 -1
  328. package/docs/design/templates/list-item.svg +1 -1
  329. package/docs/design/templates/list.svg +1 -1
  330. package/docs/design/templates/segmented-control-dark.svg +1 -1
  331. package/docs/design/templates/segmented-control.svg +1 -1
  332. package/docs/design/templates/skeleton-dark.svg +1 -1
  333. package/docs/design/templates/skeleton.svg +1 -1
  334. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  335. package/docs/design/templates/state-banner/danger.svg +1 -1
  336. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
  337. package/docs/design/templates/state-banner/info-badge.svg +1 -1
  338. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  339. package/docs/design/templates/state-banner/info.svg +1 -1
  340. package/docs/design/templates/state-banner/strip-dark.svg +1 -1
  341. package/docs/design/templates/state-banner/strip.svg +1 -1
  342. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  343. package/docs/design/templates/state-banner/success.svg +1 -1
  344. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  345. package/docs/design/templates/state-banner/warning.svg +1 -1
  346. package/docs/design/templates/state-banner-dark.svg +1 -1
  347. package/docs/design/templates/state-banner.svg +1 -1
  348. package/docs/design/templates/tab-bar-dark.svg +1 -1
  349. package/docs/design/templates/tab-bar.svg +1 -1
  350. package/docs/design/templates/token-search-field-dark.svg +1 -1
  351. package/docs/design/templates/token-search-field.svg +1 -1
  352. package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
  353. package/docs/design/templates/toolbar-control-group.svg +1 -1
  354. package/docs/design/templates/toolbar-dark.svg +1 -1
  355. package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
  356. package/docs/design/templates/toolbar-text/default.svg +1 -1
  357. package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
  358. package/docs/design/templates/toolbar-text/large.svg +1 -1
  359. package/docs/design/templates/toolbar-text-dark.svg +1 -1
  360. package/docs/design/templates/toolbar-text.svg +1 -1
  361. package/docs/design/templates/toolbar.svg +1 -1
  362. package/docs/design/templates/value-table/details-dark.svg +1 -1
  363. package/docs/design/templates/value-table/details.svg +1 -1
  364. package/docs/design/templates/value-table-dark.svg +1 -1
  365. package/docs/design/templates/value-table.svg +1 -1
  366. package/docs/design-philosophy.md +9 -1
  367. package/docs/examples/command-palette-adapter.tsx +3 -3
  368. package/docs/layout.md +147 -14
  369. package/docs/nav-stack.md +132 -8
  370. package/docs/recipes.md +9 -9
  371. package/docs/split-view.md +3 -3
  372. package/docs/sunken-panel.md +2 -2
  373. package/docs/surface-scaffold.md +138 -7
  374. package/docs/tab-navigator.md +38 -1
  375. package/docs/type-contracts.md +16 -16
  376. package/docs/ui-analyzer.md +3 -1
  377. package/docs/ui-doctor.md +71 -0
  378. package/docs/ux-demo.md +6 -6
  379. package/docs/webawesome-theme.md +7 -0
  380. package/docs/workbench.md +10 -6
  381. package/docs/writing.md +152 -0
  382. package/doctor/copy-capitalization-checks.mjs +591 -0
  383. package/doctor/index.mjs +17 -8
  384. package/llms.txt +105 -11
  385. package/package.json +15 -1
  386. package/ux-demo/recipes/app-shell.tsx +11 -11
  387. package/ux-demo/recipes/collapsible-sidebar.tsx +12 -11
  388. package/ux-demo/recipes/compact-toolbar.tsx +10 -10
  389. package/ux-demo/recipes/composer-form.tsx +8 -8
  390. package/ux-demo/recipes/list-detail-dialog.tsx +13 -13
  391. package/ux-demo/recipes/list-workspace-states.tsx +13 -13
  392. package/ux-demo/recipes/loading-inspector.tsx +10 -10
  393. package/ux-demo/recipes/navigation-sidebar.tsx +7 -7
  394. package/ux-demo/recipes/navigation-stack.tsx +5 -5
  395. package/ux-demo/recipes/workspace-header.tsx +5 -5
  396. package/dist/chunk-36TL6BCR.js.map +0 -1
  397. package/dist/chunk-4LOK4634.js +0 -21
  398. package/dist/chunk-4LOK4634.js.map +0 -1
  399. package/dist/chunk-6BRRUPJY.js.map +0 -1
  400. package/dist/chunk-6STQXRT4.js.map +0 -1
  401. package/dist/chunk-76PWEN5Y.js +0 -64
  402. package/dist/chunk-76PWEN5Y.js.map +0 -1
  403. package/dist/chunk-AYHC62OZ.js.map +0 -1
  404. package/dist/chunk-BU23Z5HZ.js.map +0 -1
  405. package/dist/chunk-DQDTZE4W.js +0 -70
  406. package/dist/chunk-DQDTZE4W.js.map +0 -1
  407. package/dist/chunk-FOQK4F3L.js.map +0 -1
  408. package/dist/chunk-GJYQ27C2.js.map +0 -1
  409. package/dist/chunk-JYD7G4RG.js.map +0 -1
  410. package/dist/chunk-KQDU7Z7P.js.map +0 -1
  411. package/dist/chunk-P74VXMB6.js.map +0 -1
  412. package/dist/chunk-PBT3CPPY.js.map +0 -1
  413. package/dist/chunk-PRG4CL3Q.js.map +0 -1
  414. package/dist/chunk-ROZLJULF.js.map +0 -1
  415. package/dist/chunk-U657IHFB.js.map +0 -1
  416. package/dist/chunk-V6W56V3N.js.map +0 -1
@@ -188,6 +188,90 @@
188
188
  position: relative;
189
189
  }
190
190
 
191
+ /* `chromePresentation="overlay"`: the top chrome (and any copy cross-fading
192
+ out of it) paints the translucent chrome material (opaque under reduced
193
+ transparency or increased contrast, without `backdrop-filter`, or in
194
+ forced colors). Once `wireNavStack` has measured the live chrome
195
+ (`data-chrome-overlay="measured"`, with its border-box block size, top
196
+ safe area included, published on this root), the chrome lies over the
197
+ viewport's top edge and the viewport hands that size to its views as the
198
+ block-start edge context, so a plain view, a sole Pane, or a nested layout
199
+ pads and scroll-pads by it: content scrolls beneath the chrome yet rests
200
+ clear of it. Unwired, the chrome stays docked in its own band, so it never
201
+ covers content it has not measured. */
202
+ .kui-nav-stack[data-chrome-presentation="overlay"] > .kui-nav-stack__chrome {
203
+ -webkit-backdrop-filter: var(--kui-chrome-material-filter);
204
+ backdrop-filter: var(--kui-chrome-material-filter);
205
+ background: var(--kui-chrome-material);
206
+ }
207
+
208
+ .kui-nav-stack[data-chrome-presentation="overlay"][data-chrome-overlay="measured"]
209
+ > .kui-nav-stack__chrome:not(.kui-nav-stack__chrome-copy) {
210
+ position: absolute;
211
+ z-index: 2;
212
+ inset-block-start: 0;
213
+ /* A classic (space-taking) vertical scrollbar in the active view stays
214
+ uncovered: `wireNavStack` publishes its inline size, so the chrome ends
215
+ where the track begins and its thumb and arrows stay usable. An overlay
216
+ scrollbar takes no space and passes beneath the material like the
217
+ content. */
218
+ inset-inline: 0 var(--_kui-nav-stack-scrollbar-inline-size, 0px);
219
+ }
220
+
221
+ .kui-nav-stack[data-chrome-presentation="overlay"][data-chrome-overlay="measured"]
222
+ > .kui-nav-stack__viewport {
223
+ --kui-edge-inset-block-start: var(--_kui-nav-stack-chrome-block-size, 0px);
224
+ }
225
+
226
+ /* `bottomToolbarPresentation="overlay"`: the bottom toolbar (and any copy
227
+ cross-fading out of it) paints the same material. Once `wireNavStack` has
228
+ measured the live toolbar (`data-bottom-toolbar-overlay="measured"`, with
229
+ its border-box block size, bottom safe area and scroll-divider border
230
+ included, published on this root), the toolbar lies over the viewport's
231
+ bottom edge and the viewport hands that size to its views as the
232
+ block-end edge context (outranking the docked rule above that zeroes it),
233
+ so a plain view, a sole Pane's content or footer, or a nested layout pads
234
+ and scroll-pads by it: content scrolls beneath the toolbar yet its last
235
+ item rests clear of it. Unwired, the toolbar stays docked. */
236
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"]
237
+ > .kui-nav-stack__bottom {
238
+ -webkit-backdrop-filter: var(--kui-chrome-material-filter);
239
+ backdrop-filter: var(--kui-chrome-material-filter);
240
+ background: var(--kui-chrome-material);
241
+ }
242
+
243
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"][data-bottom-toolbar-overlay="measured"]
244
+ > .kui-nav-stack__bottom:not(.kui-nav-stack__chrome-copy) {
245
+ position: absolute;
246
+ z-index: 2;
247
+ inset-block-end: 0;
248
+ /* Like the top chrome, it ends where a classic scrollbar's track begins. */
249
+ inset-inline: 0 var(--_kui-nav-stack-bottom-scrollbar-inline-size, 0px);
250
+ }
251
+
252
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"][data-bottom-toolbar-overlay="measured"]
253
+ > .kui-nav-stack__viewport {
254
+ --kui-edge-inset-block-end: var(--_kui-nav-stack-bottom-block-size, 0px);
255
+ }
256
+
257
+ @media (forced-colors: active) {
258
+ .kui-nav-stack[data-chrome-presentation="overlay"] > .kui-nav-stack__chrome {
259
+ -webkit-backdrop-filter: none;
260
+ backdrop-filter: none;
261
+ background: Canvas;
262
+ border-block-end: 1px solid CanvasText;
263
+ }
264
+
265
+ /* Its always-present 1px top border becomes the visible edge. */
266
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"]
267
+ > .kui-nav-stack__bottom {
268
+ -webkit-backdrop-filter: none;
269
+ backdrop-filter: none;
270
+ background: Canvas;
271
+ border-block-start-color: CanvasText;
272
+ }
273
+ }
274
+
191
275
  /* Chrome dividers: with `chromeDividers="scroll"` (the default, no
192
276
  attribute) the top chrome draws a line along its bottom edge while the
193
277
  active view's content is scrolled beneath it, and the bottom toolbar
@@ -159,14 +159,17 @@
159
159
  --kui-pane-content-inset-inline-start: var(--_kui-pane-safe-inline-start);
160
160
  --kui-pane-content-inset-inline-end: var(--_kui-pane-safe-inline-end);
161
161
  --_kui-pane-deep-block-inset: 0px;
162
+ --_kui-pane-clearance-block-start: 0px;
163
+ --_kui-pane-clearance-block-end: 0px;
162
164
  --_kui-pane-content-safe-block-start: var(--_kui-pane-safe-block-start);
163
165
  --_kui-pane-content-safe-block-end: var(--_kui-pane-safe-block-end);
164
166
  --_kui-pane-content-block-start: calc(
165
167
  var(--_kui-pane-content-safe-block-start) +
166
- var(--_kui-pane-deep-block-inset)
168
+ var(--_kui-pane-deep-block-inset) + var(--_kui-pane-clearance-block-start)
167
169
  );
168
170
  --_kui-pane-content-block-end: calc(
169
- var(--_kui-pane-content-safe-block-end) + var(--_kui-pane-deep-block-inset)
171
+ var(--_kui-pane-content-safe-block-end) +
172
+ var(--_kui-pane-deep-block-inset) + var(--_kui-pane-clearance-block-end)
170
173
  );
171
174
  min-width: 0;
172
175
  min-height: 0;
@@ -184,6 +187,82 @@
184
187
  var(--_kui-pane-content-block-end);
185
188
  }
186
189
 
190
+ /* `scrollClearance`: chrome lying over the content's block edge (a dialog's
191
+ floating footer) publishes how far it covers that edge through the
192
+ inherited `--kui-scroll-clearance-block-*` context. The content scroller
193
+ adds it to the block padding and scroll padding above, so content scrolls
194
+ visibly beneath that chrome yet its first and last items can always rest
195
+ clear of it. */
196
+ .kui-pane:is(
197
+ [data-scroll-clearance="block-start"],
198
+ [data-scroll-clearance="both"]
199
+ )
200
+ > .kui-pane__content {
201
+ --_kui-pane-clearance-block-start: var(
202
+ --kui-scroll-clearance-block-start,
203
+ 0px
204
+ );
205
+ }
206
+
207
+ .kui-pane:is(
208
+ [data-scroll-clearance="block-end"],
209
+ [data-scroll-clearance="both"]
210
+ )
211
+ > .kui-pane__content {
212
+ --_kui-pane-clearance-block-end: var(--kui-scroll-clearance-block-end, 0px);
213
+ }
214
+
215
+ /* `headerPresentation="overlay"`: the header paints the translucent chrome
216
+ material (opaque under reduced transparency, without `backdrop-filter`, or
217
+ in forced colors). Once `wireScrollDividers` has measured it
218
+ (`data-header-overlay="measured"`, with its border-box height published as
219
+ `--kui-scroll-clearance-block-start` on this root), the header moves into
220
+ the content cell above the scroller, and the scroller clears it through
221
+ the same block padding and scroll padding `scrollClearance` uses, and the
222
+ header leaves a classic scrollbar uncovered. Unwired,
223
+ or with `chromePlacement="auto"`, the header stays docked in its own row,
224
+ so it never covers content it has not measured. */
225
+ .kui-pane[data-header-presentation="overlay"] > .kui-pane__header {
226
+ -webkit-backdrop-filter: var(--kui-chrome-material-filter);
227
+ backdrop-filter: var(--kui-chrome-material-filter);
228
+ background: var(--kui-chrome-material);
229
+ }
230
+
231
+ .kui-pane[data-header-presentation="overlay"][data-header-overlay="measured"]:not(
232
+ [data-chrome-placement="auto"]
233
+ )
234
+ > .kui-pane__header {
235
+ position: relative;
236
+ z-index: 1;
237
+ align-self: start;
238
+ grid-area: content;
239
+ /* A classic (space-taking) vertical scrollbar stays uncovered: the wiring
240
+ publishes its inline size, so the header ends where the scrollbar's
241
+ track begins and its thumb and arrow buttons stay visible and usable.
242
+ An overlay scrollbar takes no space and leaves this unset, so it passes
243
+ beneath the material like the content. */
244
+ margin-inline-end: var(--kui-pane-scrollbar-inline-size, 0px);
245
+ }
246
+
247
+ .kui-pane[data-header-presentation="overlay"][data-header-overlay="measured"]:not(
248
+ [data-chrome-placement="auto"]
249
+ )
250
+ > .kui-pane__content {
251
+ --_kui-pane-clearance-block-start: var(
252
+ --kui-scroll-clearance-block-start,
253
+ 0px
254
+ );
255
+ }
256
+
257
+ @media (forced-colors: active) {
258
+ .kui-pane[data-header-presentation="overlay"] > .kui-pane__header {
259
+ -webkit-backdrop-filter: none;
260
+ backdrop-filter: none;
261
+ background: Canvas;
262
+ border-block-end: 1px solid CanvasText;
263
+ }
264
+ }
265
+
187
266
  /* Add one outer gutter without changing the inherited item-margin token.
188
267
  Nested Row, List, and Grid therefore keep their own default 8px insets. */
189
268
  .kui-pane[data-deep-inset="true"] > .kui-pane__content {
@@ -13,7 +13,9 @@
13
13
 
14
14
  /* PopupMenu shares the Select's caret motion, surface inset, row rhythm,
15
15
  current-row fill, and group titles from the popup-choice contract in
16
- foundation.css. Only checkbox items reserve a check column. */
16
+ foundation.css. Checkbox items reserve a check column, and so do the
17
+ plain items in any level that holds one; a level without a choice keeps the
18
+ compact start. */
17
19
 
18
20
  /* The trigger caret turns to face the open menu, like the Select's. */
19
21
  .kui-popup-menu > wa-button::part(caret) {
@@ -28,10 +30,17 @@
28
30
  90%. Holding the scale leaves the shared fade. */
29
31
  .kui-popup-menu::part(menu) {
30
32
  padding: var(--_kui-popup-inset);
33
+ background: var(--_kui-popup-scroll-cue);
31
34
  gap: var(--_kui-popup-row-gap);
32
35
  scale: none !important;
33
36
  }
34
37
 
38
+ /* A submenu capped beside its parent menu (a phone placement) scrolls with
39
+ the same edge cue as the menu and a Select's listbox. */
40
+ .kui-popup-menu wa-dropdown-item::part(submenu) {
41
+ background: var(--_kui-popup-scroll-cue);
42
+ }
43
+
35
44
  .kui-popup-menu wa-dropdown-item {
36
45
  /* A plain command starts at the checkbox glyph's leading edge. The glyph
37
46
  sits half a smaller-font em beyond the row's base inset; its label starts
@@ -49,13 +58,21 @@
49
58
  );
50
59
  }
51
60
  /* Web Awesome's nested submenu owns its item host padding. Move its exposed
52
- checkmark inside the panel and leave room for the label beside it. */
61
+ checkmark inside the panel: in flow, the checkmark and its gap advance the
62
+ row's content by the same check column as at the top level. */
53
63
  .kui-popup-menu
54
64
  wa-dropdown-item[slot="submenu"][type="checkbox"]::part(checkmark) {
55
65
  margin-inline-start: 0;
56
66
  }
57
- .kui-popup-menu wa-dropdown-item[slot="submenu"][type="checkbox"]::part(label) {
58
- padding-inline-start: 1em;
67
+ /* A plain item beside checkbox choices holds their check column with an empty
68
+ icon-slot spacer, at either level. Web Awesome sizes a slotted icon in its
69
+ smaller font and spaces it 0.75em (!important) from the next item; with
70
+ that gap, 1em of width equals the 1.25em checkmark plus its 0.5em gap. */
71
+ .kui-popup-menu__check-space {
72
+ display: block;
73
+ width: 1em;
74
+ height: 1px;
75
+ flex: none;
59
76
  }
60
77
  .kui-popup-menu wa-dropdown-item::part(label) {
61
78
  padding-block: var(--_kui-popup-row-label-padding-block);
@@ -213,6 +213,7 @@
213
213
  }
214
214
  .kui-select::part(listbox) {
215
215
  padding: var(--_kui-popup-inset);
216
+ background: var(--_kui-popup-scroll-cue);
216
217
  width: max-content;
217
218
  min-width: 100%;
218
219
  max-width: min(20rem, calc(100vw - 1.25rem));
@@ -29,7 +29,16 @@
29
29
  --kui-state-banner-action-hover-background,
30
30
  var(--kui-color-surface)
31
31
  );
32
- display: grid;
32
+ /* A wrapping flex row, not a three-track grid: a trailing action stays
33
+ beside the copy only while the copy keeps its minimum readable width,
34
+ then wraps onto its own trailing row. The decision follows the banner's
35
+ own width and content, so it holds on a phone, in a narrow rail on a wide
36
+ screen, and in an intrinsically sized host such as CornerStatus, where a
37
+ container query's size containment would collapse the banner. A grid
38
+ gave the action an `auto` track at its full width and squeezed the copy
39
+ until its words ran under the action. */
40
+ display: flex;
41
+ flex-wrap: wrap;
33
42
  min-height: 2.75rem;
34
43
  margin-inline: var(--kui-layout-inline-margin, 0.5rem);
35
44
  padding: var(--kui-layout-item-padding, 0.5rem);
@@ -37,7 +46,6 @@
37
46
  border-radius: var(--kui-layout-rounded-radius, calc(1px + 0.6875rem));
38
47
  color: var(--_kui-state-banner-foreground);
39
48
  background: var(--_kui-state-banner-background);
40
- grid-template-columns: auto minmax(0, 1fr) auto;
41
49
  align-items: center;
42
50
  gap: var(--kui-layout-item-gap, 0.5rem);
43
51
  }
@@ -175,6 +183,7 @@
175
183
  }
176
184
  .kui-state-banner__icon {
177
185
  display: grid;
186
+ flex: none;
178
187
  place-items: center;
179
188
  }
180
189
  .kui-state-banner__icon svg {
@@ -190,6 +199,9 @@
190
199
  gap, so no margin lands at the start of a wrapped line. */
191
200
  .kui-state-banner__copy {
192
201
  min-width: 0;
202
+ /* The copy's minimum readable width before a trailing action wraps below
203
+ it; the copy grows to fill whatever its line leaves. */
204
+ flex: 1 1 12rem;
193
205
  /* The title's size, so a wrapped title's lines keep the title's own line
194
206
  height instead of the larger inherited strut. */
195
207
  font-size: var(--kui-font-xs);
@@ -219,17 +231,11 @@
219
231
  overflow: visible;
220
232
  text-overflow: clip;
221
233
  }
222
- .kui-state-banner[data-action-placement="below"] {
223
- grid-template-columns: auto minmax(0, 1fr);
224
- }
225
- .kui-state-banner[data-action-placement="below"]:not(
226
- :has(> .kui-state-banner__icon)
227
- )
228
- > .kui-state-banner__copy {
229
- grid-column: 1 / -1;
230
- }
234
+ /* `below` always gives the action its own end-aligned trailing row. */
231
235
  .kui-state-banner[data-action-placement="below"] > .kui-state-banner__action {
232
- grid-column: 1 / -1;
236
+ display: flex;
237
+ flex-basis: 100%;
238
+ justify-content: flex-end;
233
239
  }
234
240
  .kui-state-banner__copy strong {
235
241
  margin-inline-end: var(--kui-layout-item-gap, 0.5rem);
@@ -254,8 +260,13 @@
254
260
  overflow: clip;
255
261
  text-overflow: ellipsis;
256
262
  }
263
+ /* Content-sized and end-aligned on whichever line it lands; on its own line
264
+ it may shrink to the line so a wrapping action group (a `Row wrap`) wraps
265
+ its controls instead of overflowing the banner. */
257
266
  .kui-state-banner__action {
258
- justify-self: end;
267
+ max-width: 100%;
268
+ margin-inline-start: auto;
269
+ flex: 0 1 auto;
259
270
  }
260
271
  .kui-state-banner__action button {
261
272
  min-height: 1.8rem;
@@ -27,6 +27,7 @@
27
27
  @import "./anchored-surface.css";
28
28
  @import "./segmented-control.css";
29
29
  @import "./choice-chips.css";
30
+ @import "./composer.css";
30
31
  @import "./token-search-field.css";
31
32
  @import "./state-banner.css";
32
33
  @import "./corner-status.css";
@@ -96,6 +96,185 @@
96
96
  .kui-dialog-surface[data-footer-inset="comfortable"] > wa-dialog::part(footer) {
97
97
  padding: var(--kui-wa-container-inset, 1rem);
98
98
  }
99
+ /* Fixed rows above one filling row: the leading children keep their natural
100
+ height and the last unslotted child (the light-DOM children are the body
101
+ slot's flex items) takes the rest and owns its scrolling. */
102
+ .kui-dialog-surface[data-body-layout="fill-last"] > wa-dialog::part(body) {
103
+ display: flex;
104
+ flex-direction: column;
105
+ overflow: hidden;
106
+ }
107
+ .kui-dialog-surface[data-body-layout="fill-last"] > wa-dialog > :not([slot]) {
108
+ flex: none;
109
+ }
110
+ .kui-dialog-surface[data-body-layout="fill-last"]
111
+ > wa-dialog
112
+ > :nth-last-child(1 of :not([slot])) {
113
+ flex: 1 1 0;
114
+ min-block-size: 0;
115
+ }
116
+ /* A floating footer lies over the body's block end, inset from the panel's
117
+ inline and block-end edges; the top-layer panel is its positioning
118
+ context. The register publishes the footer's measured block size on the
119
+ panel, and the body reserves it (plus the offset) after its own inset, so
120
+ flowing content scrolls beneath the footer and a filling child's scrollport
121
+ ends above it: the last content is never hidden. */
122
+ .kui-dialog-surface[data-footer-presentation="floating"] > wa-dialog {
123
+ --_kui-dialog-surface-footer-resolved-offset: max(
124
+ 0px,
125
+ var(
126
+ --_kui-dialog-surface-footer-offset,
127
+ var(--kui-wa-container-inset, 1rem)
128
+ )
129
+ );
130
+ }
131
+ .kui-dialog-surface[data-footer-presentation="floating"]
132
+ > wa-dialog::part(footer) {
133
+ position: absolute;
134
+ inset-inline: var(--_kui-dialog-surface-footer-resolved-offset);
135
+ inset-block-end: var(--_kui-dialog-surface-footer-resolved-offset);
136
+ z-index: 1;
137
+ background: transparent;
138
+ }
139
+ .kui-dialog-surface[data-footer-presentation="floating"]
140
+ > wa-dialog::part(body) {
141
+ --_kui-dialog-surface-footer-clearance: calc(
142
+ var(--_kui-dialog-surface-footer-block-size, 0px) +
143
+ var(--_kui-dialog-surface-footer-resolved-offset)
144
+ );
145
+ scroll-padding-block-end: var(--_kui-dialog-surface-footer-clearance);
146
+ }
147
+ .kui-dialog-surface[data-footer-presentation="floating"][data-body-inset="none"]
148
+ > wa-dialog::part(body) {
149
+ padding-block-end: var(--_kui-dialog-surface-footer-clearance);
150
+ }
151
+ .kui-dialog-surface[data-footer-presentation="floating"][data-body-inset="compact"]
152
+ > wa-dialog::part(body) {
153
+ padding-block-end: calc(
154
+ var(--kui-wa-surface-inset, 0.5rem) +
155
+ var(--_kui-dialog-surface-footer-clearance)
156
+ );
157
+ }
158
+ .kui-dialog-surface[data-footer-presentation="floating"][data-body-inset="comfortable"]
159
+ > wa-dialog::part(body) {
160
+ padding-block-end: calc(
161
+ var(--kui-wa-container-inset, 1rem) +
162
+ var(--_kui-dialog-surface-footer-clearance)
163
+ );
164
+ }
165
+ /* Scroll clearance. A dialog body starts a new scroll context, so it clears
166
+ any `--kui-scroll-clearance-*` a page region published around the dialog.
167
+ With a floating footer over a filling child that opts into block-end
168
+ `scrollClearance` (a transcript List or Pane), the body stops reserving the
169
+ footer below that child: the child reaches the panel's block end, the body
170
+ publishes the footer's clearance for it, and the child adds it inside its
171
+ own scroll area, so content scrolls visibly beneath the transparent footer
172
+ while its last item still comes to rest above it. */
173
+ .kui-dialog-surface > wa-dialog::part(body) {
174
+ --kui-scroll-clearance-block-start: 0px;
175
+ --kui-scroll-clearance-block-end: 0px;
176
+ }
177
+ .kui-dialog-surface[data-footer-presentation="floating"]:is(
178
+ [data-body-layout="fill"],
179
+ [data-body-layout="fill-last"]
180
+ )
181
+ > wa-dialog:has(
182
+ > :nth-last-child(1 of :not([slot])):is(
183
+ [data-scroll-clearance="block-end"],
184
+ [data-scroll-clearance="both"]
185
+ )
186
+ )::part(body) {
187
+ --kui-scroll-clearance-block-end: var(--_kui-dialog-surface-footer-clearance);
188
+ padding-block-end: 0;
189
+ }
190
+ /* A floating header lies over the body's block-start edge on the
191
+ translucent chrome material (opaque under reduced transparency, increased
192
+ contrast, or without backdrop-filter; a system surface in forced colors).
193
+ The register publishes the header's measured block size on the panel; the
194
+ header gives that height back as a negative block-end margin, so the body
195
+ starts at the panel's block-start edge beneath it, and the body reserves it
196
+ again before its own inset (with a matching scroll-padding): flowing
197
+ content rests below the title bar and scrolls beneath it. Unmeasured, the
198
+ size resolves to 0px and the header stays docked. */
199
+ .kui-dialog-surface[data-header-presentation="floating"]
200
+ > wa-dialog::part(header) {
201
+ position: relative;
202
+ z-index: 1;
203
+ margin-block-end: calc(
204
+ -1 * var(--_kui-dialog-surface-header-block-size, 0px)
205
+ );
206
+ -webkit-backdrop-filter: var(--kui-chrome-material-filter);
207
+ backdrop-filter: var(--kui-chrome-material-filter);
208
+ background: var(--kui-chrome-material-raised);
209
+ box-shadow: inset 0 -1px
210
+ var(--_kui-dialog-surface-header-divider, transparent);
211
+ }
212
+ /* The floating header's divider is scroll state, as on a Pane's overlay
213
+ header: the register publishes `--_kui-dialog-surface-header-divider` on
214
+ the panel (as this color) only while the body, or a filling child that
215
+ reaches beneath the header, is scrolled away from its top. The line is an
216
+ inset shadow, so showing it never moves the header or the content. */
217
+ .kui-dialog-surface[data-header-presentation="floating"] > wa-dialog {
218
+ --_kui-dialog-surface-header-divider-color: var(
219
+ --kui-color-neutral-border-normal
220
+ );
221
+ }
222
+ .kui-dialog-surface[data-header-presentation="floating"]
223
+ > wa-dialog::part(body) {
224
+ --_kui-dialog-surface-header-clearance: var(
225
+ --_kui-dialog-surface-header-block-size,
226
+ 0px
227
+ );
228
+ scroll-padding-block-start: var(--_kui-dialog-surface-header-clearance);
229
+ }
230
+ .kui-dialog-surface[data-header-presentation="floating"][data-body-inset="none"]
231
+ > wa-dialog::part(body) {
232
+ padding-block-start: var(--_kui-dialog-surface-header-clearance);
233
+ }
234
+ .kui-dialog-surface[data-header-presentation="floating"][data-body-inset="compact"]
235
+ > wa-dialog::part(body) {
236
+ padding-block-start: calc(
237
+ var(--kui-wa-surface-inset, 0.5rem) +
238
+ var(--_kui-dialog-surface-header-clearance)
239
+ );
240
+ }
241
+ .kui-dialog-surface[data-header-presentation="floating"][data-body-inset="comfortable"]
242
+ > wa-dialog::part(body) {
243
+ padding-block-start: calc(
244
+ var(--kui-wa-container-inset, 1rem) +
245
+ var(--_kui-dialog-surface-header-clearance)
246
+ );
247
+ }
248
+ /* A filling child that is the body's only child and opts into block-start
249
+ `scrollClearance` reaches the panel's block-start edge beneath the floating
250
+ header: the body publishes the header's clearance for it, and the child
251
+ adds it inside its own scroll area, so content scrolls visibly beneath the
252
+ title bar while its first item still rests below it. Leading children of
253
+ `fill-last` keep the body's reservation instead. */
254
+ .kui-dialog-surface[data-header-presentation="floating"]:is(
255
+ [data-body-layout="fill"],
256
+ [data-body-layout="fill-last"]
257
+ )
258
+ > wa-dialog:has(
259
+ > :nth-child(1 of :not([slot])):nth-last-child(1 of :not([slot])):is(
260
+ [data-scroll-clearance="block-start"],
261
+ [data-scroll-clearance="both"]
262
+ )
263
+ )::part(body) {
264
+ --kui-scroll-clearance-block-start: var(
265
+ --_kui-dialog-surface-header-clearance
266
+ );
267
+ padding-block-start: 0;
268
+ }
269
+ @media (forced-colors: active) {
270
+ .kui-dialog-surface[data-header-presentation="floating"]
271
+ > wa-dialog::part(header) {
272
+ -webkit-backdrop-filter: none;
273
+ backdrop-filter: none;
274
+ background: Canvas;
275
+ border-block-end: 1px solid CanvasText;
276
+ }
277
+ }
99
278
  .kui-dialog-surface[data-presentation="side-sheet"] > wa-dialog::part(dialog) {
100
279
  width: min(30rem, 100vw);
101
280
  max-width: 100vw;
@@ -199,6 +378,22 @@
199
378
  overflow: hidden;
200
379
  grid-template-rows: minmax(0, 1fr);
201
380
  }
381
+ /* Fixed rows above one filling last child, which owns its scrolling. */
382
+ .kui-popover-dialog-surface[data-body-layout="fill-last"]:is(
383
+ :popover-open,
384
+ [data-presentation="embedded"]
385
+ ) {
386
+ display: flex;
387
+ flex-direction: column;
388
+ overflow: hidden;
389
+ }
390
+ .kui-popover-dialog-surface[data-body-layout="fill-last"] > * {
391
+ flex: none;
392
+ }
393
+ .kui-popover-dialog-surface[data-body-layout="fill-last"] > :last-child {
394
+ flex: 1 1 0;
395
+ min-block-size: 0;
396
+ }
202
397
  /* In flow for a catalog or inline use: the same surface without the top
203
398
  layer, never wider than its container. */
204
399
  .kui-popover-dialog-surface[data-presentation="embedded"] {
@@ -48,10 +48,21 @@
48
48
  .kui-tab-bar__tabs[data-snap-tabs="true"] {
49
49
  scroll-snap-type: x mandatory;
50
50
  scroll-padding-inline-start: var(--kui-tab-bar-snap-inset, 0px);
51
- padding-inline-end: calc(
52
- var(--kui-tab-bar-strip-padding, 1px) +
53
- var(--kui-tab-bar-snap-end-extra, 0px)
54
- );
51
+ }
52
+ /* The snap end room is scrollable content after the last tab, not padding on
53
+ the strip: padding is part of the strip's box, which a flex item cannot
54
+ shrink below, so a room measured at one width would hold the strip open
55
+ past its allocation when it narrows and push the trailing and end zones out
56
+ of the bar. As content it lengthens only the scroll range, and the strip
57
+ still shrinks to its allocation. The start margin gives back the strip gap,
58
+ so an empty room adds no width. */
59
+ .kui-tab-bar__tabs[data-snap-tabs="true"]::after {
60
+ content: "";
61
+ inline-size: var(--kui-tab-bar-snap-end-extra, 0px);
62
+ margin-inline-start: calc(-1 * var(--kui-tab-bar-strip-gap, 0px));
63
+ pointer-events: none;
64
+ align-self: stretch;
65
+ flex: none;
55
66
  }
56
67
  .kui-tab-bar[data-icon-only-at] .kui-tab-bar__tabs {
57
68
  container: kui-tab-bar-tabs / inline-size;