@adia-ai/gen-ui 0.8.37

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 (631) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +77 -0
  3. package/compose/CHANGELOG.md +1707 -0
  4. package/compose/README.md +215 -0
  5. package/compose/core/artifacts.js +262 -0
  6. package/compose/core/context-store.js +218 -0
  7. package/compose/core/generator.d.ts +4 -0
  8. package/compose/core/generator.js +602 -0
  9. package/compose/core/pipeline/engine.js +289 -0
  10. package/compose/core/pipeline/types.js +91 -0
  11. package/compose/core/plan-primitives.js +120 -0
  12. package/compose/core/plan-turn.js +145 -0
  13. package/compose/core/reference.js +150 -0
  14. package/compose/core/state.js +15 -0
  15. package/compose/evals/harness.d.ts +4 -0
  16. package/compose/evals/harness.mjs +193 -0
  17. package/compose/index.d.ts +4 -0
  18. package/compose/index.js +16 -0
  19. package/compose/shared/validate-and-repair.js +122 -0
  20. package/compose/strategies/_shared/chunk-loader.js +282 -0
  21. package/compose/strategies/cascade.d.ts +67 -0
  22. package/compose/strategies/cascade.js +165 -0
  23. package/compose/strategies/escalation.d.ts +13 -0
  24. package/compose/strategies/escalation.js +132 -0
  25. package/compose/strategies/free-form-composer/index.js +254 -0
  26. package/compose/strategies/free-form-composer/system-prompt.js +205 -0
  27. package/compose/strategies/free-form-composer/transpile.js +279 -0
  28. package/compose/strategies/monolithic/_shared.js +1619 -0
  29. package/compose/strategies/monolithic/generate-instant.js +228 -0
  30. package/compose/strategies/monolithic/generate-pro.js +490 -0
  31. package/compose/strategies/monolithic/generate-thinking.js +206 -0
  32. package/compose/strategies/registry.d.ts +20 -0
  33. package/compose/strategies/registry.js +495 -0
  34. package/compose/strategies/zettel/_smoke.js +27 -0
  35. package/compose/strategies/zettel/chunk-composer.js +214 -0
  36. package/compose/strategies/zettel/chunk-refiner.js +582 -0
  37. package/compose/strategies/zettel/chunk-synthesizer.js +458 -0
  38. package/compose/strategies/zettel/composer.js +78 -0
  39. package/compose/strategies/zettel/composition-library.js +418 -0
  40. package/compose/strategies/zettel/generate.js +15 -0
  41. package/compose/strategies/zettel/generator-adapter.d.ts +4 -0
  42. package/compose/strategies/zettel/generator-adapter.js +242 -0
  43. package/compose/strategies/zettel/issue-reporter.js +607 -0
  44. package/compose/strategies/zettel/session-store.js +121 -0
  45. package/compose/strategies/zettel/state-cache.js +158 -0
  46. package/compose/transpiler/transpiler-maps.js +675 -0
  47. package/compose/transpiler/transpiler.d.ts +4 -0
  48. package/compose/transpiler/transpiler.js +962 -0
  49. package/corpus/CHANGELOG.md +1957 -0
  50. package/corpus/README.md +279 -0
  51. package/corpus/catalog-a2ui_0_9.d.ts +4 -0
  52. package/corpus/catalog-a2ui_0_9.json +29571 -0
  53. package/corpus/catalog-a2ui_0_9_rules.txt +1215 -0
  54. package/corpus/chunk-embeddings.d.ts +4 -0
  55. package/corpus/chunk-embeddings.json +1 -0
  56. package/corpus/chunks/_index.json +16658 -0
  57. package/corpus/chunks/_source-hashes.json +571 -0
  58. package/corpus/chunks/access-denied-with-request.json +124 -0
  59. package/corpus/chunks/access-request-form.json +166 -0
  60. package/corpus/chunks/access-request-pending.json +133 -0
  61. package/corpus/chunks/accordion-settings.json +176 -0
  62. package/corpus/chunks/achievement-badges.json +413 -0
  63. package/corpus/chunks/achievement-unlock.json +104 -0
  64. package/corpus/chunks/action-list-record-actions.json +84 -0
  65. package/corpus/chunks/activity-feed.json +390 -0
  66. package/corpus/chunks/admin-page-header-flush.json +83 -0
  67. package/corpus/chunks/admin-page-header-title-description.json +80 -0
  68. package/corpus/chunks/admin-page-header-with-actions.json +107 -0
  69. package/corpus/chunks/admin-page-header-with-tabs.json +144 -0
  70. package/corpus/chunks/admin-shell-rounded-borderless.json +287 -0
  71. package/corpus/chunks/admin-shell-standard.json +310 -0
  72. package/corpus/chunks/admin-sidebar-brand-signin.json +158 -0
  73. package/corpus/chunks/admin-sidebar-brand-version.json +130 -0
  74. package/corpus/chunks/admin-sidebar-flat-nav.json +131 -0
  75. package/corpus/chunks/admin-sidebar-nav-dividers.json +150 -0
  76. package/corpus/chunks/admin-sidebar-nav-groups.json +171 -0
  77. package/corpus/chunks/admin-sidebar-workspace-switcher.json +139 -0
  78. package/corpus/chunks/admin-topbar-breadcrumb-actions.json +130 -0
  79. package/corpus/chunks/admin-topbar-breadcrumb-minimal.json +79 -0
  80. package/corpus/chunks/admin-topbar-deep-breadcrumb.json +129 -0
  81. package/corpus/chunks/admin-topbar-search.json +104 -0
  82. package/corpus/chunks/admin-topbar-status-indicator.json +122 -0
  83. package/corpus/chunks/admin-topbar-trailing-toggle.json +114 -0
  84. package/corpus/chunks/agent-activity-feed.json +163 -0
  85. package/corpus/chunks/agent-artifact-stub-card.json +115 -0
  86. package/corpus/chunks/agent-canvas-shell.json +305 -0
  87. package/corpus/chunks/agent-citations-source-chips.json +82 -0
  88. package/corpus/chunks/agent-command-palette-search.json +120 -0
  89. package/corpus/chunks/agent-cost-detailed.json +260 -0
  90. package/corpus/chunks/agent-cost-inline.json +78 -0
  91. package/corpus/chunks/agent-memory-detail.json +181 -0
  92. package/corpus/chunks/agent-memory-editor.json +173 -0
  93. package/corpus/chunks/agent-memory-list.json +207 -0
  94. package/corpus/chunks/agent-pipeline-status-stages.json +61 -0
  95. package/corpus/chunks/agent-prompt-card.json +179 -0
  96. package/corpus/chunks/agent-prompt-library-grid.json +341 -0
  97. package/corpus/chunks/agent-prompt-picker.json +282 -0
  98. package/corpus/chunks/agent-rate-limit.json +100 -0
  99. package/corpus/chunks/agent-reasoning-collapsed.json +128 -0
  100. package/corpus/chunks/agent-tool-call-accordion.json +109 -0
  101. package/corpus/chunks/agent-tool-call-collapsed.json +98 -0
  102. package/corpus/chunks/agent-tool-call-error.json +112 -0
  103. package/corpus/chunks/agent-tool-call-result.json +145 -0
  104. package/corpus/chunks/agent-tool-call-running.json +85 -0
  105. package/corpus/chunks/agent-tool-call-success.json +137 -0
  106. package/corpus/chunks/agent-trace-timeline.json +244 -0
  107. package/corpus/chunks/ai-streaming-response.json +147 -0
  108. package/corpus/chunks/alert-banner-stack.json +78 -0
  109. package/corpus/chunks/alert-banner.json +55 -0
  110. package/corpus/chunks/alert-dialog-simple.json +72 -0
  111. package/corpus/chunks/alert-dialog-typed.json +107 -0
  112. package/corpus/chunks/alert-dialog-unsaved.json +81 -0
  113. package/corpus/chunks/analytics-chart.json +213 -0
  114. package/corpus/chunks/analytics-sparklines-dashboard.json +259 -0
  115. package/corpus/chunks/anchor-bar-selection-bar.json +226 -0
  116. package/corpus/chunks/api-key-table.json +148 -0
  117. package/corpus/chunks/api-keys-create.json +140 -0
  118. package/corpus/chunks/api-keys-list.json +271 -0
  119. package/corpus/chunks/app-nav-badges-counts.json +77 -0
  120. package/corpus/chunks/app-nav-badges-group-rollup-badges.json +100 -0
  121. package/corpus/chunks/app-nav-badges-plan-tiers.json +76 -0
  122. package/corpus/chunks/app-nav-badges-status-callouts.json +75 -0
  123. package/corpus/chunks/app-nav-full-example.json +195 -0
  124. package/corpus/chunks/app-nav-groups.json +103 -0
  125. package/corpus/chunks/app-nav-items.json +74 -0
  126. package/corpus/chunks/app-nav-labels-and-dividers.json +92 -0
  127. package/corpus/chunks/app-nav-spacer.json +77 -0
  128. package/corpus/chunks/app-product-listing-card.json +214 -0
  129. package/corpus/chunks/approvals-detail.json +240 -0
  130. package/corpus/chunks/approvals-queue.json +321 -0
  131. package/corpus/chunks/audit-log-basic.json +184 -0
  132. package/corpus/chunks/audit-log.json +174 -0
  133. package/corpus/chunks/auth-account-deleted-actions.json +51 -0
  134. package/corpus/chunks/auth-account-deleted.json +202 -0
  135. package/corpus/chunks/auth-card-content.json +260 -0
  136. package/corpus/chunks/auth-card-header.json +205 -0
  137. package/corpus/chunks/auth-email-entry.json +65 -0
  138. package/corpus/chunks/auth-email-verify-confirm.json +52 -0
  139. package/corpus/chunks/auth-email-verify.json +196 -0
  140. package/corpus/chunks/auth-forbidden-actions.json +59 -0
  141. package/corpus/chunks/auth-forbidden.json +203 -0
  142. package/corpus/chunks/auth-invite-actions.json +49 -0
  143. package/corpus/chunks/auth-invite-team-card.json +86 -0
  144. package/corpus/chunks/auth-link-expired-form.json +65 -0
  145. package/corpus/chunks/auth-link-expired.json +196 -0
  146. package/corpus/chunks/auth-locked-account.json +211 -0
  147. package/corpus/chunks/auth-locked-recovery-options.json +60 -0
  148. package/corpus/chunks/auth-mfa-enrollment-submit.json +54 -0
  149. package/corpus/chunks/auth-mfa-enrollment.json +284 -0
  150. package/corpus/chunks/auth-mfa-fallback-actions.json +52 -0
  151. package/corpus/chunks/auth-mfa-recovery.json +61 -0
  152. package/corpus/chunks/auth-new-password-form.json +75 -0
  153. package/corpus/chunks/auth-new-password.json +217 -0
  154. package/corpus/chunks/auth-oauth-fallback-actions.json +52 -0
  155. package/corpus/chunks/auth-oauth-interstitial.json +160 -0
  156. package/corpus/chunks/auth-password-challenge.json +94 -0
  157. package/corpus/chunks/auth-password-reset-form.json +64 -0
  158. package/corpus/chunks/auth-password-reset.json +195 -0
  159. package/corpus/chunks/auth-profile-form.json +72 -0
  160. package/corpus/chunks/auth-profile-setup.json +194 -0
  161. package/corpus/chunks/auth-reset-sent.json +188 -0
  162. package/corpus/chunks/auth-session-expired-actions.json +52 -0
  163. package/corpus/chunks/auth-session-expired.json +201 -0
  164. package/corpus/chunks/auth-signin-card-email.json +245 -0
  165. package/corpus/chunks/auth-signin-card-magic-link.json +147 -0
  166. package/corpus/chunks/auth-signin-card-mfa.json +231 -0
  167. package/corpus/chunks/auth-signin-card-otp.json +205 -0
  168. package/corpus/chunks/auth-signin-card-password.json +264 -0
  169. package/corpus/chunks/auth-signin-card-recovery.json +218 -0
  170. package/corpus/chunks/auth-signout-actions.json +51 -0
  171. package/corpus/chunks/auth-signout.json +184 -0
  172. package/corpus/chunks/auth-signup-email-entry.json +66 -0
  173. package/corpus/chunks/auth-signup-entry.json +281 -0
  174. package/corpus/chunks/auth-signup-social-auths.json +54 -0
  175. package/corpus/chunks/auth-signup-verify.json +227 -0
  176. package/corpus/chunks/auth-social-auths.json +62 -0
  177. package/corpus/chunks/auth-sso-providers.json +55 -0
  178. package/corpus/chunks/auth-sso-required.json +213 -0
  179. package/corpus/chunks/auth-team-invite.json +288 -0
  180. package/corpus/chunks/avatar-group-overflow.json +137 -0
  181. package/corpus/chunks/avatar-stack-overflow.json +124 -0
  182. package/corpus/chunks/banner-announcement-beta.json +99 -0
  183. package/corpus/chunks/banner-announcement-promo.json +102 -0
  184. package/corpus/chunks/banner-live-update.json +102 -0
  185. package/corpus/chunks/banner-system-maintenance.json +101 -0
  186. package/corpus/chunks/banner-system-offline.json +85 -0
  187. package/corpus/chunks/banner-system-update.json +102 -0
  188. package/corpus/chunks/bell-menu-empty.json +107 -0
  189. package/corpus/chunks/bell-menu-unread.json +395 -0
  190. package/corpus/chunks/billing-cancel-subscription-danger.json +61 -0
  191. package/corpus/chunks/billing-invoice-history-table.json +75 -0
  192. package/corpus/chunks/billing-overview.json +202 -0
  193. package/corpus/chunks/billing-payment-method-card-on-file.json +157 -0
  194. package/corpus/chunks/billing-progress-label.json +101 -0
  195. package/corpus/chunks/blog-post-card.json +212 -0
  196. package/corpus/chunks/breadcrumb-navigation.json +72 -0
  197. package/corpus/chunks/bulk-action-toolbar-floating.json +199 -0
  198. package/corpus/chunks/bulk-action-toolbar-swap.json +158 -0
  199. package/corpus/chunks/bulk-selection-actions-bar.json +162 -0
  200. package/corpus/chunks/business-address-form.json +953 -0
  201. package/corpus/chunks/calendar-month-view.json +74 -0
  202. package/corpus/chunks/card-grid-images.json +459 -0
  203. package/corpus/chunks/card-header-with-description.json +47 -0
  204. package/corpus/chunks/card-with-empty-state.json +96 -0
  205. package/corpus/chunks/card-with-form.json +143 -0
  206. package/corpus/chunks/card-with-sparkline.json +90 -0
  207. package/corpus/chunks/card-with-stat-kpi.json +86 -0
  208. package/corpus/chunks/changelog-feed-basic.json +470 -0
  209. package/corpus/chunks/chart-in-card-chart-plus-breakdown.json +188 -0
  210. package/corpus/chunks/chart-in-card-chart-plus-stat.json +89 -0
  211. package/corpus/chunks/chart-in-card-chart-with-filter-pills.json +124 -0
  212. package/corpus/chunks/chart-in-card-full-bleed-legend.json +116 -0
  213. package/corpus/chunks/chart-in-card-full-chart.json +107 -0
  214. package/corpus/chunks/chart-in-card-sparkline-tile.json +93 -0
  215. package/corpus/chunks/chart-in-card-stat-with-sparkline.json +73 -0
  216. package/corpus/chunks/chart-in-card-trend-footer.json +115 -0
  217. package/corpus/chunks/chart-with-filter-pills.json +169 -0
  218. package/corpus/chunks/chat-empty-state-hero.json +102 -0
  219. package/corpus/chunks/chat-message-assistant-byline.json +85 -0
  220. package/corpus/chunks/chat-message-user-byline.json +84 -0
  221. package/corpus/chunks/chat-page-shell.json +379 -0
  222. package/corpus/chunks/chat-streaming-surface.json +169 -0
  223. package/corpus/chunks/checkout-order-summary-card.json +140 -0
  224. package/corpus/chunks/code-snippet.json +107 -0
  225. package/corpus/chunks/col-form-stack.json +93 -0
  226. package/corpus/chunks/col-heading-body-action.json +79 -0
  227. package/corpus/chunks/col-stat-label.json +63 -0
  228. package/corpus/chunks/color-picker-swatches.json +153 -0
  229. package/corpus/chunks/command-palette.json +327 -0
  230. package/corpus/chunks/comments-composer.json +158 -0
  231. package/corpus/chunks/comments-mention-menu.json +237 -0
  232. package/corpus/chunks/comments-thread.json +344 -0
  233. package/corpus/chunks/commerce-pricing-tiers.json +401 -0
  234. package/corpus/chunks/comparison-table.json +246 -0
  235. package/corpus/chunks/contact-form-card.json +197 -0
  236. package/corpus/chunks/contact-form.json +157 -0
  237. package/corpus/chunks/contact-support-form.json +702 -0
  238. package/corpus/chunks/conversion-funnel-4-step-funnel.json +139 -0
  239. package/corpus/chunks/conversion-funnel-6step.json +151 -0
  240. package/corpus/chunks/conversion-funnel-wide-summary.json +192 -0
  241. package/corpus/chunks/conversion-funnel-with-segment-compare.json +202 -0
  242. package/corpus/chunks/cta-banner-centered.json +102 -0
  243. package/corpus/chunks/dashboard-acquisition-panel.json +212 -0
  244. package/corpus/chunks/dashboard-admin-page.json +104 -0
  245. package/corpus/chunks/dashboard-audience-kpis.json +165 -0
  246. package/corpus/chunks/dashboard-audience-panel.json +756 -0
  247. package/corpus/chunks/dashboard-behavior-panel.json +114 -0
  248. package/corpus/chunks/dashboard-chart-recent.json +566 -0
  249. package/corpus/chunks/dashboard-cohort-retention.json +83 -0
  250. package/corpus/chunks/dashboard-conversion-panel.json +234 -0
  251. package/corpus/chunks/dashboard-country-list.json +304 -0
  252. package/corpus/chunks/dashboard-filter-bar.json +118 -0
  253. package/corpus/chunks/dashboard-funnel.json +142 -0
  254. package/corpus/chunks/dashboard-notifications-panel.json +423 -0
  255. package/corpus/chunks/dashboard-overview-panel.json +1644 -0
  256. package/corpus/chunks/dashboard-page-header.json +166 -0
  257. package/corpus/chunks/dashboard-pages-table.json +86 -0
  258. package/corpus/chunks/dashboard-quick-actions.json +116 -0
  259. package/corpus/chunks/dashboard-reports-panel.json +166 -0
  260. package/corpus/chunks/dashboard-reports-table.json +138 -0
  261. package/corpus/chunks/dashboard-storage-card.json +117 -0
  262. package/corpus/chunks/dashboard-tabs.json +86 -0
  263. package/corpus/chunks/dashboard-team-actions-storage.json +605 -0
  264. package/corpus/chunks/dashboard-team-list.json +334 -0
  265. package/corpus/chunks/dashboard-traffic-channels.json +184 -0
  266. package/corpus/chunks/dashboard-transactions-table.json +145 -0
  267. package/corpus/chunks/data-export-history.json +192 -0
  268. package/corpus/chunks/data-export-request.json +197 -0
  269. package/corpus/chunks/data-import-wizard.json +391 -0
  270. package/corpus/chunks/date-range-picker.json +156 -0
  271. package/corpus/chunks/date-time-picker-form.json +222 -0
  272. package/corpus/chunks/departments-checkbox-form.json +390 -0
  273. package/corpus/chunks/destructive-confirm-modal.json +149 -0
  274. package/corpus/chunks/diff-inline.json +84 -0
  275. package/corpus/chunks/diff-side-by-side.json +131 -0
  276. package/corpus/chunks/diff-structured.json +216 -0
  277. package/corpus/chunks/digest-email-preview.json +374 -0
  278. package/corpus/chunks/divider-text-label.json +87 -0
  279. package/corpus/chunks/doc-editor-shell.json +356 -0
  280. package/corpus/chunks/drawer-2fa-key.json +273 -0
  281. package/corpus/chunks/drawer-2fa-sms.json +261 -0
  282. package/corpus/chunks/drawer-2fa-totp.json +385 -0
  283. package/corpus/chunks/drawer-cancel-sub.json +636 -0
  284. package/corpus/chunks/drawer-change-plan.json +561 -0
  285. package/corpus/chunks/drawer-custom-roles.json +696 -0
  286. package/corpus/chunks/drawer-data-start.json +171 -0
  287. package/corpus/chunks/drawer-delete-account.json +341 -0
  288. package/corpus/chunks/drawer-delete-workspace.json +362 -0
  289. package/corpus/chunks/drawer-discord.json +434 -0
  290. package/corpus/chunks/drawer-figma.json +401 -0
  291. package/corpus/chunks/drawer-first-dashboard.json +220 -0
  292. package/corpus/chunks/drawer-gcal.json +475 -0
  293. package/corpus/chunks/drawer-github.json +589 -0
  294. package/corpus/chunks/drawer-invite.json +397 -0
  295. package/corpus/chunks/drawer-record-detail.json +44 -0
  296. package/corpus/chunks/drawer-report.json +528 -0
  297. package/corpus/chunks/drawer-revoke-session.json +331 -0
  298. package/corpus/chunks/drawer-role.json +190 -0
  299. package/corpus/chunks/drawer-slack.json +429 -0
  300. package/corpus/chunks/drawer-smtp.json +476 -0
  301. package/corpus/chunks/drawer-source.json +294 -0
  302. package/corpus/chunks/drawer-transaction.json +493 -0
  303. package/corpus/chunks/drawer-with-create-form.json +43 -0
  304. package/corpus/chunks/editor-code-pane.json +204 -0
  305. package/corpus/chunks/editor-page-shell.json +149 -0
  306. package/corpus/chunks/editor-preview-pane.json +136 -0
  307. package/corpus/chunks/editor-statusbar-ready.json +99 -0
  308. package/corpus/chunks/editor-toolbar-import-export.json +195 -0
  309. package/corpus/chunks/email-inbox-list.json +678 -0
  310. package/corpus/chunks/empty-state-danger.json +58 -0
  311. package/corpus/chunks/empty-state-minimal.json +44 -0
  312. package/corpus/chunks/empty-state-warning.json +53 -0
  313. package/corpus/chunks/empty-state.json +65 -0
  314. package/corpus/chunks/error-404-actions.json +54 -0
  315. package/corpus/chunks/error-404.json +204 -0
  316. package/corpus/chunks/error-500-actions.json +61 -0
  317. package/corpus/chunks/error-500.json +220 -0
  318. package/corpus/chunks/error-maintenance-actions.json +53 -0
  319. package/corpus/chunks/error-maintenance.json +203 -0
  320. package/corpus/chunks/error-page-shell.json +132 -0
  321. package/corpus/chunks/export-flow-async.json +210 -0
  322. package/corpus/chunks/export-flow-delivery.json +163 -0
  323. package/corpus/chunks/export-flow-sync.json +162 -0
  324. package/corpus/chunks/extended-profile-form.json +512 -0
  325. package/corpus/chunks/faq-accordion.json +123 -0
  326. package/corpus/chunks/feature-grid-icons.json +314 -0
  327. package/corpus/chunks/feature-grid-three-cards.json +187 -0
  328. package/corpus/chunks/feature-toggle-switch-grid.json +213 -0
  329. package/corpus/chunks/file-upload-dnd.json +166 -0
  330. package/corpus/chunks/file-upload-field.json +97 -0
  331. package/corpus/chunks/file-upload-form.json +251 -0
  332. package/corpus/chunks/filter-bar-active-filters.json +176 -0
  333. package/corpus/chunks/filter-bar-filter-bar-with-table.json +113 -0
  334. package/corpus/chunks/filter-bar-saved-views.json +117 -0
  335. package/corpus/chunks/filter-popover-form.json +137 -0
  336. package/corpus/chunks/footer-multi-column.json +270 -0
  337. package/corpus/chunks/footer-primary-only.json +41 -0
  338. package/corpus/chunks/form-checkbox-group.json +65 -0
  339. package/corpus/chunks/form-drawer-edit-form.json +178 -0
  340. package/corpus/chunks/form-drawer-simple-form.json +151 -0
  341. package/corpus/chunks/form-drawer-tall-form.json +325 -0
  342. package/corpus/chunks/form-field-email-hint.json +53 -0
  343. package/corpus/chunks/form-field-range.json +54 -0
  344. package/corpus/chunks/form-field-required.json +52 -0
  345. package/corpus/chunks/form-field-select.json +66 -0
  346. package/corpus/chunks/form-field-textarea.json +51 -0
  347. package/corpus/chunks/form-field-with-error.json +151 -0
  348. package/corpus/chunks/form-fields-two-column.json +69 -0
  349. package/corpus/chunks/form-page-shell.json +146 -0
  350. package/corpus/chunks/form-switch-toggle.json +41 -0
  351. package/corpus/chunks/form-system-live-demo.json +123 -0
  352. package/corpus/chunks/forms-address-autocomplete.json +277 -0
  353. package/corpus/chunks/forms-address-fields.json +221 -0
  354. package/corpus/chunks/forms-conditional-reveal.json +195 -0
  355. package/corpus/chunks/gallery-page-shell.json +444 -0
  356. package/corpus/chunks/grid-2col-entry-cards.json +140 -0
  357. package/corpus/chunks/grid-kpi-4col.json +164 -0
  358. package/corpus/chunks/grid-responsive-kpi.json +165 -0
  359. package/corpus/chunks/hero-cta-simple.json +107 -0
  360. package/corpus/chunks/hero-cta-split.json +183 -0
  361. package/corpus/chunks/hero-section-split.json +111 -0
  362. package/corpus/chunks/icon-text-row.json +60 -0
  363. package/corpus/chunks/image-caption-tile.json +99 -0
  364. package/corpus/chunks/image-carousel.json +156 -0
  365. package/corpus/chunks/image-thumbnail-grid.json +77 -0
  366. package/corpus/chunks/image-upload-preview.json +118 -0
  367. package/corpus/chunks/import-mapping-flow.json +972 -0
  368. package/corpus/chunks/inline-dialog-rename.json +128 -0
  369. package/corpus/chunks/inline-dialog-schedule.json +154 -0
  370. package/corpus/chunks/inline-dialog-status.json +179 -0
  371. package/corpus/chunks/integrations-api-keys-card-list.json +475 -0
  372. package/corpus/chunks/integrations-connect-form.json +550 -0
  373. package/corpus/chunks/integrations-grid.json +141 -0
  374. package/corpus/chunks/integrations-webhooks-empty-state.json +66 -0
  375. package/corpus/chunks/inventory-list-stock.json +137 -0
  376. package/corpus/chunks/invite-members.json +153 -0
  377. package/corpus/chunks/invoice-line-items.json +493 -0
  378. package/corpus/chunks/kanban-board-3col.json +713 -0
  379. package/corpus/chunks/kanban-page-shell.json +671 -0
  380. package/corpus/chunks/key-value-detail-list.json +242 -0
  381. package/corpus/chunks/keyboard-shortcut-display.json +250 -0
  382. package/corpus/chunks/labeled-textarea.json +45 -0
  383. package/corpus/chunks/leaderboard-table.json +140 -0
  384. package/corpus/chunks/library-browser-search-filter.json +109 -0
  385. package/corpus/chunks/linked-record-row.json +61 -0
  386. package/corpus/chunks/loading-skeleton-placeholder.json +387 -0
  387. package/corpus/chunks/login-form-card.json +207 -0
  388. package/corpus/chunks/logo-cloud-trusted-by.json +235 -0
  389. package/corpus/chunks/map-with-location-list.json +293 -0
  390. package/corpus/chunks/marketing-hero-cta.json +102 -0
  391. package/corpus/chunks/marketing-page-shell.json +352 -0
  392. package/corpus/chunks/masonry-gallery.json +154 -0
  393. package/corpus/chunks/member-edit-drawer.json +236 -0
  394. package/corpus/chunks/members-active-table-search-filter.json +184 -0
  395. package/corpus/chunks/members-pending-invites-cards.json +251 -0
  396. package/corpus/chunks/members-roles-permissions-list.json +146 -0
  397. package/corpus/chunks/menu-context-actions.json +113 -0
  398. package/corpus/chunks/metadata-description-list.json +178 -0
  399. package/corpus/chunks/modal-create-project-form.json +133 -0
  400. package/corpus/chunks/modal-preferences-tabs.json +147 -0
  401. package/corpus/chunks/multi-field-form-validation.json +394 -0
  402. package/corpus/chunks/nav-menu-icons.json +74 -0
  403. package/corpus/chunks/newsletter-subscription.json +190 -0
  404. package/corpus/chunks/notification-badges-feed.json +411 -0
  405. package/corpus/chunks/notification-preferences-panel.json +238 -0
  406. package/corpus/chunks/onb-completion.json +139 -0
  407. package/corpus/chunks/onb-extension-install.json +172 -0
  408. package/corpus/chunks/onb-hero-welcome.json +156 -0
  409. package/corpus/chunks/onb-import-picker.json +86 -0
  410. package/corpus/chunks/onb-mobile-handoff.json +121 -0
  411. package/corpus/chunks/onb-notification-prefs.json +83 -0
  412. package/corpus/chunks/onb-persona-picker.json +82 -0
  413. package/corpus/chunks/onb-provider-tiles.json +137 -0
  414. package/corpus/chunks/onb-settings-review.json +257 -0
  415. package/corpus/chunks/onb-step-footer.json +121 -0
  416. package/corpus/chunks/onb-step-header.json +121 -0
  417. package/corpus/chunks/onb-step-progress.json +140 -0
  418. package/corpus/chunks/onb-step-shell.json +380 -0
  419. package/corpus/chunks/onb-story-pane.json +121 -0
  420. package/corpus/chunks/onb-tutorial-steps.json +193 -0
  421. package/corpus/chunks/order-confirmation-success-card.json +177 -0
  422. package/corpus/chunks/order-tracking-timeline.json +131 -0
  423. package/corpus/chunks/pagination-controls.json +82 -0
  424. package/corpus/chunks/pane-settings-sidebar.json +204 -0
  425. package/corpus/chunks/patient-visit-shell.json +191 -0
  426. package/corpus/chunks/payment-checkout-form.json +341 -0
  427. package/corpus/chunks/payment-method-form.json +328 -0
  428. package/corpus/chunks/period-comparison.json +236 -0
  429. package/corpus/chunks/permission-matrix-table.json +438 -0
  430. package/corpus/chunks/permissions-matrix-grid.json +111 -0
  431. package/corpus/chunks/permissions-matrix-summary.json +157 -0
  432. package/corpus/chunks/permissions-role-picker-radio.json +107 -0
  433. package/corpus/chunks/permissions-role-picker-select.json +101 -0
  434. package/corpus/chunks/permissions-share-link.json +256 -0
  435. package/corpus/chunks/permissions-share-people.json +297 -0
  436. package/corpus/chunks/permissions-sharing-scopes.json +109 -0
  437. package/corpus/chunks/plan-selection-form.json +529 -0
  438. package/corpus/chunks/playground-a2ui.json +181 -0
  439. package/corpus/chunks/playground-agent-admin.json +117 -0
  440. package/corpus/chunks/playground-agent-chat.json +126 -0
  441. package/corpus/chunks/playground-app-shell.json +488 -0
  442. package/corpus/chunks/playground-chat.json +265 -0
  443. package/corpus/chunks/playground-construct-canvas.json +118 -0
  444. package/corpus/chunks/playground-css-channel.json +487 -0
  445. package/corpus/chunks/playground-gen-ui.json +224 -0
  446. package/corpus/chunks/playground-render-preview.json +369 -0
  447. package/corpus/chunks/playground-streams-bridge.json +437 -0
  448. package/corpus/chunks/playground-table-toolbar.json +38 -0
  449. package/corpus/chunks/popover-with-content.json +118 -0
  450. package/corpus/chunks/pricing-tiers.json +561 -0
  451. package/corpus/chunks/product-tour.json +158 -0
  452. package/corpus/chunks/profile-public.json +297 -0
  453. package/corpus/chunks/progress-tracker-milestones.json +294 -0
  454. package/corpus/chunks/radio-button-group.json +83 -0
  455. package/corpus/chunks/rating-stars-review-summary.json +259 -0
  456. package/corpus/chunks/reactions-bar.json +75 -0
  457. package/corpus/chunks/reactions-picker.json +245 -0
  458. package/corpus/chunks/real-time-metrics-dashboard.json +344 -0
  459. package/corpus/chunks/record-detail-drawer-simple-detail.json +296 -0
  460. package/corpus/chunks/record-detail-drawer-tabbed-detail.json +443 -0
  461. package/corpus/chunks/referral-share-link.json +128 -0
  462. package/corpus/chunks/referral-status.json +243 -0
  463. package/corpus/chunks/reg-address-form.json +825 -0
  464. package/corpus/chunks/reg-billing-card.json +210 -0
  465. package/corpus/chunks/reg-brand-scrape.json +599 -0
  466. package/corpus/chunks/reg-departments-toggle.json +259 -0
  467. package/corpus/chunks/reg-extended-profile.json +356 -0
  468. package/corpus/chunks/reg-final-done.json +457 -0
  469. package/corpus/chunks/reg-helpdesk-grid.json +571 -0
  470. package/corpus/chunks/reg-import-picker.json +112 -0
  471. package/corpus/chunks/reg-integrations-grid.json +418 -0
  472. package/corpus/chunks/reg-invite-form.json +245 -0
  473. package/corpus/chunks/reg-legal-entity.json +260 -0
  474. package/corpus/chunks/reg-org-chart-review.json +891 -0
  475. package/corpus/chunks/reg-profile-identity.json +188 -0
  476. package/corpus/chunks/reg-step-footer.json +201 -0
  477. package/corpus/chunks/reg-step-header.json +201 -0
  478. package/corpus/chunks/reg-step-progress.json +236 -0
  479. package/corpus/chunks/reg-step-shell.json +605 -0
  480. package/corpus/chunks/reg-story-pane.json +201 -0
  481. package/corpus/chunks/reg-success-summary.json +257 -0
  482. package/corpus/chunks/reg-team-size.json +128 -0
  483. package/corpus/chunks/reg-usecase-picker.json +104 -0
  484. package/corpus/chunks/reg-workspace-name.json +159 -0
  485. package/corpus/chunks/responsive-grid-pattern.json +71 -0
  486. package/corpus/chunks/responsive-kpi-grid.json +166 -0
  487. package/corpus/chunks/responsive-row-pattern.json +71 -0
  488. package/corpus/chunks/responsive-shell-sidebar.json +308 -0
  489. package/corpus/chunks/responsive-wrap-at-pattern.json +124 -0
  490. package/corpus/chunks/retention-cohort-default-retention.json +80 -0
  491. package/corpus/chunks/retention-cohort-stat-pair.json +163 -0
  492. package/corpus/chunks/retention-cohort-with-legend.json +135 -0
  493. package/corpus/chunks/revenue-heatmap.json +82 -0
  494. package/corpus/chunks/role-management.json +272 -0
  495. package/corpus/chunks/row-action-cluster.json +54 -0
  496. package/corpus/chunks/row-avatar-name-role.json +71 -0
  497. package/corpus/chunks/row-icon-label.json +52 -0
  498. package/corpus/chunks/row-spread-label-value.json +54 -0
  499. package/corpus/chunks/row-wrap-tags.json +72 -0
  500. package/corpus/chunks/schedule-meeting-form-card.json +229 -0
  501. package/corpus/chunks/search-recents-menu.json +195 -0
  502. package/corpus/chunks/search-results-grouped.json +357 -0
  503. package/corpus/chunks/search-results-list.json +202 -0
  504. package/corpus/chunks/search-saved-views.json +356 -0
  505. package/corpus/chunks/search-with-filters.json +311 -0
  506. package/corpus/chunks/searchable-picker-modal.json +164 -0
  507. package/corpus/chunks/section-with-stack.json +48 -0
  508. package/corpus/chunks/security-active-sessions-devices.json +287 -0
  509. package/corpus/chunks/security-change-password-form.json +102 -0
  510. package/corpus/chunks/security-delete-account-danger.json +79 -0
  511. package/corpus/chunks/segmented-control-billing-tabs.json +164 -0
  512. package/corpus/chunks/select-multiple-preselected.json +70 -0
  513. package/corpus/chunks/settings-2fa-setup.json +307 -0
  514. package/corpus/chunks/settings-admin-page.json +1205 -0
  515. package/corpus/chunks/settings-appearance-primitives.json +145 -0
  516. package/corpus/chunks/settings-appearance-theme-panel.json +55 -0
  517. package/corpus/chunks/settings-appearance.json +81 -0
  518. package/corpus/chunks/settings-danger-zone-delete-workspace.json +93 -0
  519. package/corpus/chunks/settings-general-form.json +69 -0
  520. package/corpus/chunks/settings-integrations.json +298 -0
  521. package/corpus/chunks/settings-members-invite.json +112 -0
  522. package/corpus/chunks/settings-notification-activity-checkboxes.json +108 -0
  523. package/corpus/chunks/settings-notification-channels-switches.json +101 -0
  524. package/corpus/chunks/settings-page-shell.json +190 -0
  525. package/corpus/chunks/settings-privacy.json +83 -0
  526. package/corpus/chunks/settings-profile-security.json +122 -0
  527. package/corpus/chunks/settings-toggle-switches.json +66 -0
  528. package/corpus/chunks/sidebar-nav.json +120 -0
  529. package/corpus/chunks/sidebar-navigation-panel.json +165 -0
  530. package/corpus/chunks/signup-form-card.json +218 -0
  531. package/corpus/chunks/signup-team-size-form.json +259 -0
  532. package/corpus/chunks/single-select-card-form.json +231 -0
  533. package/corpus/chunks/slider-range-controls.json +119 -0
  534. package/corpus/chunks/social-media-post-card.json +159 -0
  535. package/corpus/chunks/sortable-list.json +307 -0
  536. package/corpus/chunks/sortable-search-paginate-table.json +162 -0
  537. package/corpus/chunks/split-pane-editor.json +146 -0
  538. package/corpus/chunks/stack-avatar-badge-overlay.json +53 -0
  539. package/corpus/chunks/stack-image-shimmer.json +51 -0
  540. package/corpus/chunks/stat-cards-kpi-dashboard.json +178 -0
  541. package/corpus/chunks/stats-band-big-numbers.json +175 -0
  542. package/corpus/chunks/status-dashboard.json +282 -0
  543. package/corpus/chunks/stepper-form-wizard.json +165 -0
  544. package/corpus/chunks/subscription-status-renewal-card.json +285 -0
  545. package/corpus/chunks/survey-rating-form.json +165 -0
  546. package/corpus/chunks/swiper-product-carousel.json +349 -0
  547. package/corpus/chunks/swiper-testimonial-carousel.json +279 -0
  548. package/corpus/chunks/table-empty-state.json +116 -0
  549. package/corpus/chunks/table-inline-edit-row.json +269 -0
  550. package/corpus/chunks/table-spreadsheet-cells.json +334 -0
  551. package/corpus/chunks/table-toolbar-no-search.json +42 -0
  552. package/corpus/chunks/table-toolbar-with-table.json +208 -0
  553. package/corpus/chunks/table-with-toolbar-card.json +80 -0
  554. package/corpus/chunks/tabs-with-panels.json +187 -0
  555. package/corpus/chunks/tag-chips-filter.json +100 -0
  556. package/corpus/chunks/team-invite-form.json +380 -0
  557. package/corpus/chunks/team-members-list.json +341 -0
  558. package/corpus/chunks/testimonial-grid.json +269 -0
  559. package/corpus/chunks/testimonial-pull-quote.json +137 -0
  560. package/corpus/chunks/testimonials-avatar-cards.json +286 -0
  561. package/corpus/chunks/timeline-events.json +89 -0
  562. package/corpus/chunks/timezone-selector-basic.json +99 -0
  563. package/corpus/chunks/timezone-selector-preview.json +104 -0
  564. package/corpus/chunks/toolbar-icons.json +216 -0
  565. package/corpus/chunks/toolbar-rich-text-editor.json +230 -0
  566. package/corpus/chunks/toolbar-tooltips.json +191 -0
  567. package/corpus/chunks/tooltip-hover-button.json +106 -0
  568. package/corpus/chunks/tree-file-explorer.json +136 -0
  569. package/corpus/chunks/tree-table-basic.json +171 -0
  570. package/corpus/chunks/trial-banner.json +158 -0
  571. package/corpus/chunks/url-import-form.json +728 -0
  572. package/corpus/chunks/usage-quota-meter-card.json +217 -0
  573. package/corpus/chunks/user-identity-row.json +81 -0
  574. package/corpus/chunks/user-onboarding-checklist.json +301 -0
  575. package/corpus/chunks/user-profile-card.json +192 -0
  576. package/corpus/chunks/users-table-badge.json +135 -0
  577. package/corpus/chunks/verification-document-upload.json +179 -0
  578. package/corpus/chunks/verification-status.json +97 -0
  579. package/corpus/chunks/verification-stepper.json +111 -0
  580. package/corpus/chunks/video-player-controls.json +120 -0
  581. package/corpus/chunks/webhook-config.json +209 -0
  582. package/corpus/chunks/webhooks-list.json +204 -0
  583. package/corpus/chunks/wizard-drawer-three-step-wizard.json +443 -0
  584. package/corpus/manifest.d.ts +4 -0
  585. package/corpus/manifest.json +6 -0
  586. package/corpus/scripts/chunk-library.d.ts +4 -0
  587. package/corpus/scripts/chunk-library.js +335 -0
  588. package/node-shims.d.ts +48 -0
  589. package/package.json +215 -0
  590. package/retrieval/CHANGELOG.md +1073 -0
  591. package/retrieval/README.md +71 -0
  592. package/retrieval/anti-patterns.js +189 -0
  593. package/retrieval/authoring/index.d.ts +4 -0
  594. package/retrieval/authoring/index.js +9 -0
  595. package/retrieval/authoring/web-research.js +220 -0
  596. package/retrieval/catalog.js +250 -0
  597. package/retrieval/component-catalog.js +168 -0
  598. package/retrieval/component-entry.js +80 -0
  599. package/retrieval/context-assembler.js +174 -0
  600. package/retrieval/domain-router.js +417 -0
  601. package/retrieval/embedding/chunk-embedding-retriever.js +117 -0
  602. package/retrieval/embedding/embedding-provider.js +72 -0
  603. package/retrieval/embedding/index.d.ts +4 -0
  604. package/retrieval/embedding/index.js +2 -0
  605. package/retrieval/feedback/dialog-recorder.js +107 -0
  606. package/retrieval/feedback/feedback-analyzer.js +180 -0
  607. package/retrieval/feedback/feedback-store.js +194 -0
  608. package/retrieval/feedback/feedback.js +117 -0
  609. package/retrieval/feedback/gap-registry.js +80 -0
  610. package/retrieval/feedback/human-signal.js +113 -0
  611. package/retrieval/feedback/index.d.ts +4 -0
  612. package/retrieval/feedback/index.js +24 -0
  613. package/retrieval/feedback/submit-feedback.js +45 -0
  614. package/retrieval/index.d.ts +4 -0
  615. package/retrieval/index.js +53 -0
  616. package/retrieval/intent/clarity.js +139 -0
  617. package/retrieval/intent/decomposer.js +124 -0
  618. package/retrieval/intent/index.d.ts +4 -0
  619. package/retrieval/intent/index.js +18 -0
  620. package/retrieval/intent/intent-alignment.js +172 -0
  621. package/retrieval/intent/intent-categorizer.js +69 -0
  622. package/retrieval/intent/intent-gate.js +96 -0
  623. package/retrieval/intent/prompt-analyzer.js +162 -0
  624. package/retrieval/wiring-catalog.js +168 -0
  625. package/validate/catalog-validator.d.ts +4 -0
  626. package/validate/catalog-validator.js +327 -0
  627. package/validate/semantic/cache.js +54 -0
  628. package/validate/semantic/classify-intent.js +128 -0
  629. package/validate/semantic/index.js +163 -0
  630. package/validate/semantic/intent-specs.js +162 -0
  631. package/validate/semantic/judge.js +180 -0
