@kerfjs/ui 5.0.0-beta.98 → 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 (407) 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 +487 -77
  47. package/ai/skill.md +40 -13
  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 +22 -5
  59. package/dist/catalog.js +50 -31
  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-AZWE2FB5.js → chunk-CMETHPKR.js} +12 -15
  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-527IAEWG.js → chunk-PYBBYSZ3.js} +10 -17
  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-Cp3Y8kJ9.d.ts → nav-stack-VXTumzKa.d.ts} +48 -3
  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.js +1 -1
  189. package/dist/skeleton.js +1 -1
  190. package/dist/spacer.js +1 -1
  191. package/dist/split-button.js +1 -1
  192. package/dist/split-view.d.ts +7 -5
  193. package/dist/split-view.js +6 -3
  194. package/dist/split-view.js.map +1 -1
  195. package/dist/state-banner.d.ts +6 -1
  196. package/dist/state-banner.js +1 -1
  197. package/dist/styles/anchored-surface.css +27 -1
  198. package/dist/styles/catalog/components/catalog-example.css +33 -0
  199. package/dist/styles/catalog/components/catalog-stage.css +7 -0
  200. package/dist/styles/chip.css +70 -0
  201. package/dist/styles/components/actions/popup-menu/popup-menu.css +14 -4
  202. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +75 -1
  203. package/dist/styles/components/actions/toolbar-text/toolbar-text.css +66 -0
  204. package/dist/styles/components/collections/list/list.css +77 -7
  205. package/dist/styles/components/collections/list-action-row/list-action-row.css +177 -22
  206. package/dist/styles/components/collections/list-item/list-item.css +158 -11
  207. package/dist/styles/components/feedback/anchored-surface/anchored-surface.css +27 -1
  208. package/dist/styles/components/feedback/chip/chip.css +70 -0
  209. package/dist/styles/components/feedback/state-banner/state-banner.css +24 -13
  210. package/dist/styles/components/forms/composer/composer.css +100 -0
  211. package/dist/styles/components/forms/token-search-field/token-search-field.css +13 -2
  212. package/dist/styles/components/layout/pane/pane.css +81 -2
  213. package/dist/styles/components/navigation/nav-stack/nav-stack.css +84 -0
  214. package/dist/styles/components/navigation/tab-bar/tab-bar.css +15 -4
  215. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +79 -4
  216. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +195 -0
  217. package/dist/styles/composer.css +100 -0
  218. package/dist/styles/foundation.css +40 -0
  219. package/dist/styles/list-action-row.css +177 -22
  220. package/dist/styles/list-item.css +158 -11
  221. package/dist/styles/list.css +77 -7
  222. package/dist/styles/nav-stack.css +84 -0
  223. package/dist/styles/pane.css +81 -2
  224. package/dist/styles/popup-menu.css +14 -4
  225. package/dist/styles/state-banner.css +24 -13
  226. package/dist/styles/styles.css +1 -0
  227. package/dist/styles/surface-scaffold.css +195 -0
  228. package/dist/styles/tab-bar.css +15 -4
  229. package/dist/styles/tab-navigator.css +79 -4
  230. package/dist/styles/token-search-field.css +13 -2
  231. package/dist/styles/toolbar-control-group.css +75 -1
  232. package/dist/styles/toolbar-text.css +66 -0
  233. package/dist/surface-scaffold-register.d.ts +6 -1
  234. package/dist/surface-scaffold-register.js +89 -3
  235. package/dist/surface-scaffold-register.js.map +1 -1
  236. package/dist/surface-scaffold.d.ts +66 -7
  237. package/dist/surface-scaffold.js +1 -1
  238. package/dist/tab-navigator.d.ts +23 -2
  239. package/dist/tab-navigator.js +2 -0
  240. package/dist/tab-navigator.js.map +1 -1
  241. package/dist/token-search-field.d.ts +1 -1
  242. package/dist/token-search-field.js +1 -1
  243. package/dist/{token-search-model-DTcTXWMS.d.ts → token-search-model-aYR0YAei.d.ts} +32 -2
  244. package/dist/token-search-model.d.ts +1 -1
  245. package/dist/toolbar-control-group.js +1 -1
  246. package/dist/toolbar-text.js +1 -1
  247. package/dist/toolbar.d.ts +1 -0
  248. package/dist/value-table.js +1 -1
  249. package/dist/wire-catalog.d.ts +3 -2
  250. package/dist/wire-catalog.js +2 -2
  251. package/dist/wire-composers.d.ts +16 -0
  252. package/dist/wire-composers.js +3 -0
  253. package/dist/wire-composers.js.map +1 -0
  254. package/dist/wire-list-focus-scroll.d.ts +16 -0
  255. package/dist/wire-list-focus-scroll.js +3 -0
  256. package/dist/wire-list-focus-scroll.js.map +1 -0
  257. package/dist/wire-nav-stack.js +135 -0
  258. package/dist/wire-nav-stack.js.map +1 -1
  259. package/dist/wire-scroll-dividers.d.ts +9 -0
  260. package/dist/wire-scroll-dividers.js +1 -1
  261. package/dist/wire-tab-bars.js +1 -1
  262. package/dist/wire-tab-navigator.d.ts +3 -1
  263. package/dist/wire-tab-navigator.js +133 -1
  264. package/dist/wire-tab-navigator.js.map +1 -1
  265. package/dist/wire-token-search-fields.d.ts +1 -1
  266. package/dist/wire-token-search-fields.js +1 -1
  267. package/dist/workbench.d.ts +8 -3
  268. package/dist/workbench.js +2 -1
  269. package/docs/accessibility.md +132 -3
  270. package/docs/anchored-surface.md +46 -4
  271. package/docs/app-layouts.md +23 -2
  272. package/docs/apple-hig.md +1 -0
  273. package/docs/catalog.md +54 -8
  274. package/docs/collapsible-panel.md +9 -6
  275. package/docs/component-contract.md +41 -12
  276. package/docs/component-selection.md +143 -19
  277. package/docs/composer.md +143 -0
  278. package/docs/design/templates/choice-chips/multiple-dark.svg +1 -0
  279. package/docs/design/templates/choice-chips/multiple.svg +1 -0
  280. package/docs/design/templates/choice-chips-dark.svg +1 -1
  281. package/docs/design/templates/choice-chips.svg +1 -1
  282. package/docs/design/templates/composer/chat-dark.svg +1 -0
  283. package/docs/design/templates/composer/chat.svg +1 -0
  284. package/docs/design/templates/composer/prompt-dark.svg +1 -0
  285. package/docs/design/templates/composer/prompt.svg +1 -0
  286. package/docs/design/templates/composer-dark.svg +1 -0
  287. package/docs/design/templates/composer.svg +1 -0
  288. package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
  289. package/docs/design/templates/empty-state/filtered.svg +1 -1
  290. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  291. package/docs/design/templates/empty-state/with-action.svg +1 -1
  292. package/docs/design/templates/empty-state-dark.svg +1 -1
  293. package/docs/design/templates/empty-state.svg +1 -1
  294. package/docs/design/templates/list/compact-dark.svg +1 -1
  295. package/docs/design/templates/list/compact.svg +1 -1
  296. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  297. package/docs/design/templates/list-action-row/default.svg +1 -1
  298. package/docs/design/templates/list-action-row/icon-tile-dark.svg +1 -0
  299. package/docs/design/templates/list-action-row/icon-tile.svg +1 -0
  300. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  301. package/docs/design/templates/list-action-row/selected.svg +1 -1
  302. package/docs/design/templates/list-action-row/trailing-menu-dark.svg +1 -1
  303. package/docs/design/templates/list-action-row/trailing-menu.svg +1 -1
  304. package/docs/design/templates/list-action-row-dark.svg +1 -1
  305. package/docs/design/templates/list-action-row.svg +1 -1
  306. package/docs/design/templates/list-dark.svg +1 -1
  307. package/docs/design/templates/list-header/size-l-dark.svg +1 -1
  308. package/docs/design/templates/list-header/size-l.svg +1 -1
  309. package/docs/design/templates/list-header/size-m-dark.svg +1 -1
  310. package/docs/design/templates/list-header/size-m.svg +1 -1
  311. package/docs/design/templates/list-header/size-xl-dark.svg +1 -1
  312. package/docs/design/templates/list-header/size-xl.svg +1 -1
  313. package/docs/design/templates/list-header-dark.svg +1 -1
  314. package/docs/design/templates/list-header.svg +1 -1
  315. package/docs/design/templates/list-item/icon-tile-dark.svg +1 -0
  316. package/docs/design/templates/list-item/icon-tile.svg +1 -0
  317. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  318. package/docs/design/templates/list-item/selected.svg +1 -1
  319. package/docs/design/templates/list-item-dark.svg +1 -1
  320. package/docs/design/templates/list-item.svg +1 -1
  321. package/docs/design/templates/list.svg +1 -1
  322. package/docs/design/templates/segmented-control-dark.svg +1 -1
  323. package/docs/design/templates/segmented-control.svg +1 -1
  324. package/docs/design/templates/skeleton-dark.svg +1 -1
  325. package/docs/design/templates/skeleton.svg +1 -1
  326. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  327. package/docs/design/templates/state-banner/danger.svg +1 -1
  328. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
  329. package/docs/design/templates/state-banner/info-badge.svg +1 -1
  330. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  331. package/docs/design/templates/state-banner/info.svg +1 -1
  332. package/docs/design/templates/state-banner/strip-dark.svg +1 -1
  333. package/docs/design/templates/state-banner/strip.svg +1 -1
  334. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  335. package/docs/design/templates/state-banner/success.svg +1 -1
  336. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  337. package/docs/design/templates/state-banner/warning.svg +1 -1
  338. package/docs/design/templates/state-banner-dark.svg +1 -1
  339. package/docs/design/templates/state-banner.svg +1 -1
  340. package/docs/design/templates/tab-bar-dark.svg +1 -1
  341. package/docs/design/templates/tab-bar.svg +1 -1
  342. package/docs/design/templates/token-search-field-dark.svg +1 -1
  343. package/docs/design/templates/token-search-field.svg +1 -1
  344. package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
  345. package/docs/design/templates/toolbar-control-group.svg +1 -1
  346. package/docs/design/templates/toolbar-dark.svg +1 -1
  347. package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
  348. package/docs/design/templates/toolbar-text/default.svg +1 -1
  349. package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
  350. package/docs/design/templates/toolbar-text/large.svg +1 -1
  351. package/docs/design/templates/toolbar-text-dark.svg +1 -1
  352. package/docs/design/templates/toolbar-text.svg +1 -1
  353. package/docs/design/templates/toolbar.svg +1 -1
  354. package/docs/design/templates/value-table/details-dark.svg +1 -1
  355. package/docs/design/templates/value-table/details.svg +1 -1
  356. package/docs/design/templates/value-table-dark.svg +1 -1
  357. package/docs/design/templates/value-table.svg +1 -1
  358. package/docs/design-philosophy.md +9 -1
  359. package/docs/examples/command-palette-adapter.tsx +3 -3
  360. package/docs/layout.md +147 -14
  361. package/docs/nav-stack.md +112 -2
  362. package/docs/recipes.md +9 -9
  363. package/docs/split-view.md +3 -3
  364. package/docs/sunken-panel.md +2 -2
  365. package/docs/surface-scaffold.md +138 -7
  366. package/docs/tab-navigator.md +38 -1
  367. package/docs/type-contracts.md +16 -16
  368. package/docs/ui-analyzer.md +3 -1
  369. package/docs/ui-doctor.md +71 -0
  370. package/docs/ux-demo.md +6 -6
  371. package/docs/workbench.md +10 -6
  372. package/docs/writing.md +152 -0
  373. package/doctor/copy-capitalization-checks.mjs +591 -0
  374. package/doctor/index.mjs +17 -8
  375. package/llms.txt +105 -11
  376. package/package.json +15 -1
  377. package/ux-demo/recipes/app-shell.tsx +11 -11
  378. package/ux-demo/recipes/collapsible-sidebar.tsx +12 -11
  379. package/ux-demo/recipes/compact-toolbar.tsx +10 -10
  380. package/ux-demo/recipes/composer-form.tsx +8 -8
  381. package/ux-demo/recipes/list-detail-dialog.tsx +13 -13
  382. package/ux-demo/recipes/list-workspace-states.tsx +13 -13
  383. package/ux-demo/recipes/loading-inspector.tsx +10 -10
  384. package/ux-demo/recipes/navigation-sidebar.tsx +7 -7
  385. package/ux-demo/recipes/navigation-stack.tsx +5 -5
  386. package/ux-demo/recipes/workspace-header.tsx +5 -5
  387. package/dist/chunk-36TL6BCR.js.map +0 -1
  388. package/dist/chunk-4LOK4634.js +0 -21
  389. package/dist/chunk-4LOK4634.js.map +0 -1
  390. package/dist/chunk-527IAEWG.js.map +0 -1
  391. package/dist/chunk-6BRRUPJY.js.map +0 -1
  392. package/dist/chunk-6STQXRT4.js.map +0 -1
  393. package/dist/chunk-76PWEN5Y.js +0 -64
  394. package/dist/chunk-76PWEN5Y.js.map +0 -1
  395. package/dist/chunk-AZWE2FB5.js.map +0 -1
  396. package/dist/chunk-DQDTZE4W.js +0 -70
  397. package/dist/chunk-DQDTZE4W.js.map +0 -1
  398. package/dist/chunk-FOQK4F3L.js.map +0 -1
  399. package/dist/chunk-GJYQ27C2.js.map +0 -1
  400. package/dist/chunk-JYD7G4RG.js.map +0 -1
  401. package/dist/chunk-KQDU7Z7P.js.map +0 -1
  402. package/dist/chunk-P74VXMB6.js.map +0 -1
  403. package/dist/chunk-PBT3CPPY.js.map +0 -1
  404. package/dist/chunk-PRG4CL3Q.js.map +0 -1
  405. package/dist/chunk-ROZLJULF.js.map +0 -1
  406. package/dist/chunk-U657IHFB.js.map +0 -1
  407. package/dist/chunk-V6W56V3N.js.map +0 -1
