create-ailk 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/component-catalog.md +210 -52
  2. package/dist/cli.js +0 -0
  3. package/dist/lib/apply-module-patches.d.ts +47 -0
  4. package/dist/lib/apply-module-patches.js +370 -0
  5. package/dist/lib/extract-module-bundle.d.ts +12 -3
  6. package/dist/lib/extract-module-bundle.js +236 -24
  7. package/dist/lib/fetch-module.d.ts +3 -38
  8. package/dist/lib/fetch-module.js +26 -8
  9. package/dist/lib/module-license-gate.d.ts +2 -0
  10. package/dist/lib/module-license-gate.js +1 -0
  11. package/dist/lib/paid-paths.d.ts +16 -0
  12. package/dist/lib/paid-paths.js +90 -0
  13. package/dist/module-architecture.d.ts +139 -23
  14. package/dist/module-architecture.js +668 -25
  15. package/dist/parse-args.d.ts +2 -2
  16. package/dist/parse-args.js +3 -1
  17. package/dist/programmatic.d.ts +2 -1
  18. package/dist/programmatic.js +15 -4
  19. package/dist/surfaces.d.ts +12 -36
  20. package/dist/surfaces.js +35 -5
  21. package/dist/sync-routes.js +31 -1
  22. package/package.json +14 -15
  23. package/templates/.claude/agents/web.md +2 -3
  24. package/templates/.claude/rules/architecture.md +5 -5
  25. package/templates/.claude/skills/README.md +2 -1
  26. package/templates/.env.example +21 -9
  27. package/templates/CONVENTIONS.md +6 -7
  28. package/templates/apps/api/.env.example +9 -0
  29. package/templates/apps/api/CLAUDE.md +35 -4
  30. package/templates/apps/api/package.json +0 -1
  31. package/templates/apps/api/src/__tests__/cors.test.ts +195 -0
  32. package/templates/apps/api/src/__tests__/module-exclusion.test.ts +60 -2
  33. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +159 -0
  34. package/templates/apps/api/src/config/__tests__/modules.test.ts +76 -0
  35. package/templates/apps/api/src/config/index.ts +19 -0
  36. package/templates/apps/api/src/config/modules.ts +12 -14
  37. package/templates/apps/api/src/lib/__mocks__/prisma.ts +13 -0
  38. package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +89 -0
  39. package/templates/apps/api/src/lib/slice-load.ts +90 -0
  40. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +52 -32
  41. package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +182 -0
  42. package/templates/apps/api/src/openapi/__tests__/surface-drift.test.ts +293 -0
  43. package/templates/apps/api/src/openapi/index.ts +9 -3
  44. package/templates/apps/api/src/openapi/spec.ts +505 -65
  45. package/templates/apps/api/src/openapi/surface-drift.ts +195 -0
  46. package/templates/apps/api/src/routes/content/__tests__/create.test.ts +14 -0
  47. package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +14 -0
  48. package/templates/apps/api/src/routes/content/__tests__/update.test.ts +14 -0
  49. package/templates/apps/api/src/routes/content/index.ts +38 -11
  50. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +28 -0
  51. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +144 -0
  52. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +796 -0
  53. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +478 -0
  54. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +38 -0
  55. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +814 -0
  56. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +717 -0
  57. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +35 -0
  58. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +484 -0
  59. package/templates/apps/api/src/routes/project-listings/index.ts +52 -10
  60. package/templates/apps/api/src/routes/project-listings/me.ts +86 -0
  61. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +5 -0
  62. package/templates/apps/api/src/routes/project-listings/public.ts +5 -0
  63. package/templates/apps/api/src/routes/project-listings/respond.ts +11 -0
  64. package/templates/apps/api/src/routes/project-listings/resume-token.ts +5 -0
  65. package/templates/apps/api/src/routes/project-listings/start.ts +38 -0
  66. package/templates/apps/api/src/routes/project-listings/submit.ts +5 -0
  67. package/templates/apps/api/src/routes/project-listings/verify-email.ts +150 -0
  68. package/templates/apps/api/src/server.ts +471 -133
  69. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +65 -0
  70. package/templates/apps/api/src/services/__tests__/consent.test.ts +282 -0
  71. package/templates/apps/api/src/services/consent.ts +236 -0
  72. package/templates/apps/api/src/services/deliverable-fulfillment.ts +10 -0
  73. package/templates/apps/api/src/services/listing-config.ts +58 -0
  74. package/templates/apps/api/src/services/project-listing-resume-email.ts +326 -0
  75. package/templates/apps/api/src/services/project-listings.ts +602 -29
  76. package/templates/apps/api/src/vercel-handler.ts +60 -26
  77. package/templates/apps/mcp/.env.example +8 -0
  78. package/templates/apps/mcp/CLAUDE.md +2 -2
  79. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +21 -0
  80. package/templates/apps/mcp/__tests__/config/modules.test.ts +78 -0
  81. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +1 -1
  82. package/templates/apps/mcp/src/config/modules.ts +14 -13
  83. package/templates/apps/mcp/src/server.ts +8 -4
  84. package/templates/apps/mcp/src/tools/index.ts +7 -22
  85. package/templates/apps/web/.env.example +15 -0
  86. package/templates/apps/web/app/[locale]/(authed)/{waitlist/__tests__ → __tests__}/gate.test.tsx +4 -4
  87. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +2 -1
  88. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +2 -1
  89. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +2 -1
  90. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/flow.actions.test.ts +1 -0
  91. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +1 -0
  92. package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +2 -1
  93. package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +1 -0
  94. package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +1 -0
  95. package/templates/apps/web/app/[locale]/layout.tsx +13 -1
  96. package/templates/apps/web/app/llms.txt/route.ts +12 -9
  97. package/templates/apps/web/jest.config.cjs +20 -13
  98. package/templates/apps/web/lib/__tests__/site-theme.test.ts +112 -0
  99. package/templates/apps/web/lib/site-brand.tsx +4 -1
  100. package/templates/apps/web/lib/site-theme.ts +74 -0
  101. package/templates/apps/web/next.config.mjs +1 -3
  102. package/templates/apps/web/package.json +1 -6
  103. package/templates/apps/web/public/android-chrome-192x192.png +0 -0
  104. package/templates/apps/web/public/android-chrome-512x512.png +0 -0
  105. package/templates/apps/web/public/apple-touch-icon.png +0 -0
  106. package/templates/apps/web/public/favicon-16x16.png +0 -0
  107. package/templates/apps/web/public/favicon-32x32.png +0 -0
  108. package/templates/apps/web/public/favicon.ico +0 -0
  109. package/templates/apps/web/public/favicon.svg +6 -3
  110. package/templates/apps/web/public/lockup-horizontal.svg +4 -0
  111. package/templates/apps/web/public/logomark.svg +4 -0
  112. package/templates/apps/web/public/site.webmanifest +2 -2
  113. package/templates/apps/web/public/wordmark.svg +4 -0
  114. package/templates/content/_site.mdx +12 -0
  115. package/templates/database/CHANGELOG.md +94 -0
  116. package/templates/database/inbox/schema.prisma +165 -0
  117. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +32 -0
  118. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +71 -0
  119. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +30 -0
  120. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +49 -0
  121. package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +123 -0
  122. package/templates/database/package.json +1 -1
  123. package/templates/database/scripts/db-generate-locked.sh +0 -0
  124. package/templates/package.json +1 -1
  125. package/templates/.claude/skills/scaffold-commerce/SKILL.md +0 -807
  126. package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +0 -71
  127. package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +0 -83
  128. package/templates/.claude/skills/scaffold-commerce/templates/checkout-route.template.ts +0 -370
  129. package/templates/.claude/skills/scaffold-commerce/templates/invoice-route.template.ts +0 -376
  130. package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +0 -72
  131. package/templates/.claude/skills/scaffold-commerce/templates/payment-link-route.template.ts +0 -471
  132. package/templates/.claude/skills/scaffold-commerce/templates/portal-route.template.ts +0 -365
  133. package/templates/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts +0 -60
  134. package/templates/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts +0 -446
  135. package/templates/apps/api/src/__tests__/server.test.ts +0 -253
  136. package/templates/apps/api/src/bin/deliverable-resend.ts +0 -144
  137. package/templates/apps/api/src/bin/deliverable-upload.ts +0 -114
  138. package/templates/apps/api/src/bin/followup-sweep.ts +0 -44
  139. package/templates/apps/api/src/bin/listing-csv-sweep.ts +0 -46
  140. package/templates/apps/api/src/bin/seed-presets.ts +0 -58
  141. package/templates/apps/api/src/bin/seed-waitlist-experiments.ts +0 -104
  142. package/templates/apps/api/src/bin/session-retention-sweep.ts +0 -46
  143. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -74
  144. package/templates/apps/api/src/lib/stripe.ts +0 -52
  145. package/templates/apps/api/src/lib/tenant-db.ts +0 -225
  146. package/templates/apps/api/src/lib/ws-token.ts +0 -91
  147. package/templates/apps/api/src/middleware/tenant.ts +0 -99
  148. package/templates/apps/api/src/routes/billing/__tests__/portal.test.ts +0 -450
  149. package/templates/apps/api/src/routes/billing/__tests__/read.test.ts +0 -262
  150. package/templates/apps/api/src/routes/billing/__tests__/usage.test.ts +0 -436
  151. package/templates/apps/api/src/routes/billing/index.ts +0 -36
  152. package/templates/apps/api/src/routes/billing/portal.ts +0 -182
  153. package/templates/apps/api/src/routes/billing/read.ts +0 -75
  154. package/templates/apps/api/src/routes/billing/usage.ts +0 -153
  155. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -687
  156. package/templates/apps/api/src/routes/checkout/index.ts +0 -13
  157. package/templates/apps/api/src/routes/checkout/sessions.ts +0 -197
  158. package/templates/apps/api/src/routes/deliverables/__tests__/index.test.ts +0 -393
  159. package/templates/apps/api/src/routes/deliverables/index.ts +0 -200
  160. package/templates/apps/api/src/routes/flow-checkouts/__tests__/index.test.ts +0 -443
  161. package/templates/apps/api/src/routes/flow-checkouts/index.ts +0 -82
  162. package/templates/apps/api/src/routes/flows/README.md +0 -147
  163. package/templates/apps/api/src/routes/flows/__tests__/index.test.ts +0 -752
  164. package/templates/apps/api/src/routes/flows/__tests__/recommender.test.ts +0 -671
  165. package/templates/apps/api/src/routes/flows/index.ts +0 -202
  166. package/templates/apps/api/src/routes/flows/recommender.ts +0 -443
  167. package/templates/apps/api/src/routes/project-listings/__tests__/copy-edit.test.ts +0 -815
  168. package/templates/apps/api/src/routes/project-listings/__tests__/tenant-isolation.test.ts +0 -566
  169. package/templates/apps/api/src/routes/project-listings/get.ts +0 -70
  170. package/templates/apps/api/src/routes/project-listings/list.ts +0 -47
  171. package/templates/apps/api/src/routes/project-listings/patch.ts +0 -136
  172. package/templates/apps/api/src/routes/schedule/__tests__/index.test.ts +0 -490
  173. package/templates/apps/api/src/routes/schedule/index.ts +0 -249
  174. package/templates/apps/api/src/routes/slack/__tests__/actions.test.ts +0 -385
  175. package/templates/apps/api/src/routes/slack/actions.ts +0 -177
  176. package/templates/apps/api/src/routes/slack/index.ts +0 -38
  177. package/templates/apps/api/src/routes/waitlist-experiments/__tests__/tenant-isolation.test.ts +0 -577
  178. package/templates/apps/api/src/routes/waitlist-experiments/comparison.ts +0 -78
  179. package/templates/apps/api/src/routes/waitlist-experiments/index.ts +0 -41
  180. package/templates/apps/api/src/routes/waitlist-experiments/list.ts +0 -64
  181. package/templates/apps/api/src/routes/waitlist-experiments/respond.ts +0 -42
  182. package/templates/apps/api/src/routes/waitlist-experiments/signup.ts +0 -84
  183. package/templates/apps/api/src/routes/waitlist-experiments/signups.ts +0 -119
  184. package/templates/apps/api/src/routes/waitlist-signups/__tests__/index.test.ts +0 -238
  185. package/templates/apps/api/src/routes/waitlist-signups/index.ts +0 -101
  186. package/templates/apps/api/src/routes/webhooks/README.md +0 -80
  187. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -315
  188. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -247
  189. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -270
  190. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -198
  191. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -633
  192. package/templates/apps/api/src/routes/webhooks/index.ts +0 -41
  193. package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -481
  194. package/templates/apps/api/src/routes/workspaces/__tests__/config-tenant-isolation.test.ts +0 -356
  195. package/templates/apps/api/src/routes/workspaces/__tests__/tenant-isolation.test.ts +0 -671
  196. package/templates/apps/api/src/routes/workspaces/config.ts +0 -125
  197. package/templates/apps/api/src/routes/workspaces/index.ts +0 -194
  198. package/templates/apps/api/src/routes/workspaces/sessions.ts +0 -218
  199. package/templates/apps/api/src/services/__tests__/flow-aggregate.test.ts +0 -425
  200. package/templates/apps/api/src/services/__tests__/flow-engine.test.ts +0 -2840
  201. package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +0 -393
  202. package/templates/apps/api/src/services/__tests__/listing-csv-sweep.test.ts +0 -560
  203. package/templates/apps/api/src/services/__tests__/playbook-compile.test.ts +0 -406
  204. package/templates/apps/api/src/services/__tests__/playbook-render.test.ts +0 -290
  205. package/templates/apps/api/src/services/__tests__/project-listing-decision.test.ts +0 -736
  206. package/templates/apps/api/src/services/__tests__/project-listing-flow.test.ts +0 -475
  207. package/templates/apps/api/src/services/__tests__/project-listing-issue.test.ts +0 -340
  208. package/templates/apps/api/src/services/__tests__/recommender-capture.test.ts +0 -983
  209. package/templates/apps/api/src/services/__tests__/tenant-context-cascade.test.ts +0 -71
  210. package/templates/apps/api/src/services/__tests__/tenant-context.test.ts +0 -379
  211. package/templates/apps/api/src/services/__tests__/usage-metering.test.ts +0 -768
  212. package/templates/apps/api/src/services/__tests__/waitlist-dashboard.test.ts +0 -1314
  213. package/templates/apps/api/src/services/__tests__/waitlist-experiments.test.ts +0 -341
  214. package/templates/apps/api/src/services/__tests__/waitlist-followup.test.ts +0 -567
  215. package/templates/apps/api/src/services/__tests__/waitlist-scoring.test.ts +0 -474
  216. package/templates/apps/api/src/services/__tests__/waitlist-signups.test.ts +0 -354
  217. package/templates/apps/api/src/services/flow-aggregate.ts +0 -232
  218. package/templates/apps/api/src/services/flow-checkouts.ts +0 -123
  219. package/templates/apps/api/src/services/flow-engine.ts +0 -1278
  220. package/templates/apps/api/src/services/lead-promotion.ts +0 -176
  221. package/templates/apps/api/src/services/listing-csv-sweep.ts +0 -455
  222. package/templates/apps/api/src/services/playbook-compile.ts +0 -398
  223. package/templates/apps/api/src/services/playbook-render.ts +0 -263
  224. package/templates/apps/api/src/services/project-listing-decision.ts +0 -490
  225. package/templates/apps/api/src/services/project-listing-flow.ts +0 -426
  226. package/templates/apps/api/src/services/project-listing-issue.ts +0 -251
  227. package/templates/apps/api/src/services/recommender-capture.ts +0 -835
  228. package/templates/apps/api/src/services/scheduling/cal-provider.ts +0 -392
  229. package/templates/apps/api/src/services/scheduling/index.ts +0 -63
  230. package/templates/apps/api/src/services/scheduling/types.ts +0 -88
  231. package/templates/apps/api/src/services/tenant-context.ts +0 -451
  232. package/templates/apps/api/src/services/usage-metering.ts +0 -699
  233. package/templates/apps/api/src/services/waitlist-dashboard.ts +0 -947
  234. package/templates/apps/api/src/services/waitlist-experiments.ts +0 -213
  235. package/templates/apps/api/src/services/waitlist-followup.ts +0 -486
  236. package/templates/apps/api/src/services/waitlist-scoring.ts +0 -166
  237. package/templates/apps/api/src/services/waitlist-signups.ts +0 -165
  238. package/templates/apps/mcp/__tests__/schedule_tools.test.ts +0 -242
  239. package/templates/apps/mcp/src/tools/create_booking.ts +0 -58
  240. package/templates/apps/mcp/src/tools/get_event_meta.ts +0 -55
  241. package/templates/apps/mcp/src/tools/get_flow.ts +0 -61
  242. package/templates/apps/mcp/src/tools/list_availability.ts +0 -67
  243. package/templates/apps/mcp/src/tools/submit_flow_step.ts +0 -83
  244. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx +0 -309
  245. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx +0 -149
  246. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/comparison.test.tsx +0 -273
  247. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/list.test.tsx +0 -171
  248. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/signup.test.tsx +0 -179
  249. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx +0 -116
  250. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx +0 -66
  251. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx +0 -61
  252. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx +0 -114
  253. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx +0 -139
  254. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx +0 -85
  255. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx +0 -67
  256. package/templates/apps/web/app/[locale]/(authed)/waitlist/page.tsx +0 -179
  257. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +0 -178
  258. package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +0 -160
  259. package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +0 -25
  260. package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +0 -117
  261. package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +0 -58
  262. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +0 -119
  263. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/checkout.actions.test.ts +0 -287
  264. package/templates/apps/web/app/[locale]/flows/[slug]/checkout.actions.ts +0 -254
  265. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx +0 -532
  266. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx +0 -121
  267. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/ResultsClient.checkout.test.tsx +0 -457
  268. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/page.test.tsx +0 -396
  269. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx +0 -114
  270. package/templates/apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx +0 -110
  271. package/templates/apps/web/app/[locale]/projects/apply/__tests__/ListingApplicationClient.test.tsx +0 -96
  272. package/templates/apps/web/app/[locale]/schedule/__tests__/page.test.tsx +0 -117
  273. package/templates/apps/web/app/[locale]/schedule/confirmed/__tests__/page.test.tsx +0 -96
  274. package/templates/apps/web/app/[locale]/schedule/confirmed/page.tsx +0 -92
  275. package/templates/apps/web/app/[locale]/schedule/page.tsx +0 -82
  276. package/templates/apps/web/content/en/blog/README.txt +0 -25
  277. package/templates/apps/web/content/en/docs/index.mdx +0 -28
  278. package/templates/apps/web/lib/__mocks__/source-server.js +0 -31
  279. package/templates/apps/web/lib/blog-list-data.ts +0 -95
  280. package/templates/apps/web/lib/blog-post-data.ts +0 -79
  281. package/templates/apps/web/lib/source.ts +0 -34
  282. package/templates/apps/web/public/logomark-dark.svg +0 -4
  283. package/templates/apps/web/public/logomark-light.svg +0 -4
  284. package/templates/apps/web/source.config.ts +0 -78