@@ -0,0 +1,1215 @@
1
+ # AdiaUI Catalog — LLM Rules (v0.9)
2
+
3
+ # Cross-component and contextual constraints that the JSON Schema validator
4
+ # cannot express. Concatenated into the agent system prompt.
5
+ # Generated from each component YAML's `a2ui.rules:` entries.
6
+
7
+ ## AccordionItem
8
+ - Child of <accordion-ui> — places one collapsible section with header + body.
9
+ - Toggle behavior: click anywhere on the row toggles, unless inside [slot='actions'] or [data-no-toggle].
10
+ - For single-button disclosures (one expanding panel without a list) use <details>/<summary> or compose <button-ui> + <section-ui>.
11
+ - An item inherits its host accordion-ui's [variant]; set variant="flat" or variant="contained" directly on ONE item to override just that item against the host.
12
+
13
+ ## Accordion
14
+ - Hosts <accordion-item-ui> children. One or more sections may be open simultaneously (set single= to enforce only-one-open).
15
+ - For tab-switched panels (always exactly one open) use <tabs-ui>; accordion supports zero-open and multi-open.
16
+ - Item ordering is DOM-order; no auto-sort.
17
+ - Set variant="contained" for a bounded per-item surface (background, border, radius, and an open-state divider) — the composition to reach for when nesting inside <card-ui>. Default variant="flat" (no chrome) suits settings pages and FAQ blocks sitting on the page canvas.
18
+
19
+ ## ActionItem
20
+ - Child of <action-list-ui> — one inline-action row with icon + label + optional shortcut + optional sublabel.
21
+ - Different from <menu-item-ui>: action-items live inline in content surfaces; menu-items live inside <menu-ui> popovers.
22
+ - For navigation entries (route-changing) use <nav-item-ui> instead.
23
+
24
+ ## ActionList
25
+ - Hosts <action-item-ui> children as a vertical command list inline in content surfaces.
26
+ - For popover-style menus use <menu-ui> + <menu-item-ui> instead.
27
+ - Typical use: command palettes, settings panels, agent suggestion lists.
28
+
29
+ ## AdiaMark
30
+ - Use <AdiaMark> for the Adia brand/app-identity mark — a favicon-style app-switcher tile, a splash/loading screen, an about-panel header. Do not use it as a generic icon; it has no [name] prop and always renders the same wordmark.
31
+ - Do not wrap <AdiaMark> in <Icon> or pass it a color/tone override — the background/foreground pairing is fixed by design (always inverse-on-inverse for contrast), not a themeable variant.
32
+ - Prefer <AdiaMark size="sm"> in a nav/topbar brand slot (a Row alongside the product name); reserve larger sizes (lg, xl) for splash screens or empty-state headers. Set [inline] only when the mark sits directly inside a run of prose text, not inside a Row/flex layout (block-level children compose fine as flex items already).
33
+ - Use <AdiaMark> for the square icon/tile use (app-switcher slot, favicon-style avatar) — always the fixed inverse-on-inverse pairing. Use <AdiaWordmark> instead for the standalone "Adia" text logotype meant to sit directly on a surface with no background chip.
34
+
35
+ ## AdiaWordmark
36
+ - Use <AdiaWordmark> for the Adia text logotype standing alone directly on a surface — a login/marketing header, a footer, an about panel, a splash screen with no background chip. Use <AdiaMark> instead for the square icon/tile use (app-switcher slot, favicon-style avatar).
37
+ - Do not wrap <AdiaWordmark> in <Icon> or pass it a color/tone override tied to an inverse pairing — it has no [name] prop, always renders the same logotype path data, and its fill is meant to track the current surface's foreground token.
38
+ - Prefer <AdiaWordmark size="sm"> in a nav/topbar brand slot; reserve larger sizes (lg, xl) for splash or login screens. Set [inline] only when the wordmark sits directly inside a run of prose text, not inside a Row/flex layout (block-level children compose fine as flex items already).
39
+
40
+ ## AgentArtifact
41
+ - Inline container for structured agent payloads inside <chat-thread-ui> message bodies or <inspector-ui> panes.
42
+ - kind attribute (a2ui|json|ticket|code|...) sets content-type-aware rendering and icon/badge styling.
43
+ - For free-text agent output use <text-ui> or <richtext-ui>; artifact-ui is for structured payloads only.
44
+ - primary + secondary slots for header chrome; default slot for the artifact body.
45
+
46
+ ## AgentFeedbackBar
47
+ - Thumbs-up / thumbs-down rating row + optional Save action, rendered beneath an LLM-generated message.
48
+ - Different from <rating-ui> (star-based ordinal) — agent-feedback is binary good/bad.
49
+ - Emits feedback events with value=up|down and optional save action; consumer wires the actual feedback API call.
50
+ - Place at the end of an assistant message in <chat-thread-ui>, not on user messages.
51
+
52
+ ## AgentQuestions
53
+ - Multi-choice clarifying-question card emitted by an agent when it needs disambiguation before proceeding.
54
+ - multi attribute controls single-select (default) vs multi-select answer behavior.
55
+ - Slot accepts <button-ui> answer chips; for radio-card style use <segmented-ui> + <segment-ui> children instead.
56
+ - Different from <agent-suggestions-ui> (follow-up suggestions, optional) — agent-questions is gating (agent waits for answer).
57
+
58
+ ## AgentReasoning
59
+ - Agent inner-monologue + pipeline viewer with steps, thoughts, plans, and iterations.
60
+ - JS-property-driven ONLY — steps arrive via addStep()/addThought(); the component renders them internally as <timeline-item-ui> rows. Authored light-DOM children are NOT consumed (gh#938) — for a static/harvestable reasoning-steps surface, author a plain <timeline-ui> with <timeline-item-ui> children instead.
61
+ - noAutocollapse attribute prevents the auto-collapse-on-complete behavior; useful for debug surfaces.
62
+ - Different from <agent-trace-ui> (metrics + tool-call summary) — reasoning is narrative, trace is structured-data.
63
+
64
+ ## AgentSuggestions
65
+ - Row of follow-up suggestion chips presented under an agent response. User taps to send the chip text as the next prompt.
66
+ - Hosts <button-ui> children with chip-style variant; auto-applies variant if children don't set one.
67
+ - Different from <agent-questions-ui> (required disambiguation) — suggestions are optional and the agent doesn't wait.
68
+ - Place at the end of an assistant message in <chat-thread-ui>; not for first-message empty-state suggestions (use <empty-state-ui>).
69
+
70
+ ## AgentTrace
71
+ - Collapsible metrics + training-feedback panel showing reasoning steps, tool calls, latency, and token counts.
72
+ - Place inside <chat-thread-ui> message bodies for expert/debug views; hide by default in user-facing chat.
73
+ - Different from <agent-reasoning-ui> (narrative inner monologue) — agent-trace is structured metrics.
74
+ - Default collapsed=true; expand-on-demand keeps chat-thread visual density low.
75
+
76
+ ## Alert
77
+ - Inline alert/banner for status messages within a content region. Severity via variant (info, success, warning, danger) — those four plus the family-less default are the whole enum.
78
+ - For ephemeral toast notifications use <toast-ui> (or post to <feed-ui>); alert-ui is persistent inline.
79
+ - For modal-style critical alerts use <modal-ui> with alert content.
80
+ - Billing dunning / payment-failed notices use pattern="dunning" + amount + currency + dueAt props, NOT inlined into title/description strings.
81
+ - pattern="dunning" SHOULD use variant="danger" (default) or variant="warning" (grace period); never variant="info" or "success".
82
+ - When pattern="dunning", slot at least one button-ui in slot="actions" with data-dunning-action ("update" or "retry").
83
+
84
+ ## AnchorBar
85
+ - Persistent, non-blocking anchored surface. Use for floating bulk-action toolbars, undo bars, and wizard/commit footers — never for transient notifications (use <toast-ui>) or blocking dialogs (use <modal-ui> / <drawer-ui>).
86
+ - Default [viewport=false] anchors within the nearest scroll container via position:sticky — the correct choice when the bar sits over a bounded scroll region (e.g. a table's own scroll box). Set [viewport] only when the surface must anchor to the browser viewport regardless of ancestor scroll containers (e.g. an undo bar over an arbitrary page layout).
87
+ - Does NOT join the modal mutual-exclusion convention — it is not a modal surface and coexists with page interaction and open popovers.
88
+
89
+ ## Aside
90
+ - Use <aside-ui> as a slot stub inside an IN-PAGE primitive container parent (<card-ui>, <drawer-ui>, <modal-ui>, <page-ui>) for two-column layouts with a semantic side region. It ships no behavior; the parent reads [collapsible] and [width] via @scope. Typical contents: <list-ui> / <tree-ui> / <nav-ui variant="section">.
91
+ - Do NOT use <aside-ui> for app-shell sidebars. <admin-shell> no longer reads <aside-ui slot="leading|trailing"> (retired in v0.4.0 per ADR-0024). Use the bespoke <admin-sidebar slot="leading|trailing" collapsible resizable> with reflected [collapsed] / [resizing] state. Same rule for <chat-sidebar> under <chat-shell> and <editor-sidebar> under <editor-shell>.
92
+ - Do NOT confuse <aside-ui> with <pane-ui>: aside-ui declares the semantic side role (a11y + parent layout hint); <pane-ui> owns resize / collapse interaction. When you need interactive resize inside an aside, nest <pane-ui resizable> inside.
93
+ - Width hints map to tokens: `width="rail"` ≈ icon-only nav, `width="panel"` ≈ nav with labels, `width="wide"` ≈ workspace pane. Unset defers to the parent default. Only pair `collapsible` with parents that wire a toggle (the prop is a hint, not a behavior).
94
+ - For the settings-page description rail (label + help text on the left, controls on the right) use plain HTML <aside> inside a [data-section] flex layout — see apps/saas/billing and apps/saas/members. That pattern is NOT aside-ui; the primitive is for slotted container parents only.
95
+
96
+ ## AvatarGroup
97
+ - Cluster of overlapping <avatar-ui> children with negative-margin stacking + +N overflow indicator.
98
+ - max attribute controls visible-avatar count before +N overflow kicks in.
99
+ - For a single user use <avatar-ui> standalone; avatar-group only for 2+ users.
100
+
101
+ ## Avatar
102
+ - Use for representing a single person, account, or entity. Image, initials, or icon fallback in priority order.
103
+ - For clusters of multiple users, wrap multiple <avatar-ui> in <avatar-group-ui> instead of placing them inline.
104
+ - Do not embed inside <button-ui> for clickable avatars — make the <avatar-ui> itself the click target with role='button'.
105
+
106
+ ## Badge
107
+ - Use for small status/count labels attached to another element (notification counts, status pills, version tags).
108
+ - A bare Badge (no [tone]) renders a solid, saturated status stamp. Set [tone="muted"] for the quieter tinted look on dense metadata rows.
109
+ - Place adjacent to or absolutely-positioned over the badged element, not inside it.
110
+ - For dismissable taxonomy labels (filter chips, selected items in multi-select), use <tag-ui> instead.
111
+
112
+ ## Block
113
+ - Generic semantic block — use for arbitrary content groupings without strong layout semantics.
114
+ - For row/column layouts use <row-ui> / <col-ui>; for grid use <stack-ui>; block is for content-flow groupings.
115
+ - Block-ui does not impose padding/gap by default — wrap in <section-ui> if you want chrome.
116
+
117
+ ## Blockquote
118
+ - Use for pull-quotes, testimonials, or inline citations. Renders italic body text with a left rule indicator + optional em-dash attribution line.
119
+ - Set [cite] for plain-string attribution; use [slot="cite"] for rich attribution (linked source, role pairing). Slot content overrides the [cite] prop when both are set.
120
+ - Do NOT wrap blockquote-ui in a native <blockquote> element — that produces nested-blockquote semantics. The tag IS the blockquote.
121
+
122
+ ## Breadcrumb
123
+ - Canonical placement: render <breadcrumb-ui> inside <admin-topbar> for hierarchical page-context display. It is the topbar's heading region — typically preceded by a sidebar-toggle <button-ui icon="sidebar" variant="ghost" size="sm"> and followed by topbar actions in [slot="action"]. The host stamps role="navigation" + aria-label="Breadcrumb" automatically.
124
+ - Child shape: each crumb is either an <a href> (ancestor link) or a plain <span> (terminal / non-link current page). The LAST child is the current page and MUST be a plain <span> — the component auto-applies aria-current="page" and disables pointer events on it. Optional first child may be an <icon-ui> (or <a> wrapping one with aria-label) for an app / home glyph.
125
+ - Separator + overflow: do NOT insert your own separator elements ([data-sep] spans are stamped automatically between children). For deep trails (4+ items) prefer the `collapse` attribute over manual truncation; tune visible edges with [collapse-keep-leading] / [collapse-keep-trailing]. Collapsed middle crumbs are presented as a `…` <menu-ui data-overflow> popover.
126
+ - Decision rule: <breadcrumb-ui> is read-only PATH-CONTEXT display ("where am I"). For primary navigation (sidebar) use <nav-ui> + <nav-item-ui> inside <admin-sidebar>. For switching sub-views within a page use <tabs-ui>. Never use <breadcrumb-ui> as the primary navigation control or wrap navigation controls (selects, tabs, form controls) inside it.
127
+
128
+ ## Button
129
+ - Canonical clickable affordance — text + optional icon. Variant attribute sets primary/secondary/ghost/destructive intent.
130
+ - Do not repeat the icon's glyph in text=. Icon provides the symbol; text= carries only the words.
131
+ - For navigation (route-change) use <nav-item-ui> or anchor; button-ui is for actions only.
132
+ - For toggleable on/off state use <switch-ui>; for multi-select clusters use <toggle-group-ui> + <toggle-option-ui>.
133
+
134
+ ## CalendarGrid
135
+ - Use <CalendarGrid> only as a substrate primitive composed inside a higher-level component (date-range picker, datetime picker, custom date affordance). For a full single-date input, use <CalendarPicker> — it adds a trigger button, popover surface, and form-association.
136
+ - <CalendarGrid> is NOT form-associated. Its emitted `change` event is the sole signal to the parent — the parent owns the canonical value + form participation.
137
+
138
+ ## CalendarPicker
139
+ - Form-associated date input. Trigger button + popover calendar grid; emits ISO date string via change events.
140
+ - Use for single-date input. For date ranges compose two pickers or use a dedicated range component.
141
+ - min/max attributes constrain selectable range; disabled-dates accepts a function or date list.
142
+
143
+ ## Canvas
144
+ - A2UI rendering surface — consumes a DocStore / A2UI document and renders the component tree from it.
145
+ - Typically wrapped by <a2ui-root> internally; for direct-mount use <canvas-ui> as the root.
146
+ - Do not place static children inside — the runtime owns the rendered DOM.
147
+ - theme attribute scopes the AdiaUI token theme to the canvas subtree.
148
+
149
+ ## Card
150
+ - The card's <header> grid activates only for DIRECT-child slotted elements. If you need an icon column, place the icon element (avatar-ui, icon-ui) directly in the header with slot="icon" — not inside a wrapper.
151
+ - Heading slot accepts inline badges/metadata: <span slot="heading"><text-ui strong>Title</text-ui><badge-ui text="New" variant="primary"></badge-ui></span> renders title + badge on one row.
152
+ - Description slot also accepts bare <p> or <small> elements as siblings of the heading — they participate in the grid's row 2 without needing slot="description".
153
+ - Multiple <section> siblings are allowed and stack vertically. [bleed] on a section removes its margin for edge-to-edge content (tables, charts); [padding] adds a canvas-scrim background for hero regions.
154
+ - When neither [raw] nor [frameless] is present, a <table-ui> placed directly inside a <section bleed> automatically renders chromeless (background/box-shadow/border-radius reset; card.css, gh#796): the card already owns the frame, so the table doesn't need its own. table.yaml's [raw]/[frameless] docs describe the same composition; an explicit [raw] or [frameless] on the table still applies and is honored. A plain (non-bleed) <section> is unaffected — its own padding keeps a nested table's frame legible as an intentional nested surface.
155
+ - [grow] on a section makes it fill the card's remaining height (flex:1 — same semantics as col-ui[grow]/row-ui[grow]). The card becomes a flex column so the section absorbs the leftover space after the header/footer. Requires the card to have a definite height (inline height, grid row track, or flex parent) — a content-sized card has nothing to fill. Combine with [bleed] for edge-to-edge fill: <section bleed grow>. A <chart-ui> directly inside a <section bleed> auto-grows without [grow] (zero-config convenience for the common chart case).
156
+ - Footer with a [slot="description"] + [slot="action"] pair triggers justify-content: space-between — useful for a "Last saved …" note on the left and a Save/Cancel button group on the right.
157
+ - Do NOT substitute <card-ui> for shell/page containers. <admin-page>, <admin-content>, and <page-ui> own routed page layout; <card-ui> is a localized bordered surface that lives INSIDE them. For overlays use <modal-ui> (centered) or <drawer-ui> (edge-anchored) — both share the same 4-stub <header>/<section>/<footer> vocabulary.
158
+ - Use [raw] when a parent already owns the surface chrome (e.g. an auth screen centred on the viewport — see apps/user-flow/auth). Use [elevation] 0–3 for shadow depth; [variant="ghost"|"flat"] to remove shadow without removing structure. [draggable] emits a drag-end event; only enable on cards meant to move.
159
+
160
+ ## ChartLegend
161
+ - Standalone legend primitive — a row of <badge-ui>+<swatch-ui> chips that are keyboard-focusable and click-toggleable.
162
+ - Pairs with <chart-ui> via [for] id-ref (auto-bidirectional series toggling) or via items= for standalone use.
163
+ - position attribute (top|bottom|left|right) places legend relative to its chart; static= disables interactivity.
164
+
165
+ ## Chart
166
+ - Declarative SVG chart supporting 18 types via the type attribute (bar, line, pie, donut, radar, area, ...).
167
+ - For density-grid visualizations (calendar heatmap, etc.) use <heatmap-ui> instead.
168
+ - Pair with <chart-legend-ui [for]=...> for keyboard-toggleable series legends; otherwise use the built-in inline legend.
169
+ - title + empty slots for chart chrome; canvas slot for chart-internal overlays.
170
+
171
+ ## ChatInput
172
+ - ChatInput is a self-contained composer — it stamps its own textarea + model picker + send button. DO NOT add a separate Button sibling for "send" inside the same parent. The user gets two send buttons (one built-in, one redundant).
173
+ - For chat interfaces emit ChatInput as the sole input component inside the chat shell. The submit event fires on Enter or send-button click; `detail` is `{ text, model }`.
174
+ - To customize models, set the `models` prop with an array of {value, label} option objects. Do not stamp a separate Select next to ChatInput for model selection — the built-in model picker handles it.
175
+
176
+ ## ChatThread
177
+ - Primitive chat-message scroll container — ad-hoc message rendering surface.
178
+ - Different from the bespoke <chat-thread> (module-tier, lives inside <chat-shell-ui>, owns scroll + load-more affordances).
179
+ - Hosts arbitrary children — typical content: agent + user message blocks, <agent-feedback-bar-ui>, <agent-suggestions-ui>.
180
+ - streaming attribute hints the consumer to show a streaming indicator (composes well with <stream-ui> children).
181
+
182
+ ## Check
183
+ - Self-labeling widget — use the [label] attribute directly; do NOT wrap in <field-ui>. The widget renders its own label inline via CSS attr() pattern. Wrapping breaks the consent-row layout (see field-ui anti_patterns).
184
+ - When check-ui is used as a list-item icon/indicator beside a separate title element carrying the same name (a title column, a list-item-ui slot="text"), set [label-hidden] alongside [label] so the accessible name is preserved without painting the name twice.
185
+ - Three states supported: unchecked (default), checked (via [checked]), and indeterminate (via [indeterminate]); form-associated.
186
+ - For binary on/off toggles where visual switch metaphor matters, use <switch-ui> instead; check-ui is for multi-select sets and form-acceptance gates.
187
+
188
+ ## Code
189
+ - Inline (default) for short tokens in prose; block variant (display='block') for multi-line snippets.
190
+ - Do not use for editable code — use <richtext-ui> with code variant or a dedicated editor primitive.
191
+ - Inside <agent-artifact-ui> blocks for agent-emitted code snippets; lang= sets syntax-highlighting hint.
192
+
193
+ ## Col
194
+ - Vertical-stack flex container. Children flow top-to-bottom with token-driven gap.
195
+ - Pair with <row-ui> for horizontal layouts; both share the same gap-token contract.
196
+ - Set align/justify attributes for cross-axis / main-axis alignment; default is start/start.
197
+
198
+ ## ColorInput
199
+ - Use <color-input-ui> for any form-row color field — it canonicalizes the popover + button + color-picker recipe and is the only form-bearing color primitive. Do not hand-roll the composition; reach for color-input-ui directly.
200
+ - Set [format="oklch"] when the persisted value feeds CSS tokens or perceptual math; [format="hex"] for legacy / design-tool interop. Event detail (`change` / `input`) carries BOTH `hex` and `oklch` views regardless of [format], plus parsed `{l, c, h}` channel scalars.
201
+ - For brand-palette constraints, set [maxChroma] / [minL] / [maxL] / [hueDriftMax] (with [baseHue]) on the host — they forward to the inner <color-picker-ui> and clamp generation. Useful for Tokens-Studio-style guarded color generation.
202
+ - Use <color-picker-ui> DIRECTLY (no color-input-ui wrapper) only for full-surface editors where the picker IS the page (e.g. Tokens Studio main canvas). For inline form-row use, always reach for <color-input-ui>.
203
+ - Per ADR-0027 (cross-primitive composition imports), consumer pages MUST explicitly import <button-ui>, <popover-ui>, and <color-picker-ui> before <color-input-ui>. The primitive composes them but does NOT auto-register them.
204
+
205
+ ## ColorPicker
206
+ - OKLCH-native color picker with 2D color area + H/C/L sliders. Form-associated; emits OKLCH color strings.
207
+ - For simple color swatches (read-only display) use <swatch-ui>; for hex/rgb text input use <color-input-ui>.
208
+ - Output format defaults to oklch(); set format= to override (hex, rgb, hsl).
209
+
210
+ ## Combobox
211
+ - Use <combobox-ui> for typeahead-filterable single-select with a constrained-choice value model. `value` MUST be one of `options[].value` unless `[free-text]` is set. For ≤ 4 options, use <segmented-ui> or <radio-ui> instead.
212
+ - For free-form text entry with suggestions, use <autocomplete-input-ui> (SPEC-035) — combobox is constrained-choice. For button-first dropdowns where the trigger should be closed by default, use <select-ui searchable>.
213
+ - Compose options via native <option> / <optgroup> children, OR set `.options` programmatically as an array of `{value, label, disabled?}` (grouped form: `{label, options:[…]}`). Setting `value` to a string not in `options` is invalid mid-state (free-text=false) and the validator should reject it.
214
+ - `[creatable]` implies `[free-text]` and adds the "Create '{value}'" footer affordance + `create` event. Consumer wires the create event to a backend flow.
215
+ - Multi-select goes through <select-ui multiple> (chips in the trigger, checkbox-style option rows), not combobox. Combobox is single-select; there is no <multi-select-ui> tag.
216
+
217
+ ## Command
218
+ - <command-ui> is the searchable PALETTE primitive (input + option list). For Cmd+K palettes, wrap it in <admin-command> at the shell tier — admin-command owns the native <dialog>, focus management, and the Cmd+K / Ctrl+K shortcut listener. command-ui is content-only and does NOT own the dialog or shortcut. Do NOT hand-roll a <dialog> + Cmd+K key listener.
219
+ - Author items as native <option value data-icon data-shortcut> elements inside <optgroup label="…"> for grouped sections, OR set `.options` programmatically as an array of `{value, label, icon?, shortcut?, disabled?}` (grouped form: `{label, options:[…]}`) — same fields, alternative to declarative children. The `select` event's detail.category mirrors the parent optgroup's label (or the group's `label` when authored via `options`). Detail = { value, label, category }.
220
+ - Decision rule vs adjacent surfaces. Use <menu-ui> for small NON-searchable popover menus (≤10 actions, triggered by a button). Use <modal-ui> for generic centered dialogs. Reach for <command-ui> only when you need a searchable, keyboard-navigable list of commands or destinations.
221
+ - command-ui MAY render inline (no dialog) for embedded search panels, but the canonical AdiaUI admin pattern is exactly one <command-ui placeholder="…"> as the sole child of <admin-command> inside <admin-shell>. See site/index.html and playgrounds/admin-shell/ for production references.
222
+
223
+ ## ContextMenu
224
+ - Use <context-menu-ui> for right-click menus on a target (table row, file item, canvas object). For button-triggered menus use <menu-ui>; for popover content that is not a menu use <popover-ui> directly.
225
+ - Items are <menu-item-ui> children inside the default slot — same shape as <menu-ui> items.
226
+ - Bind target via wrap (default-slot first non-menu-item-ui child) OR [for] selector. The selector form is useful for whole-table or whole-canvas menus where wrapping isn't practical.
227
+
228
+ ## DateRangePicker
229
+ - DateRangePicker.value MUST be `{from, to}` with both ISO 8601 dates, OR null. Either side null is invalid mid-state and the validator should reject it (use `input` event for partial state).
230
+ - DateRangePicker.value.to MUST be `>=` value.from lexicographically. Reversed ranges trigger `invalid` and do NOT commit.
231
+ - When `comparison: true`, both `value` AND `compareValue` MUST be set on commit. If only one is set, the form participation emits the set one and omits the other.
232
+ - presets array entries each require both `label` (string) and `range` (`{from, to}`). Empty preset arrays are valid (rail renders empty).
233
+ - Use DateRangePicker for date ranges. Do NOT compose two adjacent `<calendar-picker-ui>` instances + JS synchronization — that is the pattern this primitive replaces.
234
+
235
+ ## DatetimePicker
236
+ - `DatetimePicker.value` MUST be ISO 8601 datetime (`YYYY-MM-DDTHH:mm` or `YYYY-MM-DDTHH:mm:ss`) OR empty string. Date-only or time-only strings fire `invalid`.
237
+ - `precision: "second"` requires the value to include seconds when set; missing seconds are coerced to `:00` on commit.
238
+ - `min` and `max` MUST be parseable ISO 8601 datetimes if non-empty. If `value` falls outside, `invalid` fires and the value does not commit.
239
+ - `hour-cycle` overrides the locale-derived cycle in the time pane. Set explicitly when the surface needs a specific cycle (cron editors, log queries, system surfaces).
240
+ - Use DatetimePicker for combined date+time. Do NOT compose `<calendar-picker-ui>` + a free-form `<input-ui>` manually as an alternative — that is the pattern this primitive replaces.
241
+ - Per ADR-0025 NEVER wrap a native `<input type="datetime-local">` — the calendar pane + time pane composition + ElementInternals together provide form participation.
242
+
243
+ ## DemoToggle
244
+ - Demo-page-only — toggles between live and code views in component documentation surfaces.
245
+ - Do not use in apps/ — restrict to packages/web-components/components/*/<name>.html demo pages and docs surfaces.
246
+ - Behavior: shows/hides the [data-code] block when toggled.
247
+
248
+ ## DescriptionList
249
+ - Use for key:value pairs in dense detail views (user profile fields, metadata panels, audit logs).
250
+ - Do not use for editable forms — use <fields-ui> instead.
251
+ - Pairs render as label + value on the same row by default; use vertical variant for narrow panes.
252
+
253
+ ## DisplayField
254
+ - Use for a display-ONLY labeled value — a masked card number, a 'card on file' read-out, an account id — anywhere a value reads as a field but must not be editable.
255
+ - To host a third-party element (a Stripe Element iframe) under a label, slot it as the default child instead of setting value=. The label names it via role=group + aria-labelledby.
256
+ - For an editable field use field-ui + input-ui; for a prominent KPI use stat-ui; for many read-only pairs at once use description-list-ui.
257
+
258
+ ## Divider
259
+ - Use to separate visually distinct sections within a container; horizontal default, vertical via orientation='vertical'.
260
+ - Inside menus / popovers use <menu-divider-ui> instead; it has menu-specific token spacing.
261
+ - Do not stack multiple consecutive dividers — use a single divider or restructure the section.
262
+
263
+ ## Drawer
264
+ - Direct children of <drawer-ui> MUST be <header>, <section> (1..n), <footer>, or an element with slot="header|body|footer". Wrap stray <col-ui> / <row-ui> / <div> / <text-ui> in a <section>. Enforced by scripts/audit/audit-drawer-structure.mjs. Bypassing the body slot loses the section inset and teaches the gen-UI corpus the wrong pattern.
265
+ - Reflect open state via the [open] boolean attribute on the host (open=true / open=false). Do NOT toggle visibility with CSS, [hidden], or a [data-open] proxy — drawer-ui owns the native <dialog> lifecycle, focus trap, and ::backdrop. Listen for the `close` event (detail.reason ∈ escape | backdrop | close-button | programmatic) to react to dismiss.
266
+ - Use drawer-ui (not modal-ui) for edge-anchored detail / edit panels and mobile bottom-sheet patterns. Pick side="right" for inspector flows opened FROM a row/list item, side="bottom" for sheets, side="left" for navigation drawers on narrow viewports. Centered confirmations belong in modal-ui.
267
+ - Compose the drawer header with [slot="icon|heading|description| action"] direct-child elements to activate the card-ui-aligned 3-column grid (icon | heading+description | action+close). The close button is auto-stamped; do not author your own X button unless using [permanent] (which suppresses the close button).
268
+ - Never set drawer.innerHTML wholesale — it wipes the stamped <dialog> part and the author skeleton. Mutate a stable inner element inside a persistent <section> instead. Same rule as <modal-ui>.
269
+
270
+ ## Embed
271
+ - Responsive sandboxed <iframe> wrapper at constrained aspect ratio. Safe sandbox attributes are applied by default.
272
+ - For raster/vector images use <image-ui>; for icons use <icon-ui>; embed-ui is for live external content only.
273
+ - aspect attribute locks ratio (e.g. 16/9, 4/3) to prevent layout shift; width/height override when needed.
274
+ - Do not embed first-party AdiaUI app routes — use direct component composition instead.
275
+
276
+ ## EmptyState
277
+ - Use <empty-state-ui> for zero-data states: empty lists, no-results search, fresh accounts. Not for loading (use <skeleton-ui>). For inline notices within populated content use <alert-ui>. For full-section error states where the data cannot be shown at all (API failure, permission error), use <empty-state-ui variant="danger"> — the centered layout is more appropriate than an inline banner when the entire content area is replaced.
278
+ - Canonical placement: slotted into cluster-specific wrappers — <chat-empty> inside <chat-thread>, <editor-canvas-empty> inside <editor-canvas>, OR inside <card-ui><section> for in-card empty states. Compose with an <icon-ui> for the leading glyph (pick a Phosphor name that mirrors the missing entity — folder, inbox, magnifying-glass).
279
+ - Put AT MOST ONE CTA in slot="action". It should be the single next step (Create, Retry, Clear filters). Use [variant="primary"] for a create-flow CTA; leave [variant] unset for retry / secondary actions — the default (no attribute) already IS the secondary look, so don't add [variant="outline"] just to mark something as non-primary.
280
+ - Use [minimal] for inline empty rows inside <table-ui> / <list-ui> where full-canvas chrome is too prominent. The `minimal` flag (§223 v0.5.9) drops chrome for a compact placeholder cell.
281
+ - Per ADR-0027, empty-state-ui composes <icon-ui> but does NOT auto-register it. Consumer pages must explicitly import <icon-ui> before <empty-state-ui> renders correctly.
282
+
283
+ ## FeedItem
284
+ - One notification entry inside <feed-ui>. Title + description + optional icon + auto-dismiss timer.
285
+ - Typically created programmatically via UIFeed.post(...); do not place declaratively.
286
+ - Different from <alert-ui> (inline persistent) and <toast-ui> (standalone ephemeral); feed-item is feed-scoped.
287
+ - For "notification deep-link" pattern: post with action + onAction. Click navigates and auto-dismisses (router.push() / location.href / api.markRead()).
288
+
289
+ ## Feed
290
+ - Top-layer notification feed channel — singleton per position (top-right, bottom-center, etc.) mounted lazily into document.body.
291
+ - Hosts <feed-item-ui> children programmatically via static API (UIFeed.post(...)). Do not place feed-items declaratively.
292
+ - For inline persistent alerts inside content regions use <alert-ui> instead; feed is ephemeral overlay.
293
+
294
+ ## Field
295
+ - field-ui is for WIDE controls (input-ui, select-ui, textarea-ui, slider-ui, etc.) that need a separate label row. Small self-labeling widgets (check-ui, switch-ui, radio-ui, toggle-ui) carry their own [label] attribute and MUST NOT be wrapped in field-ui.
296
+ - field-ui[inline] is for inline WIDE-control rows (e.g. search field with trailing kbd hint), NOT for compact-widget rows. For settings rows or consent rows, use the widget's own [label] attribute directly without a field-ui wrapper.
297
+
298
+ ## Fields
299
+ - Container for form rows. Hosts <field-ui> children (or <row-ui>/<col-ui> with labeled inputs) with consistent label + control + help layout.
300
+ - Different from <description-list-ui> (read-only key:value display) — fields-ui is for editable inputs.
301
+ - For dynamic field arrays (repeat-able rows) compose fields-ui with manual add/remove controls.
302
+
303
+ ## Footer
304
+ - Use <footer-ui> as the bottom chrome row inside a PRIMITIVE container parent (<card-ui>, <drawer-ui>, <modal-ui>, <page-ui>). Typically holds 1–3 <button-ui> children — the most common pattern is a Cancel / Confirm pair inside <modal-ui> or <drawer-ui>.
305
+ - Use `justify="end"` (default) for Cancel+Confirm and trailing action clusters; `justify="between"` when one action lives left and one right (e.g. Back / Submit); `justify="center"` for single-button confirm flows; `justify="start"` for solo leading actions like Back.
306
+ - Do NOT substitute <footer-ui> for bespoke shell-tier bottom chrome. Inside <admin-sidebar slot="footer"> use <admin-statusbar>; inside <editor-shell> use <editor-statusbar>. <footer-ui> is exclusively the in-container action bar at the primitive tier.
307
+ - Do NOT wrap children in <row-ui> just to align them — the `justify` prop already lays children out horizontally. A nested row-ui double-applies layout and breaks the chrome's gap tokens.
308
+ - Prefer flat <button-ui> children. If you need non-button content (text summary, pagination indicator), keep it as a single flat child so `justify` resolves cleanly.
309
+
310
+ ## Frame
311
+ - Use <frame-ui> for a scroll-body-with-pinned-footer panel — the <section> scrolls; <header> / <footer> stay fixed.
312
+ - Regions are positioned by tag + DOM order (native <header> / <section> / <footer>) OR by a role slot: slot="header"/"footer" pins ANY element as a rail, slot="body" makes it the scroll region (e.g. <section slot="header"> is a pinned rail). The native tag is the 90% sugar; reach for the slot when the element you want differs from the region role.
313
+ - Most panels need only <section> + <footer>; add <header> only when the panel has its own title or toolbar.
314
+ - For a bordered/elevated surface use <card-ui>; for an overlay use <drawer-ui> / <modal-ui>; for routed page layout use <admin-page> / <page-ui>. frame-ui is the bare layout only.
315
+ - frame-ui fills its parent — give the parent a definite height (a flex/grid chain to a viewport height) or the section will not scroll.
316
+
317
+ ## Grid
318
+ - For asymmetric column ratios, use [columns="N"] plus [span="M"] on the child that should be wider. Never set gridTemplateColumns via inline style in compositions — the component's responsive resolver sets it internally for @bp values; direct inline style bypasses that and reads as a local hack.
319
+ - Canonical ratios: 1:1 → columns="2"; 2:1 → columns="3" + span="2"; 3:1 → columns="4" + span="3"; 3:2 → columns="5" + span="3"+"2"; 4:1 → columns="5" + span="4". Round unusual ratios (e.g. 7:5) to 3:2.
320
+ - The default (no columns attribute) gives equal auto-columns flowing in a single row. Prefer the explicit numeric attribute for dashboard rows so the layout is predictable when items wrap.
321
+ - For viewport-responsive layouts use `@bp` notation on [columns] and [gap]: columns="1 2@sm 4@lg" gives 1 column on xs, 2 from sm, 4 from lg/xl. Breakpoints (mobile-first, min-width): xs=0, sm=480, md=768, lg=1024, xl=1280. Unannotated value = base (smallest). Each @bp overrides upward until the next larger annotation takes over.
322
+
323
+ ## Header
324
+ - Use <header-ui> as the top chrome row inside a PRIMITIVE container parent: <card-ui>, <drawer-ui>, <modal-ui>, <page-ui>. It is a CSS-only slot stub — no JS, no events. The parent's @scope rules drive layout and styling.
325
+ - Compose with the default slot for the heading (typically <text-ui variant="title">) and slot="action" for trailing controls (button-ui, badge-ui). The slot vocabulary (icon / heading / description / action) is shared with <aside-ui> / <section-ui> / <footer-ui> per ADR-0009.
326
+ - Do NOT substitute <header-ui> for bespoke shell-tier chrome. Inside <admin-content> / <admin-sidebar> use <admin-topbar>; inside <chat-shell> use <chat-header>; inside <editor-shell> use <editor-toolbar>. Those modules carry shell-specific slot vocabulary and CSS that <header-ui> does not. (admin-topbar.yaml codifies this explicitly.)
327
+ - Do NOT wrap header-ui's children in <col-ui> or <row-ui>. The container parent's @scope already lays out default+icon+heading+description+action via slot vocabulary; extra layout primitives fight the chrome styling.
328
+ - The `padding` attribute is a bare boolean — it enables default header padding, but the *scale* is set by the container parent's own `padding` prop. Do not pass numeric values.
329
+
330
+ ## Heatmap
331
+ - Grid-cell heatmap visualization (calendar heatmap, density grid). Cells colored by value via OKLCH scale.
332
+ - For continuous time-series use <chart-ui> with appropriate variant; heatmap is for grid-cell density.
333
+ - Tooltip on hover shows cell value; click events emit cell coordinates.
334
+
335
+ ## Icon
336
+ - [name] must be a registered Phosphor key (e.g. "house", "gear", "trash", "warning-circle"). Free-form names render empty. When unsure, default to a semantically obvious glyph (check, x, warning-circle, info).
337
+ - Set [label] when the icon is the ONLY content of an interactive control (icon-only button); omit [label] when icon is decorative beside a text label. The host stamps role="img" + aria-label when [label] is set.
338
+ - Use named [size] tokens (sm | md | lg) — free-form px / rem values ("32", "48") for anything beyond the row, e.g. empty-state hero icons; [size="md"] is the default for inline use. A denser or larger register comes from an ancestor [scale] tier, which the named tokens track automatically.
339
+ - Use slot="icon" on parent primitives (<button-ui>, <badge-ui>, <alert-ui>, <list-item-ui>, <input-ui>, <nav-item-ui>, every chrome bar) — do NOT bare-render <icon-ui> beside text in a <row-ui> when the parent supports the [slot="icon"] convention.
340
+ - Use [weight="fill"] for selected / active toggles, [weight="regular"] (default) for inactive. Do not mix weights in the same set; the visual inconsistency reads as a bug.
341
+ - Set [tone] to carry semantic color independent of the parent's text color — e.g. a trend arrow icon that must read success/warning/danger regardless of surrounding row color. Leave [tone] unset when the icon should just inherit the ambient text color (the common case).
342
+
343
+ ## Image
344
+ - Use for content images (illustrations, screenshots, user-uploaded photos). For icons use <icon-ui>; for embedded artifacts use <embed-ui>.
345
+ - Set aspect-ratio attribute to lock dimensions and prevent layout shift during load.
346
+ - For decorative-only images, set alt='' and aria-hidden='true' so screen readers skip them.
347
+
348
+ ## InlineEdit
349
+ - Use inline-edit-ui for click-to-edit titles, draft names, table-cell text, breadcrumb labels — anywhere the user expects to edit text without opening a dialog.
350
+ - inline-edit-ui IS form-participating (extends UIFormElement). Pair with a hidden <form> + name="..." to submit edits as a field.
351
+ - Distinct from <input-ui> (always shows input chrome) and from <field-ui> (stacked label + input composition). inline-edit reads as text in the static state.
352
+ - Listen to `change` event (detail.value, detail.oldValue) for commit; `cancel` for Escape. Default commit=blur saves on focusout + Enter.
353
+
354
+ ## InlineMessage
355
+ - In-flow annotation under a form input (validation feedback, hint copy, inline confirmation). Severity via [variant] (info, success, warning, danger).
356
+ - For overlay / banner-style notices use <alert-ui> instead; for transient toasts use <toast-ui>.
357
+ - Place inside <field-ui>, <col-ui>, or <row-ui>; never as a page-level banner.
358
+ - Do not nest a focusable child (button, link with action) — InlineMessage is non-interactive annotation.
359
+
360
+ ## Input
361
+ - <input-ui> is the canonical single-line text input. The host IS the contenteditable surface — NEVER wrap a native <input>. The sole exception is type="password", which internally uses a real <input type="password"> for masking (per ADR-0025).
362
+ - Wrap <input-ui> in <field-ui label="…" hint="…" error="…"> for the canonical stacked label / hint / error chrome. The inline [label] / [hint] / [error] props are also supported on the primitive for compact use.
363
+ - Form participation is implicit via UIFormElement. Set [name] for FormData submission; [required] / [disabled] / [readonly] reflect; listen for `change` (blur or Enter commit) and `input` (per keystroke). `submit` event fires when Enter commits the value (used by <chat-composer>'s `composer-submit` forwarding).
364
+ - For numeric input use [type="number"] with [min] [max] [step] [precision] [prefix] / [suffix] — this stamps a contenteditable surface + <button-ui> / <icon-ui> stepper column with ARIA spinbutton semantics. Read `el.valueAsNumber` for the parsed Number. Never substitute a native <input type="number">.
365
+ - Inside <chat-composer>, the canonical inner input is <chat-input-ui> (chat variant subclass — adds the send button + model picker + paste-to-attach plumbing). The plain <input-ui> primitive ALSO fires a bubbling `submit` event on Enter (unconditional, no opt-in attribute); <chat-input-ui> simply builds on that semantic.
366
+
367
+ ## Inspector
368
+ - Developer-tools pane for A2UI runtime state — composes <tabs-ui> + <code-ui> internally.
369
+ - Binds to a <canvas-ui> / <a2ui-root> via value= or implicit selector; shows live doc JSON + rendered HTML + event log.
370
+ - Use only in dev/debug surfaces; not for product UI.
371
+ - Place in a right-pane inside <editor-shell-ui>'s editor-sidebar slot for editor-style inspector layouts.
372
+
373
+ ## IntegrationCard
374
+ - Use <integration-card-ui> for one tile in an integrations grid. Set `provider` and `name` — both are required for analytics keys and the accessible name. Set `description` so users don't have to look the integration up externally.
375
+ - `status` MUST be one of `available | connected | error | pending | coming-soon`. The button label and variant are DERIVED from `status` — never slot a <button-ui> directly in the card body. Use the `actions` slot for an overflow <menu-ui> with secondary actions like Reauthenticate or Disconnect.
376
+ - When `status="error"`, set `error-message` — otherwise the user sees a Retry button with no context. The message renders below the description in danger-text color.
377
+ - `logo` accepts a URL (containing `/`, renders as <img>) or a registered icon name (renders as <icon-ui>). Don't mix — one provider gets one logo source.
378
+ - Group integration cards in <grid-ui columns="auto-fit"> or use <integrations-page-ui> (SPEC-063) for the canonical Settings-panel grid. Never nest <card-ui> around an <integration-card-ui> — it IS a card variant.
379
+
380
+ ## Kbd
381
+ - Inline-only — content from innerHTML, typically one or two key labels.
382
+ - In menu items, use the kbd= attribute on <menu-item-ui> instead of nesting <kbd-ui> directly.
383
+ - Chord notation uses + between keys (Ctrl+Shift+P); platform-symbol variants ⌘⌥⇧ are fine.
384
+
385
+ ## Link
386
+ - Use `<link-ui>` for navigation; use `<button-ui>` for actions. They are NOT interchangeable.
387
+ - When wrapping action affordances that visually mimic links (e.g. 'Forgot password?' that triggers a reset flow), prefer `<button-ui variant="ghost">` over a fake `<link-ui>` — the affordance is semantically a button, just visually understated.
388
+ - For inline-sentence affordances ('I agree to the [Terms] and [Privacy]'), nest `<link-ui>` directly inside `<text-ui>` so it inherits the paragraph's font / size / line-height.
389
+
390
+ ## ListWindow
391
+ - ListWindow.items MUST be an array of plain objects OR scalars. Functions / DOM nodes / Promises are invalid.
392
+ - ListWindow.render cannot be expressed in A2UI JSON — declarative authoring MUST use a <template> child (or default <list-item-ui> for objects with a text field).
393
+ - When items.length > 200, the validator SHOULD recommend ListWindow over List to keep the DOM tractable.
394
+ - ListWindow MUST have a defined height (via parent layout or style="height:..."). An unbounded-height windowed list defeats the windowing math.
395
+ - ListWindow.item-size SHOULD be set when item heights are known and constant — the fast-path is significantly cheaper.
396
+ - Do NOT nest ListWindow inside another scroll container; double-scroll containers break the IntersectionObserver math. Use one scroll boundary.
397
+ - Do NOT use ListWindow for short lists (< 50 items). The windowing overhead exceeds the cost of rendering all rows. Use List for short lists.
398
+ - Do NOT use for tabular data — that is Table with virtualized rows.
399
+
400
+ ## ListItem
401
+ - Child of <list-ui> — one row of generic-list content.
402
+ - For navigation lists use <nav-item-ui> inside <nav-ui>; for menu items use <menu-item-ui>; for tree rows use <tree-item-ui>.
403
+ - Interactive list-items should have role='button' or be wrapped in <button-ui>; default is non-interactive.
404
+
405
+ ## List
406
+ - Generic vertical list container — hosts <list-item-ui> or arbitrary children.
407
+ - For interactive selection lists use <nav-ui> (single-select navigation) or <menu-ui> (action menu); list-ui is content display.
408
+ - For data-grid / sortable / sticky-header needs use <table-ui> instead.
409
+
410
+ ## LoadingOverlay
411
+ - <LoadingOverlay> MUST be placed inside a sized container with content (Card, Section, Table body, Chart). It absolutely positions against the nearest positioned ancestor. The parent's CSS must include `position: relative` (or any non-static positioning) — the component does not mutate parent layout styles.
412
+ - Toggle <LoadingOverlay active> from consumer code while async work is in flight. The overlay applies aria-busy="true" to its parent while active; on dismiss, both inert and aria-busy are released.
413
+ - The [delay] grace window (default 200ms) suppresses paint on fast-resolving loads. For server-rendered "definitely-slow" states (>1s known wait) consider [delay="0"] for immediate feedback.
414
+ - Do NOT use as a page-level / viewport loader — use a dedicated route-loader pattern. <LoadingOverlay> is container-scoped.
415
+ - Do NOT nest <LoadingOverlay> inside <Modal> or <Drawer> — those primitives own their own busy state. When they support it, pass [loading] to those directly.
416
+ - Do NOT use <LoadingOverlay> to disable a form during submit — use <Button type="submit" loading> for the submit affordance.
417
+ - The default slot accepts any busy indicator. When empty, a centered <Spinner size="lg"> is auto-stamped. Slot a <Skeleton> stack for placeholder-shaped loading; slot <Progress value=…> when the wait is determinate.
418
+
419
+ ## Mark
420
+ - Use mark-ui for search-result match highlighting — wrap the matched substring in <mark-ui> within the surrounding text. Inline; preserves text flow.
421
+ - variant=warning (default) is the conventional yellow-marker tone; info for brand-color highlights; success for "new since" / "added" emphasis; danger for "removed" / "deleted-line" in diff prose.
422
+ - Distinct from <text-ui strong> (weight emphasis), <tag-ui> (block pill), <code-ui> (monospace). mark-ui is specifically the "visual rail behind matched text" use case.
423
+
424
+ ## MenuDivider
425
+ - <menu-divider-ui> MUST be a direct child of <menu-ui>; a raw <hr> will render OUTSIDE the popover because <menu-ui> only hoists <menu-item-ui> and <menu-divider-ui> children via its direct-child selector.
426
+ - Use to group items by semantic tier — primary actions → secondary → destructive (danger). Avoid leading / trailing dividers and consecutive dividers; they produce visual noise without grouping value.
427
+ - Do not place a divider as the first or last child of <menu-ui> — the top / bottom popover padding already provides separation from the chrome.
428
+ - Has no props, slots, or events. Treat as an inert separator with role="separator". If you need a labeled group, split into multiple <menu-ui> instances stacked, not custom content inside a divider.
429
+
430
+ ## MenuItem
431
+ - <menu-item-ui> MUST be a direct child of <menu-ui>; do not place inside arbitrary containers or other components — <menu-ui> hoists items into its top-layer popover via a `:scope > menu-item-ui` selector that requires direct descendancy.
432
+ - Always set a stable [value] — it is the only identifier surfaced on the parent's `action` event detail. [text] is the visible label; optional [icon] is a Phosphor icon name shown leading the label.
433
+ - Use [variant="danger"] exclusively for destructive / irreversible actions (Delete, Remove). "Sign out" is NOT danger. Pair danger items with an explicit confirm flow (<modal-ui> destructive-confirm pattern) when the action cannot be undone.
434
+ - Set [disabled] (not [hidden]) when an action is contextually unavailable — disabled items remain visible for affordance discoverability but skip roving focus + don't fire `action`.
435
+ - Prefer [icon] + [text] props over slotted markup for consistency. Use slot="icon" / slot="text" only when you need custom markup (e.g. <avatar-ui slot="icon">, <kbd slot="trailing"> shortcut hint).
436
+
437
+ ## MenuLabel
438
+ - <menu-label-ui> MUST be a direct child of <menu-ui>; like menu-item-ui and menu-divider-ui it is hoisted into the top-layer popover via <menu-ui>'s direct-descendant query — a label nested elsewhere renders outside the popover.
439
+ - Use a label to NAME a group and <menu-divider-ui> to SEPARATE groups. The common pattern is one label at the top of each group with dividers between groups; avoid a label with no items beneath it.
440
+ - Non-interactive: role="presentation", no [value], fires no events, and the menu's keyboard focus skips it. For a selectable row use <menu-item-ui>; for an unavailable action use <menu-item-ui disabled>.
441
+
442
+ ## Menu
443
+ - <menu-ui> MUST have exactly one child with slot="trigger" (typically <button-ui>, but any focusable element works). Without it the menu cannot open. The trigger lives in light DOM; the items are hoisted to a top-layer popover on open.
444
+ - Default slot accepts only <menu-item-ui> and <menu-divider-ui> children — no submenus, headers, or arbitrary content. Roving tabindex + Arrow / Home / End / Enter / Escape keyboard nav is built in.
445
+ - Listen for the `action` event on <menu-ui> (or an ancestor — bubbles). Detail = { value, text }. Do NOT treat menu-ui as a value-holder; for single-select form input use <select-ui> instead. Menu fires actions, doesn't store state.
446
+ - Use <menu-ui> for transient action surfaces (kebab / ⋯ row actions, workspace / user switchers, view-as toggles). For persistent side navigation use <nav-ui>; for inline (non-popover) command lists use <action-list-ui>; for searchable command palettes use <command-ui> inside <admin-command>.
447
+ - Set [placement="top-start"] or [placement="top-end"] when the trigger sits near the bottom of the viewport (statusbar / footer menus); default [placement="bottom-start"] otherwise. Adjust [gap] (default 4px) only when chrome demands it.
448
+
449
+ ## Modal
450
+ - Reflect modal visibility via the [open] boolean attribute on the host (open=true / open=false). Do NOT toggle [hidden], CSS display, or wrap in a sibling visibility container — modal-ui owns the native <dialog> lifecycle, focus trap, ::backdrop, and Escape-dismiss. Listen for the `close` event to react to dismiss.
451
+ - Compose modal-ui with the same triplet as drawer-ui / card-ui: <header> (or [slot="header"]) + <section> (or default body) + <footer> (or [slot="footer"]). Set the title via [text] (which stamps the heading + aria-label) or a <span slot="heading">. Do not author your own close button unless using [permanent].
452
+ - Use modal-ui (centered, interruptive) for short confirmations, destructive prompts, and transient previews — typically ≤2 form fields or a single decision. For edge-anchored multi-field detail editors and mobile sheets, use <drawer-ui> instead. The destructive-confirm-modal pattern lives at catalog/ui-patterns/app/destructive-confirm-modal/ as the canonical reference.
453
+ - modal-ui is NOT the Cmd+K command palette. The palette is a bespoke shell-tier component (<admin-command> under <admin-shell>); do not model command palettes as modal-ui surfaces even though the visual is overlay-like. The palette owns its own keyboard / filter loop.
454
+ - Use [size] presets (sm = 24rem | md = 32rem | lg = 48rem | xl = 95vw) to scale width. Do not override width with inline style or wrap modal-ui in a sizing container — the [size] attribute is the only supported width contract.
455
+
456
+ ## NavGroup
457
+ - Composition: <nav-group-ui> MUST be a direct child of <nav-ui> (or standalone with explicit variant="section" outside a rail). Default slot accepts <nav-item-ui> children; do NOT wrap them in layout primitives — selection, keyboard, and the section-variant cascade all rely on direct descendancy.
458
+ - Variant cascade: when parent <nav-ui variant="section">, this group inherits section styling (static kicker header, children always visible) via CSS — without touching its JS state. Set [variant="section"] explicitly only when there is no <nav-ui> parent, OR to override a primary-rail context.
459
+ - Collapsibility: primary variant — [collapsible] (default true) toggles [open] via header click / Enter / Space; fires `group-toggle` event with detail {text, open}. When the parent <nav-ui> is collapsed to icon-only, the header opens a popover with this group's children instead. Section variant ignores [open] / [collapsible] (children always visible).
460
+ - Decision rule: use <nav-group-ui> to group ≥2 related navigation links under one label inside <nav-ui>. For a single link, use <nav-item-ui> directly. For switching sub-views inside one page, use <tabs-ui> / <tab-ui>, never <nav-group-ui>.
461
+ - Anti-patterns: do NOT nest <nav-group-ui> inside another <nav-group-ui> (flatten the hierarchy or split into two groups). Do NOT place non-<nav-item-ui> content in the default slot. Do NOT use it as a generic disclosure — for that use <accordion-ui> or <details>.
462
+
463
+ ## NavItem
464
+ - Composition: <nav-item-ui> MUST be a direct child of <nav-ui> or <nav-group-ui>. Never wrap in <col-ui> / <row-ui> / <li> / <a> — the item is already a focusable, accessible link element; wrapping breaks selection, ARIA, and the section-variant CSS cascade.
465
+ - Variant cascade: when an ancestor <nav-ui variant="section"> (or sibling-group with section variant) is present, this item inherits section styling (flat row, no reserved icon space when icon absent, left-edge selected accent) via CSS. Set [variant="section"] explicitly only when used standalone outside a section rail, or [variant="primary"] to override the cascade for a single highlighted item.
466
+ - Selection: [selected] is set by the parent <nav-ui>'s select() method; do NOT set it on multiple items simultaneously. Provide [value] as a route or anchor; consumers listen for `nav-select` on <nav-ui> rather than per-item.
467
+ - Decision rule: use <nav-item-ui> for a single navigable link (route or anchor). For an in-page view toggle, use <tab-ui>. For a popover menu action, use <menu-item-ui>. For an action button styled like a nav row, use <button-ui variant="ghost"> — not <nav-item-ui>.
468
+ - Authoring options: default stamping renders icon+text+badge from attributes. Named slots `icon`, `text`, `trailing` are also supported for custom content (e.g. a `<kbd slot="trailing">⌘K</kbd>` shortcut hint on a command-trigger item — see the admin-shell playground). Do NOT nest <nav-item-ui> inside another <nav-item-ui>.
469
+
470
+ ## Nav
471
+ - Composition: place <nav-ui> inside <admin-sidebar slot="leading"> wrapped in <section-ui> for app sidebars; inside an <aside data-subnav> with variant="section" for section / subnav rails; standalone on docs / auth pages. Children: <nav-group-ui>, <nav-item-ui>, optional <hr data-nav-divider>.
472
+ - Variants: variant="primary" (default) — app sidebar; ResizeObserver collapses to icon-only ≤96px; collapsible groups open as a popover when collapsed. variant="section" — subnav rail; quieter chrome; optional [heading] kicker rendered via ::before.
473
+ - Section-variant cascade (ADR-0015 § Nav consolidation): variant="section" on <nav-ui> cascades visually to direct <nav-group-ui> / <nav-item-ui> descendants via CSS `:not([variant])`. Children's JS state is NOT mutated; the cascade is purely visual. Explicit [variant] on a child always wins — use it to escape the cascade or style a standalone group/item.
474
+ - Decision rule: if the user navigates AWAY (different page, route, or anchor) → <nav-ui>. If the user switches VIEWS within the same logical page → <tabs-ui>. Never use <nav-ui> as an in-page section switcher.
475
+ - Anti-patterns: do NOT wrap <nav-ui> children in <col-ui> / <row-ui> — wrapping breaks selection bubbling + the variant cascade. Do NOT nest <nav-ui> inside <nav-ui>. The legacy 6-element family (<app-nav-ui> / <section-nav-ui> / <app-nav-item-ui> / <section-nav-item-ui> / <app-nav-group-ui> / <section-nav-group-ui>) was retired in ADR-0015 — only <nav-ui> / <nav-group-ui> / <nav-item-ui> remain.
476
+
477
+ ## Noodles
478
+ - SVG connection lines between children with declared ports — bezier (default), step, or straight curves.
479
+ - Place inside <canvas-ui> with port-declaring children (nodes); noodles draws connections between matching port refs.
480
+ - editable attribute enables drag-to-connect interactions; default is render-only.
481
+ - For data-flow visualizations only — for general-purpose lines/shapes use raw SVG.
482
+
483
+ ## NumberFormat
484
+ - Use for read-only numeric display with locale-aware formatting. For numeric INPUT use <input-ui type=number>; for KPI big-number display use <stat-ui>.
485
+ - [number-style=currency] REQUIRES [currency] to be set to a valid ISO 4217 code. Without it the element renders nothing rather than producing malformed output.
486
+ - [number-style=percent] treats the [value] as a fraction (0.5 → 50%). To display 50 as '50%' pass value=0.5 OR keep [number-style=decimal] and append '%' manually.
487
+ - Compact notation auto-defaults maximumFractionDigits to 1. Override only when extra precision is needed (rare for compact display — defeats the purpose).
488
+
489
+ ## OptionCard
490
+ - Use <option-card-ui> for one-of-N choices where each option needs a heading + description, a leading icon, or both (onboarding personas, plan tiers, source pickers). Use <radio-ui> for dense forms with short labels and no descriptions. Use <segmented-ui> for compact horizontal single-select with short labels.
491
+ - Group siblings by sharing the same [name] attribute — they auto-form a radiogroup. Form participation is implicit via UIFormElement: submits `name=value` with parent form. Wrap the group in <col-ui gap="2"> for default layout or <grid-ui> for [layout="tile"] hero pickers.
492
+ - Set [checked] on the recommended / default option. Never leave the group with zero checked at first paint unless [required] is set and the form intentionally demands a deliberate choice.
493
+ - Use [layout="tile"] only for hero pickers (3–4 options max) where the icon is a primary brand cue (plan tiers, role pickers). Use [layout="default"] (left-indicator) for everything else.
494
+ - Put conditional follow-up inputs (a <textarea-ui> on "Other", a <select-ui> on "Custom") in the default slot — the spillover content auto-hides when the card is not checked. Do NOT duplicate this visibility logic in JS.
495
+
496
+ ## OtpInput
497
+ - Use <otp-input-ui> for any fixed-length verification code (TOTP, email / SMS OTP, MFA enrollment) — NOT <input-ui type="number">. otp-input-ui provides per-digit focus management, paste-splitting of full codes, and the `complete` event that fires exactly once when all digits are filled.
498
+ - Always set [autocomplete="one-time-code"] so iOS / Android keyboards surface inbound SMS codes via the platform autofill UI.
499
+ - Listen for `complete` to auto-submit (fires exactly once per fill cycle), and `change` / `input` for live validation. Form participation is implicit via UIFormElement: [name] for FormData; [disabled] reflects.
500
+ - Default [length=6]. Use [length=4] only for legacy 4-digit SMS codes and [length=8] for backup codes. Never compose two <otp-input-ui> side-by-side — use a single one with the right length.
501
+ - Canonical placement: inside a <col-ui align="center"> beneath a description text. Do NOT wrap in <field-ui> — otp-input-ui has no label slot and visual centering is the canonical chrome.
502
+
503
+ ## Page
504
+ - Top-level page container — wraps an entire route's content surface.
505
+ - Inside <admin-shell-ui>, <chat-shell-ui>, or <editor-shell-ui>, use the shell's own body slot instead; page-ui is for standalone routes without shell chrome.
506
+ - Hosts arbitrary children — no enforced child contract.
507
+
508
+ ## Pagination
509
+ - Renders below tables, card grids, or list views for paginated data. Emits page-change events.
510
+ - For cursor-based / infinite-scroll patterns use a custom load-more <button-ui> instead; pagination-ui is offset-based.
511
+ - Page-number range auto-truncates with ellipsis for high counts; set siblings= to control visible window size.
512
+
513
+ ## Pane
514
+ - pane-ui is a resizable / collapsible content panel. As a standalone primitive (no [side] attribute), it carries its own four-sided chrome and a right-edge resize grabber. As a horizontal-sibling child of a layout container (set [side="leading"] or [side="trailing"]), the chrome and grabber move to the inner edge so adjacent panes share a single seam.
515
+ - Wrapped by <editor-sidebar slot="leading|trailing"> inside <editor-shell>, and by <admin-sidebar slot="leading|trailing"> inside <admin-shell>. The bespoke sidebar owns [collapsed] / [resizing] reflected state + localStorage persistence; the inner pane-ui owns the physical drag. Don't reimplement drag in the bespoke sidebar — delegate to <pane-ui resizable>.
516
+ - Inner shape inside a pane-ui is the conventional <header> + <section> + optional <footer> slot pattern. Headers carry [slot="action"] button clusters; sections hold the navigator tree, inspector form rows, or other primary content.
517
+ - For a standalone resizable two-pane layout (no shell), nest panes directly inside a flex row — both with [side]-typed chrome — and the resize handle will live on the seam between them. For a non-resizable summary pane (a fixed-width detail rail), drop [resizable] and pane-ui collapses to a static container.
518
+
519
+ ## PasswordStrength
520
+ - Pair with <input-ui type=password> via a JS listener (input.addEventListener('input', e => meter.value = e.target.value)). The meter does NOT participate in form data — it is a display indicator.
521
+ - The score is 0 (Weak) / 1 (Fair) / 2 (Good) / 3 (Strong). [min-score] sets the threshold for the `satisfied` boolean in score-change events. Use the boolean to gate a submit button.
522
+ - Do NOT set value via setAttribute — value is JS-property only and never appears in rendered HTML (security: avoids leaking the password into the DOM).
523
+
524
+ ## PipelineStatus
525
+ - Single updating pipeline status indicator — status pill with optional progress bar.
526
+ - stage + status + message attributes drive the current display state.
527
+ - For multi-step wizards use <stepper-ui>; for chronological history use <timeline-ui>; pipeline-status is a single current-state pill.
528
+ - Renders inline — place inside toolbars, status bars, or agent message bodies.
529
+
530
+ ## Popover
531
+ - <popover-ui> wraps a focusable trigger (slot="trigger", typically <button-ui>) + arbitrary interactive content (slot="content"). Never put bare text in slot="trigger" — it must be focusable so keyboard users can open the popover.
532
+ - Decision rule vs adjacent surfaces. (a) For a list of action items use <menu-ui> instead — menu-ui is the specialized popover with role=menu + roving tabindex. (b) For read-only hover hints use <tooltip-ui>. (c) For centered focus-trapping dialogs use <modal-ui>. (d) For edge-anchored multi-field forms use <drawer-ui>. popover-ui is the GENERAL anchored surface for everything else (inline forms, color pickers, theme panels, export menus with non-action content).
533
+ - Placement convention (ADR-0034): default `bottom` centers under the trigger — correct for wide pickers (calendar, color, date-range, filter forms). Use `bottom-start` for trigger-width menus (action lists, listboxes, breadcrumb overflow — popover width ≈ trigger width). Use `bottom-end` only when the trigger sits at the right edge of a container by construction (toolbar spillover). Use `top-*` when the trigger sits low in the viewport (statusbar). [gap] (default 4px) sets offset from anchor.
534
+ - [trigger="hover"] is for non-essential disclosure only — never use it for popovers containing inputs, destructive actions, or anything the user must interact with via keyboard. Default [trigger="click"] for everything interactive.
535
+ - Do NOT nest <modal-ui> or <drawer-ui> inside slot="content"; popovers are non-modal anchored surfaces, not dialog hosts. Stacking dialog surfaces inside a popover breaks focus management.
536
+
537
+ ## Preview
538
+ - Use <preview-ui> to demonstrate ANY component or recipe — wrap the example markup once; it shows the live component and its copyable HTML source together. Prefer it over a bare <code-ui> snippet (which shows code but no render) or a bare rendered sample (which shows output but no copyable HTML).
539
+ - Author the slotted markup as plain AdiaUI HTML with attributes only — no inline `style=`, no `<script>` wiring. If a sample needs inline styles to look right, the component is missing an attribute; fix the component, not the demo.
540
+ - Side-by-side ([layout="split"]) is the default. Set [layout="stack"] for wide self-framing examples (a full card / shell / table reads cramped at half width). Use [code-first] when the code is the teaching point and the render is confirmation.
541
+
542
+ ## ProgressRow
543
+ - Labeled progress row — composes a label + <progress-ui> + optional value display in one horizontal row.
544
+ - For standalone progress bars without a row context use <progress-ui> directly.
545
+ - Inside lists (multiple tasks with progress) stack multiple progress-rows in a <col-ui>.
546
+
547
+ ## Progress
548
+ - Use for in-progress task feedback with known or indeterminate state. Value < 0 = indeterminate animation.
549
+ - For labeled task lists (multiple progress bars with row labels), use <progress-row-ui> instead.
550
+ - Spinner variant (variant='spinner') for circular loading indicators; bar variant default for linear.
551
+
552
+ ## QRCode
553
+ - Set [value] for URLs / share links / plain text. The built-in encoder covers byte-mode UTF-8 up to QR version 10 (~150 chars at ECC-M, more at lower ECC levels).
554
+ - For data that exceeds version 10, switch to a higher ECC level downgrade ([error-correction=L]) OR use a BYO encoder and pass the precomputed [matrix].
555
+ - When QR sits over a non-white surface, set [background] to a solid color. White-on-image QR backgrounds are unreliable for scanners — quiet-zone contrast against the dark cells is the load-bearing visual.
556
+ - The [margin] (quiet zone) defaults to 4 cells per QR spec. Smaller margins may scan on some devices but not others; do not go below 2.
557
+
558
+ ## RadioGroup
559
+ - The canonical radio-group shape is <radio-group-ui label="…"> wrapping a set of bare <radio-ui label="…" name="…"> children — the wrapper supplies the group's accessible name (role=radiogroup + aria-labelledby); Column/Section cannot carry a role, so a bare Column of radios has no programmatic question↔group association.
560
+ - Do not put the question text as a sibling Text node before a Column of radios — put it in radio-group-ui's own [label] prop instead.
561
+ - radio-ui children keep their own [label] per-option; radio-group-ui's [label] is the shared question, not a per-option label.
562
+
563
+ ## Radio
564
+ - Self-labeling widget — use the [label] attribute directly; do NOT wrap in <field-ui>. The widget renders its own label inline via CSS attr() pattern. For radio groups, the canonical pattern is <radio-group-ui label='…'> wrapping bare <radio-ui label='…'> elements sharing a [name=] — radio-group-ui supplies the group's accessible name (role=radiogroup + aria-labelledby); a bare Column of radios cannot (gh#729).
565
+ - Use the [name] attribute to group radios — exactly one is selected per name group; form-associated.
566
+ - For button-style single-select clusters (visually richer) use <segmented-ui> + <segment-ui> instead.
567
+
568
+ ## Range
569
+ - Two-handle slider for selecting a range (min + max). Form-associated; emits two-value change events.
570
+ - Different from <slider-ui> (single value) — use range when both endpoints matter.
571
+ - Step attribute controls handle increments; min/max set the bound rails.
572
+
573
+ ## Rating
574
+ - Star/icon-based ordinal rating input. Form-associated; emits numeric value 0..max via change events.
575
+ - For thumbs-up/down agent feedback use <agent-feedback-bar-ui> instead — different semantics + visual.
576
+ - max attribute sets the scale (default 5); allow-half attribute enables half-step granularity.
577
+
578
+ ## RelativeTime
579
+ - Use for displaying a single timestamp as a relative phrase. Self-updates on a tick so the rendered text stays current; no parent re-render required.
580
+ - Set [datetime] to an ISO 8601 string. Empty datetime renders nothing — do not stamp a relative-time-ui element until you have a timestamp value.
581
+ - [update-interval=0] freezes the render (no tick). Use for historical timestamps that will never become 'just now' (audit-log rows, version-history entries from days+ ago).
582
+
583
+ ## RichText
584
+ - Rich-text display + editor primitive. Renders paragraphs, lists, headings, and inline formatting; contenteditable when editable= is set.
585
+ - Different from <text-ui> (single semantic block) — richtext handles multi-paragraph + inline marks.
586
+ - For plain code use <code-ui> or richtext with code variant; for chat input use <chat-composer-ui>.
587
+
588
+ ## Row
589
+ - Horizontal-stack flex container. Children flow left-to-right with token-driven gap.
590
+ - Pair with <col-ui> for vertical layouts; both share the same gap-token contract.
591
+ - Wrap attribute enables flex-wrap; default is nowrap.
592
+
593
+ ## Search
594
+ - Search-input variant of <input-ui> with built-in search icon + clear affordance.
595
+ - For command-palette interactions use <command-ui> (which composes search + menu).
596
+ - Emits input events on each keystroke; debounce in the consumer for live-search.
597
+
598
+ ## Section
599
+ - Use <section-ui> as the content body region inside a primitive container parent (<card-ui>, <drawer-ui>, <modal-ui>, <page-ui>) OR inside the body region of a bespoke shell-tier sidebar (<admin-sidebar> nav body — site/index.html and the admin-shell playground use this canonically). It is a CSS-only chrome stub for ADR-0009 slot vocabulary; the parent's @scope handles padding and borders.
600
+ - `scroll` is a CONDITIONAL attribute. It makes section-ui the scroll container ONLY inside <card-ui> / <drawer-ui> / <modal-ui>. Inside <page-ui> and shell-tier hosts (<admin-shell>, <admin-page-body>) it is a no-op — those parents own their own scroll surface. Never nest <section-ui scroll> inside another scroll container (nested scroll is a UX anti-pattern).
601
+ - Use `bleed` to remove section padding so children reach the card / drawer edges — typical for cover images, full-width charts, or media galleries (apps/saas/members.contents.html uses this pattern to wrap <table-ui raw>). Mix bleed and non-bleed sections in the same card to alternate edge-to-edge media with padded prose.
602
+ - Do NOT substitute <section-ui> for bespoke shell-tier body regions. Inside <admin-page> use <admin-page-body>; inside <admin-content> use the bespoke children. <section-ui> is reserved for the primitive container chrome triad + the <admin-sidebar> nav body.
603
+ - <section-ui> is the right place for layout primitives (<col-ui>, <row-ui>, <grid-ui>) that organize body content. Do NOT put those layout primitives inside <header-ui> or <footer-ui> — the parent's chrome scope already lays those rows out.
604
+
605
+ ## Segment
606
+ - Child of <segmented-ui> — one selectable option button in a single-select group.
607
+ - Different from <toggle-option-ui> (which is multi-select inside <toggle-group-ui>).
608
+ - Selected state managed by parent <segmented-ui> via active attribute; do not set selected directly on segment.
609
+
610
+ ## Segmented
611
+ - Single-select segmented control. Hosts <segment-ui> children; exactly one selected at a time.
612
+ - For multi-select use <toggle-group-ui> + <toggle-option-ui> instead.
613
+ - Use for view-mode switches (grid/list, light/dark) or short filter sets (3-5 options); for longer sets use <tabs-ui> or <select-ui>.
614
+
615
+ ## Select
616
+ - Use <select-ui> for single-select with > 4 options or any list that benefits from a popover. Prefer <segmented-ui> / <radio-ui> when ≤ 4 visible options fit the row.
617
+ - Compose options via native <option> / <optgroup> children — other tag names are silently ignored (per §225 v0.5.9) and warned once at runtime. Or set `.options` programmatically as an array of `{value, label, disabled?}` (grouped form: `{label, options:[…]}`).
618
+ - Per-option visuals: give each <option> an `icon` (Phosphor name), `avatar` (image URL), or `mark` (Adia brand mark) — `<option value="light" icon="sun">`. Each row renders its glyph in the list AND the trigger reflects the SELECTED option's icon/avatar/mark (theme pickers, assignee/account switchers, workspace switchers). `mark` wins over `avatar`, which wins over `icon`; a host-level [mark]/[icon]/[avatar] is the fallback when the selected option carries none of the three. `mark` renders `<adia-mark-ui>` — a token-driven brand mark that inverts with the color scheme, so a workspace/app switcher doesn't need a static, scheme-locked logo URL.
619
+ - For dynamic option lists rendered inside <editor-shell>, set the JSON via the [data-options] attribute — <editor-shell>'s wireSelects() finds select-ui[data-options], JSON.parses the attribute, and assigns `.options` on connect. Useful for static-HTML toolbars where JS hydration would be awkward.
620
+ - <select-ui> owns its own label / hint / error chrome (via [label] / [hint] / [error] props). Only wrap in <field-ui> when you need to share the field-chrome stack with sibling inputs in the same form row group.
621
+ - Enable [searchable] for > 10 options; add [free-text] only when unmatched values are valid (tag entry, email-with-suggestion). Use [multiple searchable] for multi-select rather than authoring a separate multi-select primitive.
622
+ - For multi-select, set [multiple] — the trigger automatically renders <tag-ui> chips per selected option; the popover renders checkbox-style option rows where clicks toggle membership without closing. Form value is comma-separated under [name]. There is NO `<multi-select-ui>` tag — that name does not exist.
623
+ - Multi-select bulk controls: [select-all] renders a "Select all" / "Clear" control above the option list; [clearable] adds a clear-all `x` affordance to the trigger. [max-chips] caps the visible chip count and renders "+N more". [min] / [max] gate form validity.
624
+
625
+ ## Skeleton
626
+ - Use to placeholder content during loading. Shape via CSS sizing (width/height/border-radius); shimmer is automatic.
627
+ - Compose multiple <skeleton-ui> blocks to mock the actual content shape (card-skeleton, row-skeleton, etc.).
628
+ - For post-load empty states use <empty-state-ui> instead; skeleton is pre-load only.
629
+
630
+ ## SkipNav
631
+ - Place as the FIRST focusable element on the page — inside <body> before any nav / shell chrome. Otherwise keyboard users still tab through the nav before hitting the skip link.
632
+ - Target [#main] (or whatever id wraps the routed content). The target element should have tabindex="-1" so focus lands on it after the link is activated (otherwise focus may move to nothing perceptible).
633
+
634
+ ## Slider
635
+ - Default mode is single-handle. Form-associated; emits numeric change events with detail.value.
636
+ - For two-handle range selection (price filters, date ranges, audio range gates), set [dual] and use [lower-value]/[upper-value] instead of [value]. Form-data submits as "<lower>,<upper>" under [name]; change event detail carries {lower, upper}. Do NOT use <range-ui> — that primitive is a draggable numeric field, not a two-thumb range slider.
637
+ - [step] controls increments for both single and dual modes. Constraint: in dual mode, [lower-value] ≤ [upper-value] is enforced on each setter; reversed values clamp to equal.
638
+
639
+ ## Spinner
640
+ - Use <Spinner> for INDETERMINATE loading where the duration is unknown. For determinate progress (a known fraction complete), use <Progress> (linear) instead. For known-shape placeholder loading, use <Skeleton>.
641
+ - When a Spinner is inside a Button, set tone="current" so it matches the button label color, and disable the button while the operation is in progress.
642
+ - When overriding [label], use a present-progressive verb form ("Loading", "Saving", "Uploading"). Never use "Spin" or "Wait" — they describe the visual, not the operation.
643
+ - Do not nest <Spinner> inside <Skeleton>; they are siblings (two different loading idioms), not parent/child.
644
+ - Do not stack multiple sibling <Spinner>s in the same viewport region. Use one parent-level Spinner instead — multiple spinners add visual noise without extra information.
645
+
646
+ ## Stack
647
+ - Overlay/layer stacking container — children occupy the same area, stacked on the z-axis.
648
+ - Use for overlapping content (image + overlay, badge-over-avatar, drop-shadow stacks).
649
+ - Do not use for vertical content flow — that's <col-ui>. Stack-ui is overlap-only.
650
+
651
+ ## Stat
652
+ - Use for prominent metric/KPI displays inside dashboard cards. Value + label + optional delta indicator.
653
+ - For inline percent/progress displays use <progress-ui>; stat is for standalone metrics, progress for completion bars.
654
+ - Delta indicator uses positive/negative semantic tokens; pass change= attribute with sign.
655
+
656
+ ## StepProgress
657
+ - Compact step indicator — N dots/segments showing current step out of total.
658
+ - Different from <stepper-ui> (labeled, expanded) — step-progress is dense and label-free.
659
+ - For multi-task progress bars (multiple labeled rows) use <progress-row-ui> stack.
660
+
661
+ ## StepperItem
662
+ - Child of <stepper-ui> — one numbered step with label + complete/current/upcoming state.
663
+ - State driven by parent's active-index; do not set state directly on stepper-item.
664
+ - For chronological events (no completion semantics) use <timeline-item-ui> instead.
665
+ - Set [disabled] to phase-gate a step out of click/keyboard reach without changing [status].
666
+
667
+ ## Stepper
668
+ - Hosts <stepper-item-ui> children with a parent active-index driving complete/current/upcoming states.
669
+ - Use for wizards, onboarding flows, multi-step forms.
670
+ - For read-only event history use <timeline-ui>; stepper requires forward progress semantics.
671
+ - Add [interactive] only when the host permits jumping to a step out of order; leave absent for a linear wizard the host advances programmatically.
672
+ - Listen for [step-request] and call preventDefault() to veto a navigation conditionally (e.g. block a phase the app has not unlocked); set [disabled] on a stepper-item-ui to phase-gate it out of reach unconditionally.
673
+
674
+ ## Stream
675
+ - Renders an AsyncIterable<string> as streaming text — canonical for LLM token streaming.
676
+ - Place inside <chat-thread-ui> message bodies for LLM responses; standalone for log tailing.
677
+ - pace attribute controls typewriter-effect speed; hide-cursor disables the blinking caret.
678
+ - For static (post-stream) display use <text-ui> or <richtext-ui>; stream-ui assumes live token feed.
679
+
680
+ ## Swatch
681
+ - Use to display a single color sample with optional label. For interactive color picking use <color-picker-ui>.
682
+ - Inside design-token displays or palette grids; not for general decoration.
683
+ - Color value accepts hex, rgb, hsl, or oklch; oklch preferred for AdiaUI token alignment.
684
+
685
+ ## Swiper
686
+ - Horizontal slide carousel with touch + arrow nav. Hosts arbitrary children as slides.
687
+ - For tab-switched peer views use <tabs-ui>; swiper is for content browsing, not panel switching.
688
+ - Set autoplay attribute for timed-rotation; otherwise user-driven only.
689
+
690
+ ## Switch
691
+ - Self-labeling widget — use the [label] attribute directly; do NOT wrap in <field-ui>. The widget renders its own label inline via CSS attr() pattern. For settings rows (label-left, switch-right), put the descriptive text in switch-ui's own [label] attribute; do not introduce a field-ui wrapper. For descriptive helper text below the switch, use <text-ui variant='caption'> as a sibling — not field-ui's hint slot.
692
+ - Binary on/off only — no third state. For tri-state controls use <check-ui> with [indeterminate].
693
+ - Use for settings toggles, feature flags, mode switches; for form gates / consent / multi-select use <check-ui> instead.
694
+
695
+ ## TableToolbar
696
+ - Pair <table-toolbar-ui> with <table-ui> via [for="<table-id>"] (or rely on first-sibling fallback when both are inside the same parent). One toolbar per table. Do NOT also use <card-ui>'s <header> on the same card — that produces a doubled chrome row.
697
+ - All four affordances (search, filter, sort, columns) default ON. Opt out individually via [no-search] / [no-filter] / [no-sort] / [no-columns]. The previous [searchable] / [filterable] attributes are deprecated — do NOT emit them.
698
+ - Place the toolbar ABOVE the <card-ui> containing the table-ui, or use [variant="card"] when standing alone outside a card-ui parent (the variant wraps the toolbar in card-style chrome).
699
+ - Use slot="action" (or [slot="actions"]) for trailing primary buttons (Invite, Export, +New). Use [text] / [count] props for the left cluster, or slotted [slot="title"] / [slot="count"] when content is markup (a <span> + <badge-ui>, etc.).
700
+ - Listen for toolbar events (`search`, `filter-change`, `sort-change`, `columns-change`) only to mirror state to URL / persistence / analytics. The toolbar already wires its changes into the bound table — you don't need to manually update the table.
701
+
702
+ ## Table
703
+ - Canonical composition: wrap <table-ui> in <card-ui><section bleed> for edge-to-edge tables. The [bleed] removes section padding so columns span the full card width (see apps/saas/members, billing, admin-dashboard).
704
+ - Pair with <table-toolbar-ui for="<table-id>"> for any table that needs search / filter / sort / columns visibility. Do NOT re-implement those affordances in the card header — the toolbar auto-wires search/filter/sort/columns changes into the bound table.
705
+ - Cells truncate single-line by default (v0.6.21 §403 truncate-default). Opt out per-table with [wrap] for whole-table multiline, or per-cell with [data-wrap] on a single column / cell.
706
+ - [raw] is a visual-and-lifecycle chrome reset for consumer-owned body markup — render()'s early return (`if (this.raw) return;`) is unconditional: no header injection, no .data/.columns reconciliation, no empty/loading overlays, no aggregation or pagination footers, even if .columns and .data are set. Reach for it only when the consumer authors 100% of the body (spreadsheet / inline-edit style patterns wrapping a native <table>) — never to "keep the data lifecycle but skip demo seeding."
707
+ - Listen for the `sort` event with detail.key + detail.dir (NOT .column / .direction). `cell-click` detail carries {key, row, value, dataIndex}. Per ADR-0027, table-ui composes check-ui, icon-ui, progress-ui, pagination-ui, skeleton-ui, badge-ui — consumer pages must explicitly import the ones they use.
708
+ - For large datasets (100+ rows), use [paginate="N"] to limit rendered rows and add a pagination bar. [virtual] is NOT a recognized prop and is silently ignored — there is no DOM-level virtual scrolling in table-ui. [paginate] is the supported performance mechanism. Wire [paginate] with optional [search] and the `page` event for server-driven pagination.
709
+
710
+ ## Tab
711
+ - <tab-ui> only renders inside <tabs-ui>. Never use it standalone. The parent reads each tab's [text] + [icon] + [value] to render the button strip; the tab's default slot is the panel content that the parent auto-hides when inactive.
712
+ - [value] is required and must be unique among siblings — the parent <tabs-ui> matches its own [value] against each <tab-ui>[value] to decide which is active. [text] is the visible button label; optional [icon] is a Phosphor icon name shown leading the label.
713
+ - Use the default slot for panel content. Inactive <tab-ui> children are auto-hidden by the parent's [hidden] toggling; do NOT set [hidden] yourself unless you want to remove the button from the strip entirely (i.e. a temporarily-disabled tab whose strip button shouldn't render at all).
714
+ - Use [disabled] to keep a tab visible in the strip but non-selectable. Do not pair <tab-ui> with <button-ui> wrappers — the strip button is parent-rendered. Do not nest <tab-ui> inside another <tab-ui>.
715
+
716
+ ## Tabs
717
+ - Decision rule: use <tabs-ui> when switching VIEWS within the same logical page (no route change, no URL change). For navigating AWAY (different page / route / anchor), use <nav-ui> instead. For a form-control segmented selector that returns a value, use <segmented-ui>.
718
+ - Children of <tabs-ui> MUST be <tab-ui> elements. The button strip is rendered from each child's [text] + optional [icon]; the parent auto-toggles [hidden] on inactive <tab-ui> children. Do not place arbitrary markup directly inside <tabs-ui> — wrap it in <tab-ui>.
719
+ - Canonical placements: inside <card-ui>'s <header> for in-card section switching; inside <editor-canvas-toolbar> for editor sub-views (see the editor sub-views recipe in patterns-recipes.md); or standalone as an in-page switcher. When standalone, wire sibling <div data-view="…"> panels via the `change` event (detail.value); for tabs whose content lives inside the <tab-ui> child, the auto-hide handles visibility.
720
+ - Set [value] to the initially active tab. If omitted, the first non-disabled <tab-ui> becomes active on connect. Set [orientation="vertical"] for left-rail tab strips.
721
+ - Variant caveat: only [variant="bordered"] is implemented (adds a subtle divider). [variant="underline"] is widely used in source but is equivalent to default (no-op). [variant="pills"] and [variant="segmented"] are declared in the enum but NOT styled — do NOT emit them; for a form-style selector use <segmented-ui>.
722
+
723
+ ## Tag
724
+ - Use <tag-ui> for INTERACTIVE / DISMISSABLE labels — filter chips, autocomplete tokens, user-managed labels. Tag-ui fires a `remove` event when [removable] is set. For READ-ONLY status flags (counts, Beta / New / Deprecated markers, notification dots) use <badge-ui> instead — badge has no remove event and includes the [status] shorthand.
725
+ - Set [removable] and listen for the `remove` event (detail: {text, value}) when the tag represents a user-applied filter or selection that can be cleared.
726
+ - [variant] maps to semantic state of the underlying record: success = active / approved, warning = pending, danger = blocked / error, info = neutral-emphasis. Default (no variant) for unlabeled categories.
727
+ - Use [size="sm"] for inline-with-text contexts (doc page headers, table cells, badges next to titles); [size="md"] (default) for filter-bar chips and standalone tag rows.
728
+ - Group multiple tags inside a <row-ui gap="2"> — never stack them vertically; vertical lists of dismissable items are an <action-list-ui> use case, not <tag-ui>.
729
+ - A family-less <tag-ui text="…"> (no [variant], no [tone]) renders the high-contrast solid pill by default (gh#794). In dense tables, tight metadata rows, or citation/footnote strips where many tags sit close together, set [tone="muted"] to keep the quieter tinted look instead — a wall of solid pills reads as visual noise there (gh#778).
730
+ - A family [variant] (info/success/warning/danger/primary) with no [tone] renders the tinted-container look by default (gh#864). Set [tone="solid"] for a saturated status stamp instead.
731
+
732
+ ## TagsInput
733
+ - Use <tags-input-ui> for OPEN-SET free-form token entry — labels, keywords, email recipients, comma-separated lists. For CLOSED option sets (pick N from a fixed list), use <select-ui multiple> (SPEC-040) — that primitive gates the value against `options[]`.
734
+ - `TagsInput.value` MUST be a string array. Pass `["a","b"]`, not the comma-joined string `"a,b"`. The host parses string-form `value` attributes as JSON; non-array shapes throw `invalid`.
735
+ - `delimiter: "enter"` disables in-line character commits; only the Enter key (or programmatic `addToken`) commits. Use this when the token grammar legitimately includes the default `,`.
736
+ - `unique: true` (default) silently coalesces accidental duplicate adds. Do NOT emit `invalid` for those — the contract specifies silent dedup for ergonomic typing.
737
+ - `validateFn` is a JS property, NOT serializable in A2UI JSON. Wire validators post-mount via DOM scripting; A2UI authors should not expect to declare a validator in the JSON payload.
738
+ - Chips are rendered automatically from `value`. Do NOT slot individual <tag-ui> children manually — that decouples the rendered DOM from the form value and breaks Backspace removal.
739
+
740
+ ## Text
741
+ - Use for typographic content with semantic role (heading, body, label, caption). Variant attribute sets the role.
742
+ - For inline-flow rich content with multiple paragraphs, use <richtext-ui> instead.
743
+ - Heading variants (h1, h2, ...) are not auto-tagged — set the role explicitly via variant.
744
+
745
+ ## Textarea
746
+ - <textarea-ui> is the canonical multi-line text input. The host IS the contenteditable surface — NEVER use a native <textarea> (banned by ADR-0025).
747
+ - Wrap <textarea-ui> in <field-ui label="…" hint="…" error="…"> for the canonical labeled stack. The inline [label] / [hint] / [error] props are also supported on the primitive for compact use.
748
+ - Form participation is implicit via UIFormElement. Set [name] for FormData submission; [required] / [disabled] / [readonly] reflect; listen for `change` (on blur after value change) and `input` (per keystroke).
749
+ - Use [rows] to set initial height (default 3) and [resize] (vertical | horizontal | both | none; default vertical) to control user resize. Never substitute a native <textarea> just to get rows / resize.
750
+ - Enter (without Shift) dispatches a bubbling `submit` event; Shift+Enter inserts a newline. This is unconditional — there is no opt-in/opt-out attribute. For chat composer surfaces wrap inside <chat-composer> + <chat-input-ui> (which adds the send button + model picker + paste-to-attach plumbing on top of the same Enter→submit semantics).
751
+
752
+ ## ThemeProvider
753
+ - Wrap a client-mounted surface root (SPA shell, embedded app, dynamic mount) in <theme-provider> so it self-provides the AdiaUI foundation — no <head> stylesheet link required.
754
+ - For multi-page / top-level pages, prefer a render-blocking <link rel="stylesheet" href=".../web-components.min.css"> in <head> instead — cacheable across navigations, styled on the first frame. <theme-provider> and the link deliver byte-identical CSS, so they coexist.
755
+ - Theme the wrapped subtree with theme="ocean" (a named preset) and/or scale="verse|prose" (compact / long-form register) — the provider adopts the matching opt-in layer on demand. The base foundation is OS light/dark automatically. Keep <theme-provider> at/near the mount root — display:contents means an ancestor "> " child selector will not reach its children.
756
+
757
+ ## TimePicker
758
+ - `<time-picker-ui>` is the canonical standalone time-of-day picker. Per ADR-0025 NEVER wrap a native `<input type="time">` — segments are contenteditable spans + ElementInternals provides form participation.
759
+ - `value` MUST be ISO 8601 time `HH:mm` or `HH:mm:ss` (24-hour), or empty string. Localized formats (e.g. "9:30 AM") are not accepted; display formatting is derived from `hour-cycle` regardless of how the value is stored.
760
+ - `step` is in seconds. 60 = minute precision (default); 900 = 15-minute precision (meeting-time common); 1 = second precision (requires `precision="second"`).
761
+ - `precision="second"` exposes the seconds segment AND emits `HH:mm:ss`. Default `precision="minute"` emits `HH:mm`.
762
+ - `hour-cycle` overrides locale-derived behavior. Set explicitly (`h12` / `h23`) when the surface needs a specific cycle (cron editors, log queries, system surfaces).
763
+ - For datetime selection use `<datetime-picker-ui>` (SPEC-038) — it composes this primitive as its time pane.
764
+
765
+ ## TimelineItem
766
+ - Child of <timeline-ui> — one chronological event with timestamp + content + optional icon dot.
767
+ - Different from <stepper-item-ui> (process steps with completion state) — timeline-item is event history.
768
+ - Order is DOM-order — no auto-sort by timestamp.
769
+
770
+ ## Timeline
771
+ - Use for chronological event lists (audit log, activity feed, version history).
772
+ - Hosts <timeline-item-ui> children only.
773
+ - For multi-step processes with progress state use <stepper-ui> instead; timeline is read-only history.
774
+
775
+ ## Toast
776
+ - Single ephemeral notification item — auto-dismissing or manually-closable.
777
+ - Typically posted into <feed-ui> via UIFeed.post(...); for inline persistent alerts use <alert-ui> instead.
778
+ - Variant maps to severity (info, success, warn, error); same tokens as <alert-ui>.
779
+
780
+ ## TableOfContents
781
+ - Use for in-page section navigation. Pair with a sticky container in an aside / right rail for the docs-site outline pattern.
782
+ - Default scans the toc-ui's parent for h2/h3 headings. Set [target] to a CSS selector for a specific container; set [headings] to a comma-separated tag list (e.g. h1,h2,h3) for different depth coverage.
783
+ - Headings missing an [id] receive an auto-generated slug from their text content. Existing ids are preserved.
784
+ - Smooth-scroll on click is handled by the global `scroll-behavior: smooth` in resets.css (gated by prefers-reduced-motion). Do NOT add per-toc-ui smooth-scroll JS — the global wins.
785
+
786
+ ## ToggleGroup
787
+ - Multi-select button cluster — hosts <toggle-option-ui> children, each independently toggleable.
788
+ - Different from <segmented-ui> (single-select) — toggle-group emits a SET of active values.
789
+ - Use for filter chips, multi-flag toggles, day-of-week pickers; for binary on/off use <switch-ui>.
790
+
791
+ ## ToggleOption
792
+ - Child of <toggle-group-ui> — one independently-toggleable button in a multi-select cluster.
793
+ - Different from <segment-ui> (which is single-select inside <segmented-ui>).
794
+ - Active state controlled via the toggle-option's own active attribute (independent of siblings).
795
+
796
+ ## ToggleScheme
797
+ - Place toggle-scheme-ui in the shell topbar's trailing action cluster — slot="action" inside <admin-topbar slot="header"> of <admin-content>. It is a persistent, app-wide preference control; never put it in a sidebar footer / <admin-statusbar>, which hosts user-account items only.
798
+ - Stores user override in localStorage and writes color-scheme inline-style to the target; falls back to prefers-color-scheme if no override is set.
799
+ - Singleton per page — placing more than one in DOM creates conflicting writes to the same target.
800
+
801
+ ## ToolbarGroup
802
+ - Child of <toolbar-ui> — clusters related action buttons with token-driven internal gap.
803
+ - Separate clusters with <divider-ui> siblings inside <toolbar-ui>.
804
+ - Do not nest toolbar-groups; flat hierarchy only.
805
+
806
+ ## Toolbar
807
+ - Horizontal action bar — hosts <button-ui>, <toolbar-group-ui>, and <divider-ui> children.
808
+ - Cluster related buttons inside <toolbar-group-ui> with <divider-ui> separating clusters.
809
+ - For navigation use <nav-ui>; for modal/popover action bars use the modal's footer slot. Toolbar is for inline action bars within content regions.
810
+
811
+ ## Tooltip
812
+ - Use <tooltip-ui> to label icon-only <button-ui> elements (text="Save" on a save-icon button, etc.) and for short descriptive hover hints. Never use it for content the user must read carefully (the bubble is transient + non-focusable).
813
+ - Never place INTERACTIVE children inside <tooltip-ui> — it is a read-only hint, not a surface. If the user must click or type, use <popover-ui> instead. Tooltips never receive keyboard focus.
814
+ - [follows="pointer"] mode requires [for] pointing at a <chart-ui> or <heatmap-ui> [id]; the tooltip subscribes to that target's `chart-hover` / `chart-leave` events to render data-viz annotations that track the cursor. Without [for] the tooltip renders nothing in pointer mode.
815
+ - Set [delay=0] only for high-frequency exploratory surfaces (sparkline ticks, chart hover). Keep the default 400ms delay elsewhere to avoid hover noise.
816
+ - [indicator] (dot | line | dashed) is meaningful only in pointer mode for per-series swatches. Omit it or leave default "none" for text-mode tooltips.
817
+
818
+ ## TourStep
819
+ - Single step inside <tour-ui>. Declares target (CSS selector) + title + body content.
820
+ - target is a CSS selector (e.g. "#dashboard", ".filters button"), NOT a bare ID. Use the # prefix.
821
+ - Renders nothing on its own — tour-ui orchestrates the popover stamping when the step becomes active.
822
+
823
+ ## Tour
824
+ - Use tour-ui for spotlight-driven product tours / walkthroughs — sequence of steps each targeting a CSS-selector-resolved element.
825
+ - Children are <tour-step target="..." title="..."> with body content as the default slot. tour-ui reads them in DOM order.
826
+ - Set [auto-start] for first-run flows (paired with [storage-key] so it only shows once). Otherwise call .start() programmatically from a "Take the tour" button.
827
+ - Distinct from <onboarding-checklist-ui> (persistent setup todo-list, user-paced) and <tooltip-ui> (single hover hint, no orchestration).
828
+ - Listen to `tour-finish` for "user completed the tour" analytics; `tour-skip` for "user opted out". Both fire once per session.
829
+
830
+ ## TreeItem
831
+ - <tree-item-ui> MUST be a direct or nested descendant of <tree-ui>. It is not a standalone primitive — outside a <tree-ui> parent, selection / expansion / keyboard nav don't wire.
832
+ - Provide a stable [value] attribute on every <tree-item-ui> that consumers will select. The `tree-select` event's detail.value is the identifier downstream code reads to know which node was picked.
833
+ - Use [open] to pre-expand branch nodes on initial render. Do NOT set [selected] declaratively on more than one item — the parent <tree-ui> manages selection. The host listens for click / Enter / Space / ArrowRight (expand) / ArrowLeft (collapse) per WAI-ARIA tree-view APG.
834
+ - Use [icon] (Phosphor name) for affordance (folder / file / component icons); use [badge] for counts or short status labels (§184 v0.5.5).
835
+ - Nest further <tree-item-ui> in the default slot only — no <list-item-ui>, <nav-item-ui>, or arbitrary content inside a tree row. The caret is auto-stamped when the row has nested tree-item-ui children.
836
+
837
+ ## Tree
838
+ - Use <tree-ui> only when data is hierarchical with arbitrary nesting AND a single selected node is meaningful. For flat lists use <list-ui>; for flat sidebar navigation use <nav-ui>; for one-level collapsible groups use <accordion-ui>.
839
+ - Canonical mount: inside <editor-sidebar slot="leading"> → <pane-ui side="leading" resizable> → <section> → <tree-ui id="…"> as the structure / navigator pane of the three-pane editor shell. Pair with a <header> in the same pane (e.g. "Structure", "Layers", "Files").
840
+ - Direct children of <tree-ui> MUST be <tree-item-ui>. No other element types in the default slot. <tree-ui> manages single-selection across the whole subtree and implements WAI-ARIA tree-view keyboard navigation (Arrow keys, Enter / Space, Home / End).
841
+ - Listen for `tree-select` on the <tree-ui>, NOT on individual rows — selection is managed by the parent and bubbles once. Detail = {item, text, value, ctrlKey, metaKey, shiftKey}.
842
+ - Per ADR-0027, <tree-ui> composes <icon-ui> (for carets) but does NOT auto-import its children. Consumer pages must explicitly import both <tree-ui> and <tree-item-ui>.
843
+
844
+ ## Upload
845
+ - File-upload input with drop zone + browse button. Form-associated; emits file-list change events.
846
+ - Multiple attribute enables multi-file selection; accept= constrains file types.
847
+ - For agent chat attachments use <chat-composer-ui>'s built-in upload affordance instead.
848
+
849
+ ## VisuallyHidden
850
+ - Wrap text that screen readers need but sighted users do not — icon-only-button labels, contextual disambiguation ("Edit profile" inside a row whose visible button just says "Edit").
851
+ - Distinct from [hidden] / display:none (hides from EVERYONE) and from aria-label (replaces visible text). Use <visually-hidden-ui> when both visible AND invisible text need to coexist on the same element.
852
+
853
+ ## AdminRoster
854
+ - Use <admin-roster-ui> for the canonical persona-switch list in an
855
+ agent-admin surface. Supply the `personas` array; the composite
856
+ owns menuitemradio semantics and the active-row check glyph.
857
+
858
+ - Listen for `persona-change` to swap the bound `SettingsStore`
859
+ (CHAT-HARNESS §Interfaces 5) — a genuine store reference change
860
+ resets the conversation + open surfaces; this composite never
861
+ touches the store itself.
862
+
863
+
864
+ ## AdminSettings
865
+ - Use <admin-settings-ui> for the canonical per-persona settings
866
+ pane. Set both `persona` and `store` as JS properties — neither
867
+ has an attribute form.
868
+
869
+ - Never author per-kind branches around this composite (a
870
+ prompt-section-specific control, a skill-specific control, …) —
871
+ `KNOWN_KINDS` is display grouping only; a seventh kind must render
872
+ through the SAME entry row with zero new code.
873
+
874
+
875
+ ## AgentAdmin
876
+ - Compose `<agent-admin-ui>` with bespoke `<admin-roster-ui>` +
877
+ `<admin-settings-ui>` + `<chat-shell>` children (chat-shell WITHOUT
878
+ `proxy-url` — external mode; this composite drives it). Set
879
+ `personas` as a JS property.
880
+
881
+ - Never bind `<chat-shell proxy-url>` inside `<agent-admin-ui>` — the
882
+ composite drives the chat pane itself via `wireAgentEvents`; a
883
+ `proxy-url` would double-drive turns.
884
+
885
+
886
+ ## BillingOverview
887
+ - BillingOverview.account is REQUIRED. The composite is meaningless without an account snapshot; emitting BillingOverview with null account and no data-stream-src renders the empty state.
888
+ - account.status MUST be one of `active` | `trialing` | `past_due` | `canceled` | `paused`. Unknown values render neutral chrome.
889
+ - account.dunning is REQUIRED when account.status is `past_due` (otherwise the dunning banner cannot render). Shape: `{amount, currency, dueAt, cardLast4?, reason?}`. The composite stamps `<alert-ui pattern="dunning">` per SPEC-006.
890
+ - account.plans is REQUIRED when [variant] is `full` (otherwise the plan-picker section has nothing to render). Omit `plans` when [variant] is `compact` or `enterprise` to skip the plan-picker section.
891
+ - account.paymentMethods is forwarded verbatim to <payment-method-list-ui>; account.invoices is forwarded verbatim to <invoice-history-ui>. Their shapes are owned by SPEC-010 and SPEC-008 respectively.
892
+ - BillingOverview MUST NOT be nested inside Modal or Drawer. The dashboard is a route, not a modal — Modal traps focus + clips on long content; this surface is designed for full-page layout.
893
+ - Wire one listener to `account-action` instead of subscribing to every child primitive's event. The composite normalises plan-action / payment-action / invoice-action / dunning-action into the single bubbling event.
894
+
895
+ ## InvoiceDetail
896
+ - InvoiceDetail MUST set `invoice` OR `data-stream-src`. Neither produces the empty state but cannot be the submission state for a billing surface.
897
+ - invoice.lines[] MUST contain at least one row with `description`, `qty`, `unitAmount`, `amount`. Empty lines arrays render the lines table empty-state row, not the host empty state.
898
+ - invoice.total MUST equal subtotal + tax − (discount or 0). The composite renders the host-supplied total verbatim; consumers are authoritative on rounding rules per locale (SPEC-007 OD-001).
899
+ - invoice.status MUST be one of draft / open / paid / past-due / void. Unknown statuses render the default badge variant + a one-shot console.warn.
900
+ - InvoiceDetail MUST NOT be nested inside Modal or Drawer. Invoices are routes, not modals — Modal traps focus + clips on long content; the composite is designed for full-page layout. Use `<a href="/invoices/{number}">` instead.
901
+ - Slot ALL header actions explicitly via `slot="header-actions"` — the composite NEVER stamps a default toolbar (SPEC-007 OD-002). Action sets vary across products; default is too opinionated.
902
+
903
+ ## InvoiceHistory
904
+ - InvoiceHistory.invoices MUST be a non-empty array on commit. Empty arrays render the empty-state (no rows).
905
+ - invoices[].status MUST be one of "draft" | "open" | "paid" | "past-due" | "void". Unknown values fall back to a neutral badge variant.
906
+ - InvoiceHistory MUST NOT receive a `columns` prop — columns are owned by the composite. Consumers needing custom columns should compose <table-ui> directly with their own column array.
907
+ - `hrefPattern` is a string template with `{number}` interpolation. Consumers needing dynamic resolution (query-strings, function- based routes) should preventDefault on `invoice-row-click` and route themselves.
908
+ - Pair with `InvoiceDetail` (SPEC-007) at the route resolved by `hrefPattern` so the row-click destination exists.
909
+
910
+ ## PaymentMethodForm
911
+ - PaymentMethodForm SHOULD be wrapped in a <Form> so its form-value (the resolved token) is delivered on submission. Standalone use requires the consumer wire `tokenize()` from a custom submit handler.
912
+ - PaymentMethodForm MUST NOT receive a `value` prop carrying raw card digits. The form value is the tokenized output; raw card digits live only inside the form's sub-fields and are never mirrored to `value`.
913
+ - PaymentMethodForm SHOULD only be used in test / demo / non-PCI surfaces. Production card-capture flows MUST tokenize via a real payment processor (Stripe Elements, Braintree, Adyen) and consume only the resulting token — this primitive is the form chrome + structured validation, not a tokenization provider.
914
+ - Wrapping PaymentMethodForm inside <Field> duplicates the label and corrupts the grid layout. PaymentMethodForm IS a field group; the host carries `aria-label` directly.
915
+ - `countries` SHOULD list every ISO 3166-1 alpha-2 code your product accepts. Empty arrays fall back to a default short list (US, CA, GB, DE, FR, AU) suitable for early-stage demos only — production deployments should set this explicitly.
916
+
917
+ ## PaymentMethodList
918
+ - PaymentMethodList.methods MUST be an array. Empty array is valid and renders the empty-state.
919
+ - methods[].id MUST be unique within the list. Duplicate ids cause row collision at diff time.
920
+ - Exactly one record in `methods` MAY have `default: true`. If none does, the primitive marks the first row as default on connect.
921
+ - methods[].brand SHOULD be from the enumerated set (visa | mastercard | amex | discover | jcb | unionpay | diners | paypal | apple-pay | google-pay | ach | sepa). Unknown brands fall back to a generic credit-card mark.
922
+ - methods[].type MUST be `card`, `bank`, or `wallet`. Drives the brand-icon fallback when `brand` is unknown.
923
+ - `value` wins on conflict with methods[].default — if both are set and disagree, value is the source of truth and the primitive emits `change` to reconcile.
924
+ - Mutations are events, not props. Wire `change` / `add` / `remove` / `select` to your billing API; the primitive does NOT write to the underlying data source.
925
+
926
+ ## PlanPicker
927
+ - PlanPicker.plans MUST be a non-empty array on commit. Empty arrays render the empty-state but cannot be the submission state.
928
+ - At most ONE plans[] record may carry `recommended: true`. Two recommended plans are visually ambiguous and defeat the treatment's purpose.
929
+ - `current` MUST match a plans[].id or be empty. Unknown ids fail silently — no anchor row renders, no current-state contextualization on siblings.
930
+ - plans[].prices.monthly is REQUIRED on every record. annual is optional; if absent and cycle="annual" the card renders the monthly price with the annual cycle suffix and no `note`.
931
+ - `cycle` MUST be `monthly` or `annual`. Other values are coerced to `monthly` and a one-shot console.warn fires.
932
+ - Use `layout="list"` for in-app settings panels where the picker sits inside a <card-ui> and width is constrained. Use the default `layout="grid"` for marketing pricing pages.
933
+ - Wire `select` (not `change`) to the actual commit handler — change fires on selection without commit (keyboard focus traversal, programmatic value-set); select fires when the user clicks the CTA inside a card.
934
+
935
+ ## ChatComposer
936
+ - chat-composer is the bespoke replacement for legacy <chat-input-ui data-chat-input> inside <chat-shell>. Place an inner <chat-input-ui> as the primary input — it emits `submit` on Enter without Shift (unconditional; delegated from the inner textarea).
937
+ - The host listens for 'composer-submit' on the composer (not on the inner input). The event detail mirrors the inner submit event so existing handlers Just Work.
938
+ - Default slot holds a single <chat-input-ui> child; trailing/attach/leading slots host action buttons (send, attach, model picker).
939
+ - For non-chat input surfaces (forms, prompts, search) use <chat-input-ui> directly without the composer wrapper.
940
+
941
+ ## ChatEmpty
942
+ - chat-empty is the bespoke replacement for legacy <empty-state-ui data-chat-empty>. Place as the first child of <chat-thread>; visibility is automatic via the [empty] reflected attribute.
943
+ - No reactive props — visibility is CSS-driven off the parent [empty] attribute, not a JS toggle.
944
+ - For non-chat empty states (lists, tables, canvas) use <empty-state-ui> primitive instead; chat-empty is chat-cluster-namespaced.
945
+
946
+ ## ChatHeader
947
+ - chat-header replaces the legacy <header> chrome bar inside <chat-shell>. Use named slots for canonical clusters; ad-hoc content goes in the default slot.
948
+ - Slots: [slot="name"] for chat title, [slot="status"] for streaming/connection indicator (<chat-status>), [slot="action"] for action buttons.
949
+ - For admin-shell-style chrome bars inside chat-shell, use <admin-topbar> instead — chat-header is for in-chat metadata only.
950
+
951
+ ## ChatShell
952
+ - chat-shell takes bespoke chat-* children only. The canonical composition is <chat-thread> (with optional first-child <chat-empty>) followed by <chat-composer> wrapping a <chat-input-ui>. Add <chat-header> / <chat-sidebar> / <chat-status> as needed.
953
+ - Don't nest col-ui / row-ui or generic layout primitives directly inside chat-shell — the shell's CSS reads child tag selectors to lay them out. Generic layout goes inside the bespoke children.
954
+ - The shell listens for 'composer-submit' on <chat-composer> (not on the inner input). Streaming state is reflected on this host and propagates to <chat-thread>[streaming] + <chat-composer>[disabled] automatically — don't toggle child attributes manually.
955
+ - Legacy data-attribute shapes were retired in v0.4.0 per ADR-0024. Do not author <section data-chat-messages>, <chat-input-ui data-chat-input>, <empty-state-ui data-chat-empty>, or <header data-chat-name> inside chat-shell.
956
+
957
+ ## ChatSidebar
958
+ - chat-sidebar is the bespoke replacement for legacy <aside data-sidebar>. Use slot="leading" or slot="trailing" to position. Add resizable + collapsible attributes to opt in to interactive behaviors.
959
+ - For chrome bars inside the sidebar, prefer <admin-topbar slot="header"> and <admin-statusbar slot="footer"> over raw <header-ui> / <footer-ui> when authoring shell-tier markup.
960
+ - Use cluster-distinct localStorage key (adia-chat-sidebar-*) to avoid collisions with admin (adia-sidebar-*) and editor (adia-editor-sidebar-*) sidebars.
961
+ - For chat-list / conversation-switcher content, host <nav-ui> + <nav-item-ui> children in the default slot.
962
+
963
+ ## ChatStatus
964
+ - chat-status replaces legacy <span data-chat-status> for the streaming/connection indicator. Place inside <chat-header slot="status">.
965
+ - CSS-only — content is innerHTML (typically a short status word like 'connected' or 'streaming' or an icon).
966
+ - Use [data-state="streaming|connected|disconnected|..."] for token-driven coloring; the CSS reads the state attribute for tinting.
967
+
968
+ ## ChatThread
969
+ - chat-thread is the bespoke replacement for legacy <section data-chat-messages> inside <chat-shell>. Use it for the message scroll surface; the host appends dynamic message divs as children.
970
+ - Place <chat-empty> as an optional first child for the empty state; the [empty] reflected attribute drives its visibility via CSS (no JS toggling).
971
+ - Different from primitive <chat-thread-ui>: chat-thread (no -ui suffix) is the module-tier shell-aware version with scroll-on-new-message + load-more + empty-state coordination.
972
+ - Hosts message blocks (typically agent/user message rows) as default-slot children; <chat-empty> goes as first child for the empty state.
973
+
974
+ ## DashboardLayout
975
+ - DashboardLayout MUST receive children via the four named slots
976
+ (toolbar / kpis / charts / table) plus the optional aside.
977
+ Children without a [slot] attribute will not render in any band.
978
+
979
+ - DashboardLayout[kpi-columns] MUST be 2-6. Out-of-range values
980
+ fall back to the default 4. Eight cards in a row is too narrow
981
+ to be legible at typical container widths; container queries
982
+ collapse the band to 2 columns ≤48em and 1 column ≤32em.
983
+
984
+ - DashboardLayout[chart-split] MUST be one of the documented
985
+ enum strings — "" (full-width) / 2 / 2:1 / 3:2 / 3:1.
986
+
987
+ - A DashboardLayout SHOULD sit inside AdminPageBody for the
988
+ canonical chrome stack. Top-level placement is allowed for
989
+ surface-only demos but not the production shape.
990
+
991
+ - A DashboardLayout MUST NOT contain another DashboardLayout as
992
+ a descendant. Two parametric-density containers fight over the
993
+ --a-density cascade. For nested dashboards use sibling
994
+ DashboardLayouts switched by Tabs.
995
+
996
+
997
+ ## DateRangeSelector
998
+ - DateRangeSelector MUST sit inside a toolbar context — typically a
999
+ Row inside DashboardLayout.slot=toolbar, or directly inside
1000
+ AdminPageHeader.slot=action. Do NOT place it as a freestanding
1001
+ block primitive at page top-level.
1002
+
1003
+ - ONLY ONE DateRangeSelector with broadcast="document" per page.
1004
+ Secondary instances on the same page MUST use broadcast="self"
1005
+ or broadcast="none". Two document-broadcasters race for the
1006
+ data-range-* attributes on <html> and produce flicker.
1007
+
1008
+ - `presets` MUST be a comma-separated subset of the documented value
1009
+ enum (today, 7d, 30d, 90d, qtd, ytd, custom). Unknown keys are
1010
+ ignored at runtime; the chip-row renders only recognized keys.
1011
+
1012
+ - When value="custom", from/to MUST be ISO-8601 dates supplied
1013
+ either declaratively (from + to attributes) or imperatively via
1014
+ setRange("custom", from, to). Without a custom from/to, the
1015
+ composite falls back to the prior resolved range.
1016
+
1017
+ - For form participation, set [name]. Without [name], the composite
1018
+ emits range-change events only and does NOT participate in form
1019
+ submission. With [name], FormData carries the value "{from}:{to}".
1020
+
1021
+
1022
+ ## EditorCanvasEmpty
1023
+ - editor-canvas-empty is the bespoke empty-state slot for <editor-canvas>. Place as the first child of <editor-canvas>; visibility is automatic via the [empty] reflected attribute.
1024
+ - CSS-only — no JS module needed in shell HTML imports.
1025
+ - For non-editor canvas empty states (raw <canvas-ui>) use <empty-state-ui> instead; editor-canvas-empty is editor-cluster-namespaced.
1026
+
1027
+ ## EditorCanvasToolbar
1028
+ - editor-canvas-toolbar is the bespoke chrome strip for the <editor-canvas> top edge. Use it to hold view-mode tabs (preview / schema / DOM) or breadcrumb-style navigation scoped to the canvas region.
1029
+ - Place as the first child of <editor-canvas>; the canvas's flex-column layout positions the toolbar above the content body automatically, and the toolbar is sticky to keep tabs visible during canvas scroll.
1030
+ - Distinct from <editor-toolbar> (app-scope, top of <editor-shell>) — this is canvas-scope, holding view-mode affordances rather than document-wide actions.
1031
+
1032
+ ## EditorCanvas
1033
+ - editor-canvas is the bespoke replacement for legacy <div data-canvas> inside <editor-shell>. Use it as the central content region for editor work surfaces.
1034
+ - Place <editor-canvas-empty> as an optional first child for the empty state; the [empty] reflected attribute drives its visibility via CSS (no JS toggling).
1035
+ - Place <editor-canvas-toolbar> as the first child to mount view-mode tabs (preview / schema / DOM, etc.), breadcrumbs, or canvas-scoped actions above the content body. Replaces the ad-hoc <div data-view-strip> pattern. Distinct from <editor-toolbar> (app-scope) — this is canvas-scope.
1036
+
1037
+ ## EditorShell
1038
+ - editor-shell takes bespoke editor-* children only. The canonical composition is <editor-toolbar> + <editor-sidebar slot="leading"> + <editor-canvas> + <editor-sidebar slot="trailing"> + <editor-statusbar>. Each child is optional except the canvas.
1039
+ - Don't nest col-ui / row-ui or generic layout primitives directly inside editor-shell — the shell's CSS reads child tag selectors to lay them out. Generic layout goes inside the bespoke children.
1040
+ - <editor-sidebar> WRAPS <pane-ui resizable> rather than implementing drag itself (delegation pattern). Inside each sidebar place a single <pane-ui resizable size="sm"> filled with <header> + <section> slots.
1041
+ - For editor-inside-admin nested-shell pages, place the editor-shell inside <admin-page-body> with `flex: 1; min-height: 0` on every ancestor in the flex chain. Without min-height: 0 the inner shell collapses to zero height.
1042
+ - Legacy data-attribute shapes were retired in v0.4.0 per ADR-0024. Do not author <div data-editor-body>, <pane-ui data-left|data-right>, <div data-canvas>, <span data-spacer>, or bare <header>/<footer> chrome inside editor-shell.
1043
+
1044
+ ## EditorSidebar
1045
+ - editor-sidebar wraps <pane-ui resizable> rather than implementing drag itself. Place a <pane-ui resizable> as the only structural child; fill the pane with header / section / footer slots.
1046
+ - The cluster-distinct localStorage prefix (adia-editor-sidebar-*) keeps editor sidebars from colliding with admin (adia-sidebar-*) and chat (adia-chat-sidebar-*) sidebars on the same domain.
1047
+ - Wraps a SINGLE <pane-ui resizable> as its only structural child; fill the pane with sub-views (nav, inspector, layers panel, etc.).
1048
+ - For multiple panes (e.g. left nav + right inspector), use two <editor-sidebar> instances at slot="leading" and slot="trailing" of <editor-shell>.
1049
+
1050
+ ## EditorStatusbar
1051
+ - editor-statusbar replaces legacy <footer> chrome bar inside <editor-shell>. Use named slots for canonical clusters; ad-hoc content goes in the default slot.
1052
+ - Slots: [slot="status"] for save/sync state, [slot="cursor"] for cursor position, [slot="zoom"] for zoom level, [slot="action"] for actions. All optional.
1053
+ - Different from <admin-statusbar> (which is for admin-shell); editor-statusbar has editor-specific slot vocabulary (cursor, zoom).
1054
+
1055
+ ## EditorToolbar
1056
+ - editor-toolbar replaces legacy <header> chrome bar inside <editor-shell>. Use named slots (title / status / action / action-leading) for canonical clusters; ad-hoc inline content goes in the default slot.
1057
+ - Buttons that should trigger named actions get [data-toolbar-action="<name>"]. The toolbar bubbles a single 'toolbar-action' event up to the host with the name in detail.
1058
+ - Different from <admin-topbar> (admin-shell chrome) — editor-toolbar has [full-screen] state + editor-specific [data-toolbar-action] event bubbling.
1059
+ - Place full-screen toggle buttons inside the toolbar with [data-toolbar-action="toggle-full-screen"]; host reflects [full-screen] up to <editor-shell>.
1060
+
1061
+ ## ConfirmDialog
1062
+ - ConfirmDialog is for NON-destructive yes/no questions ("Save changes?", "Switch theme?", "Apply preset?"). For irreversible destructive operations (delete, drop, deploy to prod) use AlertDialog instead — its danger chrome + role="alertdialog" + typed-name speed-bump are the WAI-APG pattern for that case.
1063
+ - Default focus lands on Cancel by default — this is intentional (WAI guidance: the least-destructive action is the default). Do NOT add autofocus to the confirm button or override the focus model.
1064
+ - The confirm button is primary-toned by default. Use [confirm-variant="ghost"] only when both options are roughly equivalent in weight (e.g. "Apply preset" vs "Keep current" where neither is strictly preferred).
1065
+ - Do NOT model the cancel option as a "Discard" action — if cancel means "lose data", the operation is destructive and belongs in AlertDialog. ConfirmDialog's cancel is a no-op return-to-prior- state semantically.
1066
+ - Reflect dialog visibility via the [open] boolean attribute on the ConfirmDialog host (open=true / open=false). Do NOT toggle [hidden], CSS display, or wrap in a sibling visibility container — the inner <modal-ui> owns the native <dialog> lifecycle.
1067
+
1068
+ ## FormPopover
1069
+ - Children are the form fragment, in author order: CheckBox, Radio, Input, Textarea, Divider, Field. Do NOT put Option children here — a single-value option list is Select's contract; FormPopover never rebuilds it.
1070
+ - Decision rule vs siblings: single-value choice → Select (with multiple:true for multi-select chips); pure action list → Menu; edge-anchored multi-field form → Drawer. FormPopover is only for a small MIXED fragment (checks + radios + an input) behind a summary trigger.
1071
+ - The trigger summary counts CheckBox children only — one checked shows its own label, more show "Label (N)", none shows the bare label (same contract as Select[summary-label]); Radio and Input children never count. Give every Radio child one shared name per group or the browser treats them as independent.
1072
+
1073
+ ## OnboardingChecklist
1074
+ - OnboardingChecklist MUST have a non-empty `items` array. Empty items renders an empty card.
1075
+ - Each item MUST have a unique `id` within the list — used as the storage key + event detail.
1076
+ - `storageKey` SHOULD be namespaced per product (e.g. `myapp:onboarding:v1`) to avoid cross-app collisions.
1077
+ - Items SHOULD number 3 to 8. Fewer than 3 is not worth a checklist; more than 8 should split into stages.
1078
+ - Use for the "card of optional setup tasks" case. For horizontal multi-screen wizards use <step-progress-ui>; for generic to-do lists compose <list-ui> + <check-ui> directly.
1079
+ - Do not nest two <onboarding-checklist-ui> with the same `storageKey` — they will clobber each other.
1080
+
1081
+ ## A2UIRoot
1082
+ - Mount point for an A2UI-rendered composition. Hosts the runtime-emitted DOM tree.
1083
+ - Different from <gen-root> (which is for the generative-UI lane with LLM-driven streaming).
1084
+ - Do not place static children inside; runtime owns the contents.
1085
+
1086
+ ## GenRoot
1087
+ - gen-root is an integration shell. Prefer admin-shell for admin UIs; use gen-root only for chat+canvas tooling.
1088
+ - Hosts <chat-thread-ui>, <canvas-ui>, and <inspector-ui> children via named slots — chat slot for the conversation lane, canvas slot for the artifact lane, inspector slot for the dev-tools lane.
1089
+ - Mode attribute (chat-only|split|canvas-only) controls layout; transitions are CSS-animated.
1090
+
1091
+ ## IntegrationsPage
1092
+ - Use <integrations-page-ui> for the canonical Settings >
1093
+ Integrations grid. Supply the `integrations` array — the
1094
+ composite owns the search + grouping + grid breakpoints +
1095
+ empty state.
1096
+
1097
+ - `integrations` MUST be a non-empty array OR the page renders
1098
+ the empty-state. Each item MUST satisfy the SPEC-062 card
1099
+ prop contract (provider + name required).
1100
+
1101
+ - Do NOT slot <integration-card-ui> children directly — the page
1102
+ generates cards from the `integrations` prop. Slotted children
1103
+ are ignored.
1104
+
1105
+ - Do NOT nest <integrations-page-ui> inside another
1106
+ <integrations-page-ui>.
1107
+
1108
+ - For one-off integration tile groups (e.g., a single recommended
1109
+ provider on a marketing page) use <integration-card-ui> directly
1110
+ inside <grid-ui>; reach for the page composite only when search
1111
+ + grouping + empty-state semantics are needed.
1112
+
1113
+
1114
+ ## NotificationPreferences
1115
+ - NotificationPreferences.channels MUST be non-empty. A matrix with zero columns renders nothing meaningful — author at least one channel record.
1116
+ - NotificationPreferences.preferences[].channels keys MUST match the channels[].key set. Mismatched keys silently render the cell as `false` (off) — they do NOT raise an error, but the user can never toggle them into existence either.
1117
+ - The composite is fully CONTROLLED — toggling a cell does NOT mutate `preferences`. The host MUST listen for `change` (and `bulk-toggle` for the column master), apply the change to its own state, then re-pass the new `preferences` array. Failing to do this leaves the toggle visually flipping back to its prior state on the next render.
1118
+ - For binary on/off cell toggles, use <check-ui> semantics — NOT <switch-ui>. The column-header master IS a <switch-ui> (because it's a "setting" — flip the whole column), but each cell is a multi-select-style checkbox.
1119
+ - Use `group-by="group"` only when `preferences[]` records carry a stable `group` field. Mixing grouped + ungrouped rows in the same matrix produces inconsistent section heights.
1120
+
1121
+ ## AdminCommand
1122
+ - admin-command wraps a native <dialog>; the inner <command-ui> is the actual palette. Keyboard shortcut defaults to both Cmd+K (mac) and Ctrl+K (other) — the AdiaUI convention.
1123
+ - Place admin-command as a direct child of admin-shell, NOT inside a sidebar or main column. The host coordinates triggers ([data-command-trigger]) by reaching across siblings.
1124
+ - For inline content-region command surfaces use <command-ui> directly; admin-command is the modal wrapper that opens the palette as an overlay.
1125
+ - Triggers anywhere in the shell via [data-command-trigger] attribute on any element; the host wires the open/close cycle.
1126
+
1127
+ ## AdminContent
1128
+ - admin-content is the bespoke replacement for raw <main> inside admin-shell. CSS-only; the shell's css/main.css selectors target both shapes via :is(main, admin-content).
1129
+ - Place as a direct child of <admin-shell>, not inside a sidebar or topbar; admin-content owns the center column.
1130
+ - Hosts <admin-page> children OR raw page content via the default slot; for chrome bars use <admin-topbar slot="header">.
1131
+
1132
+ ## AdminEntityItem
1133
+ - admin-entity-item is the canonical icon + label + badge identity row for shell surfaces. Slot it whole into [slot="heading"] of an <admin-topbar> / <admin-statusbar> so the icon + label + badge collapse together inside a collapsible <admin-sidebar>. Do NOT re-implement it with a bare <span> or an ad-hoc flex <div> — those have no shared collapse boundary.
1134
+ - For an INTERACTIVE workspace switcher use <select-ui variant="ghost"> instead — admin-entity-item is read-only identity display.
1135
+ - Slot whole into [slot="heading"] of <admin-topbar>/<admin-statusbar>; do not nest inside other admin-entity-items.
1136
+ - Flat hierarchy: icon + label + badge in three slots, no extra wrapping at the admin-entity-item level. For full-width metadata strips compose multiple inside <row-ui> instead.
1137
+ - For an <icon-ui> glyph, wrap it: <span slot="icon"><icon-ui name="…"></icon-ui></span>. For <img>/<avatar-ui>, slot directly (no wrapper).
1138
+
1139
+ ## AdminPageBody
1140
+ - admin-page-body is the centered body band of <admin-page>. Wraps an inner <section-ui> for centered reading-column rhythm; can host full-bleed content directly to opt out.
1141
+ - Wraps an inner <section-ui> by default for centered reading-column rhythm; for full-bleed content (tables, canvas grids) use [data-full-bleed] on the section.
1142
+ - Always inside <admin-page slot="body">; do not place admin-page-body outside admin-page.
1143
+
1144
+ ## AdminPageFooter
1145
+ - admin-page-footer is the sticky bottom band of <admin-page>, the bottom-anchored counterpart of <admin-page-header>. Wraps an inner <footer-ui> for centered reading-column rhythm.
1146
+ - Wraps an inner <footer-ui> for centered reading-column rhythm; admin-page-footer owns sticky positioning + border-top, footer-ui owns the content layout.
1147
+ - Always inside <admin-page slot="footer">; for shell-tier status chrome spanning the whole shell use <admin-statusbar> instead.
1148
+ - Optional — most pages need only <admin-page-header> + <admin-page-body>. Add a footer only for persistent page-level actions (save bar, pagination, legal); never stamp an empty one.
1149
+
1150
+ ## AdminPageHeader
1151
+ - admin-page-header is the sticky top band of <admin-page>. Wraps an inner <header-ui> for centered reading-column rhythm.
1152
+ - Wraps an inner <header-ui> for centered reading-column rhythm; admin-page-header owns sticky positioning + border, header-ui owns the content layout.
1153
+ - Always inside <admin-page slot="header">; for shell-tier chrome use <admin-topbar> instead.
1154
+ - Always wrap an inner <header-ui> — not a raw <header>. Raw <header> has no shadow DOM; slot="action" and other named slots on its children are silently dropped.
1155
+
1156
+ ## AdminPage
1157
+ - admin-page is the bespoke replacement for <article data-content-root>. Provides the page-content named container query so descendants can use @container page-content (max-width: 720px) etc.
1158
+ - Hosts a single page surface via [slot="body"] (typically <admin-page-body>) with optional [slot="header"] (<admin-page-header>) and [slot="footer"].
1159
+ - Sits inside <admin-content>'s default slot; do not place outside admin-shell.
1160
+
1161
+ ## AdminScroll
1162
+ - admin-scroll is the bespoke replacement for the legacy <section> child of <main> inside admin-shell. Single child convention — typically wraps an <admin-page> for sticky-band layout.
1163
+ - Wraps a single <admin-page> child typically; do not place multiple admin-pages side-by-side as siblings here.
1164
+ - For horizontal scrolling regions (data grids, canvas surfaces) use overflow on the inner content instead — admin-scroll is vertical-only.
1165
+
1166
+ ## AppShell
1167
+ - admin-shell takes bespoke admin-* children only. The canonical composition is <admin-topbar> + <admin-sidebar slot="leading"> + <admin-content> + <admin-sidebar slot="trailing"> + <admin-command> + optional <admin-statusbar>. The shell's CSS grid reads child tag selectors to place them.
1168
+ - Don't nest col-ui / row-ui or generic layout primitives directly inside admin-shell — app-shell.css handles grid layout based on bespoke child tags. Generic layout goes inside <admin-content> or inside <admin-page-body>.
1169
+ - Click forwarding patterns — [data-sidebar-toggle="<name>"] on a button forwards to <admin-sidebar[slot="<name>"]>.toggle(); [data-command-trigger] on a button forwards to <admin-command>.show(). The shell doesn't need to know about the buttons; the bespoke children own the behavior.
1170
+ - Legacy data-attribute shapes were retired in v0.4.0 per ADR-0024. Do not author <aside data-sidebar>, <dialog data-command>, [data-resize], <aside-ui slot=>, <span data-spacer>, or <div data-actions> inside admin-shell.
1171
+
1172
+ ## AdminSidebar
1173
+ - admin-sidebar is the bespoke replacement for legacy <aside data-sidebar>. Use slot="leading" or slot="trailing" to position. Add resizable + collapsible attributes to opt in to interactive behaviors.
1174
+ - For chrome bars inside the sidebar, prefer <admin-topbar slot="header"> and <admin-statusbar slot="footer"> over raw <header-ui> / <footer-ui> when authoring shell-tier markup.
1175
+ - [resizable] attribute enables drag-resize via internal <pane-ui resizable>; persists collapsed/width to localStorage under adia-sidebar-* keys.
1176
+ - For non-resizable static rails (fixed-width nav), omit [resizable]; the same primitive serves both modes.
1177
+
1178
+ ## AdminStatusbar
1179
+ - admin-statusbar replaces <footer-ui> at shell-tier. Same slot vocabulary as <admin-topbar>; visual treatment differs (the shell css applies a top-border instead of bottom).
1180
+ - For a user-identity row (avatar + name + role badge), slot a single <admin-entity-item slot="heading"> rather than separate slot="icon" + slot="heading" children — the wrapper collapses the name + badge together inside a collapsible <admin-sidebar>, keeping the avatar.
1181
+ - All slots optional; common pattern is [slot="heading"] + [slot="action"] only. Empty admin-statusbar renders zero-height (no visual chrome).
1182
+ - Sits at slot="footer" of <admin-shell>, <admin-content>, or <admin-sidebar>; do not place inside <admin-page slot="footer"> (use raw <footer-ui> there).
1183
+
1184
+ ## AdminTopbar
1185
+ - admin-topbar replaces <header-ui> at shell-tier — use it for chrome bars inside admin-shell, admin-content, admin-sidebar. Use <header-ui> for primitive containers (Card / Drawer / Modal).
1186
+ - For an icon + label (+ optional badge) identity row — workspace or product identity — slot a single <admin-entity-item slot="heading"> rather than separate slot="icon" + slot="heading" children. The wrapper keeps the icon and label as one unit so they truncate and collapse together inside a collapsible <admin-sidebar>.
1187
+ - All slots optional; common pattern is [slot="heading"] + [slot="action"] only. Empty admin-topbar renders zero-height (no visual chrome).
1188
+ - Sits at slot="header" of <admin-shell>, <admin-content>, or <admin-sidebar>; do not place inside <admin-page slot="header"> (use <admin-page-header> there).
1189
+
1190
+ ## AppShell
1191
+ - embed-shell takes exactly one [app] child + any number of [panel="<name>"] children. It owns layout, not content — the consumer supplies the surfaces.
1192
+ - Open a panel with an [opens="<name>"] trigger anywhere inside, or an `embed:open` event; dismiss with [close]. Do not toggle visibility manually — the shell reflects [panel] + sets [active] on the open panel.
1193
+ - Use clean attributes (ADR-0024) — [app], [panel], [opens], [close] — not the legacy data-* shapes.
1194
+
1195
+ ## SimpleContent
1196
+ - simple-content is the article surface inside simple-shell. Use for primary page body. Sibling to <simple-hero> (optional).
1197
+ - CSS-only — do not import its JS module (there isn't one); does not need an `import` in shell HTML.
1198
+ - For multi-page apps with chrome (nav, topbar, command palette) use <admin-shell-ui> with <admin-content> instead.
1199
+
1200
+ ## SimpleHero
1201
+ - simple-hero is the optional top strip inside simple-shell. Use for marketing splashes, error-page reassurance text, or single- flow page intros. Always followed by <simple-content> for body.
1202
+ - Three named slots: heading (large title), lede (supporting subtitle), actions (button cluster). All optional but order is fixed.
1203
+ - CSS-only — sibling to <simple-content> inside <simple-shell>. Do not nest hero inside content or vice versa.
1204
+
1205
+ ## SimpleShell
1206
+ - simple-shell is the bespoke shell for thin / minimal page surfaces. Use when the page has no nav rail, no chrome bars, no command palette. For full app surfaces use admin-shell; for chat surfaces use chat-shell; for design tools use editor-shell.
1207
+ - Compose with <simple-hero> (optional top hero strip) and <simple-content> (main article body). Both are CSS-only structural children — no JS, no state.
1208
+ - [centered] reflected attribute centers content vertically; [full-bleed] drops the max-width constraint on <simple-content> children. Both optional, default unset.
1209
+ - For multi-page apps with chrome (nav, topbar, command palette) use <admin-shell> instead; simple-shell has zero chrome.
1210
+
1211
+ ## ThemePanel
1212
+ - theme-panel is the canonical appearance-preferences popover. Compose inside a <popover-ui slot="content"> in the topbar of a shell (admin, chat, editor, simple) when the page exposes user theming. Avoid hardcoding it as a shell child — placement is the consumer's call.
1213
+ - Use [persist] for the docs surface or a real product app; omit [persist] for playgrounds and embedded demos so state stays ephemeral. The default is ephemeral.
1214
+ - Add boolean attributes [parametric], [presets], [register], [scheme-toggle] to enable sections; the minimum panel is the theme button grid (empty until [themes] is supplied — no default list).
1215
+