@@ -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;
@@ -0,0 +1,100 @@
1
+ /* A chat or prompt composer: a raised frame (surface-raised, the standard
2
+ neutral border, large radius, shadow-l) whose border turns brand while
3
+ focus is within. It holds a borderless message field that sizes to its
4
+ content between the min and max row counts, above an action row with a
5
+ quiet hint and trailing actions. The 8px padding puts the field's text on
6
+ the 17px text column when the composer sits 8px from a container edge. */
7
+
8
+ .kui-composer {
9
+ --_kui-composer-min-rows: 1;
10
+ --_kui-composer-max-rows: 8;
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: var(--kui-layout-control-gap, 0.5rem);
14
+ /* Fill the container's inline size: a content-sized field would otherwise
15
+ shrink the frame to its text. */
16
+ width: 100%;
17
+ min-width: 0;
18
+ box-sizing: border-box;
19
+ padding: var(--kui-layout-item-padding, 0.5rem);
20
+ border: 1px solid var(--kui-color-neutral-border-normal);
21
+ border-radius: var(--kui-radius-l);
22
+ color: var(--kui-color-neutral-on-normal);
23
+ background: var(--kui-color-surface-raised);
24
+ box-shadow: var(--kui-shadow-l);
25
+ }
26
+
27
+ /* The frame is the field's boundary, so it carries the focus state. */
28
+ .kui-composer:focus-within {
29
+ border-color: var(--kui-color-brand-border-loud);
30
+ }
31
+
32
+ .kui-composer__field {
33
+ display: block;
34
+ width: 100%;
35
+ min-width: 0;
36
+ box-sizing: border-box;
37
+ margin: 0;
38
+ padding: 0.25rem 0;
39
+ border: 0;
40
+ outline: none;
41
+ color: inherit;
42
+ background: transparent;
43
+ font: inherit;
44
+ font-size: var(--kui-font-m, inherit);
45
+ line-height: var(--wa-line-height-normal, 1.6);
46
+ resize: none;
47
+ field-sizing: content;
48
+ min-height: calc(var(--_kui-composer-min-rows) * 1lh + 0.5rem);
49
+ max-height: calc(var(--_kui-composer-max-rows) * 1lh + 0.5rem);
50
+ overflow-y: auto;
51
+ }
52
+
53
+ /* Engines without content sizing keep a three-line field, clamped to the
54
+ row bounds, that scrolls once the message is longer. */
55
+ @supports not (field-sizing: content) {
56
+ .kui-composer__field {
57
+ height: calc(
58
+ clamp(var(--_kui-composer-min-rows), 3, var(--_kui-composer-max-rows)) *
59
+ 1lh + 0.5rem
60
+ );
61
+ }
62
+ }
63
+
64
+ .kui-composer__field::placeholder {
65
+ color: var(--kui-color-neutral-on-quiet);
66
+ opacity: 1;
67
+ }
68
+
69
+ .kui-composer__field:disabled {
70
+ color: var(--kui-color-neutral-on-quiet);
71
+ cursor: not-allowed;
72
+ }
73
+
74
+ .kui-composer__actions {
75
+ display: flex;
76
+ align-items: center;
77
+ gap: var(--kui-layout-control-gap, 0.5rem);
78
+ min-width: 0;
79
+ }
80
+
81
+ .kui-composer__hint {
82
+ flex: 1 1 auto;
83
+ min-width: 0;
84
+ }
85
+
86
+ .kui-composer__trailing {
87
+ display: flex;
88
+ flex: none;
89
+ align-items: center;
90
+ gap: var(--kui-layout-control-gap, 0.5rem);
91
+ margin-inline-start: auto;
92
+ }
93
+
94
+ @media (forced-colors: active) {
95
+ .kui-composer:focus-within {
96
+ border-color: Highlight;
97
+ outline: 2px solid Highlight;
98
+ outline-offset: 1px;
99
+ }
100
+ }
@@ -172,10 +172,19 @@
172
172
  .kui-token-search__clear:hover,