@@ -2,22 +2,26 @@
2
2
 
3
3
  <!-- GENERATED FILE — do not hand-edit. Regenerate with `pnpm --filter create-ailk run build-catalog`. -->
4
4
 
5
- The composed-component inventory of `@working-theory/ui`, the library an AI Launch Kit site is built from. It exists because a name search fails: a site rebuilt five components AILK already had, because it searched for the names IT would have used and AILK uses different ones — `ContactOverlay`→`FormLightbox`, `SearchOverlay`→`SpotlightPanel`/`NavSearchTrigger`, `SiteRail`→`SidebarNav`, `FunnelNav`→`Nav`, `NumberedWorkList`→`Steps`/`StairSteps`.
5
+ The component inventory of `@working-theory/ui` and the shells of `@working-theory/templates` — the library an AI Launch Kit site is built from. It exists because a name search fails: a site rebuilt five components AILK already had, because it searched for the names IT would have used and AILK uses different ones — `ContactOverlay`→`FormLightbox`, `SearchOverlay`→`SpotlightPanel`/`NavSearchTrigger`, `SiteRail`→`SidebarNav`, `FunnelNav`→`Nav`, `NumberedWorkList`→`Steps`/`StairSteps`.
6
6
 
7
- **What this file does NOT cover.** Only three tiers are indexed: `sections/`, `blocks/` and `chrome/`. The `tokens/`, `primitives/` (Button, Heading, Text, Link, Icon, Badge, Input, Dialog, Command, Tooltip, `ThemeToggle`, …) and `panels/` (FixedPanel, ResizablePanel, CardGrid, …) tiers are **absent from this file**. Finding nothing here does not mean AILK lacks it check `packages/ui/src/primitives` and `packages/ui/src/panels` before concluding anything about a low-level control.
7
+ **What this file does NOT cover.** All six component tiers are indexed Sections, Blocks, Chrome, Primitives, Panels and Shells so a component absent from these tables is genuinely absent from the library. Outside the file: the **design tokens** (tier 0 — colors, spacing, typography, radius and the rest are values in `@working-theory/theme`, not components; `packages/ui/src/tokens/` holds their Storybook stories and the small display components those stories use); the **page compositions** in `packages/ui/src/pages/` and `packages/templates/src/pages/`, which assemble whole pages from the tiers below; and every non-component module (hooks, `utils/`, `.ts` helpers).
8
+
9
+ **Two things a listing does not promise.** First, the tables index every component file in the six tiers, **including the paid module slices** — the `Booker` family is here, and a build with the scheduling module switched off will not contain it. Listed is not the same as present in your tree; check the modules your site was scaffolded with. Second, this file carries no **props or data shapes**: it says what a component is FOR, never what it accepts. For a section's accepted `data` fields, read its Zod schema, or the `component-catalog.json` manifest the AILK source repo generates alongside this file.
8
10
 
9
11
  **Before you build a component, search this file for what it DOES.**
10
12
 
11
13
  1. Read **Find by capability** below — it maps the words people actually type to the names AILK uses.
12
14
  2. If nothing matches, grep the per-tier tables for a verb or noun from your requirement (`grep -i backdrop`, `grep -i "multi-step"`), not for your working name for the component.
13
- 3. Check the primitives and panels tiers, which this file does not index (see above).
15
+ 3. Check the Primitives, Panels and Shells tables too — a low-level control, a collapsible layout container, or a route-level frame lives there, not under Sections or Blocks.
14
16
  4. Only then build. If you do build, you are declaring the capability is genuinely absent.
15
17
 
16
- Inventory: **187 component files** across 3 tiers — 56 sections, 113 blocks, 18 chrome. 186 distinct names: `SchedulerEmbed` exists in more than one tier as genuinely different components, listed once per tier with its own source path.
18
+ Inventory: **284 component files** across 6 tiers — 59 sections, 115 blocks, 18 chrome, 79 primitives, 7 panels, 6 shells. 281 distinct names: `SchedulerEmbed`, `Separator`, `Tabs` exist in more than one tier as genuinely different components, listed once per tier with its own source path.
19
+
20
+ Description coverage: **280/284** components carry a capability description derived from source — 41 from the section registry's hand-authored when-to-use text, 211 from the component's own doc-comment header, 28 from its tier barrel's roster line. **4** have none; they are listed under [Undescribed components](#undescribed-components) rather than given a sentence invented from their name.
17
21
 
