@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
package/docs/layout.md CHANGED
@@ -185,6 +185,62 @@ Firefox, scroll-state container queries only in Chromium, and neither lets
185
185
  the pinned chrome — a sibling of the scroller — read the scroller's state on
186
186
  its own. One wiring keeps the behavior identical in every engine.
187
187
 
188
+ ### Overlay header
189
+
190
+ `headerPresentation="overlay"` lays a Pane's header over the top of its
191
+ scrolling content instead of giving it its own row, the way platform
192
+ navigation bars let content scroll visibly beneath a translucent bar:
193
+
194
+ ```tsx
195
+ <Pane
196
+ label="Inbox"
197
+ headerPresentation="overlay"
198
+ header={<Toolbar label="Inbox" leading={<ToolbarText text="Inbox" size="xlarge" />} />}
199
+ >
200
+ {messages}
201
+ </Pane>
202
+ ```
203
+
204
+ The header paints the shared chrome material, `--kui-chrome-material` (the
205
+ surface at 80% opacity) behind `--kui-chrome-material-filter` (a blur and
206
+ saturation backdrop filter), so content passing beneath it reads as softened
207
+ color, not as competing text. The material becomes the opaque surface under
208
+ `prefers-reduced-transparency: reduce` or `prefers-contrast: more`, and where
209
+ the browser lacks `backdrop-filter`. In forced colors the header paints
210
+ `Canvas` with a `CanvasText` bottom edge.
211
+
212
+ `wireScrollDividers` measures each overlay header (its border-box height,
213
+ safe-area padding included) with a `ResizeObserver` and publishes it on the
214
+ Pane as the `--kui-scroll-clearance-block-start` context (see
215
+ [Scroll clearance](#scroll-clearance)). The Pane's content clears it
216
+ automatically, with no `scrollClearance` prop. At rest the first item sits just
217
+ below the header. Mid-scroll, content passes beneath it, and anything focused
218
+ or scrolled into view still comes to rest clear of it. The clearance follows
219
+ the header as its title wraps or its text grows. The header draws its scroll
220
+ divider as a docked header does, once content is scrolled beneath it. The
221
+ wiring also marks the Pane `data-header-overlay="measured"`, and only then
222
+ does the header move over the content. Until the wiring runs, the header stays
223
+ docked in its own row, so it can never cover content it has not measured. A
224
+ re-render that drops the measurement gets it back before paint.
225
+
226
+ The overlay needs pinned chrome. With `chromePlacement="auto"`, the header
227
+ stays docked. `PaneConfig` carries `headerPresentation`, so a Workbench
228
+ `mainPane` or panel `pane`, a `CollapsiblePanel` `pane`, or a `NavStack` view's
229
+ `pane` can lay its header over its content the same way. Overlay-header text
230
+ must stay at AA over whatever passes beneath: an untoned `ToolbarText` there
231
+ takes the normal text color for its title and lifts its `description` toward
232
+ it, and other quiet secondary copy belongs in the content (see
233
+ [Accessibility › Chrome material](accessibility.md#chrome-material)).
234
+
235
+ An overlay scrollbar (macOS by default) passes beneath the header like the
236
+ content. A classic, space-taking scrollbar (Windows and Linux, or macOS with
237
+ "always show scrollbars") stays uncovered: the wiring also measures the
238
+ content's vertical scrollbar (`offsetWidth` beyond `clientWidth`) and publishes
239
+ its inline size on the Pane as `--kui-pane-scrollbar-inline-size`, and the
240
+ header ends where the scrollbar's track begins, so its thumb and arrow buttons
241
+ remain visible and usable. The measurement follows the scrollbar as content
242
+ starts or stops overflowing.
243
+
188
244
  A pane is safe-area aware. Its background and separators paint through a
189
245
  device's unsafe areas while its header, content, and footer pad for each side
190
246
  the pane still reaches; the content's block insets are scroll padding, so its
@@ -313,19 +369,24 @@ component's context stays allowed (see `KUI-L019`).
313
369
 
314
370
  ## Public roles and tokens
315
371
 
316
- | Need | Class | Token / default |
317
- | ---------------------------------------- | ---------------------------- | ------------------------------------------------------------------ |
318
- | Unpadded header/content/footer structure | `Pane`, `.kui-pane` | — |
319
- | Scrolling pane content | `.kui-pane__content` | — |
320
- | Optional logical-edge separators | `Pane.separators` | `--kui-pane-separator-width: 1px` |
321
- | Safe-area sides a pane may pad | `Pane.safeAreaEdges` | `--kui-safe-area-*: env(safe-area-inset-*)`, routed by each layout |
322
- | Major vertical rhythm | `.kui-content` | `--kui-layout-content-gap: 24px` |
323
- | Self-contained child geometry | `ContentItem` | 8px margin + 1px border + 8px padding |
324
- | Pill child | `ContentItem shape="pill"` | `--kui-layout-pill-radius: 22px` |
325
- | Visibly framed child | `ContentItem frame="framed"` | neutral 1px border, same geometry |
326
- | Related controls | `.kui-control-cluster` | `--kui-layout-control-gap: 8px` |
327
- | Inline metadata | `.kui-inline-metadata` | `--kui-layout-metadata-gap: 4px` |
328
- | Explicit scroll owner outside a pane | `.kui-scroll-owner` | `overflow: auto` |
372
+ | Need | Class | Token / default |
373
+ | ---------------------------------------- | ------------------------------------ | ------------------------------------------------------------------ |
374
+ | Unpadded header/content/footer structure | `Pane`, `.kui-pane` | — |
375
+ | Scrolling pane content | `.kui-pane__content` | — |
376
+ | Optional logical-edge separators | `Pane.separators` | `--kui-pane-separator-width: 1px` |
377
+ | Safe-area sides a pane may pad | `Pane.safeAreaEdges` | `--kui-safe-area-*: env(safe-area-inset-*)`, routed by each layout |
378
+ | Header laid over scrolling content | `Pane.headerPresentation` | `--kui-chrome-material`, `--kui-chrome-material-filter` |
379
+ | Dialog title bar laid over its body | `DialogSurface.headerPresentation` | `--kui-chrome-material-raised`, `--kui-chrome-material-filter` |
380
+ | Stack top bar laid over the active view | `NavStack.chromePresentation` | `--kui-chrome-material`, `--kui-chrome-material-filter` |
381
+ | Stack bottom toolbar laid over the view | `NavStack.bottomToolbarPresentation` | `--kui-chrome-material`, `--kui-chrome-material-filter` |
382
+ | Tab bar laid over the active scene | `TabNavigator.barPresentation` | `--kui-chrome-material`, `--kui-chrome-material-filter` |
383
+ | Major vertical rhythm | `.kui-content` | `--kui-layout-content-gap: 24px` |
384
+ | Self-contained child geometry | `ContentItem` | 8px margin + 1px border + 8px padding |
385
+ | Pill child | `ContentItem shape="pill"` | `--kui-layout-pill-radius: 22px` |
386
+ | Visibly framed child | `ContentItem frame="framed"` | neutral 1px border, same geometry |
387
+ | Related controls | `.kui-control-cluster` | `--kui-layout-control-gap: 8px` |
388
+ | Inline metadata | `.kui-inline-metadata` | `--kui-layout-metadata-gap: 4px` |
389
+ | Explicit scroll owner outside a pane | `.kui-scroll-owner` | `overflow: auto` |
329
390
 
330
391
  The component layer applies the same contract to `Toolbar`, `ListHeader`,
331
392
  `ListItem`, `Toolbar`, `StateBanner`, `ValueTable`,
@@ -409,7 +470,7 @@ import { FieldLabel } from "@kerfjs/ui/text";
409
470
 
410
471
  <div role="group" aria-labelledby="needed-by-label">
411
472
  <ListInsetControl sides="trl">
412
- <FieldLabel id="needed-by-label">Needed by</FieldLabel>
473
+ <FieldLabel id="needed-by-label">Needed By</FieldLabel>
413
474
  </ListInsetControl>
414
475
  <ContentItem>October 16, 2026</ContentItem>
415
476
  </div>;
@@ -646,6 +707,78 @@ When it has focus it draws the theme focus ring inset by the ring width and
646
707
  rounded with `--kui-radius-m`, so a rounded or `overflow: hidden` parent
647
708
  never clips it. Do not style `.kui-list` focus yourself.
648
709
 
710
+ ### Scroll clearance
711
+
712
+ Chrome that lies over a scroll owner's block edge (a `DialogSurface` floating
713
+ footer over a transcript, or translucent chrome over a scrolling region)
714
+ publishes how far it covers that edge through an inherited context:
715
+ `--kui-scroll-clearance-block-start` and `--kui-scroll-clearance-block-end`.
716
+ A scroll owner opts in per edge with `scrollClearance` (`"block-start"`,
717
+ `"block-end"`, or `"both"`) on a `scrollable` `List` or a `Pane`. It adds the
718
+ published clearance to its own block padding and `scroll-padding`, so content
719
+ scrolls visibly beneath the chrome while the first and last items (and any
720
+ item focused or scrolled into view) still come to rest clear of it. Without
721
+ the prop the context is ignored. `PaneConfig` carries `scrollClearance` too,
722
+ so a composed Pane opts in the same way: a Workbench `mainPane` or panel
723
+ `pane`, a `CollapsiblePanel` `pane`, or a `NavStack` view's `pane` (for
724
+ example a NavStack view inside a dialog with a floating composer).
725
+
726
+ Opt in only the one scroller that reaches the covered edge; a nested scroller
727
+ must not opt in again. `DialogSurface` publishes block-end for its floating
728
+ footer and block-start for its floating header (see
729
+ `docs/surface-scaffold.md`), and clears the context in every dialog body. A `Pane` with `headerPresentation="overlay"` publishes block-start for
730
+ its own header, once `wireScrollDividers` has measured it, and its content
731
+ clears it without the prop (see [Overlay header](#overlay-header)). When an application overlays its own chrome on a region (for example a
732
+ translucent toolbar laid over the top of a scrolling list), it publishes the
733
+ chrome's block size on that region's container, the one place where an app
734
+ sets this context:
735
+
736
+ ```tsx
737
+ <section style="position:relative;display:grid;--kui-scroll-clearance-block-start:48px">
738
+ <List scrollable scrollClearance="block-start">{rows}</List>
739
+ {translucentToolbar}
740
+ </section>;
741
+ ```
742
+
743
+ ### Framed result pickers
744
+
745
+ For a bounded, framed list of `ListItem` rows (search results, duplicate
746
+ candidates, a recent-items picker), configure the List instead of wrapping it
747
+ in an app-owned scroller:
748
+
749
+ ```tsx
750
+ <List scrollable frame gap="2xs" minHeight={rem(4.25)} maxHeight={rem(14)}>
751
+ {candidates.map((candidate) => (
752
+ <ListItem action="pick-duplicate" itemId={candidate.id} label={candidate.title} description={candidate.detail} multiline />
753
+ ))}
754
+ </List>;
755
+ ```
756
+
757
+ `frame` draws a 1px `--kui-color-neutral-border-normal` border with the
758
+ `--kui-radius-m` control radius and a 4px inset on every side (replacing
759
+ `inset`, `textInsets`, and `controlInsets`). That inset is exactly a row's
760
+ focus-ring reach, so the first and last rows' rings stay inside the clip at
761
+ the scroll extremes. Every `scrollable` List, framed or not, carries block
762
+ scroll padding of that reach plus 2px of slack (6px; nothing moves at rest),
763
+ so a middle row focused or scrolled into view also stops with its ring inside
764
+ the clip, even where Chromium's focus scroll stops a pixel short of the padded
765
+ target. An unframed scrollable List has no inset, so its first and last rows
766
+ still meet the clip at the scroll extremes; use `frame` when those rows must
767
+ show a whole ring.
768
+ How far `focus()` scrolls a partly visible row is up to the engine: Chromium
769
+ brings it to the nearest edge, Firefox leaves it until about half of it is
770
+ hidden and then centers it, and WebKit leaves a partly visible row where it
771
+ is. Call `wireListFocusScroll(root)` from `@kerfjs/ui/wire-list-focus-scroll`
772
+ once at the app root (keep its disposer) to make keyboard focus consistent:
773
+ when a `:focus-visible` element inside a `scrollable` List has a ring that
774
+ crosses the clip, it calls `scrollIntoView({ block: 'nearest' })`, which
775
+ honors the List's scroll padding in every engine. It leaves pointer focus
776
+ alone, so a click never scrolls its row from under the pointer, and it is a
777
+ no-op where Chromium has already scrolled. `maxHeight` and `minHeight` take typed
778
+ `CssLength`s from `@kerfjs/ui/css-values` and bound the List directly, with no
779
+ flex-column ancestor; pair `maxHeight` with `scrollable`. A frame of settings
780
+ rows with dividers between them is a `FramedList`, not a framed List.
781
+
649
782
  For long reading content, such as a reader view, pass `inset="document"`: 24px
650
783
  block and 32px inline on all four sides, narrowing to 16px inline below 576px.
651
784
  It replaces any `textInsets`/`controlInsets` on that List.
package/docs/nav-stack.md CHANGED
@@ -66,7 +66,8 @@ the view renders a `Pane`: its header and footer stay pinned around the view's
66
66
  scrolling content, and slide with that view during navigation. The header and
67
67
  footer list configuration forwards to their `List`s; `pane` forwards
68
68
  `contentElement`, `contentLabel`, `separators`, `safeAreaEdges`,
69
- `chromeDividers`, and `appearance` to the Pane. Without those fields, the view
69
+ `chromeDividers`, `appearance`, `deepInset`, `scrollClearance`, `headerPresentation`, `tabIndex`,
70
+ and `outlined` to the Pane. Without those fields, the view
70
71
  keeps its simple direct scroll area. Use `pane: { appearance: "sunken" }` for a
71
72
  lowered scrolling work surface.
72
73
  The back control appears automatically once the stack has more than one entry;
@@ -79,11 +80,23 @@ and layout content.
79
80
 
80
81
  The top chrome is a real `Toolbar`, so it follows the same zone,
81
82
  group, and responsive rules as every other toolbar. Its leading zone holds the
82
- back control (a borderless `ToolbarControlGroup`, shown once the stack has
83
- depth), then `toolbar.leading`, then `toolbar.title` as a `ToolbarText`.
84
- `toolbar.center` fills the center zone and `toolbar.trailing` fills the
85
- trailing zone. Give each zone `ToolbarControlGroup`s or `ToolbarText`,
86
- as in any toolbar.
83
+ back control (a contained, bordered `ToolbarControlGroup`, shown once the stack has
84
+ depth), then `toolbar.leading`. `toolbar.trailing` fills the trailing zone.
85
+ Give each zone `ToolbarControlGroup`s or `ToolbarText`, as in any toolbar.
86
+
87
+ Where `toolbar.title` goes depends on the back control:
88
+
89
+ - **At the root** (no back control) the title is a filling `ToolbarText` at
90
+ the end of the leading zone, so it reads left-aligned.
91
+ - **Once the stack has depth**, the title is the center zone's only child and
92
+ the toolbar is `centerAlign="balanced"`, like a platform navigation bar. The
93
+ title sits on the bar's midpoint while the sides leave room, moves away from
94
+ a wider side when they do not, and truncates with an ellipsis before it
95
+ reaches the back control or a trailing group. It keeps the root title's
96
+ full-strength text color at its smaller size. This overrides a configured
97
+ `centerAlign`, which applies to view-owned center content.
98
+ - **A view that sets `toolbar.center`** owns the center zone, so its title
99
+ stays left-aligned in the leading zone at any depth.
87
100
 
88
101
  Configure the toolbar with `toolbarConfig` instead of styling it:
89
102
 
@@ -110,7 +123,9 @@ Configure the toolbar with `toolbarConfig` instead of styling it:
110
123
  - `toolbarConfig` supplies stack-wide defaults (`dividerSides`,
111
124
  `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`) and adds
112
125
  `label` (the toolbar's accessible name), `titleSize` (the title's
113
- `ToolbarText` size, default `large`), and `headingLevel` (expose the title as
126
+ `ToolbarText` size; default `xlarge` at the root, where the title is the page
127
+ heading, and `large` once a back control shares the bar; a Workbench panel's
128
+ stack keeps `large` at every depth), and `headingLevel` (expose the title as
114
129
  a heading; default a plain span). The defaults keep the stack's own chrome:
115
130
  no divider, the standard Toolbar height (a 44px control band with 8px above and below), and the top and side safe-area edges
116
131
  claimed.
@@ -122,7 +137,7 @@ Configure the toolbar with `toolbarConfig` instead of styling it:
122
137
  view's top toolbar. `Workbench` uses it for a navigation panel's standard
123
138
  collapse toggle; the active view still owns the preceding toolbar groups.
124
139
 
125
- The catalog's **Configured toolbar** example shows these together: a level-2
140
+ The catalog's **Configured Toolbar** example shows these together: a level-2
126
141
  heading title over a bottom divider, leading and center groups on the root
127
142
  view, a trailing group on the pushed view, and `backText` set to the previous
128
143
  view's title.
@@ -172,6 +187,115 @@ top Toolbar's own `dividerSides`.
172
187
  <NavStack id="settings" label="Settings" views={views.value} chromeDividers="always" />
173
188
  ```
174
189
 
190
+ ## Overlay chrome
191
+
192
+ `chromePresentation="overlay"` lays the top chrome over the active view's top
193
+ edge, like an iOS navigation bar, instead of docking it above the view
194
+ (`"docked"`, the default). The chrome paints the shared chrome material,
195
+ `--kui-chrome-material` behind `--kui-chrome-material-filter`, so content
196
+ scrolls visibly, blurred, beneath it.
197
+
198
+ ```tsx
199
+ <NavStack id="mail" label="Mail" views={views.value} chromePresentation="overlay" />
200
+ ```
201
+
202
+ - **`wireNavStack` measures it.** The helper you already call for transitions
203
+ reads the live chrome's border-box height with a `ResizeObserver`, publishes
204
+ it on the stack root, and marks the root `data-chrome-overlay="measured"`.
205
+ Only then does the chrome leave its band. Unwired, or with `hideToolbar`, the
206
+ chrome stays docked, so it never covers content it has not measured. The
207
+ measurement follows the chrome as its title wraps, text grows, or a pushed
208
+ view changes its toolbar. A re-render that strips the measurement gets it
209
+ back before paint.
210
+ - **Every view clears it automatically.** The measured height becomes the
211
+ viewport's block-start edge context (`--kui-edge-inset-block-start`), the
212
+ same context that carries safe areas. A plain view pads and scroll-pads by
213
+ it, a sole `Pane` adds it to its content's (or its header's) block-start
214
+ inset, and a nested layout hands it on. The first item rests just below the
215
+ chrome, and anything focused or scrolled into view stops clear of it. No
216
+ `scrollClearance` prop is involved, so a Pane that also opts into
217
+ `scrollClearance` does not clear the chrome twice.
218
+ - **Safe area.** The chrome keeps claiming the top safe area: its toolbar pads
219
+ for it while the material paints through it. The measured height already
220
+ includes that padding, so views clear the chrome and the safe area exactly
221
+ once.
222
+ - **Transitions.** Only the live chrome is measured, never a cross-fading
223
+ copy. The copy keeps painting over the top edge with the same material while
224
+ it fades, and the incoming view settles at the incoming chrome's clearance.
225
+ - **Classic scrollbars.** Where the active view's scroller (the view, or a
226
+ sole header-less Pane's content) shows a classic, space-taking scrollbar,
227
+ `wireNavStack` measures it and the chrome ends where its track begins, so
228
+ the thumb and arrows stay visible and usable. An overlay scrollbar takes no
229
+ space and passes beneath the material like the content.
230
+ - **Dividers.** With `wireScrollDividers`, the line under the chrome still
231
+ appears only while content is scrolled beneath it.
232
+ - **Contrast.** The material keeps normal text at AA over any content. An
233
+ untoned `ToolbarText` in the chrome lifts itself: its title takes the normal
234
+ text color at every size and its `description` mixes the quiet color halfway
235
+ toward it, and a default-tone `ToolbarControlGroup` takes the normal text
236
+ color for its controls. Other quiet copy you place in the chrome has no such
237
+ lift, so keep it in the view (see
238
+ [Accessibility › Chrome material](accessibility.md#chrome-material)). The
239
+ material turns opaque under `prefers-reduced-transparency`,
240
+ `prefers-contrast: more`, or without `backdrop-filter`, and forced colors
241
+ paint `Canvas` with a `CanvasText` bottom edge.
242
+
243
+ `SplitView`'s `compactStack.chromePresentation` and a Workbench navigation
244
+ panel's `navStack.chromePresentation` forward the same option.
245
+ `chromePresentation` governs only the top chrome; the bottom toolbar has its
246
+ own option below.
247
+
248
+ ### Overlay bottom toolbar
249
+
250
+ `bottomToolbarPresentation="overlay"` does the same for the bottom toolbar,
251
+ like an iOS toolbar: it lies over the active view's bottom edge on the same
252
+ chrome material instead of docking below the view (`"docked"`, the default).
253
+ It is a separate prop, so either bar can be overlaid alone, and it mirrors
254
+ `Pane.headerPresentation` and `DialogSurface.footerPresentation` in naming one
255
+ edge.
256
+
257
+ ```tsx
258
+ <NavStack
259
+ id="mail"
260
+ label="Mail"
261
+ views={views.value}
262
+ chromePresentation="overlay"
263
+ bottomToolbarPresentation="overlay"
264
+ bottomToolbar={{ label: 'Mail Actions', trailing: composeGroup }}
265
+ />
266
+ ```
267
+
268
+ - **`wireNavStack` measures it.** It reads the live bottom toolbar's
269
+ border-box height (never a cross-fading copy's), publishes it on the stack
270
+ root, and marks the root `data-bottom-toolbar-overlay="measured"`. Only then
271
+ does the toolbar leave its band. Unwired, or while no bottom toolbar is
272
+ shown (a view without one and no stack-level fallback), it stays docked. The
273
+ measurement follows a view-owned toolbar as views push and pop, and a
274
+ re-render that strips it gets it back before paint.
275
+ - **Every view clears it automatically.** The measured height becomes the
276
+ viewport's block-end edge context (`--kui-edge-inset-block-end`). A plain
277
+ view pads and scroll-pads by it, a sole `Pane` adds it to its content's
278
+ block-end inset (or its footer's, so the footer rests just above the
279
+ toolbar), and a nested layout hands it on. The last item rests just above
280
+ the toolbar, and anything focused or scrolled into view stops clear of it.
281
+ - **Safe area.** The toolbar keeps claiming the bottom safe area (the home
282
+ indicator), and the measured height includes it, so views clear both exactly
283
+ once. Inside a `TabNavigator` scene the tab bar owns that edge, so the
284
+ stack's toolbar sits just above the tab bar and counts no safe area.
285
+ - **Classic scrollbars and dividers.** The toolbar ends where a classic
286
+ scrollbar's track begins (a sole Pane with a footer ends its scroller above
287
+ the toolbar, so nothing needs leaving there). With `wireScrollDividers`, the
288
+ toolbar's top line still appears only while more content lies below.
289
+ - **Contrast.** An untoned `ToolbarText` lifts itself as in the top chrome,
290
+ and a default-tone `ToolbarControlGroup` in either overlaid bar takes the
291
+ normal text color for its controls, so labels and icons keep AA over the
292
+ content beneath. The material has the same opaque fallbacks; in forced
293
+ colors the toolbar paints `Canvas` and its always-present 1px top border
294
+ becomes a `CanvasText` edge, which the measurement includes.
295
+
296
+ `SplitView`'s `compactStack.bottomToolbarPresentation` and a Workbench
297
+ navigation panel's `navStack.bottomToolbarPresentation` forward it too.
298
+
175
299
  ## Safe areas
176
300
 
177
301
  The stack paints through a device's unsafe areas. Its chrome pads for the top
package/docs/recipes.md CHANGED
@@ -26,7 +26,7 @@ The adapter is delivered as reference source, not a new package runtime export.
26
26
  `delegate()` remains a valid alternative when an application needs selector-
27
27
  specific dispatch; either way, wire once at a stable root and retain disposal.
28
28
 
29
- ## Desktop application shell
29
+ ## Desktop Application Shell
30
30
 
31
31
  [Open the recipe](../ux-demo/?component=recipe-app-shell) · [TSX source](../ux-demo/recipes/app-shell.tsx)
32
32
 
@@ -52,7 +52,7 @@ whole width). The app owns each rail's collapsed and size signals — which
52
52
  routing, persistence, and data. Adapt only public `--kui-layout-*` and
53
53
  component variables.
54
54
 
55
- ## Navigation sidebar
55
+ ## Navigation Sidebar
56
56
 
57
57
  [Open the recipe](../ux-demo/?component=recipe-navigation-sidebar) · [TSX source](../ux-demo/recipes/navigation-sidebar.tsx)
58
58
 
@@ -65,7 +65,7 @@ permissions, labels, selection, valid section counts and their localized
65
65
  content. A toggled `ListHeader` supplies the production `DisclosureArrow` when
66
66
  no custom `actionIcon` is needed; ordinary navigation rows stay chevron-free.
67
67
 
68
- ## Workspace header
68
+ ## Workspace Header
69
69
 
70
70
  [Open the recipe](../ux-demo/?component=recipe-workspace-header) · [TSX source](../ux-demo/recipes/workspace-header.tsx)
71
71
 
@@ -99,7 +99,7 @@ application owns open state, selection, the pushed detail, dismissal policy,
99
99
  and record actions. Do not put the primary title in a header spanning both
100
100
  columns, rebuild the dialog, or reach into private shadow parts.
101
101
 
102
- ## Composer form
102
+ ## Composer Form
103
103
 
104
104
  [Open the recipe](../ux-demo/?component=recipe-composer-form) · [TSX source](../ux-demo/recipes/composer-form.tsx)
105
105
 
@@ -118,7 +118,7 @@ Because upgraded Web Awesome fields retain live value properties, controlled
118
118
  resets synchronize both those properties and the rendered value attributes;
119
119
  the Reset action also announces `Draft reset` through the catalog live region.
120
120
 
121
- ## List workspace states
121
+ ## List Workspace States
122
122
 
123
123
  [Open the recipe](../ux-demo/?component=recipe-list-workspace-states) · [TSX source](../ux-demo/recipes/list-workspace-states.tsx)
124
124
 
@@ -127,7 +127,7 @@ populated, stale/background refresh, and error/retry states. The recipe owns
127
127
  feedback placement; the app owns fetching, cache age, retry policy, and domain
128
128
  rows.
129
129
 
130
- ## Compact toolbar choices and actions
130
+ ## Compact Toolbar Choices and Actions
131
131
 
132
132
  [Open the recipe](../ux-demo/?component=recipe-compact-toolbar) · [TSX source](../ux-demo/recipes/compact-toolbar.tsx)
133
133
 
@@ -140,7 +140,7 @@ widths the toolbar stacks its zones and wraps whole trailing groups onto another
140
140
  row, so the last action is never clipped. The app owns values, actions,
141
141
  persistence, and responsive priority.
142
142
 
143
- ## Navigation stack
143
+ ## Navigation Stack
144
144
 
145
145
  [Open the recipe](../ux-demo/?component=recipe-navigation-stack) · [TSX source](../ux-demo/recipes/navigation-stack.tsx)
146
146
 
@@ -152,7 +152,7 @@ layout guide
152
152
  [`app-layouts.md`](app-layouts.md) for choosing among `NavStack`, `SplitView`,
153
153
  `Workbench`, and `TabNavigator`.
154
154
 
155
- ## Loading inspector
155
+ ## Loading Inspector
156
156
 
157
157
  [Open the recipe](../ux-demo/?component=recipe-loading-inspector) · [TSX source](../ux-demo/recipes/loading-inspector.tsx)
158
158
 
@@ -166,7 +166,7 @@ the populated record — no separate skeleton markup. The composition is the poi
166
166
  record title instead of truncating it. The app owns the loading lifecycle and
167
167
  which values are still unknown.
168
168
 
169
- ## Collapsible sidebar
169
+ ## Collapsible Sidebar
170
170
 
171
171
  [Open the recipe](../ux-demo/?component=recipe-collapsible-sidebar) · [TSX source](../ux-demo/recipes/collapsible-sidebar.tsx)
172
172
 
@@ -114,12 +114,12 @@ compactStack={{
114
114
  list: { toolbar: { trailing: <ComposeGroup /> } },
115
115
  detail: {
116
116
  toolbar: { trailing: <ReplyGroup /> },
117
- bottomToolbar: { label: "Message actions", leading: <MessageActions /> },
117
+ bottomToolbar: { label: "Message Actions", leading: <MessageActions /> },
118
118
  },
119
119
  }}
120
120
  ```
121
121
 
122
- The catalog's **Interactive compact drill-down** example exercises this exact
122
+ The catalog's **Interactive Compact Drill-Down** example exercises this exact
123
123
  controlled flow: a list action sets the selected message, `detailActive` pushes
124
124
  its detail, and the wired Back action clears the selection to reveal the
125
125
  preserved list. It also forwards `compactStack`: a level-2 heading title over
@@ -128,7 +128,7 @@ bottom toolbar on the detail. Use the same structure in application demos so
128
128
  compact examples show the interaction rather than rendering a disconnected
129
129
  detail state.
130
130
 
131
- The catalog's **Resizable, collapsible list** example forwards `resizable`: a
131
+ The catalog's **Resizable, Collapsible List** example forwards `resizable`: a
132
132
  hidden separator that still resizes the list (its committed width comes back
133
133
  through `wireResizableRegions`' `onCommit` into the app's size signal), a Hide
134
134
  control in the list's own toolbar, and a `FloatingToolbar` restore control in
@@ -8,7 +8,7 @@ issue tracker or component catalog.
8
8
  ```tsx
9
9
  import { SunkenPanel } from '@kerfjs/ui/sunken-panel';
10
10
 
11
- <SunkenPanel ariaLabel="Release workspace">
11
+ <SunkenPanel ariaLabel="Release Workspace">
12
12
  <ReleaseSummary />
13
13
  <ReleaseChecks />
14
14
  </SunkenPanel>;
@@ -33,7 +33,7 @@ can shrink with its parent. Like `Grid`, `flex` accepts `true` (equivalent to
33
33
 
34
34
  ```tsx
35
35
  <List fill>
36
- <Toolbar label="Work area" />
36
+ <Toolbar label="Work Area" />
37
37
  <SunkenPanel flex>
38
38
  <WorkArea />
39
39
  </SunkenPanel>