173
173
  .kui-token-search__clear:focus-visible,
174
174
  .kui-token-search__trailing-action:hover,
175
- .kui-token-search__trailing-action:focus-visible {
175
+ .kui-token-search__trailing-action:focus-visible,
176
+ .kui-token-search__trailing-action[aria-expanded="true"],
177
+ .kui-token-search__trailing-action[aria-pressed="true"] {
176
178
  background: color-mix(in srgb, currentColor 12%, transparent);
177
179
  }
178
180
 
181
+ /* An open disclosure or an on toggle keeps the hover fill and reads at full
182
+ text strength, so its state stays visible after the pointer leaves. */
183
+ .kui-token-search__trailing-action[aria-expanded="true"],
184
+ .kui-token-search__trailing-action[aria-pressed="true"] {
185
+ color: var(--kui-color-text);
186
+ }
187
+
179
188
  .kui-token-search__token button:focus-visible,
180
189
  .kui-token-search__clear:focus-visible,
181
190
  .kui-token-search__trailing-action:focus-visible {
@@ -386,7 +395,9 @@
386
395
  box-shadow: none;
387
396
  }
388
397
 
389
- .kui-token-search[data-presentation="toolbar-group"] .kui-token-search__clear {
398
+ .kui-token-search[data-presentation="toolbar-group"] .kui-token-search__clear,
399
+ .kui-token-search[data-presentation="toolbar-group"]
400
+ .kui-token-search__trailing-action {
390
401
  border-radius: var(--kui-control-highlight-radius);
391
402
  }
392
403
 
@@ -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 {
@@ -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
@@ -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;
@@ -69,10 +69,12 @@
69
69
  ):only-child
70
70
  )
71
71
  ) {
72
- padding-block-start: var(--kui-edge-inset-block-start);
72
+ padding-block: var(--kui-edge-inset-block-start)
73
+ var(--kui-edge-inset-block-end);
73
74
  padding-inline: var(--kui-edge-inset-inline-start)
74
75
  var(--kui-edge-inset-inline-end);
75
- scroll-padding-block-start: var(--kui-edge-inset-block-start);
76
+ scroll-padding-block: var(--kui-edge-inset-block-start)
77
+ var(--kui-edge-inset-block-end);
76
78
  }