18
- Description coverage: **187/187** components carry a capability description derived from source40 from the section registry's hand-authored when-to-use text, 113 from the component's own doc-comment header, 34 from its tier barrel's roster line. No component was given a sentence invented from its name.
22
+ Of those, **251** are *strong* a capability sentence you could match a requirement against and **29** are *weak*: either one short clause, or a long one that spends itself on wiring (client boundaries, class names, which primitives it composes) instead of on what the thing is for. Weak rows are marked `(weak)` and listed in full under [Weak descriptions](#weak-descriptions). Coverage is 99%, but **findable-without-luck coverage is 88%**.
19
23
 
20
- Of those, **175** are *strong* a capability sentence you could match a requirement against and **12** are *weak*: either one short clause, or a long one that spends itself on wiring (client boundaries, class names, which primitives it composes) instead of on what the thing is for. Weak rows are marked `(weak)` and listed in full under [Weak descriptions](#weak-descriptions). Coverage is 100%, but **findable-without-luck coverage is 94%**.
24
+ Per tier, strong out of total: **Sections** 58/59 · **Blocks** 110/115 · **Chrome** 11/18 · **Primitives** 64/79 (4 undescribed) · **Panels** 6/7 · **Shells** 2/6. A tier low on this line is a tier where a capability search is most likely to come up empty on something that exists.
21
25
 
22
26
  That grade is **mechanical**. It counts what it can measure — how much a description adds beyond the component's own name, how much of it is spent on wiring, whether the extraction came out damaged — and it cannot tell a fluent paragraph about the wrong subject from a useful one. A person reading these tables will find more rows unusable than the weak count admits. Treat it as a floor on the problem, not a measurement of it, and read the source before concluding a capability is absent.
23
27
 
@@ -30,11 +34,11 @@ The left column is search vocabulary — how a person phrases the need. It is ha
30
34
  | If you are looking for… | Use | Notes |
31
35
  | --- | --- | --- |
32
36
  | contact overlay · modal form · popup form · form in a dialog · form on a dimmed backdrop · lightbox form | `FormLightbox` (sections) · `VideoLightbox` (blocks) · `SpotlightPanel` (sections) · `ContactForm` (sections) | FormLightbox is the modal-form one: a trigger opens a multi-step form inside a Radix Dialog on a dimmed/blurred backdrop (focus trap, ESC/backdrop close, scroll lock, lazy mount). ContactForm is the INLINE form — do not mistake it for the overlay and rebuild the overlay. |
33
- | search overlay · command palette · cmd-K · ⌘K search · spotlight · quick find | `NavSearchTrigger` (blocks) · `DocsSearch` (blocks) · `AskAiCommandGroup` (blocks) · `SpotlightPanel` (sections) | Read this one carefully: AILK does NOT ship a site-wide ⌘K palette. It ships the PARTS — NavSearchTrigger (the ⌘K trigger pill), DocsSearch (trigger + CommandDialog over a Fumadocs-shaped index, docs-scoped), AskAiCommandGroup (a CommandGroup you drop into your own dialog), and the Command/CommandDialog primitives in `packages/ui/src/primitives`. Composing a site palette from these is expected; forking the dialog is not. SpotlightPanel is the dimmed-backdrop centered-card band — it hosts a form/flow, not a search index. |
34
- | site rail · vertical nav column · left rail · app sidebar · icon rail · dashboard sidebar | `SidebarNav` (chrome) · `SidebarNavRailItems` (chrome) · `DocsSidebar` (chrome) · `SidePanel` (chrome) | Pick by context: SidebarNav is the DASHBOARD rail (it hardcodes a teams section and a user footer, and is the `sidebar` prop of DashboardShell) — fighting it into a marketing site is the wrong call; DocsSidebar is the DOCS rail (takes a page tree); SidebarNavRailItems is SidebarNav's collapsed icon-rail row. SidePanel is the RIGHT edge, not a left rail. |
37
+ | search overlay · command palette · cmd-K · ⌘K search · spotlight · quick find | `NavSearchTrigger` (blocks) · `AskAiCommandGroup` (blocks) · `SpotlightPanel` (sections) | Read this one carefully: AILK does NOT ship a site-wide ⌘K palette. It ships the PARTS — NavSearchTrigger (the ⌘K trigger pill), AskAiCommandGroup (a CommandGroup you drop into your own dialog), and the Command/CommandDialog primitives in `packages/ui/src/primitives`. Composing a site palette from these is expected; forking the dialog is not. SpotlightPanel is the dimmed-backdrop centered-card band — it hosts a form/flow, not a search index. |
38
+ | site rail · vertical nav column · left rail · app sidebar · icon rail · dashboard sidebar | `SidebarNav` (chrome) · `SidebarNavRailItems` (chrome) · `SidePanel` (chrome) | Pick by context: SidebarNav is the DASHBOARD rail (it hardcodes a teams section and a user footer, and is the `sidebar` prop of WorkspaceShell) — fighting it into a marketing site is the wrong call; SidebarNavRailItems is SidebarNav's collapsed icon-rail row. SidePanel is the RIGHT edge, not a left rail. |
35
39
  | funnel nav · minimal chrome with one CTA · stripped-down header · landing-page nav · one-action header · sticky CTA | `Nav` (chrome) · `SectionNav` (chrome) · `FloatingCta` (chrome) | There is no separate funnel-nav component, and there does not need to be: this is a CONFIGURATION of Nav — pass it one action and no link list. SectionNav is the in-page section jump nav; FloatingCta is the persistent floating single-action affordance. |
36
40
  | numbered work list · ordered steps · process list · how it works · 1-2-3 steps · staircase | `Steps` (blocks) · `StepFlow` (sections) · `StairSteps` (sections) · `FlowStepper` (sections) | For a numbered LIST you want Steps (presentational block) or StairSteps (staggered staircase section). StepFlow and FlowStepper are listed because the phrase collides, but they are the interactive multi-step FORM and its progress indicator — not a work list. |
37
- | accordion · collapsible · expand/collapse · show more · disclosure | `FaqItem` (blocks) · `FAQ` (sections) · `Objection` (sections) | There is no standalone Accordion the expand/collapse behavior lives in FaqItem and the FAQ/Objection sections that compose it. |
41
+ | accordion · collapsible · expand/collapse · show more · disclosure | `Accordion` (primitives) · `Collapsible` (primitives) · `FaqItem` (blocks) · `FAQ` (sections) · `Objection` (sections) | `Accordion` is the standalone primitive (Radix, multi-panel) and `Collapsible` is the single show/hide reach for those for generic disclosure. FaqItem and the FAQ/Objection sections carry their own expand/collapse and are the right choice for question-and-answer CONTENT, because they also feed the page's JSON-LD. |
38
42
  | banner · announcement bar · cookie consent · notification strip | `Banner` (chrome) · `AlertSection` (sections) | Banner is chrome (announcement + consent, with dismiss/consent islands); AlertSection is the in-page dismissible strip. |
39
43
  | logo wall · client logos · trusted by · partner marks | `LogoCloud` (sections) · `Awards` (sections) | |
40
44
  | pricing table · plan comparison · feature matrix · tier cards | `Pricing` (sections) · `PricingTierCard` (blocks) · `ComparisonMatrix` (blocks) · `ComparisonTable` (sections) · `BillingToggle` (blocks) | |
@@ -44,12 +48,12 @@ The left column is search vocabulary — how a person phrases the need. It is ha
44
48
  | email capture · newsletter signup · subscribe box | `Newsletter` (sections) · `NewsletterFormInline` (blocks) · `NewsletterDetail` (blocks) | |
45
49
  | video player · embedded video · video modal | `VideoSection` (sections) · `VideoEmbed` (blocks) · `VideoLightbox` (blocks) | |
46
50
  | image slider · gallery · carousel · lightbox for images | `Carousel` (sections) · `Gallery` (sections) · `MediaBand` (sections) | |
47
- | locale switcher · language picker · region selector · view toggle | `LocaleSwitcher` (blocks) · `MarkdownViewToggle` (blocks) | Dark-mode switching is `ThemeToggle`, a PRIMITIVE — primitives and panels are outside this catalog's three indexed tiers. Import it from `@working-theory/ui/primitives`. |
48
- | table of contents · on-page nav · jump links · sticky outline | `SectionNav` (chrome) · `DocsTocButton` (blocks) · `DocumentChassis` (sections) | |
51
+ | locale switcher · language picker · region selector · view toggle | `LocaleSwitcher` (blocks) · `MarkdownViewToggle` (blocks) | Dark-mode switching is `ThemeToggle`, a PRIMITIVE — see the Primitives table below. Import it from `@working-theory/ui/primitives`. |
52
+ | table of contents · on-page nav · jump links · sticky outline | `SectionNav` (chrome) · `DocumentChassis` (sections) | |
49
53
 
50
54
  ---
51
55
 
52
- ## Sections (56)
56
+ ## Sections (59)
53
57
 
54
58
  Page-level content bands. Most are MDX-driven (authored by `type` in page frontmatter and dispatched by `SectionRenderer`); a few are composed directly in a route.
55
59
 
@@ -76,9 +80,12 @@ Import: `import { X } from "@working-theory/ui/sections";` (or from the `@workin
76
80
  | `DecisionSplit` | An honest either-option decision block — use on /vs pages before any comparison. | MDX `type: decision-split` |
77
81
  | `Definition` | A single-term definition callout — use for one prominent 'What is X?' answer-first block. | MDX `type: definition` |
78
82
  | `DocumentChassis` | A long-read document page (privacy policy, terms, DPA, working agreement) — chrome-free header + optional stat strip + a sticky numbered section nav beside continuous prose; one document per page/route. The authored `sections` list drives both the nav and the body. | MDX `type: document-chassis` |
83
+ | `DocumentViewer` | A paginated document embedded in a page (a report, a client deliverable) — use for a 10-50 page PDF at a closed 16:9 (deck) or letter (portrait) geometry, rendered by a dynamically-imported PDF.js so it never enters the main bundle. `src` accepts a public path or the authenticated `/v1/deliverables/:grantId` route. Not for long-read prose — that is `document-chassis`. | MDX `type: document-viewer` |
84
+ | `DocumentViewerCanvas` | The PDF.js renderer for DocumentViewer. This file is reached ONLY via the dynamic import in DocumentViewerClient.tsx — that is deliberate: the static `import "pdfjs-dist"` below is what lands in this file's own route-split chunk instead of the main bundle (a static import of the renderer is a spec violation, not a style preference). | internal — compose from `packages/ui/src/sections/DocumentViewerCanvas.tsx` |
85
+ | `DocumentViewerClient` | The interactive shell for DocumentViewer. Split out of DocumentViewer.tsx (which stays RSC) for the same reason AlertSection composes AlertSectionDismissIsland: interactivity is contained to one client island. *(weak)* | internal — compose from `packages/ui/src/sections/DocumentViewerClient.tsx` |
79
86
  | `FAQ` | Question-and-answer pairs — use to pre-empt buyer objections that are naturally phrased as questions. | MDX `type: faq` · `import { FAQ } from "@working-theory/ui/sections"` |
80
87
  | `Feature` | A multi-item benefit/feature highlight grid — use to walk through several product capabilities. | MDX `type: feature` |
81
- | `FlowStepper` | Rendering a served flow config as a real multi-step form. | `import { FlowStepper } from "@working-theory/ui/sections"` |
88
+ | `FlowStepper` | Rendering a served flow config as a real multi-step form. | internal compose from `packages/ui/src/sections/FlowStepper.tsx` |
82
89
  | `FormLightbox` | The VideoLightbox dialog shell hosting a StepFlow instead of a video: a trigger (e.g. a "Let's Start" Button — any focusable element the caller supplies) opens the SAME StepFlow inside a Radix Dialog on the dimmed/blurred backdrop shared with VideoLightbox/SpotlightPanel. | `import { FormLightbox } from "@working-theory/ui/sections"` |
83
90
  | `Gallery` | An image gallery — use to showcase product screenshots or visual work. | MDX `type: gallery` · `import { Gallery } from "@working-theory/ui/sections"` |
84
91
  | `GlossaryIndex` | An A-Z glossary index — use for a browsable list of defined terms. | MDX `type: glossary-index` · `import { GlossaryIndex } from "@working-theory/ui/sections"` |
@@ -88,35 +95,35 @@ Import: `import { X } from "@working-theory/ui/sections";` (or from the `@workin
88
95
  | `HeroPromptCapture` | The Hero `promptCapture` opt-in's wiring. Composes the two new blocks — `PromptCaptureCard` (the chat-style card) and `SuggestionChipCarousel` (the one-expanded-slot chip row) — and owns the ONE piece of state they share: the typed text. A chip click writes into it; the card renders and edits it; submit carries it onward. | `import { HeroPromptCapture } from "@working-theory/ui/sections"` |
89
96
  | `HeroQuickSearch` | Surfaces the existing ⌘K quick-search as an inline trigger inside the hero CTA cluster (Chassis 2). It does NOT re-roll a search input: it composes the SearchInputTrigger primitive (an input-style control at CTA height) plus the Command palette primitive, so there is ONE search mechanism. The nav's compact 24px ⌘K pill stays as-is — the hero reads as a search INPUT, matching the 44px "Get Started" CTA. | internal — compose from `packages/ui/src/sections/HeroQuickSearch.tsx` |
90
97
  | `Items` | A general-purpose card/items grid — use for services, use cases, or any homogeneous list of cards. | MDX `type: items` · `import { Items } from "@working-theory/ui/sections"` |
91
- | `ListingApplicationFlow` | This is the thing a consuming site mounts INSTEAD of hand-writing three proxy routes, a save-on-advance form, and a decision about where a bearer token lives. | `import { ListingApplicationFlow } from "@working-theory/ui/sections"` |
98
+ | `ListingApplicationFlow` | This is the thing a consuming site mounts INSTEAD of hand-writing three proxy routes, a save-on-advance form, and a decision about where a bearer token lives. | internal compose from `packages/ui/src/sections/ListingApplicationFlow.tsx` |
92
99
  | `LogoCloud` | A customer/partner logo wall — use for trust-by-association social proof. | MDX `type: logoCloud` · `import { LogoCloud } from "@working-theory/ui/sections"` |
93
100
  | `MDXContent` | The keystone the docs route and blog both render their compiled MDX through. | `import { MDXContent } from "@working-theory/ui/sections"` |
94
101
  | `MediaBand` | A single full-width image band — use for the 1-up visual moment Gallery's 2-column minimum can't express (e.g. between pricing plan columns); renders a labeled placeholder until a real image is supplied. | MDX `type: media-band` · `import { MediaBand } from "@working-theory/ui/sections"` |
95
102
  | `ModuleAbsent` | What a slice section renders when its module is not here. The oss dispatch table must name a component for every `SectionName`, and `booker`'s real component strips with the scheduling slice. This is the entry it names instead; a slice that IS installed registers over it through `registerSliceRenderer`. | internal — compose from `packages/ui/src/sections/ModuleAbsent.tsx` |
96
103
  | `Newsletter` | An email signup form — use for a low-commitment conversion ask. | MDX `type: newsletter` · `import { Newsletter } from "@working-theory/ui/sections"` |
97
104
  | `Objection` | Objection-and-response pairs — use for you-might-think rhetoric that isn't phrased as a question. | MDX `type: objection` |
98
- | `PaymentReceipt` | A checkout payment outcome — use only on a checkout Delivery/confirmation page to show status + receipt details. | MDX `type: payment-receipt` · `import { PaymentReceipt } from "@working-theory/ui/sections"` |
105
+ | `PaymentReceipt` | A checkout payment outcome — use only on a checkout Delivery/confirmation page to show status + receipt details. | MDX `type: payment-receipt` |
99
106
  | `Pricing` | A plan comparison — the page's pricing decision surface; six variants cover tables, toggles, single-price offers, and add-on grids. | MDX `type: pricing` · `import { Pricing } from "@working-theory/ui/sections"` |
100
- | `PricingTable` | A grid of subscription plan tiers that SUBSCRIBE — the capability-bearing twin of the `Pricing` CMS section (which renders href-based marketing tier CTAs, no live Stripe call). `PricingTable` is scaffolded by `scaffold-commerce` (not registered in `SectionRenderer`'s CMS dispatch table) and each tier's action POSTs to the subscription surface's `subscribeHandler` route + redirects to the returned Stripe Checkout URL — the same `onCheckout`-callback shape `CheckoutForm` uses for one-time products. | `import { PricingTable } from "@working-theory/ui/sections"` |
101
- | `ProjectListingShelves` | Two shelves of ProjectListingCards partitioned from ONE list of public listing rows: `status === "active"` on one shelf, `status === "closed"` on the other. `closed` is COMPUTED by the API read (the window-end check lives server-side, / D6b) — this component never recomputes it, it only reads the field. | `import { ProjectListingShelves } from "@working-theory/ui/sections"` |
107
+ | `PricingTable` | A grid of subscription plan tiers that SUBSCRIBE — the capability-bearing twin of the `Pricing` CMS section (which renders href-based marketing tier CTAs, no live Stripe call). `PricingTable` is scaffolded by `scaffold-commerce` (not registered in `SectionRenderer`'s CMS dispatch table) and each tier's action POSTs to the subscription surface's `subscribeHandler` route + redirects to the returned Stripe Checkout URL — the same `onCheckout`-callback shape `CheckoutForm` uses for one-time products. | internal compose from `packages/ui/src/sections/PricingTable.tsx` |
108
+ | `ProjectListingShelves` | Two shelves of ProjectListingCards partitioned from ONE list of public listing rows: `status === "active"` on one shelf, `status === "closed"` on the other. `closed` is COMPUTED by the API read (the window-end check lives server-side, / D6b) — this component never recomputes it, it only reads the field. | internal compose from `packages/ui/src/sections/ProjectListingShelves.tsx` |
102
109
  | `SchedulerEmbed` | A declarative third-party booking iframe (e.g. Google Calendar Appointment Schedules) — use for a booking/scheduling moment; sets the provider's cookies on load, so a site classifying it as non-essential may wrap it in a consent gate. | MDX `type: scheduler-embed` · `import { SchedulerEmbed } from "@working-theory/ui/sections"` · `packages/ui/src/sections/SchedulerEmbed.tsx` |
103
110
  | `SectionEmpty` | The shared empty-state body every section's `*Empty` variant delegates to. | `import { SectionEmpty } from "@working-theory/ui/sections"` |
104
111
  | `SectionRenderer` | Typed dispatch table. Maps a section's `type` discriminant to its React component. | `import { SectionRenderer } from "@working-theory/ui/sections"` |
105
- | `Separator` | An inter-section spacer — use to add rhythm or a visible rule between two sections that need more separation than default spacing gives. | MDX `type: separator` · `import { Separator } from "@working-theory/ui/sections"` |
112
+ | `Separator` | An inter-section spacer — use to add rhythm or a visible rule between two sections that need more separation than default spacing gives. | MDX `type: separator` · `import { Separator } from "@working-theory/ui/sections"` · `packages/ui/src/sections/Separator.tsx` |
106
113
  | `SocialProof` | Tweet/post-shaped social proof items — use for lightweight, screenshot-style endorsements. | MDX `type: social-proof` · `import { SocialProof } from "@working-theory/ui/sections"` |
107
114
  | `SplitContentMedia` | Lays out a SectionHeader (text, one side) beside a media slot (the other side) — the HubSpot/wealthsmyth split content+media pattern. | `import { SplitContentMedia } from "@working-theory/ui/sections"` |
108
115
  | `SpotlightPanel` | A full-width dimmed/blurred backdrop (abstract pattern or product image) behind a centered elevated card carrying a headline, support text, and a form/flow embed — use for a demo or signup moment that needs focus without leaving the page flow (apollo.io /demo pattern). | MDX `type: spotlight-panel` · `import { SpotlightPanel } from "@working-theory/ui/sections"` |
109
116
  | `StairSteps` | A 2-5 step staircase — use for process/journey narratives where direction carries meaning (an ascending 'up-right' staircase for a build-up story, a descending 'down-right' one for the conversionfactory.co 'from idea to impact' pattern). | MDX `type: stair-steps` · `import { StairSteps } from "@working-theory/ui/sections"` |
110
117
  | `Stats` | A number-led credibility row — use to show scale or outcome metrics. An optional leadQuote can front the row with an analyst quote (staggered variant mirrors apollo.io's mixed-size evidence band). | MDX `type: stats` |
111
118
  | `StepFlow` | A data-driven multi-step lead-capture form (one small field group per step, progress affordance, per-step advance) — use for a longer qualifying gate where a single-step ContactForm would feel too long; fires onStepComplete after each step so an abandoned flow still captures a partial lead. | MDX `type: step-flow` · `import { StepFlow } from "@working-theory/ui/sections"` |
112
- | `Tabs` | Tabbed content panels — use to let a reader choose between parallel content without scrolling. | MDX `type: tabs` · `import { Tabs } from "@working-theory/ui/sections"` |
119
+ | `Tabs` | Tabbed content panels — use to let a reader choose between parallel content without scrolling. | MDX `type: tabs` · `import { Tabs } from "@working-theory/ui/sections"` · `packages/ui/src/sections/Tabs.tsx` |
113
120
  | `Team` | A team member grid — use on About pages to introduce the people behind the product. | MDX `type: team` · `import { Team } from "@working-theory/ui/sections"` |
114
121
  | `Testimonials` | Direct customer quotes — use for first-person social proof with attribution. | MDX `type: testimonials` |
115
122
  | `VideoSection` | The standard large-centered-video section (acquisition.com/workshop pattern) — optional headline/intro above a bounded-width centered video, optional caption/CTA below; renders a labeled placeholder until a real source is supplied. | MDX `type: video-section` · `import { VideoSection } from "@working-theory/ui/sections"` |
116
123
 
117
124
  ---
118
125
 
119
- ## Blocks (113)
126
+ ## Blocks (115)
120
127
 
121
128
  Intermediate composition tiles — the pieces sections are built from. Compose primitives and panels; never import a section.
122
129
 
@@ -144,12 +151,14 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
144
151
  | `BookerSlotGrid` | The selected day's open times. Two columns at 48px on mobile — the measured pixel target — widening to three at `lg` so the desktop variant shows more of the day without scrolling. Two columns is not an arbitrary density: at 390px it is the widest grid where a time still reads at a glance, and it puts eight times (a full working day's openings) inside one thumb-reachable block. | internal — compose from `packages/ui/src/blocks/BookerSlotGrid.tsx` |
145
152
  | `BrandLogo` | Brand identity lockup (mark + wordmark + badge slot) as a home link. Brand identity lockup for Nav, Footer, and other surfaces. | `import { BrandLogo } from "@working-theory/ui/blocks"` |
146
153
  | `Card` | The base surface-chrome block the section tier composes instead of hand-rolling `rounded + hairline border + surface + p-card` (7× duplicated at time). A block owns its visual identity: it looks the same everywhere it is composed, and a higher tier SELECTS a look via `variant` — it never patches via className. | `import { Card } from "@working-theory/ui/blocks"` |
147
- | `CheckoutForm` | Product/amount selection + checkout submit for the one-time checkout surface. | `import { CheckoutForm } from "@working-theory/ui/blocks"` |
148
- | `CheckoutPriceCard` | The order-summary card the flow's side panel becomes at checkout: eyebrow, offer name + description, seat/credit line items, an optional caller-supplied add-credits row, and (on the quoted arm only) total + due-today; with a `configurator` it also renders the in-card seat stepper, period toggle, add-on credits row and on-demand breakdown, pricing itself with the pure `price`. | `import { CheckoutPriceCard } from "@working-theory/ui/blocks"` |
154
+ | `CheckoutForm` | Product/amount selection + checkout submit for the one-time checkout surface. | internal compose from `packages/ui/src/blocks/CheckoutForm.tsx` |
155
+ | `CheckoutPriceCard` | DESIGN 's checkout price card: the panel's fourth view once it flips to the right and becomes an order summary — eyebrow, offer name + description, seat/credit line items, an optional caller-supplied add-credits row, and the total + due-today. | internal compose from `packages/ui/src/blocks/CheckoutPriceCard.tsx` |
149
156
  | `ChoiceCard` | Onboarding "Is this you?" disambiguation card — reimplements the ploy.ai persona-disambiguation capture: a researched candidate option vs a "none of these are me" option, confirmed by the user ("a human-input seam the user answers to orient the agent"). Purely presentational and props-driven: renders options + an optional "none of these" option + a confirm action, disabled until a selection is made. | `import { ChoiceCard } from "@working-theory/ui/blocks"` |
150
157
  | `CodeBlock` | Read-only code display with syntax highlighting. Modeled on the Claude docs code-block pattern. | `import { CodeBlock } from "@working-theory/ui/blocks"` |
151
158
  | `ComparisonMatrix` | Full feature × tier comparison matrix for the Pricing 'with-comparison-table' variant. Renders N collapsible ComparisonGroups, each containing M feature rows with per-tier values. | `import { ComparisonMatrix } from "@working-theory/ui/blocks"` |
152
159
  | `Composer` | The chat input, per the ploy.ai capture contract. | `import { Composer } from "@working-theory/ui/blocks"` |
160
+ | `ConsentGroup` | The composite control for the `consent` field kind: one real checkbox per consent purpose, each with its statement and inline policy links, inside one fieldset. | `import { ConsentGroup } from "@working-theory/ui/blocks"` |
161
+ | `ConsentStatement` | The sentence a person agrees to, with its policy links inline. | `import { ConsentStatement } from "@working-theory/ui/blocks"` |
153
162
  | `ContactChannelItem` | Renders one support channel entry: colored icon square + headline + description paragraph + CTA link (with trailing arrow icon). | `import { ContactChannelItem } from "@working-theory/ui/blocks"` |
154
163
  | `ContactFormFields` | Renders the form field grid (Input / Textarea / Select primitives) + submit Button + optional consent text footer. | `import { ContactFormFields } from "@working-theory/ui/blocks"` |
155
164
  | `ContactInfoAside` | For ContactForm 'split-with-pattern' variant. Renders address / phone / email contact info rows. Each row: sr-only &lt;dt> label + visible &lt;dd> with Icon + Text. Phone and email render as tel:/mailto: links (click-to-call / click-to-email). | `import { ContactInfoAside } from "@working-theory/ui/blocks"` |
@@ -158,30 +167,30 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
158
167
  | `DetailCard` | The collapsible console / data-panel card: a composable card with a header (title + optional actions + collapse toggle), an optional tab bar, a body slot, and an optional footer. The "deferred SidePanel DetailCard" from, built as a general content card any console / detail view can compose without inventing its own card structure. | `import { DetailCard } from "@working-theory/ui/blocks"` |
159
168
  | `DetailHeader` | The entity-bearing sibling of PageHeader: a Breadcrumb wayfinding trail above an EntityHeader identity row, plus a forwarded actions slot. | `import { DetailHeader } from "@working-theory/ui/blocks"` |
160
169
  | `DistributionList` | Per-option answer-share list over the Progress primitive. One question's answer distribution: a title, an "answered" count line, and one row per declared option (a label, a pre-formatted share `display` string, and a `Progress` bar). `display` is pre-formatted by the caller (Rule 10 — this block never formats numbers itself); `share` drives the `Progress` fill, scaled to the primitive's 0–100 range. | `import { DistributionList } from "@working-theory/ui/blocks"` |
161
- | `DocsActionBar` | The agent-facing article toolbar that lands in the DocsArticleHeader `actionBar` slot, presented as the Claude-docs **"Copy page ▾" split button**. The in-page rendered↔markdown toggle is NOT reimplemented here — that is the existing MarkdownViewToggle block, which the route mounts around the article body. This bar only adds the copy + open-in affordances. | `import { DocsActionBar } from "@working-theory/ui/blocks"` |
162
- | `DocsArticleHeader` | The article header: a breadcrumb trail (with the TOC popover button at its inline-end), the page title (the single &lt;h1>), an optional lead description, and an "updated" meta line. Leaves an `actionBar` slot for the Phase-5 DocsActionBar (markdown toggle / copy / share) — empty until then. | `import { DocsArticleHeader } from "@working-theory/ui/blocks"` |
163
- | `DocsFeedback` | The article-footer feedback widget: a "Was this helpful?" thumbs yes/no pair plus an "Edit this page on GitHub" link. Clicking a thumb records the answer (fires a `gtag` analytics event when the site's GA is present) and, on "no", reveals an optional free-text note. After answering, the prompt is replaced with a thank-you line. | `import { DocsFeedback } from "@working-theory/ui/blocks"` |
164
- | `DocsSearch` | The cmd-K documentation search: a ⌘K trigger pill (NavSearchTrigger) that opens a CommandDialog over a passed-in search index. Typing filters the index by title/description (cmdk's built-in filter, fed a `value` that bundles both); selecting a result navigates there. | `import { DocsSearch } from "@working-theory/ui/blocks"` |
165
- | `DocsTocButton` | Clicking the `List`-icon button opens a Popover rendering the shared `TableOfContents` (styling preserved). Esc / outside-click closes it (Radix default); in-page anchor jumps work as they do in the rail. The button renders nothing when there are no TOC entries, so the breadcrumb row stays clean on heading-less / `wide` pages. | `import { DocsTocButton } from "@working-theory/ui/blocks"` |
170
+ | `DocsActionBar` | The agent-facing article toolbar that lands in the DocsArticleHeader `actionBar` slot, presented as the Claude-docs **"Copy page ▾" split button**. The in-page rendered↔markdown toggle is NOT reimplemented here — that is the existing MarkdownViewToggle block, which the route mounts around the article body. This bar only adds the copy + open-in affordances. | internal compose from `packages/ui/src/blocks/DocsActionBar.tsx` |
171
+ | `DocsArticleHeader` | The article header: a breadcrumb trail (with the TOC popover button at its inline-end), the page title (the single &lt;h1>), an optional lead description, and an "updated" meta line. Leaves an `actionBar` slot for the Phase-5 DocsActionBar (markdown toggle / copy / share) — empty until then. | internal compose from `packages/ui/src/blocks/DocsArticleHeader.tsx` |
172
+ | `DocsFeedback` | The article-footer feedback widget: a "Was this helpful?" thumbs yes/no pair plus an "Edit this page on GitHub" link. Clicking a thumb records the answer (fires a `gtag` analytics event when the site's GA is present) and, on "no", reveals an optional free-text note. After answering, the prompt is replaced with a thank-you line. | internal compose from `packages/ui/src/blocks/DocsFeedback.tsx` |
173
+ | `DocsSearch` | The cmd-K documentation search: a ⌘K trigger pill (NavSearchTrigger) that opens a CommandDialog over a passed-in search index. Typing filters the index by title/description (cmdk's built-in filter, fed a `value` that bundles both); selecting a result navigates there. | internal compose from `packages/ui/src/blocks/DocsSearch.tsx` |
174
+ | `DocsTocButton` | Clicking the `List`-icon button opens a Popover rendering the shared `TableOfContents` (styling preserved). Esc / outside-click closes it (Radix default); in-page anchor jumps work as they do in the rail. The button renders nothing when there are no TOC entries, so the breadcrumb row stays clean on heading-less / `wide` pages. | internal compose from `packages/ui/src/blocks/DocsTocButton.tsx` |
166
175
  | `EntityHeader` | The single identity-row source: an optional leading avatar, a title/name (Heading), an optional subtitle/meta line (Text), an optional type-badge slot above the title, and an optional trailing actions slot. | `import { EntityHeader } from "@working-theory/ui/blocks"` |
167
176
  | `FaqItem` | Q&A pair block for FAQ section families (expanded + accordion). Defaults reproduce the current render except the deliberate item-spacing-asymmetry fix. | `import { FaqItem } from "@working-theory/ui/blocks"` |
168
177
  | `FeatureCard` | Icon badge + title + a short check-list + an optional "Learn more" link — the card used in HubSpot's right-hand product grid. Generalizes the inline card markup currently hand-rolled in sections/Feature.tsx. | `import { FeatureCard } from "@working-theory/ui/blocks"` |
169
178
  | `FeatureCardGrid` | Responsive column schedule (mobile-first, uniform cells): base. Uniform responsive grid of FeatureCard tiles. Strictly equal-span cells at every breakpoint; use BentoGrid for variable-span layouts. | `import { FeatureCardGrid } from "@working-theory/ui/blocks"` |
170
179
  | `FloatingBar` | Z-40 (spec) — the same rung Nav's sticky bar and FloatingCta already occupy; no new z-index token. The same-slot takeover works by DOM ORDER, not a higher z: a `position="sticky"` FloatingBar rendered later in the document (inside body content, after the nav) paints over a `fixed` FloatingBar at equal z-40 once it sticks, given an `opaque` surface. | internal — compose from `packages/ui/src/blocks/FloatingBar.tsx` |
171
- | `FlowSidePanel` | The per-view side panel of the flow/recommender surface. ONE CHASSIS, THREE VIEWS. | `import { FlowSidePanel } from "@working-theory/ui/blocks"` |
180
+ | `FlowSidePanel` | The per-view side panel of the flow/recommender surface. ONE CHASSIS, THREE VIEWS. | internal compose from `packages/ui/src/blocks/FlowSidePanel.tsx` |
172
181
  | `FooterBottomBar` | Separator + copyright line (+ optional trailing social). Bottom bar with a single top divider + copyright line. | `import { FooterBottomBar } from "@working-theory/ui/blocks"` |
173
182
  | `FooterNav` | Data-driven footer nav: flat row or titled columns (row/columns layout). These two renderings of the same footer-link data were used mutually-exclusively by the chrome `Footer`'s `layout` switch — collapsing them removes a real either/or the parent managed. | `import { FooterNav } from "@working-theory/ui/blocks"` |
174
183
  | `FormCard` | Stateless, centered max-w-md form-card chassis: a Card wrapping an optional title + description header, a field-stack body (children), and a footer slot for the primary action + a secondary line below it. The SHARED look composed by both the contact-form section's 'card' variant and the auth-panel section — this block owns none of their field/state machinery, only the surrounding chrome. | `import { FormCard } from "@working-theory/ui/blocks"` |
175
184
  | `InviteMemberDialog` | The invite modal — reimplements the ploy.ai "Invite Team Member" capture (Email textbox + Role select, default Member, options Member/Admin, helper "Admins can invite and remove members." + Send Invitation). | `import { InviteMemberDialog } from "@working-theory/ui/blocks"` |
176
- | `InvoiceForm` | Draft-invoice creation form. Creates a draft invoice (single line item), for the invoice surface (U4). | `import { InvoiceForm } from "@working-theory/ui/blocks"` |
177
- | `InvoiceList` | Capability-bearing invoice rows (status + amount + hosted-invoice link). A customer's invoice rows, shared by the invoice surface (U4). Capability-bearing: binds a schema.org `Invoice` resource-payload fragment per row (imported from `@working-theory/schema`) — so a co-located `.text.ts` + `.text.test.ts` renderer is required and gated by `scripts/check-ax-parity.sh`. | `import { InvoiceList } from "@working-theory/ui/blocks"` |
185
+ | `InvoiceForm` | Creates a draft invoice (single line item), for the invoice surface (U4). | internal compose from `packages/ui/src/blocks/InvoiceForm.tsx` |
186
+ | `InvoiceList` | A customer's invoice rows, shared by the invoice surface (U4). Capability-bearing: binds a schema.org `Invoice` resource-payload fragment per row (imported from `@working-theory/schema`) — so a co-located `.text.ts` + `.text.test.ts` renderer is required and gated by `scripts/check-ax-parity.sh`. | internal compose from `packages/ui/src/blocks/InvoiceList.tsx` |
178
187
  | `KeyPointsPanel` | ONE shared block composed by two consumers: Hero's `panel` variant (text-left / panel-right) and Pricing's `band-hero` arrangement (header-left / panel-right, tiers below). | internal — compose from `packages/ui/src/blocks/KeyPointsPanel.tsx` |
179
188
  | `LinkCard` | A whole-tile link card: the entire tile IS the anchor (Claude-docs link-card anatomy). Optional leading icon, a title heading, and an optional description paragraph. Hover fill + chrome are intrinsic to the block — never props. | `import { LinkCard } from "@working-theory/ui/blocks"` |
180
189
  | `LinkListItem` | Hub-page spoke list row: prose Link + optional description, enlarged to the 44px touch-target floor. Fix: the enlarged-hit-area pattern (same idiom as ShortcutTrigger, SegmentedControl's touchTargetFloor) — `min-h-(control-height-big)` clamps the anchor's clickable box to 44px while `inline-flex items-center` keeps the visible text at its normal prose size. | `import { LinkListItem } from "@working-theory/ui/blocks"` |
181
- | `ListingFullPreview` | The full-page-preview `custom` step renderer. The founder's assembled application, rendered as a page, with an edit link back to the step that owns each rendered part. Purely presentational: every entry's label and formatted value arrive pre-built on `entries` (this block does no formatting of its own), and `onEdit` is the only way it ever changes anything — it never mutates, saves, or fetches. | `import { ListingFullPreview } from "@working-theory/ui/blocks"` |
182
- | `ListingPrivacyNotice` | The per-listing privacy notice. It names the FOUNDER — not the platform — as the party collecting a visitor's personal data, and it renders ON THE FLOW (where a visitor submits answers), not on the listing page. | `import { ListingPrivacyNotice } from "@working-theory/ui/blocks"` |
183
- | `ListingQuestionReview` | The edit-only question-review `custom` step renderer. The founder is refining a diagnostic template the SITE authored, not composing one from nothing (`projectListingQuestionsSchema`, `packages/validation/src/schemas/project-listings.ts`). | `import { ListingQuestionReview } from "@working-theory/ui/blocks"` |
184
- | `ListingTilePreview` | The founder's tile, as it will look, updating as they type. | `import { ListingTilePreview } from "@working-theory/ui/blocks"` |
190
+ | `ListingFullPreview` | The full-page-preview `custom` step renderer. The founder's assembled application, rendered as a page, with an edit link back to the step that owns each rendered part. Purely presentational: every entry's label and formatted value arrive pre-built on `entries` (this block does no formatting of its own), and `onEdit` is the only way it ever changes anything — it never mutates, saves, or fetches. | internal compose from `packages/ui/src/blocks/ListingFullPreview.tsx` |
191
+ | `ListingPrivacyNotice` | The per-listing privacy notice. It names the FOUNDER — not the platform — as the party collecting a visitor's personal data, and it renders ON THE FLOW (where a visitor submits answers), not on the listing page. | internal compose from `packages/ui/src/blocks/ListingPrivacyNotice.tsx` |
192
+ | `ListingQuestionReview` | The edit-only question-review `custom` step renderer. The founder is refining a diagnostic template the SITE authored, not composing one from nothing (`projectListingQuestionsSchema`, `packages/validation/src/schemas/project-listings.ts`). | internal compose from `packages/ui/src/blocks/ListingQuestionReview.tsx` |
193
+ | `ListingTilePreview` | The founder's tile, as it will look, updating as they type. | internal compose from `packages/ui/src/blocks/ListingTilePreview.tsx` |
185
194
  | `LocaleSwitcher` | Compact globe + locale dropdown. Extracts the "🌐 English ▾" affordance that lived as an inline node in the chrome Footer story into a reusable block. Composes the `Select` primitive (NOT a raw &lt;select>): a leading globe icon, the current locale label (via SelectValue), and the trigger's built-in chevron. | `import { LocaleSwitcher } from "@working-theory/ui/blocks"` |
186
195
  | `LogoRow` | The ONE logo-strip implementation; bounded layout/treatment/logoSize plus an opt-in motion-safe marquee; composed by the LogoCloud section and the Hero logoStrip opt-in. | `import { LogoRow } from "@working-theory/ui/blocks"` |
187
196
  | `MarkdownViewToggle` | 2-state rendered ↔ markdown view toggle for content pages. The human complement to the agent-facing /llms.txt surface. Mirrors the Claude-docs "view/copy as markdown" affordance. Ships at Tier 3 (Block) because it is an interactive view-toggle control composing the SegmentedControl primitive with the CodeBlock block — not a page-level layout shell. | `import { MarkdownViewToggle } from "@working-theory/ui/blocks"` |
@@ -195,27 +204,27 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
195
204
  | `NewsletterDetail` | One "why subscribe" detail item: colored icon square + headline + description. Vertically arranged (icon top, heading + description below). Used in the right-column 2-up grid of the 'side-by-side-with-details' variant. | `import { NewsletterDetail } from "@working-theory/ui/blocks"` |
196
205
  | `NewsletterFormInline` | Inline email signup form: email Input + submit Button side-by-side at sm+, stacked on mobile (input full-width on its own row, Subscribe below). Manages its own submit state so the parent Newsletter section can remain RSC-oriented (only this block needs the client boundary). | `import { NewsletterFormInline } from "@working-theory/ui/blocks"` |
197
206
  | `OnboardingChecklist` | Global onboarding launcher: floating "N/5" bubble expanding into a Popover (lg+) / bottom Sheet (&lt;lg) checklist with SegmentedProgress + item rows (ploy-capture recomposition). The global onboarding launcher captured off ploy.ai's app frame (behavior spec: `post-ftu-checklist` — "global onboarding launcher (floating, all pages)"). | `import { OnboardingChecklist } from "@working-theory/ui/blocks"` |
198
- | `PageHeader` | RSC. Page-level header composing the Breadcrumb primitive for the left-side wayfinding trail, a generic right-side `actions` slot, and an optional `switcher` slot for header-owned segment switching. Fills AppShell's `header` slot (DashboardShell and similar). No accent bar. No tab API. No named action props — the caller assembles whatever button/menu nodes it needs and passes them as `actions`. *(weak)* | `import { PageHeader } from "@working-theory/ui/blocks"` |
207
+ | `PageHeader` | RSC. Page-level header composing the Breadcrumb primitive for the left-side wayfinding trail, a generic right-side `actions` slot, and an optional `switcher` slot for header-owned segment switching. Fills AppShell's `header` slot (WorkspaceShell and similar). No accent bar. No tab API. No named action props — the caller assembles whatever button/menu nodes it needs and passes them as `actions`. *(weak)* | `import { PageHeader } from "@working-theory/ui/blocks"` |
199
208
  | `PageHeaderSwitcher` | Header-owned context-switcher island (DropdownMenu-backed). Header-owned segment switcher rendered inside PageHeader's `switcher` slot. Composes DropdownMenu (Radix-backed — positioning, click-outside, Escape, focus management, and roving keyboard nav all come for free). | `import { PageHeaderSwitcher } from "@working-theory/ui/blocks"` |
200
209
  | `PairingCard` | Quiet card naming a matched WaitlistRecommendation pairing: both resolved offer names + the resolved reason, joined against a caller-supplied offers[] by key. | `import { PairingCard } from "@working-theory/ui/blocks"` |
201
- | `PaymentLinkCard` | A single shareable Stripe Payment Link (pay-by-link surface). Renders the link's offer name, active-status chip, optional amount, and the hosted URL with a one-click copy action. | `import { PaymentLinkCard } from "@working-theory/ui/blocks"` |
202
- | `PaymentLinkForm` | Product selection + "create link" submit for the pay-by-link surface. | `import { PaymentLinkForm } from "@working-theory/ui/blocks"` |
203
- | `PaymentLinkList` | Presentational list composing PaymentLinkCard rows. A site owner's shareable payment links (pay-by-link surface). Composes one `PaymentLinkCard` per link. | `import { PaymentLinkList } from "@working-theory/ui/blocks"` |
204
- | `PaymentResult` | Success/cancel result state for the one-time checkout surface — the terminal render a consumer's success/cancel return-URL page shows after the Stripe-hosted Checkout redirect. | `import { PaymentResult } from "@working-theory/ui/blocks"` |
205
- | `PaymentStatusBadge` | Capability-bearing payment/invoice/subscription status chip. Payment-state chip shared by the invoice-status (U4) and subscription-status (U5) surfaces. | `import { PaymentStatusBadge } from "@working-theory/ui/blocks"` |
210
+ | `PaymentLinkCard` | A single shareable Stripe Payment Link (pay-by-link surface). Renders the link's offer name, active-status chip, optional amount, and the hosted URL with a one-click copy action. | internal compose from `packages/ui/src/blocks/PaymentLinkCard.tsx` |
211
+ | `PaymentLinkForm` | Product selection + "create link" submit for the pay-by-link surface. | internal compose from `packages/ui/src/blocks/PaymentLinkForm.tsx` |
212
+ | `PaymentLinkList` | A site owner's shareable payment links (pay-by-link surface). Composes one `PaymentLinkCard` per link. | internal compose from `packages/ui/src/blocks/PaymentLinkList.tsx` |
213
+ | `PaymentResult` | Success/cancel result state for the one-time checkout surface — the terminal render a consumer's success/cancel return-URL page shows after the Stripe-hosted Checkout redirect. | internal compose from `packages/ui/src/blocks/PaymentResult.tsx` |
214
+ | `PaymentStatusBadge` | Payment-state chip shared by the invoice-status (U4) and subscription-status (U5) surfaces. | internal compose from `packages/ui/src/blocks/PaymentStatusBadge.tsx` |
206
215
  | `PhoneNumberField` | Single-box combo phone input for the "tel" field kind (supersedes the two-segment country-Select + number-Input layout). | `import { PhoneNumberField } from "@working-theory/ui/blocks"` |
207
- | `PortalEntry` | Presentational "Manage billing" entry action, reuses U1 StripeActionButton; target of U5 SubscriptionStatus's Manage action. A standalone "Manage billing" entry point into Stripe's hosted Customer Portal — the smallest surface (spec: AILK owns only the entry; Stripe hosts the portal itself). | `import { PortalEntry } from "@working-theory/ui/blocks"` |
216
+ | `PortalEntry` | A standalone "Manage billing" entry point into Stripe's hosted Customer Portal — the smallest surface (spec: AILK owns only the entry; Stripe hosts the portal itself). | internal compose from `packages/ui/src/blocks/PortalEntry.tsx` |
208
217
  | `PostRow` | A single horizontal row in the two-column blog index: a landscape cover thumbnail (left) followed by the post's title · excerpt · author+date meta · tag list. The WHOLE row is one link (aria-labelled by the title, so screen readers announce the post title rather than the concatenated row content). | `import { PostRow } from "@working-theory/ui/blocks"` |
209
218
  | `PricingExtraTierRow` | Compact horizontal extra-tier row for the Pricing 'two-tiers-with-extra-tier' variant. Renders plan name + description on the left and a CTA on the right. Structurally different from PricingTierCard (no price display in this variant). | `import { PricingExtraTierRow } from "@working-theory/ui/blocks"` |
210
219
  | `PricingTierCard` | Single pricing tier card (all 4 Pricing variants). Renders a single pricing tier: plan name + optional badge, description, price display, CTA button, and feature checklist. | `import { PricingTierCard } from "@working-theory/ui/blocks"` |
211
220
  | `PricingTierCardFeaturesDisclosure` | Phone-breakpoint (&lt;md, 768px — the same phone/tablet step CardGrid's own mobile-stacking ramp uses) presentation of a tier card's feature list: collapsed behind a disclosure button so price + CTA (which render ABOVE this row, see PricingTierCard's row-slot ordering) fit the first card view on a phone — the wisprflow.ai/pricing pattern. `md` and up renders the SAME feature list, always expanded, in a second, non-interactive tree — desktop/tablet is unaffected by the collapse. | `import { PricingTierCardFeaturesDisclosure } from "@working-theory/ui/blocks"` |
212
221
  | `PricingTierCardSeatControl` | Seat-count range picker for the Team tier card. Renders a Select primitive that lets the user choose an "Up to N seats" option from a caller-supplied list of numbers. The parent PricingTierCard stays a pure RSC; only this tiny island is hydrated. Pattern mirrors PageHeaderSwitcher.tsx: small "use client" island imported by an otherwise-server-rendered parent, keeping the client bundle minimal. *(weak)* | `import { PricingTierCardSeatControl } from "@working-theory/ui/blocks"` |
213
- | `ProjectListingCard` | The tile for one listing on a shelf (`ProjectListingShelves`). The whole tile is a single anchor (LinkCard's bespoke-by-semantics precedent: Card renders a &lt;div> and cannot satisfy a whole-tile-link contract, so this composes Link directly rather than Card). | `import { ProjectListingCard } from "@working-theory/ui/blocks"` |
222
+ | `ProjectListingCard` | The tile for one listing on a shelf (`ProjectListingShelves`). The whole tile is a single anchor (LinkCard's bespoke-by-semantics precedent: Card renders a &lt;div> and cannot satisfy a whole-tile-link contract, so this composes Link directly rather than Card). | internal compose from `packages/ui/src/blocks/ProjectListingCard.tsx` |
214
223
  | `PromptCaptureCard` | The chat-style prompt card: a multiline field carrying the authored placeholder, with a circular arrow submit control pinned bottom-right that stays muted (disabled) until the visitor has typed something. Enter submits; Shift+Enter inserts a newline — the chat-composer convention. | `import { PromptCaptureCard } from "@working-theory/ui/blocks"` |
215
224
  | `Prose` | The single typography wrapper both the docs route and blog render their compiled-MDX body inside. It styles every RAW markdown element a compiled document emits — h2–h6, p, ul/ol/li, blockquote, table parts, hr, a, inline code, pre, img, kbd, strong/em — via `@working-theory/theme` semantic tokens and type roles. No raw color or spacing literals; dark mode rides the semantic tokens (no `dark:` variants needed). | `import { Prose } from "@working-theory/ui/blocks"` |
216
225
  | `RecommendationCard` | "For you" proactive-recommendation tile: status + title + description + "Why this?" disclosure + context chip + action + dismiss (ploy-capture recomposition). The "For you" proactive-recommendation card captured off ploy.ai's Overview page (behavior spec: -2, — `overview-page` "For you" feed / rebuild-triage row "For you" recommendation card"). | `import { RecommendationCard } from "@working-theory/ui/blocks"` |
217
- | `ResponseChart` | The single-question aggregate chart of the diagnostic's results reveal. Renders exactly ONE `FlowAggregateQuestion`. The chart type is FIXED by `question.answerType` — a closed `single \| multi` union — and there is no `chartType`/`variant` prop: an author cannot request a doughnut for a multi-select question, because there is no prop through which to ask. | `import { ResponseChart } from "@working-theory/ui/blocks"` |
218
- | `ResultsReveal` | The results-reveal active-region composition: one ResponseChart per resultsReveal-flagged, aggregate-matched segmentation step, in served order. | `import { ResultsReveal } from "@working-theory/ui/blocks"` |
226
+ | `ResponseChart` | The single-question aggregate chart of the diagnostic's results reveal. Renders exactly ONE `FlowAggregateQuestion`. The chart type is FIXED by `question.answerType` — a closed `single \| multi` union — and there is no `chartType`/`variant` prop: an author cannot request a doughnut for a multi-select question, because there is no prop through which to ask. | internal compose from `packages/ui/src/blocks/ResponseChart.tsx` |
227
+ | `ResultsReveal` | The results-reveal active-region composition: one ResponseChart per resultsReveal-flagged, aggregate-matched segmentation step, in served order. | internal compose from `packages/ui/src/blocks/ResultsReveal.tsx` |
219
228
  | `SchedulerEmbed` | A declarative third-party booking iframe. Renders a full-width, border-0, lazy-loaded &lt;iframe> at `src` with a graceful loading skeleton (shown until the iframe's own `load` event fires) and a timeout-gated plain-link fallback beneath it — for environments that block third-party frames (ad blockers, a strict CSP `frame-src`) where the iframe may load blank or never load at all. | `import { SchedulerEmbed } from "@working-theory/ui/blocks"` · `packages/ui/src/blocks/SchedulerEmbed.tsx` |
220
229
  | `SectionHeader` | Alignment-parameterized section header (eyebrow/subtitle/description/supportLink). The same component serves two ranks (headingLevel="section" \| "subsection") and three alignments (align="start" \| "center" \| "end"). It knows nothing about columns/splits/carousels — it is width-flexible and fills whatever container the section places it in. | `import { SectionHeader } from "@working-theory/ui/blocks"` |
221
230
  | `ShareBar` | The reader-facing counterpart to DocsActionBar. Both surfaces share the same SplitButton *affordance + slot* (outline variant, right-justified on the post title row) but fill it with different actions: DocsActionBar carries the AI-ingestion set (Copy page + Open in …), ShareBar carries the social-share set (X · LinkedIn · Bluesky · Copy link). One primitive, two configs. | `import { ShareBar } from "@working-theory/ui/blocks"` |
@@ -224,8 +233,8 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
224
233
  | `StatTicker` | Static, horizontally overflow-scrollable workspace stat strip with an optional trailing CTA; no auto-scroll marquee (ploy-capture recomposition). The Overview stat strip captured off ploy.ai (behavior spec: -2, — `overview-ticker` "-viewport"/"-track"/"-segment"/"-value"/"-cta"). | `import { StatTicker } from "@working-theory/ui/blocks"` |
225
234
  | `Steps` | The numbered install/guide walkthrough: an ordered list of `Step` items, each a zero-padded number marker + an optional per-step heading + body, joined top-to-bottom by a connecting vertical rule. The classic docs "follow these steps" surface, rendered from `@working-theory/ui` so docs pages stay design-system citizens. | `import { Steps } from "@working-theory/ui/blocks"` |
226
235
  | `StreamingMessage` | One chat turn's message rendering, per the ploy.ai capture contract. | `import { StreamingMessage } from "@working-theory/ui/blocks"` |
227
- | `StripeActionButton` | Checkout/portal entry-point trigger with pending + test-mode affordances. The checkout/portal entry-point action button shared by the checkout (U2) and billing-portal (U6) surfaces. | `import { StripeActionButton } from "@working-theory/ui/blocks"` |
228
- | `SubscriptionStatus` | Current plan + lifecycle state for the subscriptions surface — shows state via U1's `PaymentStatusBadge` plus a portal "Manage" action. | `import { SubscriptionStatus } from "@working-theory/ui/blocks"` |
236
+ | `StripeActionButton` | The checkout/portal entry-point action button shared by the checkout (U2) and billing-portal (U6) surfaces. | internal compose from `packages/ui/src/blocks/StripeActionButton.tsx` |
237
+ | `SubscriptionStatus` | Current plan + lifecycle state for the subscriptions surface — shows state via U1's `PaymentStatusBadge` plus a portal "Manage" action. | internal compose from `packages/ui/src/blocks/SubscriptionStatus.tsx` |
229
238
  | `SuggestionChipCarousel` | A 3-6 icon-chip row with exactly one chip expanded (muted category + bold prompt), auto-rotating motion-safe with hover/focus pause; a click hands the chip's prompt to the host. A row of 3-6 icon chips in which exactly ONE is expanded at a time. | `import { SuggestionChipCarousel } from "@working-theory/ui/blocks"` |
230
239
  | `TableOfContents` | The shared "On this page" rail consumed by the docs shell and the blog post layout (do not couple it to docs-only context). Renders a flat list of heading anchors and scroll-spies the heading currently in view, highlighting the matching item. | `import { TableOfContents } from "@working-theory/ui/blocks"` |
231
240
  | `TeamMemberCard` | Renders one team member in either of two layout modes: 'inline' — small circular avatar left + name/role right (with-small-images variant) 'stacked' — large circular avatar top + name/role/social-links below (with-large-images variant). | `import { TeamMemberCard } from "@working-theory/ui/blocks"` |
@@ -253,7 +262,7 @@ Import: `import { X } from "@working-theory/ui/chrome";` (or from the `@working-
253
262
  | `Banner` | Site-wide announcement and consent banner chrome. *(weak)* | `import { Banner } from "@working-theory/ui/chrome"` |
254
263
  | `BannerConsentIsland` | Accept / Reject action cluster for the consent Banner. Isolated to "use client" so Banner stays RSC. The onAccept / onReject callbacks must be Server Actions when used inside an RSC tree; they may be regular functions in client contexts (Storybook, testing). *(weak)* | internal — compose from `packages/ui/src/chrome/BannerConsentIsland.tsx` |
255
264
  | `BannerDismissIsland` | Isolated to "use client" so Banner (Server Component) stays RSC. Mirrors the Nav / NavMobileMenu split: interactivity is contained here. Rendering: wraps its children in a relative-positioned div and absolutely places the × dismiss button at the end (RTL-safe: `end-4`) of the bar. *(weak)* | internal — compose from `packages/ui/src/chrome/BannerDismissIsland.tsx` |
256
- | `DocsSidebar` | The left documentation rail. Consumes a `tree` prop (structurally a Fumadocs `source.pageTree` Root) and renders its folders (static section groups), pages (links), and separators (section captions / dividers). The current page is highlighted via `aria-current="page"`. Kept repo-agnostic: the route passes `docsSource.pageTree`; no nav data is hardcoded here, so a fork reuses it unchanged. | `import { DocsSidebar } from "@working-theory/ui/chrome"` |
265
+ | `DocsSidebar` | The left documentation rail. Consumes a `tree` prop (structurally a Fumadocs `source.pageTree` Root) and renders its folders (static section groups), pages (links), and separators (section captions / dividers). The current page is highlighted via `aria-current="page"`. Kept repo-agnostic: the route passes `docsSource.pageTree`; no nav data is hardcoded here, so a fork reuses it unchanged. | internal compose from `packages/ui/src/chrome/DocsSidebar.tsx` |
257
266
  | `FacetNav` | Chrome-tier faceted secondary navigation (ploy-capture recomposition). One reusable component servicing THREE captured consumers: Settings' grouped Org/Workspace nav, Assets' All + tag-facet counts, and Docs' All + folder tree + tag facets. | `import { FacetNav } from "@working-theory/ui/chrome"` |
258
267
  | `FloatingCta` | Persistent fixed corner action pill. *(weak)* | `import { FloatingCta } from "@working-theory/ui/chrome"` |
259
268
  | `Footer` | Site footer server component with secondary nav links. Label resolution order for navItems labels. Resolved labels are passed into FooterNav as pre-resolved strings — no duplicated resolution logic across variants. | `import { Footer } from "@working-theory/ui/chrome"` |
@@ -262,21 +271,147 @@ Import: `import { X } from "@working-theory/ui/chrome";` (or from the `@working-
262
271
  | `NavOverflowMenu` | The Nav row's per-breakpoint link-overflow disclosure. The desktop link row never wraps: a fixed per-breakpoint inline-link budget (4 at md, 6 at lg+) is enforced by the caller (Nav), which splits `navItems` into an inline slice and an overflow slice. This component renders ONLY the overflow slice, behind a disclosure trigger, in source order — it never computes the budget itself. | internal — compose from `packages/ui/src/chrome/NavOverflowMenu.tsx` |
263
272
  | `NotificationsMenu` | Bell trigger + notifications popover chrome (ploy-capture app-frame). Presentational, props-driven. The unread count and row list arrive entirely via props — this component carries NO fetch/polling logic of its own. Rows are pre-formatted at the call site (relative time, heading, empty copy) per the AILK i18n/formatting convention (design-system-rules Rule 10). | `import { NotificationsMenu } from "@working-theory/ui/chrome"` |
264
273
  | `SectionNav` | Chrome-tier route-aware section navigation. A horizontal, tab-styled section nav promoting Working Theory's bespoke `UnifiedTabs`/`TheoriesTabs` to a tokenized, tier-correct AILK component. | `import { SectionNav } from "@working-theory/ui/chrome"` |
265
- | `SidebarNav` | Application sidebar rail (nav + teams + user) for dashboard shells. Server Component (RSC). Renders the vertical sidebar rail for application-shell layouts. Used as the `sidebar` prop of DashboardShell. Wrap in a FixedPanel (panels tier) to get the expanded ↔ rail ↔ hidden state machinery. Independently reusable in future shells (settings, analytics, etc.). *(weak)* | `import { SidebarNav } from "@working-theory/ui/chrome"` |
274
+ | `SidebarNav` | Application sidebar rail (nav + teams + user) for dashboard shells. Server Component (RSC). Renders the vertical sidebar rail for application-shell layouts. Used as the `sidebar` prop of WorkspaceShell. Wrap in a FixedPanel (panels tier) to get the expanded ↔ rail ↔ hidden state machinery. Independently reusable in future shells (settings, analytics, etc.). *(weak)* | `import { SidebarNav } from "@working-theory/ui/chrome"` |
266
275
  | `SidebarNavRailItems` | Client boundary for the collapsed rail tooltip affordance. Isolated "use client" boundary so SidebarNav itself stays a Server Component. Renders icon-only nav links with Tooltip labels when the rail is collapsed. *(weak)* | internal — compose from `packages/ui/src/chrome/SidebarNavRailItems.tsx` |
267
276
  | `SidePanel` | Chrome-tier right-edge content panel. Fills the ResizablePanel right-edge slot in AppShell. Provides a rich header (title / subtitle / type-badge / avatar / actions / close), a scrollable body, and an optional footer. Mirrors how SidebarNav fills the left edge. | `import { SidePanel } from "@working-theory/ui/chrome"` |
268
277
  | `WorkspaceSwitcher` | Org/workspace switcher chrome (ploy-capture app-frame). Presentational, props-driven. Tenancy data (org, user, workspace list, credit meters, actions) arrives entirely via the optional `tenancy` prop — this component carries NO fetch/session logic of its own. When `tenancy` is absent it degrades cleanly to a static, non-interactive single-tenant identity row: no popover, no chevron, no menu semantics. | `import { WorkspaceSwitcher } from "@working-theory/ui/chrome"` |
269
278
 
270
279
  ---
271
280
 
281
+ ## Primitives (79)
282
+
283
+ The base control and text vocabulary — Button, Heading, Text, Link, Icon, Input, Dialog, Command, Tooltip, ThemeToggle and the rest. This is the only tier allowed to render raw HTML elements; every tier above it composes these instead. Search here before building any low-level control.
284
+
285
+ Import: `import { X } from "@working-theory/ui/primitives";` (or from the `@working-theory/ui` root barrel). Components marked *internal* are not re-exported — they are implementation details of a sibling in the same tier.
286
+
287
+ | Component | What it does | How to use it |
288
+ | --- | --- | --- |
289
+ | `Accordion` | Collapsible panel set built on @radix-ui/react-accordion. | `import { Accordion } from "@working-theory/ui/primitives"` |
290
+ | `Alert` | Contextual status message for user feedback. Supports four semantic variants (default, error, warning, success, info) that map to AILK Brand 1.3 status tokens. | `import { Alert } from "@working-theory/ui/primitives"` |
291
+ | `AlertBanner` | Full-width status or promotional banner strip. Renders a horizontally-centered, full-width bar for site-level notices: informational, success, warning, error, and promotional messages. | `import { AlertBanner } from "@working-theory/ui/primitives"` |
292
+ | `AlertDialog` | Confirmation overlay composed from @radix-ui/react-alert-dialog. Unlike Dialog, AlertDialog traps focus and requires the user to explicitly confirm or cancel before dismissing — appropriate for destructive actions. | `import { AlertDialog } from "@working-theory/ui/primitives"` |
293
+ | `AlertDot` | Colored status dot with optional notification count. Use on integration cards, avatars, or any icon needing inline status indication. Pass `count` to render a capped badge (e.g. "99+") instead of a plain dot. Announces status to assistive technology via role="status" and a caller-supplied aria-label (required by accessibility contract). | `import { AlertDot } from "@working-theory/ui/primitives"` |
294
+ | `AspectRatio` | Constrains content to a given width/height ratio. Thin re-export of @radix-ui/react-aspect-ratio. RSC-safe: no hooks or browser APIs — default server component. *(weak)* | `import { AspectRatio } from "@working-theory/ui/primitives"` |
295
+ | `Avatar` | Circular or square user/company avatar with image, initials, or icon fallback. | `import { Avatar } from "@working-theory/ui/primitives"` |
296
+ | `Badge` | Inline label chip with semantic status variants and size scale. | `import { Badge } from "@working-theory/ui/primitives"` |
297
+ | `Breadcrumb` | Navigation primitive that renders an ordered wayfinding trail with accessible current-page marking and logical-direction separators. | `import { Breadcrumb } from "@working-theory/ui/primitives"` |
298
+ | `Button` | `&lt;button>` (or any element via `asChild`) with cva variant + size styling via @working-theory/theme tokens. | `import { Button } from "@working-theory/ui/primitives"` |
299
+ | `Calendar` | Date picker built on react-day-picker with AILK semantic tokens. | `import { Calendar } from "@working-theory/ui/primitives"` |
300
+ | `Checkbox` | Accessible checkbox control backed by @radix-ui/react-checkbox. Renders a 16×16 checkbox with a Check icon when checked. Supports disabled state, custom className, and all Radix Checkbox.Root props. | `import { Checkbox } from "@working-theory/ui/primitives"` |
301
+ | `ChipInput` | Row of dismissible chips with an optional add button. | `import { ChipInput } from "@working-theory/ui/primitives"` |
302
+ | `CitationMarker` | Inline citation/source marker for agent-generated content. Renders a compact numbered or labeled source reference inline with text. Used alongside AI-generated content to surface provenance for individual claims. | `import { CitationMarker } from "@working-theory/ui/primitives"` |
303
+ | `Code` | Code inline primitive — renders a semantic &lt;code> for code/variable spans inside prose. Inline sibling of Text. | `import { Code } from "@working-theory/ui/primitives"` |
304
+ | `Collapsible` | Thin re-export of the Radix Collapsible root and content parts, plus the styled CollapsibleTrigger button. | `import { Collapsible } from "@working-theory/ui/primitives"` |
305
+ | `Command` | Keyboard-navigable command palette / search input. Thin wrapper over the `cmdk` library (Command component) with AILK semantic token styling. Provides the full sub-component set: Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut. | `import { Command } from "@working-theory/ui/primitives"` |
306
+ | `ConfidenceIndicator` | Accessible confidence-level badge for AI-generated claims. Bound to the `@working-theory/validation` confidence shape: confidence_level = "low" \| "medium" \| "high" This matches the `overallConfidence` enum in market-landscape-summary and canonical-messaging-summary schemas, and the free-text `confidence_level` on HypothesisClaim. | `import { ConfidenceIndicator } from "@working-theory/ui/primitives"` |
307
+ | `Container` | _no description in source — read `packages/ui/src/primitives/Container.tsx`_ | `import { Container } from "@working-theory/ui/primitives"` |
308
+ | `ContextMenu` | Right-click / long-press contextual action menu. Thin wrapper over @radix-ui/react-context-menu with AILK semantic token styling. Provides the full Radix sub-component set: Root, Trigger, Portal, Content, Group, Label, Item, CheckboxItem, RadioGroup, RadioItem, ItemIndicator, Separator, Sub, SubTrigger, SubContent, Shortcut. | `import { ContextMenu } from "@working-theory/ui/primitives"` |
309
+ | `CopyButton` | CopyButton Primitive. *(weak)* | `import { CopyButton } from "@working-theory/ui/primitives"` |
310
+ | `Delta` | Sign-driven semantic indicator for numeric change. *(weak)* | `import { Delta } from "@working-theory/ui/primitives"` |
311
+ | `Dialog` | Modal overlay composed from @radix-ui/react-dialog. *(weak)* | `import { Dialog } from "@working-theory/ui/primitives"` |
312
+ | `DropdownMenu` | Contextual action menu anchored to a trigger. Thin wrapper over @radix-ui/react-dropdown-menu with AILK semantic token styling. Provides the full Radix sub-component set: Root, Trigger, Portal, Content, Group, Label, Item, CheckboxItem, RadioGroup, RadioItem, ItemIndicator, Separator, Sub, SubTrigger, SubContent, Shortcut. | `import { DropdownMenu } from "@working-theory/ui/primitives"` |
313
+ | `EmptyState` | Purposeful empty / zero-item state indicator. Distinct from loading (`Skeleton`, `SectionSkeleton`) and error (`SectionErrorBoundary`) states. Use `EmptyState` when content is absent by design (no items yet, no search results, no activity), not when content is loading or a render error occurred. | `import { EmptyState } from "@working-theory/ui/primitives"` |
314
+ | `Field` | Composes Label + a control slot + helper/error text. | `import { Field } from "@working-theory/ui/primitives"` |
315
+ | `Form` | `preventDefault` + native Validity State + ARIA wiring. | `import { Form } from "@working-theory/ui/primitives"` |
316
+ | `GradientText` | Mechanism (pure CSS, no client JS): the `.gt-text` utility in `@working-theory/theme`'s tokens.css sets `background-image: var(gradient-brand)` plus `background-clip: text` + transparent fill, so the gradient shows through the glyphs. That is the SAME technique `ShimmerText` uses via `.st-text`, minus the sweep: no `background-size` stretch, no `@keyframes`, no animate companion class. | `import { GradientText } from "@working-theory/ui/primitives"` |
317
+ | `Heading` | _no description in source — read `packages/ui/src/primitives/Heading.tsx`_ | `import { Heading } from "@working-theory/ui/primitives"` |
318
+ | `HoverCard` | Floating card revealed on hover, built on @radix-ui/react-hover-card. Exports Root, Trigger, and Content. The trigger is typically an anchor or interactive element; the content floats alongside it on pointer hover/focus. | `import { HoverCard } from "@working-theory/ui/primitives"` |
319
+ | `Icon` | Single rendering path for Lucide UI icons and brand/channel logos (Simple Icons raw paths). | `import { Icon } from "@working-theory/ui/primitives"` |
320
+ | `Image` | Wraps `next/image` and closes foot-guns at the type level. | `import { Image } from "@working-theory/ui/primitives"` |
321
+ | `InlineMessage` | Quiet helper/error/warning text for forms. | `import { InlineMessage } from "@working-theory/ui/primitives"` |
322
+ | `Input` | Single-line text input with variant styling. Supports default, warning, and error validation states, three size variants, and optional leading/trailing icon slots. | `import { Input } from "@working-theory/ui/primitives"` |
323
+ | `Label` | Form field label with peer-disabled state styling. Wraps @radix-ui/react-label for correct association with form controls via `htmlFor`. Automatically dims and shows a not-allowed cursor when the associated control carries the `disabled` attribute (peer-disabled). | `import { Label } from "@working-theory/ui/primitives"` |
324
+ | `Link` | _no description in source — read `packages/ui/src/primitives/Link.tsx`_ | `import { Link } from "@working-theory/ui/primitives"` |
325
+ | `LoaderRing` | Compact loading-animation indicator. Renders the three loading animations (spinner, dots, check-transition) and, for terminal status, composes the shared StatusBadge primitive (success/error/warning). Sizes track the AILK icon-size token scale; all colors are AILK Brand 1.3 semantic tokens. | `import { LoaderRing } from "@working-theory/ui/primitives"` |
326
+ | `Menubar` | Horizontal application menu bar with keyboard navigation. | `import { Menubar } from "@working-theory/ui/primitives"` |
327
+ | `MenuItem` | Interactive menu item for dropdowns, context menus, etc. Full-width, left-aligned button with support for left/right icons, secondary text, selection state, and destructive variant. | `import { MenuItem } from "@working-theory/ui/primitives"` |
328
+ | `MoneyAmount` | Locale-aware currency display. *(weak)* | `import { MoneyAmount } from "@working-theory/ui/primitives"` |
329
+ | `NavigationMenu` | Accessible site navigation with flyout content. Thin wrapper over @radix-ui/react-navigation-menu with AILK semantic token styling. Provides the full Radix sub-component set: Root, List, Item, Trigger, Content, Link, Viewport, Indicator. | `import { NavigationMenu } from "@working-theory/ui/primitives"` |
330
+ | `Pagination` | • Link mode (default, RSC-safe) — prev/next render as `&lt;a>` links built from `baseUrl` (`?page=N`); the inactive boundary control is a disabled `&lt;span>`. This is the original behaviour and is unchanged. | `import { Pagination } from "@working-theory/ui/primitives"` |
331
+ | `PanelEdgeHandle` | Presentational primitive (Primitives tier, Tier 1). A full-height vertical edge handle with a ≥44px touch target (min-w-11). Used by tier-2 panels as the interactive edge handle — FixedPanel (collapse/expand) and ResizablePanel (drag-resize). | `import { PanelEdgeHandle } from "@working-theory/ui/primitives"` |
332
+ | `Popover` | Floating content panel anchored to a trigger. Thin wrapper over @radix-ui/react-popover with AILK semantic token styling. Provides: Popover (root), PopoverTrigger, PopoverAnchor, PopoverContent, PopoverClose — the full Radix sub-component set. | `import { Popover } from "@working-theory/ui/primitives"` |
333
+ | `Progress` | Wraps @radix-ui/react-progress with AILK token-driven styling. Supports three size variants (sm, md, lg) and two track colors (default, secondary). The indicator fill switches to the success emphasis token when `isComplete` is true. | `import { Progress } from "@working-theory/ui/primitives"` |
334
+ | `ProgressRing` | Circular SVG progress indicator. Renders a ring (stroke arc) or pie (filled wedge) progress meter, plus success/error/warning filled-ring status states that mirror LoaderRing's status variants for consistent visual language. | `import { ProgressRing } from "@working-theory/ui/primitives"` |
335
+ | `ProvenanceBadge` | Agent/human/system authorship chip with optional audit id. | `import { ProvenanceBadge } from "@working-theory/ui/primitives"` |
336
+ | `RadioGroup` | Accessible radio button group backed by @radix-ui/react-radio-group. Exports RadioGroup (Root) and RadioGroupItem. The Root renders as a grid with gap-2 by default; items are 16×16 px filled circles. | `import { RadioGroup } from "@working-theory/ui/primitives"` |
337
+ | `Rating` | Renders star icons for a 0–5 numeric rating, with full and half-star support and an accessible aria-label. | `import { Rating } from "@working-theory/ui/primitives"` |
338
+ | `ScrollArea` | Custom-styled scroll container built on @radix-ui/react-scroll-area. Exposes ScrollArea (Root + Viewport + Corner composite) and ScrollBar as separately composable sub-components. | `import { ScrollArea } from "@working-theory/ui/primitives"` |
339
+ | `SearchInputTrigger` | It is NOT search-or hero-specific: every visual axis (height, width, corner radius, background, border, placeholder, shortcut hint) is a token-driven prop so the same control can be restyled per placement. It does not own a real &lt;input>; clicking it (or pressing the hinted shortcut) fires `onClick`, which the caller wires to open a Command palette. | `import { SearchInputTrigger } from "@working-theory/ui/primitives"` |
340
+ | `SectionErrorBoundary` | Wraps any section in a render-error containment layer. When a child throws during render, the boundary catches the error, logs it, and renders `&lt;SectionSkeleton>` as the fallback. | `import { SectionErrorBoundary } from "@working-theory/ui/primitives"` |
341
+ | `SectionSkeleton` | Minimal animated placeholder block. Used as the default fallback by SectionErrorBoundary and as a loading skeleton in suspense-enabled section consumers. Renders a single animated rectangle respecting an optional aspect-ratio and className. | `import { SectionSkeleton } from "@working-theory/ui/primitives"` |
342
+ | `SegmentedControl` | A compact single-select pill group with radiogroup semantics. | `import { SegmentedControl } from "@working-theory/ui/primitives"` |
343
+ | `SegmentedProgress` | Discrete N-segment progress indicator. Renders `max` equal-width rounded bars in a row; the first `value` segments render filled (brand fill token), the remainder render as unfilled track segments. Distinct from the continuous `Progress` primitive (a single sliding-fill track) — use SegmentedProgress for step/checklist-style progress such as an onboarding checklist or a multi-step wizard. | `import { SegmentedProgress } from "@working-theory/ui/primitives"` |
344
+ | `Select` | Accessible dropdown select backed by @radix-ui/react-select. Exports the full Radix sub-component set: Select (Root), SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator. | `import { Select } from "@working-theory/ui/primitives"` |
345
+ | `Separator` | Thin divider line between content regions. | `import { Separator } from "@working-theory/ui/primitives"` · `packages/ui/src/primitives/Separator.tsx` |
346
+ | `Sheet` | Slide-out panel anchored to any viewport edge. | `import { Sheet } from "@working-theory/ui/primitives"` |
347
+ | `ShimmerText` | Mechanism (pure CSS, no client JS). All configurable values flow as CSS custom properties via the style prop so they are tunable at call-site without arbitrary Tailwind values. | `import { ShimmerText } from "@working-theory/ui/primitives"` |
348
+ | `ShortcutTrigger` | Button-family primitive: a compact icon trigger with an optional keyboard-shortcut hint (e.g. ⌘K). | `import { ShortcutTrigger } from "@working-theory/ui/primitives"` |
349
+ | `Skeleton` | Animated placeholder shown while content is loading. | `import { Skeleton } from "@working-theory/ui/primitives"` |
350
+ | `Slider` | Range input built on @radix-ui/react-slider. Exposes the full Radix sub-component set (Root, Track, Range, Thumb) for composition, and provides a pre-composed &lt;Slider> default. | `import { Slider } from "@working-theory/ui/primitives"` |
351
+ | `SplitButton` | A main action button paired with a dropdown trigger. *(weak)* | `import { SplitButton } from "@working-theory/ui/primitives"` |
352
+ | `StatusBadge` | Colored circle + glyph status indicator. *(weak)* | `import { StatusBadge } from "@working-theory/ui/primitives"` |
353
+ | `Surface` | Establishes a color-token context for its subtree. The `emphasis` variant marks the wrapper with `data-surface="emphasis"`, which remaps the theme-flipping semantic color tokens to their dark-palette values within the subtree (see the [data-surface="emphasis"] rule in @working-theory/theme/tokens.css). | `import { Surface } from "@working-theory/ui/primitives"` |
354
+ | `Switch` | A toggleable on/off control built on @radix-ui/react-switch. | `import { Switch } from "@working-theory/ui/primitives"` |
355
+ | `Table` | Semantic HTML table with token-driven styling. Exposes Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, and TableCaption as composable sub-components. | `import { Table } from "@working-theory/ui/primitives"` |
356
+ | `Tabs` | Radix-backed tablist/tab/tabpanel with optional per-tab count badges and an optional "More ▾" overflow menu. | `import { Tabs } from "@working-theory/ui/primitives"` · `packages/ui/src/primitives/Tabs.tsx` |
357
+ | `Text` | _no description in source — read `packages/ui/src/primitives/Text.tsx`_ | `import { Text } from "@working-theory/ui/primitives"` |
358
+ | `Textarea` | Multi-line text input with variant styling. Supports default, warning, and error validation states and three size variants. Compose with &lt;Label> and &lt;Form> for accessible form fields. | `import { Textarea } from "@working-theory/ui/primitives"` |
359
+ | `ThemeToggle` | Stateful 3-state theme owner. *(weak)* | `import { ThemeToggle } from "@working-theory/ui/primitives"` |
360
+ | `ThemeToggleView` | 3-state icon segmented control. A presentational, controlled component. It renders what `value` says and calls `onChange` when the user picks a different mode. All theme persistence (cookies, DOM attribute writes) is the responsibility of the stateful owner {@link ThemeToggle}. | internal — compose from `packages/ui/src/primitives/ThemeToggleView.tsx` |
361
+ | `TimePicker` | Time-of-day selector with 12h/24h formats. A dropdown of time slots (48 per day at the default 30-minute step), NOT an analog clock face. Composes the Select primitive — the generated slots render as Select options, inheriting Select's combobox/listbox a11y, keyboard, type-ahead, and styling (incl. the corner-radius fix). | `import { TimePicker } from "@working-theory/ui/primitives"` |
362
+ | `Toast` | Radix-backed transient notification system. *(weak)* | `import { Toast } from "@working-theory/ui/primitives"` |
363
+ | `Toaster` | Renders the toast viewport and maps queued toasts from `useToast` into individual `&lt;Toast>` instances. | `import { Toaster } from "@working-theory/ui/primitives"` |
364
+ | `Toggle` | Toggle Primitive. *(weak)* | `import { Toggle } from "@working-theory/ui/primitives"` |
365
+ | `Tooltip` | Radix-backed floating label anchored to a trigger element. | `import { Tooltip } from "@working-theory/ui/primitives"` |
366
+ | `VisuallyHidden` | Renders its children so they are present in the DOM and the accessibility tree but visually hidden. Standardizes the ad-hoc `sr-only` className pattern previously hand-rolled across primitives (Dialog/Sheet/Toast close labels) and section headers. *(weak)* | `import { VisuallyHidden } from "@working-theory/ui/primitives"` |
367
+ | `WorkingIndicator` | Renders the authentic Claude Code "working" indicator: a glyph that blooms frame-by-frame from a middle dot through increasingly complex Unicode star shapes to a full-star, then resets. Beside it sits a steady-colored label ("Thinking…" by default). | `import { WorkingIndicator } from "@working-theory/ui/primitives"` |
368
+
369
+ ---
370
+
371
+ ## Panels (7)
372
+
373
+ Reusable layout containers that own their own interaction state (collapse, rail, drag-to-resize, off-canvas drawer below `lg`). Not page shells — composable containers that sit between primitives and blocks.
374
+
375
+ Import: `import { X } from "@working-theory/ui/panels";` (or from the `@working-theory/ui` root barrel). Components marked *internal* are not re-exported — they are implementation details of a sibling in the same tier.
376
+
377
+ | Component | What it does | How to use it |
378
+ | --- | --- | --- |
379
+ | `CardGrid` | The shared owner of how card-grid cells are arranged and separated — columns, gap, and the inter-cell SEPARATION treatment. Seven sections (BentoGrid, Items, Pricing, SocialProof, Stats, Testimonials, Team) currently hand-roll `grid gap-grid grid-cols-*`; this panel is the foundation they compose instead, the direct analogue of how `SectionFrame` collapsed 23× frame duplication. | `import { CardGrid } from "@working-theory/ui/panels"` |
380
+ | `FixedPanel` | Collapsible layout-container primitive (Tier 2 — Panels). A three-state panel: expanded ↔ rail ↔ hidden. Controlled only — callers manage state via `state` + `onStateChange`. | `import { FixedPanel } from "@working-theory/ui/panels"` |
381
+ | `FlowFrame` | The // frame: a full-viewport ground on the site `bg` token, two 50/50 regions (a persistent side panel + an active region) that stack below `md:` (side panel first, in DOM and visual order), and a bottom bar pinned to the VISIBLE viewport (`position: fixed`, safe-area aware) carrying a single continuous accent progress line, `leading` / `label` (center) / `trailing` slots, and a prop-controlled "Powered by Working Theory" line. *(weak)* | `import { FlowFrame } from "@working-theory/ui/panels"` |
382
+ | `InvoiceDetail` | A single invoice's detail view, for the invoice surface (U4). Capability-bearing: binds a schema.org `Invoice` resource-payload fragment (imported from `@working-theory/schema`) — so a co-located `.text.ts` + `.text.test.ts` renderer is required and gated by `scripts/check-ax-parity.sh`. | internal — compose from `packages/ui/src/panels/InvoiceDetail.tsx` |
383
+ | `ResizablePanel` | Drag-resizable layout-container primitive (Panels tier, Tier 2). Provides a resizable side panel container for layout composition. The panel width is controlled by the parent via `width` + `onWidthChange`/`onWidthChangeEnd`. The panel itself manages the drag interaction; the parent persists the committed width (e.g. via localStorage or server state). | `import { ResizablePanel } from "@working-theory/ui/panels"` |
384
+ | `SectionFrame` | The shared frame the section tier composes instead of hand-rolling the `SectionErrorBoundary` + `&lt;section className="py-section bg-bg">` + `Container` plumbing (23× duplicated at time). | `import { SectionFrame } from "@working-theory/ui/panels"` |
385
+ | `StickyColumn` | Makes one column of a two-column layout stick (`lg:sticky` with a top offset) while the sibling column scrolls — the HubSpot "left header sticks, right content scrolls" pattern. `lg`-only: below `lg` it is NOT sticky (normal flow, stacks). Consumed by SplitContentMedia; reusable by any two-column layout. | `import { StickyColumn } from "@working-theory/ui/panels"` |
386
+
387
+ ---
388
+
389
+ ## Shells (6)
390
+
391
+ Route-level slot-frames — the outermost layout a page is placed into. They supply geometry and slots (nav / sidebar / main / footer), not content: you inject the real Nav, Footer and sidebar. A different package from every tier above: `@working-theory/templates`.
392
+
393
+ Import: `import { X } from "@working-theory/templates/shells";` (or from the `@working-theory/templates` root barrel). Components marked *internal* are not re-exported — they are implementation details of a sibling in the same tier.
394
+
395
+ | Component | What it does | How to use it |
396
+ | --- | --- | --- |
397
+ | `AppShell` | Shared authed-app base frame. Layout ownership: AppShell is the SINGLE owner of the authed sidebar frame layout. The `sidebar` prop is CONTENT (e.g. a &lt;SidebarNav>), never a layout component. Do NOT pass SidebarShell or FixedPanel as the sidebar — that nests two incompatible layout systems (a fixed-width shell vs a variable-width panel). | `import { AppShell } from "@working-theory/templates/shells"` |
398
+ | `BlogShell` | Blog reading **slot-frame** (DOCS-UI-8). Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* and *where content goes*, owning **geometry only**. Chrome (Nav/Footer) and content (the post meta rail + the reconciled BlogPost body) **fill** the slots — nothing is baked in. Peer to MarketingShell / DocsShell; see. *(weak)* | internal — compose from `packages/templates/src/shells/BlogShell.tsx` |
399
+ | `DeckHeroObserver` | Internal client island for MarketingShell's `deckHero` option. | internal — compose from `packages/templates/src/shells/DeckHeroObserver.tsx` |
400
+ | `DocsShell` | Documentation reading **slot-frame** (DOCS-UI-4). Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* and *where content goes*, owning **geometry only**. Chrome (DocsSidebar) and content (DocsArticleHeader + MDXContent + ArticlePager + DocsFeedback) **fill** the slots — nothing is baked in. Peer to MarketingShell; see. *(weak)* | internal — compose from `packages/templates/src/shells/DocsShell.tsx` |
401
+ | `MarketingShell` | Public-facing marketing site **slot-frame**. Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* (top + bottom) and *where sections go* (the body), owning **geometry only**. Chrome (Nav/Footer) and sections **fill** the slots — nothing is baked into the component. See (first instance). *(weak)* | `import { MarketingShell } from "@working-theory/templates/shells"` |
402
+ | `PortalShell` | Customer-facing portal (sidebar + branded top chrome + main);. Thin composition of AppShell + SidebarNav. Converged from the hand-rolled layout in the prior MVP to match the AppShell pattern established by the canonical authed-app shell (moved to the multi-tenant module's own app by /D-45). *(weak)* | `import { PortalShell } from "@working-theory/templates/shells"` |
403
+
404
+ ---
405
+
272
406
  ## Weak descriptions
273
407
 
274
- These 12 components have a description that is accurate but does not do the job well: too short to match against, or long but spent on implementation. A capability search reaches them only if the searcher's word happens to be in it, so they are the most likely place for this catalog to repeat the failure it was built to fix. Read the source before concluding the capability is absent — and if you own one of these components, its header is the fix.
408
+ These 29 components have a description that is accurate but does not do the job well: too short to match against, or long but spent on implementation. A capability search reaches them only if the searcher's word happens to be in it, so they are the most likely place for this catalog to repeat the failure it was built to fix. Read the source before concluding the capability is absent — and if you own one of these components, its header is the fix.
275
409
 
276
410
  | Component | Tier | What the source gives us |
277
411
  | --- | --- | --- |
412
+ | `DocumentViewerClient` | sections | The interactive shell for DocumentViewer. Split out of DocumentViewer.tsx (which stays RSC) for the same reason AlertSection composes AlertSectionDismissIsland: interactivity is contained to one client island. |
278
413
  | `AgentContextCard` | blocks | Capability-bearing block that renders agent provenance. RSC note: no hooks or browser APIs — server-renderable by default. |
279
- | `PageHeader` | blocks | RSC. Page-level header composing the Breadcrumb primitive for the left-side wayfinding trail, a generic right-side `actions` slot, and an optional `switcher` slot for header-owned segment switching. Fills AppShell's `header` slot (DashboardShell and similar). No accent bar. No tab API. No named action props — the caller assembles whatever button/menu nodes it needs and passes them as `actions`. |
414
+ | `PageHeader` | blocks | RSC. Page-level header composing the Breadcrumb primitive for the left-side wayfinding trail, a generic right-side `actions` slot, and an optional `switcher` slot for header-owned segment switching. Fills AppShell's `header` slot (WorkspaceShell and similar). No accent bar. No tab API. No named action props — the caller assembles whatever button/menu nodes it needs and passes them as `actions`. |
280
415
  | `PricingTierCardSeatControl` | blocks | Seat-count range picker for the Team tier card. Renders a Select primitive that lets the user choose an "Up to N seats" option from a caller-supplied list of numbers. The parent PricingTierCard stays a pure RSC; only this tiny island is hydrated. Pattern mirrors PageHeaderSwitcher.tsx: small "use client" island imported by an otherwise-server-rendered parent, keeping the client bundle minimal. |
281
416
  | `SinglePriceCard` | blocks | 2-column split card for the Pricing 'single-price-with-details' variant. |
282
417
  | `SocialIcons` | blocks | Horizontal row of social icon links. Renders brand icons (via Icon primitive + simple-icons paths) inside accessible Link primitives. Each platform link gets an aria-label. Shared by company-mission, simple-centered, and newsletter-below footer variants, and composed by TeamMemberCard for member social links. |
@@ -285,11 +420,34 @@ These 12 components have a description that is accurate but does not do the job
285
420
  | `BannerDismissIsland` | chrome | Isolated to "use client" so Banner (Server Component) stays RSC. Mirrors the Nav / NavMobileMenu split: interactivity is contained here. Rendering: wraps its children in a relative-positioned div and absolutely places the × dismiss button at the end (RTL-safe: `end-4`) of the bar. |
286
421
  | `FloatingCta` | chrome | Persistent fixed corner action pill. |
287
422
  | `NavMobileMenu` | chrome | Client subcomponent for mobile hamburger state. Isolates "use client" to this narrow component so Nav (Server Component) stays clean. Renders a hamburger button + collapsible link list. Closes the menu automatically when the pathname changes (route navigation). |
288
- | `SidebarNav` | chrome | Application sidebar rail (nav + teams + user) for dashboard shells. Server Component (RSC). Renders the vertical sidebar rail for application-shell layouts. Used as the `sidebar` prop of DashboardShell. Wrap in a FixedPanel (panels tier) to get the expanded ↔ rail ↔ hidden state machinery. Independently reusable in future shells (settings, analytics, etc.). |
423
+ | `SidebarNav` | chrome | Application sidebar rail (nav + teams + user) for dashboard shells. Server Component (RSC). Renders the vertical sidebar rail for application-shell layouts. Used as the `sidebar` prop of WorkspaceShell. Wrap in a FixedPanel (panels tier) to get the expanded ↔ rail ↔ hidden state machinery. Independently reusable in future shells (settings, analytics, etc.). |
289
424
  | `SidebarNavRailItems` | chrome | Client boundary for the collapsed rail tooltip affordance. Isolated "use client" boundary so SidebarNav itself stays a Server Component. Renders icon-only nav links with Tooltip labels when the rail is collapsed. |
425
+ | `AspectRatio` | primitives | Constrains content to a given width/height ratio. Thin re-export of @radix-ui/react-aspect-ratio. RSC-safe: no hooks or browser APIs — default server component. |
426
+ | `CopyButton` | primitives | CopyButton Primitive. |
427
+ | `Delta` | primitives | Sign-driven semantic indicator for numeric change. |
428
+ | `Dialog` | primitives | Modal overlay composed from @radix-ui/react-dialog. |
429
+ | `MoneyAmount` | primitives | Locale-aware currency display. |
430
+ | `SplitButton` | primitives | A main action button paired with a dropdown trigger. |
431
+ | `StatusBadge` | primitives | Colored circle + glyph status indicator. |
432
+ | `ThemeToggle` | primitives | Stateful 3-state theme owner. |
433
+ | `Toast` | primitives | Radix-backed transient notification system. |
434
+ | `Toggle` | primitives | Toggle Primitive. |
435
+ | `VisuallyHidden` | primitives | Renders its children so they are present in the DOM and the accessibility tree but visually hidden. Standardizes the ad-hoc `sr-only` className pattern previously hand-rolled across primitives (Dialog/Sheet/Toast close labels) and section headers. |
436
+ | `FlowFrame` | panels | The // frame: a full-viewport ground on the site `bg` token, two 50/50 regions (a persistent side panel + an active region) that stack below `md:` (side panel first, in DOM and visual order), and a bottom bar pinned to the VISIBLE viewport (`position: fixed`, safe-area aware) carrying a single continuous accent progress line, `leading` / `label` (center) / `trailing` slots, and a prop-controlled "Powered by Working Theory" line. |
437
+ | `BlogShell` | shells | Blog reading **slot-frame** (DOCS-UI-8). Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* and *where content goes*, owning **geometry only**. Chrome (Nav/Footer) and content (the post meta rail + the reconciled BlogPost body) **fill** the slots — nothing is baked in. Peer to MarketingShell / DocsShell; see. |
438
+ | `DocsShell` | shells | Documentation reading **slot-frame** (DOCS-UI-4). Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* and *where content goes*, owning **geometry only**. Chrome (DocsSidebar) and content (DocsArticleHeader + MDXContent + ArticlePager + DocsFeedback) **fill** the slots — nothing is baked in. Peer to MarketingShell; see. |
439
+ | `MarketingShell` | shells | Public-facing marketing site **slot-frame**. Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* (top + bottom) and *where sections go* (the body), owning **geometry only**. Chrome (Nav/Footer) and sections **fill** the slots — nothing is baked into the component. See (first instance). |
440
+ | `PortalShell` | shells | Customer-facing portal (sidebar + branded top chrome + main);. Thin composition of AppShell + SidebarNav. Converged from the hand-rolled layout in the prior MVP to match the AppShell pattern established by the canonical authed-app shell (moved to the multi-tenant module's own app by /D-45). |
290
441
 
291
442
  ---
292
443
 
293
444
  ## Undescribed components
294
445
 
295
- Noneevery component in the inventory carries a real description.
446
+ These 4 components carry no capability description recoverable from source: no section-registry entry, no substantive doc-comment header, no tier-barrel roster line. They are this catalog's blind spots a capability search will not find them, so read the source before concluding AILK lacks something.
447
+
448
+ | Component | Tier | Source |
449
+ | --- | --- | --- |
450
+ | `Container` | primitives | `packages/ui/src/primitives/Container.tsx` |
451
+ | `Heading` | primitives | `packages/ui/src/primitives/Heading.tsx` |
452
+ | `Link` | primitives | `packages/ui/src/primitives/Link.tsx` |
453
+ | `Text` | primitives | `packages/ui/src/primitives/Text.tsx` |