77
79
 
78
80
  /* A plain scene adds one outer gutter; a sole Pane or layout keeps ownership
@@ -91,13 +93,15 @@
91
93
  padding-block-start: calc(
92
94
  var(--kui-edge-inset-block-start) + var(--kui-space-xs)
93
95
  );
94
- padding-block-end: var(--kui-space-xs);
96
+ padding-block-end: calc(
97
+ var(--kui-edge-inset-block-end) + var(--kui-space-xs)
98
+ );
95
99
  padding-inline: calc(var(--kui-edge-inset-inline-start) + var(--kui-space-xs))
96
100
  calc(var(--kui-edge-inset-inline-end) + var(--kui-space-xs));
97
101
  scroll-padding-block: calc(
98
102
  var(--kui-edge-inset-block-start) + var(--kui-space-xs)
99
103
  )
100
- var(--kui-space-xs);
104
+ calc(var(--kui-edge-inset-block-end) + var(--kui-space-xs));
101
105
  }
102
106
 
103
107
  .kui-tab-scaffold__scene
@@ -164,6 +168,51 @@
164
168
  --_kui-tab-scaffold-bar-divider: var(--kui-color-neutral-border-normal);
165
169
  }
166
170
 
171
+ /* `barPresentation="overlay"`: the bar paints the translucent chrome
172
+ material. Once `wireTabNavigator` has measured the live bar
173
+ (`data-bar-overlay="measured"`, with its border-box block size, bottom safe
174
+ area and 1px top edge included, published on this root), the bar lies over
175
+ the scenes' bottom edge and the scenes hand that size to their content as
176
+ the block-end edge context (outranking the docked 0px above): a plain scene
177
+ pads and scroll-pads by it, and a sole Pane or layout (a NavStack, whose own
178
+ bottom toolbar then sits just above the bar) clears it itself. Content
179
+ scrolls visibly beneath the bar while its last item rests clear of it.
180
+ Unwired, the bar stays docked. */
181
+ .kui-tab-scaffold[data-bar-presentation="overlay"] > .kui-tab-scaffold__bar {
182
+ -webkit-backdrop-filter: var(--kui-chrome-material-filter);
183
+ backdrop-filter: var(--kui-chrome-material-filter);
184
+ background: var(--kui-chrome-material);
185
+ }
186
+
187
+ .kui-tab-scaffold[data-bar-presentation="overlay"][data-bar-overlay="measured"] {
188
+ position: relative;
189
+ }
190
+
191
+ .kui-tab-scaffold[data-bar-presentation="overlay"][data-bar-overlay="measured"]
192
+ > .kui-tab-scaffold__bar {
193
+ position: absolute;
194
+ z-index: 2;
195
+ inset-block-end: 0;
196
+ /* Like the NavStack overlay bars, it ends where a classic scrollbar's
197
+ track begins, so the thumb and buttons stay visible and usable. */
198
+ inset-inline: 0 var(--_kui-tab-scaffold-bar-scrollbar-inline-size, 0px);
199
+ }
200
+
201
+ .kui-tab-scaffold[data-bar-presentation="overlay"][data-bar-overlay="measured"]
202
+ > .kui-tab-scaffold__scenes {
203
+ --kui-edge-inset-block-end: var(--_kui-tab-scaffold-bar-block-size, 0px);
204
+ }
205
+
206
+ @media (forced-colors: active) {
207
+ /* Its always-present 1px top border becomes the visible edge. */
208
+ .kui-tab-scaffold[data-bar-presentation="overlay"] > .kui-tab-scaffold__bar {
209
+ -webkit-backdrop-filter: none;
210
+ backdrop-filter: none;
211
+ background: Canvas;
212
+ border-block-start-color: CanvasText;
213
+ }
214
+ }
215
+
167
216
  .kui-tab-scaffold__tab {
168
217
  display: flex;
169
218
  flex: 1 1 0;
@@ -185,6 +234,32 @@
185
234
  color: var(--kui-color-brand-on-quiet);
186
235
  }
187
236
 
237
+ /* Over the material, content of any color passes beneath the bar. Both label
238
+ colors fall below AA over the worst case (the material over black in light,
239
+ white in dark): the quiet unselected color, and in light the brand selected
240
+ color (about 3.2:1). An unselected tab lifts halfway toward the normal text
241
+ color, as an overlaid ToolbarText description does, and the selected tab
242
+ mixes 40% of it into the brand color, staying plainly the brand hue. */
243
+ .kui-tab-scaffold[data-bar-presentation="overlay"]
244
+ > .kui-tab-scaffold__bar
245
+ > .kui-tab-scaffold__tab:not([aria-selected="true"]) {
246
+ color: color-mix(
247
+ in srgb,
248
+ var(--kui-color-text-quiet),
249
+ var(--kui-color-text) 50%
250
+ );
251
+ }
252
+
253
+ .kui-tab-scaffold[data-bar-presentation="overlay"]
254
+ > .kui-tab-scaffold__bar
255
+ > .kui-tab-scaffold__tab[aria-selected="true"] {
256
+ color: color-mix(
257
+ in srgb,
258
+ var(--kui-color-brand-on-quiet),
259
+ var(--kui-color-text) 40%
260
+ );
261
+ }
262
+
188
263
  .kui-tab-scaffold__tab:focus-visible {
189
264
  outline: var(--kui-focus-ring);
190
265
  outline-offset: -2px;