create-ailk 0.1.0 → 0.2.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 (620) hide show
  1. package/README.md +124 -3
  2. package/component-catalog.md +456 -0
  3. package/dist/cli.js +92 -16
  4. package/dist/component-catalog.d.ts +11 -0
  5. package/dist/component-catalog.js +39 -0
  6. package/dist/copy.d.ts +7 -0
  7. package/dist/copy.js +24 -0
  8. package/dist/derive-architecture.d.ts +13 -0
  9. package/dist/derive-architecture.js +238 -0
  10. package/dist/index.d.ts +7 -2
  11. package/dist/index.js +19 -2
  12. package/dist/lib/extract-module-bundle.d.ts +16 -0
  13. package/dist/lib/extract-module-bundle.js +184 -0
  14. package/dist/lib/fetch-module.d.ts +55 -0
  15. package/dist/lib/fetch-module.js +125 -0
  16. package/dist/lib/module-license-gate.d.ts +48 -0
  17. package/dist/lib/module-license-gate.js +67 -0
  18. package/dist/lib/module-tier.d.ts +35 -0
  19. package/dist/lib/module-tier.js +37 -0
  20. package/dist/module-architecture.d.ts +175 -0
  21. package/dist/module-architecture.js +663 -0
  22. package/dist/parse-args.d.ts +47 -1
  23. package/dist/parse-args.js +143 -2
  24. package/dist/programmatic.d.ts +160 -3
  25. package/dist/programmatic.js +196 -7
  26. package/dist/surfaces.d.ts +211 -0
  27. package/dist/surfaces.js +532 -0
  28. package/dist/sync-routes.d.ts +92 -0
  29. package/dist/sync-routes.js +350 -0
  30. package/package.json +12 -5
  31. package/templates/.claude/rules/architecture.md +6 -2
  32. package/templates/.claude/skills/README.md +9 -9
  33. package/templates/.claude/skills/add-schema/SKILL.md +14 -7
  34. package/templates/.claude/skills/add-schema/references/schema-types.md +109 -6
  35. package/templates/.claude/skills/provision-config/SKILL.md +1 -1
  36. package/templates/.claude/skills/scaffold-commerce/SKILL.md +498 -1
  37. package/templates/.claude/skills/scaffold-commerce/templates/checkout-route.template.ts +370 -0
  38. package/templates/.claude/skills/scaffold-commerce/templates/invoice-route.template.ts +376 -0
  39. package/templates/.claude/skills/scaffold-commerce/templates/payment-link-route.template.ts +471 -0
  40. package/templates/.claude/skills/scaffold-commerce/templates/portal-route.template.ts +365 -0
  41. package/templates/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts +60 -0
  42. package/templates/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts +446 -0
  43. package/templates/.claude/skills/suggest-site-pages/references/categories.md +4 -4
  44. package/templates/.env.example +126 -2
  45. package/templates/CLAUDE.md +11 -5
  46. package/templates/README.md +1 -1
  47. package/templates/apps/api/.env.example +38 -0
  48. package/templates/apps/api/CLAUDE.md +78 -1
  49. package/templates/apps/api/LICENSE +201 -0
  50. package/templates/apps/api/api/index.ts +6 -141
  51. package/templates/apps/api/jest.config.cjs +16 -0
  52. package/templates/apps/api/package.json +22 -6
  53. package/templates/apps/api/src/__tests__/module-exclusion.test.ts +141 -0
  54. package/templates/apps/api/src/__tests__/server.test.ts +46 -0
  55. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +211 -0
  56. package/templates/apps/api/src/bin/abandon-sweep.ts +42 -0
  57. package/templates/apps/api/src/bin/deliverable-resend.ts +144 -0
  58. package/templates/apps/api/src/bin/deliverable-upload.ts +114 -0
  59. package/templates/apps/api/src/bin/followup-sweep.ts +44 -0
  60. package/templates/apps/api/src/bin/listing-csv-sweep.ts +46 -0
  61. package/templates/apps/api/src/bin/seed-presets.ts +58 -0
  62. package/templates/apps/api/src/bin/seed-waitlist-experiments.ts +104 -0
  63. package/templates/apps/api/src/bin/session-retention-sweep.ts +46 -0
  64. package/templates/apps/api/src/cli.ts +5 -11
  65. package/templates/apps/api/src/config/index.ts +35 -0
  66. package/templates/apps/api/src/config/modules.ts +43 -0
  67. package/templates/apps/api/src/lib/__mocks__/prisma-client.js +11 -0
  68. package/templates/apps/api/src/lib/__mocks__/prisma.ts +241 -0
  69. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +2 -2
  70. package/templates/apps/api/src/lib/site.ts +16 -0
  71. package/templates/apps/api/src/lib/stripe.ts +22 -0
  72. package/templates/apps/api/src/lib/tenant-db.ts +225 -0
  73. package/templates/apps/api/src/lib/ws-token.ts +91 -0
  74. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +7 -1
  75. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +7 -1
  76. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +91 -4
  77. package/templates/apps/api/src/middleware/auth.ts +43 -8
  78. package/templates/apps/api/src/middleware/rate-limit.ts +78 -3
  79. package/templates/apps/api/src/middleware/tenant.ts +99 -0
  80. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +92 -0
  81. package/templates/apps/api/src/openapi/spec.ts +312 -3
  82. package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +175 -0
  83. package/templates/apps/api/src/routes/aeo/index.ts +107 -0
  84. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +5 -2
  85. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +22 -3
  86. package/templates/apps/api/src/routes/auth/tokens.ts +13 -1
  87. package/templates/apps/api/src/routes/billing/__tests__/portal.test.ts +450 -0
  88. package/templates/apps/api/src/routes/billing/__tests__/read.test.ts +262 -0
  89. package/templates/apps/api/src/routes/billing/__tests__/usage.test.ts +436 -0
  90. package/templates/apps/api/src/routes/billing/index.ts +36 -0
  91. package/templates/apps/api/src/routes/billing/portal.ts +182 -0
  92. package/templates/apps/api/src/routes/billing/read.ts +75 -0
  93. package/templates/apps/api/src/routes/billing/usage.ts +153 -0
  94. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +99 -0
  95. package/templates/apps/api/src/routes/checkout/sessions.ts +20 -8
  96. package/templates/apps/api/src/routes/content/create.ts +1 -0
  97. package/templates/apps/api/src/routes/content/delete.ts +1 -0
  98. package/templates/apps/api/src/routes/content/index.ts +42 -6
  99. package/templates/apps/api/src/routes/content/update.ts +1 -0
  100. package/templates/apps/api/src/routes/deliverables/__tests__/index.test.ts +393 -0
  101. package/templates/apps/api/src/routes/deliverables/index.ts +200 -0
  102. package/templates/apps/api/src/routes/flow-checkouts/__tests__/index.test.ts +443 -0
  103. package/templates/apps/api/src/routes/flow-checkouts/index.ts +82 -0
  104. package/templates/apps/api/src/routes/flows/README.md +147 -0
  105. package/templates/apps/api/src/routes/flows/__tests__/index.test.ts +752 -0
  106. package/templates/apps/api/src/routes/flows/__tests__/recommender.test.ts +671 -0
  107. package/templates/apps/api/src/routes/flows/index.ts +202 -0
  108. package/templates/apps/api/src/routes/flows/recommender.ts +443 -0
  109. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +438 -31
  110. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +10 -10
  111. package/templates/apps/api/src/routes/leads/index.ts +43 -9
  112. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +558 -0
  113. package/templates/apps/api/src/routes/project-listings/__tests__/copy-edit.test.ts +815 -0
  114. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +869 -0
  115. package/templates/apps/api/src/routes/project-listings/__tests__/me-route-precedence.test.ts +221 -0
  116. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +468 -0
  117. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +424 -0
  118. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +707 -0
  119. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +375 -0
  120. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +467 -0
  121. package/templates/apps/api/src/routes/project-listings/__tests__/tenant-isolation.test.ts +566 -0
  122. package/templates/apps/api/src/routes/project-listings/get.ts +70 -0
  123. package/templates/apps/api/src/routes/project-listings/index.ts +120 -0
  124. package/templates/apps/api/src/routes/project-listings/list.ts +47 -0
  125. package/templates/apps/api/src/routes/project-listings/me.ts +76 -0
  126. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +222 -0
  127. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +97 -0
  128. package/templates/apps/api/src/routes/project-listings/patch.ts +136 -0
  129. package/templates/apps/api/src/routes/project-listings/public.ts +52 -0
  130. package/templates/apps/api/src/routes/project-listings/respond.ts +37 -0
  131. package/templates/apps/api/src/routes/project-listings/resume-token.ts +22 -0
  132. package/templates/apps/api/src/routes/project-listings/start.ts +106 -0
  133. package/templates/apps/api/src/routes/project-listings/submit.ts +122 -0
  134. package/templates/apps/api/src/routes/schedule/__tests__/index.test.ts +490 -0
  135. package/templates/apps/api/src/routes/schedule/index.ts +249 -0
  136. package/templates/apps/api/src/routes/slack/__tests__/actions.test.ts +385 -0
  137. package/templates/apps/api/src/routes/slack/actions.ts +177 -0
  138. package/templates/apps/api/src/routes/slack/index.ts +38 -0
  139. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +16 -6
  140. package/templates/apps/api/src/routes/test/auth/session.ts +8 -6
  141. package/templates/apps/api/src/routes/waitlist-experiments/__tests__/tenant-isolation.test.ts +577 -0
  142. package/templates/apps/api/src/routes/waitlist-experiments/comparison.ts +78 -0
  143. package/templates/apps/api/src/routes/waitlist-experiments/index.ts +41 -0
  144. package/templates/apps/api/src/routes/waitlist-experiments/list.ts +64 -0
  145. package/templates/apps/api/src/routes/waitlist-experiments/respond.ts +42 -0
  146. package/templates/apps/api/src/routes/waitlist-experiments/signup.ts +84 -0
  147. package/templates/apps/api/src/routes/waitlist-experiments/signups.ts +119 -0
  148. package/templates/apps/api/src/routes/waitlist-signups/__tests__/index.test.ts +238 -0
  149. package/templates/apps/api/src/routes/waitlist-signups/index.ts +101 -0
  150. package/templates/apps/api/src/routes/webhooks/README.md +35 -12
  151. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +315 -0
  152. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +270 -0
  153. package/templates/apps/api/src/routes/webhooks/stripe.ts +248 -20
  154. package/templates/apps/api/src/routes/workspaces/__tests__/config-tenant-isolation.test.ts +356 -0
  155. package/templates/apps/api/src/routes/workspaces/__tests__/tenant-isolation.test.ts +671 -0
  156. package/templates/apps/api/src/routes/workspaces/config.ts +125 -0
  157. package/templates/apps/api/src/routes/workspaces/index.ts +194 -0
  158. package/templates/apps/api/src/routes/workspaces/sessions.ts +218 -0
  159. package/templates/apps/api/src/server.ts +307 -7
  160. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +489 -0
  161. package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +475 -0
  162. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +132 -0
  163. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +65 -0
  164. package/templates/apps/api/src/services/__tests__/consent.test.ts +282 -0
  165. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +523 -0
  166. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +359 -0
  167. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +142 -0
  168. package/templates/apps/api/src/services/__tests__/flow-aggregate.test.ts +425 -0
  169. package/templates/apps/api/src/services/__tests__/flow-engine.test.ts +2840 -0
  170. package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +393 -0
  171. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +8 -8
  172. package/templates/apps/api/src/services/__tests__/listing-csv-sweep.test.ts +560 -0
  173. package/templates/apps/api/src/services/__tests__/listing-promotion.test.ts +684 -0
  174. package/templates/apps/api/src/services/__tests__/playbook-compile.test.ts +406 -0
  175. package/templates/apps/api/src/services/__tests__/playbook-render.test.ts +290 -0
  176. package/templates/apps/api/src/services/__tests__/project-listing-decision.test.ts +736 -0
  177. package/templates/apps/api/src/services/__tests__/project-listing-flow.test.ts +475 -0
  178. package/templates/apps/api/src/services/__tests__/project-listing-issue.test.ts +340 -0
  179. package/templates/apps/api/src/services/__tests__/recommender-capture.test.ts +983 -0
  180. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +278 -0
  181. package/templates/apps/api/src/services/__tests__/tenant-context-cascade.test.ts +71 -0
  182. package/templates/apps/api/src/services/__tests__/tenant-context.test.ts +379 -0
  183. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +941 -0
  184. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +588 -0
  185. package/templates/apps/api/src/services/__tests__/usage-metering.test.ts +768 -0
  186. package/templates/apps/api/src/services/__tests__/waitlist-dashboard.test.ts +1314 -0
  187. package/templates/apps/api/src/services/__tests__/waitlist-experiments.test.ts +341 -0
  188. package/templates/apps/api/src/services/__tests__/waitlist-followup.test.ts +567 -0
  189. package/templates/apps/api/src/services/__tests__/waitlist-scoring.test.ts +474 -0
  190. package/templates/apps/api/src/services/__tests__/waitlist-signups.test.ts +354 -0
  191. package/templates/apps/api/src/services/abandon-email.ts +307 -0
  192. package/templates/apps/api/src/services/aeo-score.ts +288 -0
  193. package/templates/apps/api/src/services/answer-distributions.ts +138 -0
  194. package/templates/apps/api/src/services/consent.ts +236 -0
  195. package/templates/apps/api/src/services/deliverable-fulfillment.ts +523 -0
  196. package/templates/apps/api/src/services/entitlements.ts +102 -0
  197. package/templates/apps/api/src/services/flow-aggregate.ts +232 -0
  198. package/templates/apps/api/src/services/flow-checkouts.ts +123 -0
  199. package/templates/apps/api/src/services/flow-engine.ts +1296 -0
  200. package/templates/apps/api/src/services/lead-promotion.ts +176 -0
  201. package/templates/apps/api/src/services/lead-routing.ts +3 -3
  202. package/templates/apps/api/src/services/listing-config.ts +102 -0
  203. package/templates/apps/api/src/services/listing-csv-sweep.ts +455 -0
  204. package/templates/apps/api/src/services/listing-promotion.ts +342 -0
  205. package/templates/apps/api/src/services/playbook-compile.ts +398 -0
  206. package/templates/apps/api/src/services/playbook-render.ts +263 -0
  207. package/templates/apps/api/src/services/project-listing-decision.ts +510 -0
  208. package/templates/apps/api/src/services/project-listing-flow.ts +426 -0
  209. package/templates/apps/api/src/services/project-listing-issue.ts +251 -0
  210. package/templates/apps/api/src/services/project-listings.ts +1472 -0
  211. package/templates/apps/api/src/services/recommender-capture.ts +835 -0
  212. package/templates/apps/api/src/services/scheduling/cal-provider.ts +392 -0
  213. package/templates/apps/api/src/services/scheduling/index.ts +63 -0
  214. package/templates/apps/api/src/services/scheduling/types.ts +88 -0
  215. package/templates/apps/api/src/services/slack-notify.ts +240 -0
  216. package/templates/apps/api/src/services/tenant-context.ts +451 -0
  217. package/templates/apps/api/src/services/usage-aggregation.ts +516 -0
  218. package/templates/apps/api/src/services/usage-credits.ts +340 -0
  219. package/templates/apps/api/src/services/usage-metering.ts +699 -0
  220. package/templates/apps/api/src/services/waitlist-dashboard.ts +947 -0
  221. package/templates/apps/api/src/services/waitlist-experiments.ts +213 -0
  222. package/templates/apps/api/src/services/waitlist-followup.ts +486 -0
  223. package/templates/apps/api/src/services/waitlist-scoring.ts +166 -0
  224. package/templates/apps/api/src/services/waitlist-signups.ts +165 -0
  225. package/templates/apps/api/src/vercel-handler.ts +165 -0
  226. package/templates/apps/api/tsconfig.json +0 -12
  227. package/templates/apps/mcp/CLAUDE.md +19 -9
  228. package/templates/apps/mcp/LICENSE +201 -0
  229. package/templates/apps/mcp/__tests__/create_page.test.ts +1 -0
  230. package/templates/apps/mcp/__tests__/delete_page.test.ts +1 -0
  231. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +105 -0
  232. package/templates/apps/mcp/__tests__/parity.test.ts +70 -6
  233. package/templates/apps/mcp/__tests__/request_callback.test.ts +4 -4
  234. package/templates/apps/mcp/__tests__/schedule_tools.test.ts +242 -0
  235. package/templates/apps/mcp/__tests__/submit_lead.test.ts +4 -4
  236. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +4 -4
  237. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +47 -0
  238. package/templates/apps/mcp/__tests__/update_page.test.ts +1 -0
  239. package/templates/apps/mcp/package.json +6 -4
  240. package/templates/apps/mcp/src/config/modules.ts +37 -0
  241. package/templates/apps/mcp/src/server.ts +109 -18
  242. package/templates/apps/mcp/src/tools/capture_lead.ts +1 -1
  243. package/templates/apps/mcp/src/tools/create_booking.ts +58 -0
  244. package/templates/apps/mcp/src/tools/create_page.ts +1 -0
  245. package/templates/apps/mcp/src/tools/delete_page.ts +1 -0
  246. package/templates/apps/mcp/src/tools/get_event_meta.ts +55 -0
  247. package/templates/apps/mcp/src/tools/get_flow.ts +61 -0
  248. package/templates/apps/mcp/src/tools/index.ts +25 -0
  249. package/templates/apps/mcp/src/tools/list_availability.ts +67 -0
  250. package/templates/apps/mcp/src/tools/purchase.ts +3 -0
  251. package/templates/apps/mcp/src/tools/submit_flow_step.ts +83 -0
  252. package/templates/apps/mcp/src/tools/update_page.ts +1 -0
  253. package/templates/apps/mcp/tsconfig.json +1 -9
  254. package/templates/apps/web/.env.example +44 -0
  255. package/templates/apps/web/CLAUDE.md +28 -0
  256. package/templates/apps/web/LICENSE +201 -0
  257. package/templates/apps/web/__tests__/__mocks__/code-highlight.jest-stub.ts +24 -0
  258. package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +33 -0
  259. package/templates/apps/web/__tests__/__mocks__/next-intl.ts +18 -0
  260. package/templates/apps/web/__tests__/__mocks__/server-only.ts +13 -0
  261. package/templates/apps/web/__tests__/__mocks__/style-mock.js +4 -0
  262. package/templates/apps/web/__tests__/__mocks__/vercel-analytics-server.ts +9 -0
  263. package/templates/apps/web/__tests__/jest-support/import-meta-transformer.cjs +90 -0
  264. package/templates/apps/web/__tests__/setup.ts +22 -32
  265. package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +6 -3
  266. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +8 -2
  267. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +260 -0
  268. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +263 -0
  269. package/templates/apps/web/app/[locale]/(authed)/account/sign-out-button.tsx +39 -0
  270. package/templates/apps/web/app/[locale]/(authed)/layout.tsx +54 -0
  271. package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +96 -0
  272. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx +309 -0
  273. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx +149 -0
  274. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/comparison.test.tsx +273 -0
  275. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/gate.test.tsx +172 -0
  276. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/list.test.tsx +171 -0
  277. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/signup.test.tsx +179 -0
  278. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx +116 -0
  279. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ForbiddenState.tsx +24 -0
  280. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx +66 -0
  281. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx +61 -0
  282. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx +114 -0
  283. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx +139 -0
  284. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx +85 -0
  285. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx +67 -0
  286. package/templates/apps/web/app/[locale]/(authed)/waitlist/format.ts +111 -0
  287. package/templates/apps/web/app/[locale]/(authed)/waitlist/page.tsx +179 -0
  288. package/templates/apps/web/app/[locale]/about/page.tsx +10 -1
  289. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +6 -1
  290. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +9 -0
  291. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +3 -3
  292. package/templates/apps/web/app/[locale]/careers/page.tsx +9 -1
  293. package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +9 -0
  294. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +3 -3
  295. package/templates/apps/web/app/[locale]/case-studies/page.tsx +13 -1
  296. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +11 -1
  297. package/templates/apps/web/app/[locale]/clients/page.tsx +9 -1
  298. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +21 -1
  299. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +188 -0
  300. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +242 -0
  301. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +29 -0
  302. package/templates/apps/web/app/[locale]/contact/__tests__/intake-analytics.test.ts +51 -0
  303. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +39 -15
  304. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +21 -3
  305. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +49 -0
  306. package/templates/apps/web/app/[locale]/contact/intake-script.ts +66 -0
  307. package/templates/apps/web/app/[locale]/contact/page.tsx +14 -4
  308. package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +13 -1
  309. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +3 -3
  310. package/templates/apps/web/app/[locale]/courses/page.tsx +9 -1
  311. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +1 -0
  312. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +11 -1
  313. package/templates/apps/web/app/[locale]/downloads/page.tsx +13 -1
  314. package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +9 -0
  315. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +12 -2
  316. package/templates/apps/web/app/[locale]/events/page.tsx +9 -1
  317. package/templates/apps/web/app/[locale]/faq/page.tsx +10 -1
  318. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +265 -0
  319. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +445 -0
  320. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +341 -0
  321. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/checkout.actions.test.ts +287 -0
  322. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/flow.actions.test.ts +302 -0
  323. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +128 -0
  324. package/templates/apps/web/app/[locale]/flows/[slug]/checkout.actions.ts +254 -0
  325. package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +144 -0
  326. package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +108 -0
  327. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx +532 -0
  328. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx +121 -0
  329. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/ResultsClient.checkout.test.tsx +457 -0
  330. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/page.test.tsx +396 -0
  331. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx +114 -0
  332. package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +52 -0
  333. package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +13 -1
  334. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
  335. package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +9 -0
  336. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +3 -3
  337. package/templates/apps/web/app/[locale]/integrations/page.tsx +13 -1
  338. package/templates/apps/web/app/[locale]/launch-service/page.tsx +14 -1
  339. package/templates/apps/web/app/[locale]/layout.tsx +127 -16
  340. package/templates/apps/web/app/[locale]/page.tsx +10 -1
  341. package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +9 -0
  342. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +3 -3
  343. package/templates/apps/web/app/[locale]/partners/page.tsx +9 -1
  344. package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +9 -0
  345. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +3 -3
  346. package/templates/apps/web/app/[locale]/products/page.tsx +9 -1
  347. package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +13 -1
  348. package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +10 -0
  349. package/templates/apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx +110 -0
  350. package/templates/apps/web/app/[locale]/projects/apply/__tests__/ListingApplicationClient.test.tsx +96 -0
  351. package/templates/apps/web/app/[locale]/projects/page.tsx +13 -1
  352. package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +9 -0
  353. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +12 -2
  354. package/templates/apps/web/app/[locale]/resources/page.tsx +13 -1
  355. package/templates/apps/web/app/[locale]/schedule/__tests__/page.test.tsx +117 -0
  356. package/templates/apps/web/app/[locale]/schedule/confirmed/__tests__/page.test.tsx +96 -0
  357. package/templates/apps/web/app/[locale]/schedule/confirmed/page.tsx +92 -0
  358. package/templates/apps/web/app/[locale]/schedule/page.tsx +82 -0
  359. package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +9 -0
  360. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +3 -3
  361. package/templates/apps/web/app/[locale]/services/page.tsx +9 -1
  362. package/templates/apps/web/app/[locale]/sign-in/__tests__/next-path.test.ts +31 -0
  363. package/templates/apps/web/app/[locale]/sign-in/__tests__/page.test.tsx +152 -0
  364. package/templates/apps/web/app/[locale]/sign-in/next-path.ts +0 -0
  365. package/templates/apps/web/app/[locale]/sign-in/page.tsx +83 -0
  366. package/templates/apps/web/app/[locale]/sign-in/sign-in-card.tsx +123 -0
  367. package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +13 -1
  368. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
  369. package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +13 -1
  370. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
  371. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +11 -1
  372. package/templates/apps/web/app/[locale]/testimonials/page.tsx +13 -1
  373. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +93 -0
  374. package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +48 -0
  375. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +11 -1
  376. package/templates/apps/web/app/[locale]/use-cases/page.tsx +13 -1
  377. package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +13 -1
  378. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
  379. package/templates/apps/web/app/globals.css +35 -0
  380. package/templates/apps/web/app/llms.txt/route.ts +2 -1
  381. package/templates/apps/web/app/og/route.tsx +10 -2
  382. package/templates/apps/web/auth.ts +8 -0
  383. package/templates/apps/web/components/sign-out-trigger.tsx +42 -0
  384. package/templates/apps/web/content/en/blog/README.txt +25 -0
  385. package/templates/apps/web/content/en/docs/index.mdx +28 -0
  386. package/templates/apps/web/jest.config.cjs +90 -27
  387. package/templates/apps/web/lib/__tests__/site-brand.test.ts +119 -0
  388. package/templates/apps/web/lib/__tests__/site-theme.test.ts +112 -0
  389. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +499 -0
  390. package/templates/apps/web/lib/account-config.ts +13 -0
  391. package/templates/apps/web/lib/server-api.ts +85 -0
  392. package/templates/apps/web/lib/site-brand.tsx +121 -0
  393. package/templates/apps/web/lib/site-theme.ts +74 -0
  394. package/templates/apps/web/messages/en.json +275 -7
  395. package/templates/apps/web/middleware.ts +11 -3
  396. package/templates/apps/web/next.config.mjs +8 -2
  397. package/templates/apps/web/package.json +17 -7
  398. package/templates/apps/web/postcss.config.mjs +23 -0
  399. package/templates/apps/web/public/.well-known/security.txt +3 -3
  400. package/templates/apps/web/src/lib/routes.ts +15 -2
  401. package/templates/apps/web/tsconfig.json +1 -16
  402. package/templates/content/_site.mdx +36 -25
  403. package/templates/content/en/AboutPage/about.mdx +24 -14
  404. package/templates/content/en/ContactPage/contact.mdx +23 -14
  405. package/templates/content/en/FAQPage/faq.mdx +10 -392
  406. package/templates/content/en/HomePage/home.mdx +14 -285
  407. package/templates/database/CHANGELOG.md +443 -0
  408. package/templates/database/LICENSE +201 -0
  409. package/templates/database/README.md +3 -1
  410. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +392 -0
  411. package/templates/database/__tests__/flows-presets.test.ts +173 -0
  412. package/templates/database/__tests__/prefixed-ids.db.test.ts +146 -0
  413. package/templates/database/__tests__/seed.test.ts +88 -0
  414. package/templates/database/__tests__/user-cascade.test.ts +19 -4
  415. package/templates/database/auth/schema.prisma +521 -0
  416. package/templates/database/config/schema.prisma +234 -0
  417. package/templates/database/content/schema.prisma +263 -0
  418. package/templates/database/flows/listing-diagnostic.ts +182 -0
  419. package/templates/database/flows/presets.ts +315 -0
  420. package/templates/database/inbox/__tests__/schema.test.ts +4 -0
  421. package/templates/database/inbox/schema.prisma +574 -3
  422. package/templates/database/jest.config.cjs +8 -0
  423. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +201 -0
  424. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +67 -0
  425. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +46 -0
  426. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +25 -0
  427. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +49 -0
  428. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +197 -0
  429. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +32 -0
  430. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +22 -0
  431. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +151 -0
  432. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +223 -0
  433. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +22 -0
  434. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +32 -0
  435. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +40 -0
  436. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +4 -0
  437. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +2 -0
  438. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +2 -0
  439. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +29 -0
  440. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +6 -0
  441. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +39 -0
  442. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +24 -0
  443. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +3 -0
  444. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +33 -0
  445. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +30 -0
  446. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +47 -0
  447. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +16 -0
  448. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +47 -0
  449. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +10 -0
  450. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +26 -0
  451. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +90 -0
  452. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +174 -0
  453. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +14 -0
  454. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +25 -0
  455. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +32 -0
  456. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +71 -0
  457. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +30 -0
  458. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +49 -0
  459. package/templates/database/ops/schema.prisma +27 -0
  460. package/templates/database/package.json +42 -4
  461. package/templates/database/prisma.config.ts +1 -1
  462. package/templates/database/schema.prisma +19 -435
  463. package/templates/database/seed-test.ts +14 -4
  464. package/templates/database/seed.ts +148 -0
  465. package/templates/database/tenancy.ts +45 -0
  466. package/templates/database/tsconfig.flows.json +15 -0
  467. package/templates/database/tsconfig.json +7 -1
  468. package/templates/database/tsconfig.tenancy.json +14 -0
  469. package/templates/package.json +30 -55
  470. package/templates/pnpm-workspace.yaml +0 -3
  471. package/templates/project.yaml +1 -1
  472. package/templates/tsconfig.json +1 -37
  473. package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +0 -94
  474. package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +0 -75
  475. package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +0 -82
  476. package/templates/apps/web/__tests__/auth/env-helpers.test.ts +0 -168
  477. package/templates/apps/web/__tests__/authority-list-routes.test.tsx +0 -208
  478. package/templates/apps/web/__tests__/better-stack.test.ts +0 -66
  479. package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +0 -87
  480. package/templates/apps/web/__tests__/blog-source-populated.test.ts +0 -130
  481. package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +0 -60
  482. package/templates/apps/web/__tests__/google-analytics.test.tsx +0 -104
  483. package/templates/apps/web/__tests__/i18n/middleware.test.ts +0 -119
  484. package/templates/apps/web/__tests__/i18n/routing.test.ts +0 -114
  485. package/templates/apps/web/__tests__/i18n/translations.test.ts +0 -191
  486. package/templates/apps/web/__tests__/json-ld.test.ts +0 -98
  487. package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +0 -580
  488. package/templates/apps/web/__tests__/layout-stealth.test.ts +0 -39
  489. package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +0 -103
  490. package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +0 -114
  491. package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +0 -94
  492. package/templates/apps/web/__tests__/page.test.tsx +0 -230
  493. package/templates/apps/web/__tests__/products-services-phase1.test.tsx +0 -321
  494. package/templates/apps/web/__tests__/projects-routes.test.tsx +0 -392
  495. package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +0 -475
  496. package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +0 -53
  497. package/templates/apps/web/__tests__/routes/blog-route.test.tsx +0 -191
  498. package/templates/apps/web/__tests__/routes/llms-txt.test.ts +0 -123
  499. package/templates/apps/web/__tests__/routes/robots-txt.test.ts +0 -52
  500. package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +0 -78
  501. package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +0 -203
  502. package/templates/apps/web/__tests__/section-routes.test.tsx +0 -693
  503. package/templates/apps/web/__tests__/security-headers.test.ts +0 -201
  504. package/templates/apps/web/__tests__/sentry-config.test.ts +0 -116
  505. package/templates/apps/web/__tests__/sitemap-locales.test.ts +0 -415
  506. package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +0 -844
  507. package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +0 -120
  508. package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +0 -202
  509. package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +0 -152
  510. package/templates/apps/web/content/en/blog/index.mdx +0 -15
  511. package/templates/apps/web/content/en/blog/launching-ailk.mdx +0 -20
  512. package/templates/apps/web/content/en/docs/getting-started.mdx +0 -30
  513. package/templates/content/.gitkeep +0 -0
  514. package/templates/content/CLAUDE.md +0 -85
  515. package/templates/content/ar/HomePage/home.mdx +0 -123
  516. package/templates/content/ar/_site.mdx +0 -35
  517. package/templates/content/de/_site.mdx +0 -29
  518. package/templates/content/en/.gitkeep +0 -0
  519. package/templates/content/en/AboutPage/about.schema.json +0 -82
  520. package/templates/content/en/BookCall/book-call.mdx +0 -19
  521. package/templates/content/en/BookCall/book-call.schema.json +0 -121
  522. package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +0 -20
  523. package/templates/content/en/CareersList/careers.mdx +0 -24
  524. package/templates/content/en/CaseStudiesList/case-studies.mdx +0 -22
  525. package/templates/content/en/CaseStudiesList/showcase.mdx +0 -8
  526. package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +0 -32
  527. package/templates/content/en/CaseStudy/schema-builder-migration.mdx +0 -41
  528. package/templates/content/en/ClientsList/clients.mdx +0 -38
  529. package/templates/content/en/ContactPage/contact.schema.json +0 -100
  530. package/templates/content/en/ContactPoint/primary.mdx +0 -14
  531. package/templates/content/en/Course/aeo-fundamentals.mdx +0 -37
  532. package/templates/content/en/Course/schema-builder-workshop.mdx +0 -62
  533. package/templates/content/en/CoursesList/courses.mdx +0 -22
  534. package/templates/content/en/DownloadsList/downloads.mdx +0 -22
  535. package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +0 -39
  536. package/templates/content/en/Event/ailk-launch-day-2026.mdx +0 -35
  537. package/templates/content/en/EventsList/events.mdx +0 -26
  538. package/templates/content/en/FAQPage/faq.schema.json +0 -231
  539. package/templates/content/en/GlossaryList/glossary.mdx +0 -19
  540. package/templates/content/en/GlossaryList/glossary.schema.json +0 -300
  541. package/templates/content/en/HomePage/home.schema.json +0 -88
  542. package/templates/content/en/HomePage/launch-service.mdx +0 -475
  543. package/templates/content/en/HomePage/launch-service.schema.json +0 -138
  544. package/templates/content/en/HowTo/add-mdx-content.mdx +0 -38
  545. package/templates/content/en/HowTo/configure-aeo-scoring.mdx +0 -35
  546. package/templates/content/en/HowTo/set-up-json-ld.mdx +0 -36
  547. package/templates/content/en/Integration/github-actions.mdx +0 -31
  548. package/templates/content/en/Integration/openai-api.mdx +0 -26
  549. package/templates/content/en/Integration/vercel.mdx +0 -32
  550. package/templates/content/en/IntegrationsList/integrations.mdx +0 -22
  551. package/templates/content/en/JobPosting/content-strategist.mdx +0 -46
  552. package/templates/content/en/JobPosting/developer-advocate.mdx +0 -47
  553. package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +0 -57
  554. package/templates/content/en/LandingPage/aeo-audit.mdx +0 -19
  555. package/templates/content/en/LandingPage/aeo-audit.schema.json +0 -92
  556. package/templates/content/en/LandingPage/agency-waitlist.mdx +0 -340
  557. package/templates/content/en/LandingPage/agency-waitlist.schema.json +0 -152
  558. package/templates/content/en/LandingPage/developers.mdx +0 -19
  559. package/templates/content/en/LandingPage/developers.schema.json +0 -109
  560. package/templates/content/en/LandingPage/for-agencies.mdx +0 -390
  561. package/templates/content/en/LandingPage/for-agencies.schema.json +0 -107
  562. package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +0 -417
  563. package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +0 -105
  564. package/templates/content/en/LandingPage/for-businesses.mdx +0 -19
  565. package/templates/content/en/LandingPage/for-businesses.schema.json +0 -96
  566. package/templates/content/en/LandingPage/platform.mdx +0 -369
  567. package/templates/content/en/LandingPage/platform.schema.json +0 -166
  568. package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +0 -19
  569. package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +0 -102
  570. package/templates/content/en/LandingPage/vs-wordpress.mdx +0 -19
  571. package/templates/content/en/LandingPage/vs-wordpress.schema.json +0 -53
  572. package/templates/content/en/NewsletterSignup/newsletter.mdx +0 -236
  573. package/templates/content/en/NewsletterSignup/newsletter.schema.json +0 -91
  574. package/templates/content/en/Organization/site-owner.mdx +0 -16
  575. package/templates/content/en/Partner/prisma.mdx +0 -31
  576. package/templates/content/en/Partner/supabase.mdx +0 -30
  577. package/templates/content/en/Partner/vercel.mdx +0 -28
  578. package/templates/content/en/PartnersList/partners.mdx +0 -22
  579. package/templates/content/en/Person/founder.mdx +0 -18
  580. package/templates/content/en/Pricing/pricing.mdx +0 -538
  581. package/templates/content/en/Pricing/pricing.schema.json +0 -209
  582. package/templates/content/en/PrivacyPage/privacy.mdx +0 -165
  583. package/templates/content/en/PrivacyPage/privacy.schema.json +0 -64
  584. package/templates/content/en/Product/ailk.mdx +0 -19
  585. package/templates/content/en/Product/ailk.schema.json +0 -94
  586. package/templates/content/en/Product/api-launch-kit.mdx +0 -26
  587. package/templates/content/en/Product/launch-kit.mdx +0 -28
  588. package/templates/content/en/ProductsList/products.mdx +0 -26
  589. package/templates/content/en/Project/ailk-phase-2.mdx +0 -54
  590. package/templates/content/en/ProjectsList/projects.mdx +0 -25
  591. package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +0 -27
  592. package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +0 -28
  593. package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +0 -39
  594. package/templates/content/en/ResourcesHub/resources.mdx +0 -22
  595. package/templates/content/en/Service/consulting.mdx +0 -22
  596. package/templates/content/en/Service/implementation.mdx +0 -30
  597. package/templates/content/en/Service/launch-service.mdx +0 -232
  598. package/templates/content/en/Service/launch.mdx +0 -228
  599. package/templates/content/en/ServicesList/services.mdx +0 -84
  600. package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +0 -44
  601. package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +0 -47
  602. package/templates/content/en/SoftwareProduct/ailk-schema.mdx +0 -49
  603. package/templates/content/en/TeamList/team.mdx +0 -63
  604. package/templates/content/en/TeamMember/founder.mdx +0 -72
  605. package/templates/content/en/TermsPage/terms.mdx +0 -19
  606. package/templates/content/en/TermsPage/terms.schema.json +0 -99
  607. package/templates/content/en/TestimonialsList/testimonials.mdx +0 -44
  608. package/templates/content/en/UseCasesList/use-cases.mdx +0 -30
  609. package/templates/content/en/Whitepaper/ax-first-product-development.mdx +0 -27
  610. package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +0 -27
  611. package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +0 -31
  612. package/templates/content/en-XA/AboutPage/about.mdx +0 -8
  613. package/templates/content/en-XA/FAQPage/faq.mdx +0 -8
  614. package/templates/content/en-XA/HomePage/home.mdx +0 -8
  615. package/templates/content/es/_site.mdx +0 -30
  616. package/templates/content/fr/_site.mdx +0 -30
  617. package/templates/content/ja/_site.mdx +0 -30
  618. package/templates/content/pt-BR/AboutPage/about.mdx +0 -8
  619. package/templates/content/pt-BR/FAQPage/faq.mdx +0 -8
  620. package/templates/content/pt-BR/HomePage/home.mdx +0 -23
@@ -0,0 +1,456 @@
1
+ # AILK component catalog — search by capability, not by name
2
+
3
+ <!-- GENERATED FILE — do not hand-edit. Regenerate with `pnpm --filter create-ailk run build-catalog`. -->
4
+
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
+
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.
10
+
11
+ **Before you build a component, search this file for what it DOES.**
12
+
13
+ 1. Read **Find by capability** below — it maps the words people actually type to the names AILK uses.
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.
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.
16
+ 4. Only then build. If you do build, you are declaring the capability is genuinely absent.
17
+
18
+ Inventory: **286 component files** across 6 tiers — 59 sections, 115 blocks, 18 chrome, 79 primitives, 7 panels, 8 shells. 283 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: **282/286** components carry a capability description derived from source — 41 from the section registry's hand-authored when-to-use text, 204 from the component's own doc-comment header, 37 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.
21
+
22
+ Of those, **252** are *strong* — a capability sentence you could match a requirement against — and **30** 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%**.
23
+
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** 3/8. A tier low on this line is a tier where a capability search is most likely to come up empty on something that exists.
25
+
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.
27
+
28
+ ---
29
+
30
+ ## Find by capability
31
+
32
+ The left column is search vocabulary — how a person phrases the need. It is hand-authored (no source file calls `FormLightbox` a "contact overlay"), but every component named on the right is checked against the live inventory when this file is generated, so a row can never point at a component that no longer exists.
33
+
34
+ | If you are looking for… | Use | Notes |
35
+ | --- | --- | --- |
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. |
37
+ | 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. |
38
+ | 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. |
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. |
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. |
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. |
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. |
43
+ | logo wall · client logos · trusted by · partner marks | `LogoCloud` (sections) · `Awards` (sections) | |
44
+ | pricing table · plan comparison · feature matrix · tier cards | `Pricing` (sections) · `PricingTierCard` (blocks) · `ComparisonMatrix` (blocks) · `ComparisonTable` (sections) · `BillingToggle` (blocks) | |
45
+ | avatar stack · people grid · about-us team · bios | `Team` (sections) · `TeamMemberCard` (blocks) | |
46
+ | booking · scheduling · calendar · pick a time · appointment | `Booker` (sections) · `SchedulerEmbed` (blocks) | Booker is the in-page day-strip/slot-grid transaction; SchedulerEmbed is the third-party provider iframe. |
47
+ | sign in · sign up · login form · oauth buttons · account menu | `AuthPanel` (sections) · `AuthCard` (blocks) · `AccountMenu` (chrome) | |
48
+ | email capture · newsletter signup · subscribe box | `Newsletter` (sections) · `NewsletterFormInline` (blocks) · `NewsletterDetail` (blocks) | |
49
+ | video player · embedded video · video modal | `VideoSection` (sections) · `VideoEmbed` (blocks) · `VideoLightbox` (blocks) | |
50
+ | image slider · gallery · carousel · lightbox for images | `Carousel` (sections) · `Gallery` (sections) · `MediaBand` (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) · `DocsTocButton` (blocks) · `DocumentChassis` (sections) | |
53
+
54
+ ---
55
+
56
+ ## Sections (59)
57
+
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.
59
+
60
+ Import: `import { X } from "@working-theory/ui/sections";` (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.
61
+
62
+ | Component | What it does | How to use it |
63
+ | --- | --- | --- |
64
+ | `AlertSection` | A compact, dismissible in-page alert strip — use for a confirmation or status notice (e.g. a delivery-page 'your download is on its way' message), typically the first section on the page. Bounded to success/info/warning tone; dismissal persists per-visitor. | MDX `type: alert` |
65
+ | `AlertSectionDismissIsland` | Dismiss state + × button for AlertSection. Mirrors the chrome Banner's dismiss-persistence precedent (`packages/ui/src/chrome/BannerDismissIsland.tsx`): a localStorage-backed dismissed flag, read on mount and written on dismiss, with graceful degradation when localStorage is unavailable (SSR, iframe, quota, etc.). | internal — compose from `packages/ui/src/sections/AlertSectionDismissIsland.tsx` |
66
+ | `AskAi` | Use above the footer — hands the visitor to a third-party AI seeded with the entity question. Bounded to five measured providers (ChatGPT/Claude/Google AI/Grok/Perplexity), each deep-linked with an authored prompt. The `ticker` variant renders a compact full-width band instead of the default headline/description/provider-row layout. | MDX `type: ask-ai` |
67
+ | `AuthPanel` | A sign-in/sign-up panel with an optional bounded OAuth provider row (google, github) — UI-contract only, no auth backend; submit and provider clicks are callback props the composing page wires up. | MDX `type: auth-panel` · `import { AuthPanel } from "@working-theory/ui/sections"` |
68
+ | `Awards` | A two-column evidence band — headline/CTA left, up to 5 award or press badges right — use for third-party recognition (badges may render as labeled placeholders until real marks are supplied). | MDX `type: awards` |
69
+ | `BentoGrid` | A mixed-span mosaic of feature cards — use for a visually varied capability overview. | MDX `type: bento-grid` · `import { BentoGrid } from "@working-theory/ui/sections"` |
70
+ | `BlogList` | A blog post list with pagination — use for the blog index page only. | MDX `type: blog-list` · `import { BlogList } from "@working-theory/ui/sections"` |
71
+ | `BlogPost` | A single blog post body with TOC and related posts — use only on the blog-post chassis. | MDX `type: blog-post` · `import { BlogPost } from "@working-theory/ui/sections"` |
72
+ | `Booker` | The custom booker — use on a scheduling page where the whole see-days/pick-slot/confirm transaction should land in the page itself rather than a provider iframe (the `scheduler-embed` alternative). Authors supply only `calLink` plus optional eyebrow/headline framing; duration, meeting type, and timezone are DERIVED from the calendar via /v1/schedule/availability and can never be typed into content. | MDX `type: booker` |
73
+ | `BookerIsland` | The island owns exactly two things: the state machine, and the two calls across the scheduling seam. It talks to `/v1/schedule/availability` and `/v1/schedule/book` — never to a provider — so the day this deploy flips to the self-hosted engine, nothing in this file changes. | internal — compose from `packages/ui/src/sections/BookerIsland.tsx` |
74
+ | `Carousel` | An image carousel/slider — use for a sequential set of visual items in constrained space. | MDX `type: carousel` · `import { Carousel } from "@working-theory/ui/sections"` |
75
+ | `ComparisonTable` | A general-purpose entity-vs-entity comparison — use for /vs pages, not tied to pricing plans. | MDX `type: comparison-table` |
76
+ | `ContactChannels` | A support channel directory — use to list alternate ways to reach the team (icon + title + description + CTA). | MDX `type: contact-channels` · `import { ContactChannels } from "@working-theory/ui/sections"` |
77
+ | `ContactForm` | A contact form with typed fields — use as the primary conversion action on Contact pages. | MDX `type: contact-form` · `import { ContactForm } from "@working-theory/ui/sections"` |
78
+ | `ContentBlock` | Long-form prose with optional media — use for narrative explanation that doesn't fit a card grid. | MDX `type: content-block` |
79
+ | `CTA` | A focused call-to-action block — use to end a page or section with one clear next step. | MDX `type: cta` · `import { CTA } from "@working-theory/ui/sections"` |
80
+ | `DecisionSplit` | An honest either-option decision block — use on /vs pages before any comparison. | MDX `type: decision-split` |
81
+ | `Definition` | A single-term definition callout — use for one prominent 'What is X?' answer-first block. | MDX `type: definition` |
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` |
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"` |
87
+ | `Feature` | A multi-item benefit/feature highlight grid — use to walk through several product capabilities. | MDX `type: feature` |
88
+ | `FlowStepper` | Rendering a served flow config as a real multi-step form. | `import { FlowStepper } from "@working-theory/ui/sections"` |
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"` |
90
+ | `Gallery` | An image gallery — use to showcase product screenshots or visual work. | MDX `type: gallery` · `import { Gallery } from "@working-theory/ui/sections"` |
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"` |
92
+ | `Hero` | Top-of-page introduction — headline, optional subhead and CTAs; use once per page as the first section. | MDX `type: hero` · `import { Hero } from "@working-theory/ui/sections"` |
93
+ | `HeroFormSlot` | The panel hero's right-column gate card: a `FormCard` wrapping either the consumer's conversational intake (when eligible and a `HeroIntakeProvider` is mounted) or the embedded multi-step `StepFlow`, which is also where `controls.showForm` hands the surface over. /. | `import { HeroFormSlot } from "@working-theory/ui/sections"` |
94
+ | `HeroIntakeContext` | The bounded seam through which a consumer page mounts its own conversational intake as the FIRST surface INSIDE one of Hero's existing gate surfaces (the `lightboxCta` FormLightbox, or the panel variant's form-slot card), with the existing multi-step StepFlow as the in-gate fallback (correcting 's whole-page swap). | `import { HeroIntakeContext } from "@working-theory/ui/sections"` |
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"` |
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` |
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"` |
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. | `import { ListingApplicationFlow } from "@working-theory/ui/sections"` |
99
+ | `LogoCloud` | A customer/partner logo wall — use for trust-by-association social proof. | MDX `type: logoCloud` · `import { LogoCloud } from "@working-theory/ui/sections"` |
100
+ | `MDXContent` | The keystone the docs route and blog both render their compiled MDX through. | `import { MDXContent } from "@working-theory/ui/sections"` |
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"` |
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` |
103
+ | `Newsletter` | An email signup form — use for a low-commitment conversion ask. | MDX `type: newsletter` · `import { Newsletter } from "@working-theory/ui/sections"` |
104
+ | `Objection` | Objection-and-response pairs — use for you-might-think rhetoric that isn't phrased as a question. | MDX `type: objection` |
105
+ | `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"` |
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"` |
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. | `import { PricingTable } from "@working-theory/ui/sections"` |
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. | `import { ProjectListingShelves } from "@working-theory/ui/sections"` |
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` |
110
+ | `SectionEmpty` | The shared empty-state body every section's `*Empty` variant delegates to. | `import { SectionEmpty } from "@working-theory/ui/sections"` |
111
+ | `SectionRenderer` | Typed dispatch table. Maps a section's `type` discriminant to its React component. | `import { SectionRenderer } 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` |
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"` |
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"` |
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"` |
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"` |
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` |
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"` |
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` |
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"` |
121
+ | `Testimonials` | Direct customer quotes — use for first-person social proof with attribution. | MDX `type: testimonials` |
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"` |
123
+
124
+ ---
125
+
126
+ ## Blocks (115)
127
+
128
+ Intermediate composition tiles — the pieces sections are built from. Compose primitives and panels; never import a section.
129
+
130
+ Import: `import { X } from "@working-theory/ui/blocks";` (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.
131
+
132
+ | Component | What it does | How to use it |
133
+ | --- | --- | --- |
134
+ | `AddonCard` | Apollo.io-pattern add-on tile: header-area eyebrow+name+price, optional qualifier/CTA, titled or plain-string feature rows with a selectable checkmark tone (Pricing addons variant). | `import { AddonCard } from "@working-theory/ui/blocks"` |
135
+ | `AddressFieldset` | The composite control for StepFlow's "address" field type. No such component existed in the library before this — built by composing the existing Field/Input/Select primitives, no bespoke markup, no new primitive. Mirrors PhoneNumberField's division of labor for the "tel" field type: this block renders the six named controls; the consuming section combines/reads them, it does no combining itself. | `import { AddressFieldset } from "@working-theory/ui/blocks"` |
136
+ | `AgentContextCard` | Capability-bearing block that renders agent provenance. RSC note: no hooks or browser APIs — server-renderable by default. *(weak)* | `import { AgentContextCard } from "@working-theory/ui/blocks"` |
137
+ | `ArticleHeaderAtoms` | They define the title / meta-line / tags / back-link / action-bar treatment ONCE so the docs and blog headers cannot drift. `DocsArticleHeader` (top layout) and `BlogPostHeader` (sticky-rail layout) are thin wrappers that COMPOSE these atoms — there is no `layout` switch or stack of `show*` booleans; the two arrangements differ only in which atoms each wrapper places and in what order. | `import { ArticleHeaderAtoms } from "@working-theory/ui/blocks"` |
138
+ | `ArticlePager` | The footer prev/next pager. Given the previous and next destinations — docs pages in tree order, or blog posts in date order — renders two link tiles (a directional label + the destination title). Either side may be absent (first / last item) — the present side still anchors to its edge. Renders nothing when both sides are absent. | `import { ArticlePager } from "@working-theory/ui/blocks"` |
139
+ | `AskAiCommandGroup` | The ⌘K palette's composable "Ask AI" group; one CommandItem per provider seeding "About &lt;entity>: &lt;query>" (or the entity promptText when the query is empty); composed by the consumer's own CommandDialog. | `import { AskAiCommandGroup } from "@working-theory/ui/blocks"` |
140
+ | `AskAiProviderRow` | The ONE shared provider-link row every ask-AI placement composes — the AskAi section (band + ticker variant) and the Hero `askAi` opt-in all render THIS block, never a per-placement fork. Renders a bounded set of five measured providers, each a deep link seeded with an AUTHORED `promptText` — the prompt is always consumer-supplied data, never derived from page context (headline, entity name, etc.). | `import { AskAiProviderRow } from "@working-theory/ui/blocks"` |
141
+ | `AuthCard` | Logo (top-center, inside). Axes: intent: "sign-in" \| "sign-up" — drives heading / subhead / footer copy. method: "password" \| "magic-link" \| "sso" — drives the body + primary action. | `import { AuthCard } from "@working-theory/ui/blocks"` |
142
+ | `AwardBadgePlaceholder` | The labeled placeholder an Awards badge slot renders when no image has been supplied — mirrors MediaPlaceholder's role but in an award-chevron/ laurel badge silhouette rather than a generic photo frame, since an unfilled award slot should read as "an award badge goes here," not "a photo goes here." The shape (a laurel-flanked medallion over a chevron ribbon) is a hand-drawn SVG outline — never a copied G2/Capterra/Apollo asset. | internal — compose from `packages/ui/src/blocks/AwardBadgePlaceholder.tsx` |
143
+ | `BackgroundPattern` | Decorative SVG dot-grid / line pattern for ContactForm section. Decorative block (generalized beyond its original single consumer). Renders an absolutely-positioned decoration behind a section's content. Originally the pattern anchored behind ContactForm's form column; SpotlightPanel composes it as a full-bleed section backdrop (dimmed + blurred, behind a centered card) — same block, a second placement. | `import { BackgroundPattern } from "@working-theory/ui/blocks"` |
144
+ | `BadgeRow` | Horizontal cluster of static badge labels used by Hero and Feature section families for `data.badge` and tag-list patterns. | `import { BadgeRow } from "@working-theory/ui/blocks"` |
145
+ | `BillingToggle` | Monthly / Annual billing period toggle for the Pricing section. Purely presentational — click handlers come from the parent (Pricing section). No "use client" needed at the block level; the parent Pricing section is "use client" and passes the callbacks down. | `import { BillingToggle } from "@working-theory/ui/blocks"` |
146
+ | `BlogPostHeader` | Layout: the better-auth sticky left rail — eyebrow ← back-link · decorative title · author byline · date/reading-time meta · tags. Per the title here is DECORATIVE (aria-hidden): the semantic `&lt;h1>` is rendered atop the right content column by `BlogPost` (bodyOnly), so the page keeps exactly one heading. | `import { BlogPostHeader } from "@working-theory/ui/blocks"` |
147
+ | `BookerAttendeeFields` | TWO FIELDS. A booking needs somewhere to send the invite and a name to put on it; every additional field is one more reason to abandon a transaction the user had already decided to complete. Notes, phone, and company are deliberately absent — the provider collects them after the invite lands, if the operator wants them at all. | internal — compose from `packages/ui/src/blocks/BookerAttendeeFields.tsx` |
148
+ | `BookerDateStrip` | ONLY DAYS THAT HAVE OPEN SLOTS APPEAR. That is the structural argument this block makes, and the reason the composition is a horizontal strip rather than the month grid every booking widget reaches for: a month grid spends its whole area rendering the ~24 days you cannot book, then needs a second interaction to reveal which of the remaining six are live. | internal — compose from `packages/ui/src/blocks/BookerDateStrip.tsx` |
149
+ | `BookerEventHeader` | TWO KINDS OF TEXT, AND THE DIFFERENCE MATTERS. `eyebrow` and `headline` are AUTHORED: the operator's words about why someone would book. Everything in the meta row — duration, meeting type, timezone — is DERIVED from the calendar on the availability read, which is why the section schema has no field for any of it. | internal — compose from `packages/ui/src/blocks/BookerEventHeader.tsx` |
150
+ | `BookerPanel` | The booking card, fully controlled. One chassis, five views, ONE FOOTER. | internal — compose from `packages/ui/src/blocks/BookerPanel.tsx` |
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` |
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"` |
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"` |
154
+ | `CheckoutForm` | Product/amount selection + checkout submit for the one-time checkout surface. | `import { CheckoutForm } from "@working-theory/ui/blocks"` |
155
+ | `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"` |
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"` |
157
+ | `CodeBlock` | Read-only code display with syntax highlighting. Modeled on the Claude docs code-block pattern. | `import { CodeBlock } from "@working-theory/ui/blocks"` |
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"` |
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"` |
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"` |
163
+ | `ContactFormFields` | Renders the form field grid (Input / Textarea / Select primitives) + submit Button + optional consent text footer. | `import { ContactFormFields } from "@working-theory/ui/blocks"` |
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"` |
165
+ | `ConversationalIntake` | The UI half of the conversational-intake feature: renders the transcript, closed-question answer pills, a free-text form, a thinking indicator, and Skip — driven entirely through the `NextTurn` interface exported by `./engine` (merged). | internal — compose from `packages/ui/src/blocks/conversational-intake/ConversationalIntake.tsx` |
166
+ | `DescriptionList` | Semantic &lt;dl> of aligned term/definition rows (rows + inline layouts). A semantic &lt;dl> rendering label/value rows from an `items` prop. Each item is a &lt;dt> (muted, min-width-aligned term) paired with a &lt;dd> (value). The value is a ReactNode, so callers compose richer values (spans, lists, mono text) inside it. | `import { DescriptionList } from "@working-theory/ui/blocks"` |
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"` |
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"` |
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"` |
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. | `import { DocsActionBar } from "@working-theory/ui/blocks"` |
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. | `import { DocsArticleHeader } from "@working-theory/ui/blocks"` |
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. | `import { DocsFeedback } from "@working-theory/ui/blocks"` |
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. | `import { DocsSearch } from "@working-theory/ui/blocks"` |
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. | `import { DocsTocButton } from "@working-theory/ui/blocks"` |
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"` |
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"` |
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"` |
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"` |
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` |
180
+ | `FlowSidePanel` | The per-view side panel of the flow/recommender surface. ONE CHASSIS, THREE VIEWS. | `import { FlowSidePanel } from "@working-theory/ui/blocks"` |
181
+ | `FooterBottomBar` | Separator + copyright line (+ optional trailing social). Bottom bar with a single top divider + copyright line. | `import { FooterBottomBar } from "@working-theory/ui/blocks"` |
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"` |
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"` |
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"` |
185
+ | `InvoiceForm` | Draft-invoice creation form. Creates a draft invoice (single line item), for the invoice surface (U4). | `import { InvoiceForm } from "@working-theory/ui/blocks"` |
186
+ | `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"` |
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` |
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"` |
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"` |
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. | `import { ListingFullPreview } from "@working-theory/ui/blocks"` |
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. | `import { ListingPrivacyNotice } from "@working-theory/ui/blocks"` |
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`). | `import { ListingQuestionReview } from "@working-theory/ui/blocks"` |
193
+ | `ListingTilePreview` | The founder's tile, as it will look, updating as they type. | `import { ListingTilePreview } from "@working-theory/ui/blocks"` |
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"` |
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"` |
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"` |
197
+ | `MediaFigure` | The reusable *frame* for the visual half of a split section: an `Image` constrained by an optional `AspectRatio`, with consistent rounding, an optional caption, an optional decorative frame, and an optional overlay slot + scrim for text/badges/play-buttons over media. | `import { MediaFigure } from "@working-theory/ui/blocks"` |
198
+ | `MediaPlaceholder` | The single shared labeled placeholder a declared IMAGERY SLOT renders when no asset has been supplied yet — a chassis never silently ships an empty slot, and never renders an accidental image. Composed by `Hero`/`Feature`/`Gallery` (sections tier) whenever their `imagerySlot` data flag is `true` and the corresponding asset is absent. | internal — compose from `packages/ui/src/blocks/MediaPlaceholder.tsx` |
199
+ | `MemberList` | Settings "People" member rows — reimplements the ploy.ai Team Members list capture (avatar + email + "(you)" + role Badge). Purely presentational and props-driven: no session/permission logic; the caller supplies the member list, role labels, and an optional per-row actions slot (e.g. a "Remove" menu). | `import { MemberList } from "@working-theory/ui/blocks"` |
200
+ | `MetricComparisonTable` | A numeric comparison table over the Table primitive. The operator-dashboard comparison view's core surface: one column per waitlist (plus a "total" column) and one row per metric (raw, qualified, qualification rate, one row per tier). | `import { MetricComparisonTable } from "@working-theory/ui/blocks"` |
201
+ | `NavActionList` | CTA action cluster block (one shared button chrome; variant = paint, size = box). Extracts the action-cluster variant routing that was duplicated verbatim between Nav (ActionCluster, Nav.tsx:240–342) and NavMobileMenu (action map, NavMobileMenu.tsx:344–435). This block is the vehicle for the later Nav + NavMobileMenu refactors — both will compose it. | `import { NavActionList } from "@working-theory/ui/blocks"` |
202
+ | `NavFlyoutPanel` | Mega-menu body block (feature grid + action bar) for Nav flyouts. Renders the content of a flyout (mega-menu) panel opened by a NavigationMenu trigger in the Nav chrome component. | `import { NavFlyoutPanel } from "@working-theory/ui/blocks"` |
203
+ | `NavSearchTrigger` | ⌘K search trigger control for Nav desktop pill + mobile icon-only surfaces. ⌘K search trigger button for Nav, desktop + mobile. Thin domain wrapper over the ShortcutTrigger primitive: it resolves the i18n "Open search" label and passes the search specifics (Search icon, the ⌘/K shortcut, the onSearchOpen handler) to ShortcutTrigger. | `import { NavSearchTrigger } from "@working-theory/ui/blocks"` |
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"` |
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"` |
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"` |
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 (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"` |
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"` |
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"` |
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. | `import { PaymentLinkCard } from "@working-theory/ui/blocks"` |
211
+ | `PaymentLinkForm` | Product selection + "create link" submit for the pay-by-link surface. | `import { PaymentLinkForm } from "@working-theory/ui/blocks"` |
212
+ | `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"` |
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. | `import { PaymentResult } from "@working-theory/ui/blocks"` |
214
+ | `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"` |
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"` |
216
+ | `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"` |
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"` |
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"` |
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"` |
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"` |
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"` |
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). | `import { ProjectListingCard } from "@working-theory/ui/blocks"` |
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"` |
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"` |
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"` |
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. | `import { ResponseChart } from "@working-theory/ui/blocks"` |
227
+ | `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"` |
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` |
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"` |
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"` |
231
+ | `SinglePriceCard` | 2-column split card for the Pricing 'single-price-with-details' variant. *(weak)* | `import { SinglePriceCard } from "@working-theory/ui/blocks"` |
232
+ | `SocialIcons` | 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. *(weak)* | `import { SocialIcons } from "@working-theory/ui/blocks"` |
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"` |
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"` |
235
+ | `StreamingMessage` | One chat turn's message rendering, per the ploy.ai capture contract. | `import { StreamingMessage } from "@working-theory/ui/blocks"` |
236
+ | `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"` |
237
+ | `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"` |
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"` |
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"` |
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"` |
241
+ | `TestimonialAside` | For ContactForm 'with-testimonial' variant. Rating (optional 0–5): rendered via Rating primitive with accessible label. avatar (optional): composed via Avatar + AvatarFallback + AvatarImage (initials fallback). | `import { TestimonialAside } from "@working-theory/ui/blocks"` |
242
+ | `UserBlock` | Position-agnostic identity/account trigger block: avatar + primary label + optional secondary line, with density/affordance/collapsed/truncation variants. A single focusable button-rooted element that forwardRef's + spreads props so DropdownMenuTrigger asChild (AccountMenu) can clone it as its trigger anchor. | `import { UserBlock } from "@working-theory/ui/blocks"` |
243
+ | `VerifyCodeField` | Presentational code-entry unit for StepFlow's `verify` step type: a status line ("We sent a code to…"), a 6-digit numeric code Field, and a resend link. Composes existing Field/Input/Button/Text primitives — no bespoke markup, no new primitive. | `import { VerifyCodeField } from "@working-theory/ui/blocks"` |
244
+ | `VersionHistory` | Day-grouped auto-saved version list with a "Current" marker — reimplements the ploy.ai artifact-editor Versions capture ("10 auto-saved versions", grouped by day, `Current` on one entry). Purely presentational and props-driven: renders the grouped list only. Designed to be embedded inside a popover by a higher tier — this block does NOT render the popover/trigger itself. | `import { VersionHistory } from "@working-theory/ui/blocks"` |
245
+ | `VersionSwitcher` | Version-dropdown block for brand lockup accessory slots. Renders the current version label as a Badge-styled trigger pill that opens a DropdownMenu of older available versions. Designed for use in the `brandAccessory`/`badge` slot of Nav and BrandLogo so both surfaces render the version accessory identically from a single shared source. | `import { VersionSwitcher } from "@working-theory/ui/blocks"` |
246
+ | `VideoEmbed` | The shared video player: poster + large Play affordance (click, default) or muted autoplay with native controls, reduced-motion-aware. 'click' (default) — the acquisition.com thank-you pattern: a poster image with a large, labeled Play affordance. Nothing plays, nothing is fetched, until the visitor activates it — the video element itself only mounts on activation. | `import { VideoEmbed } from "@working-theory/ui/blocks"` |
247
+ | `VideoLightbox` | The shared video player, presented as a DIALOG. A trigger (a poster thumbnail, a "Watch the video" button — any focusable element the caller supplies) opens the SAME VideoEmbed inside a Radix Dialog on a dimmed/blurred backdrop. | `import { VideoLightbox } from "@working-theory/ui/blocks"` |
248
+ | `VideoPlaceholder` | The true-to-size, play-marked placeholder a declared VIDEO slot renders when no source has been supplied yet — the video-flavored sibling of `MediaPlaceholder`: a circle-with-centered-triangle play mark (mirroring `VideoEmbed`'s own poster/Play affordance styling) inside a dashed aspect box sized to the SAME `ratio` the real player would use, so swapping in a real source never shifts the slot's footprint. | `import { VideoPlaceholder } from "@working-theory/ui/blocks"` |
249
+
250
+ ---
251
+
252
+ ## Chrome (18)
253
+
254
+ Persistent framing UI that wraps page content — navigation, footers, sidebars, banners. Not MDX-driven.
255
+
256
+ Import: `import { X } from "@working-theory/ui/chrome";` (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.
257
+
258
+ | Component | What it does | How to use it |
259
+ | --- | --- | --- |
260
+ | `AccountMenu` | Auth-agnostic account dropdown (theme + settings + admin + sign-out). Composes the DropdownMenu primitive (Radix-backed — positioning, click-outside, Escape, focus management, and roving keyboard nav all come for free) with the Icon, Link, and ThemeToggle primitives. AccountMenu carries NO session, routing, or sign-out logic of its own: every behaviour arrives via props, so the same component serves any auth stack. | `import { AccountMenu } from "@working-theory/ui/chrome"` |
261
+ | `ArtifactToolbar` | Chrome-tier artifact-canvas toolbar (ploy-capture recomposition). Reimplements the captured ploy.ai artifact-canvas toolbar: artifact tab strip ("All outputs" gallery tab + per-artifact tabs with close ×) · Preview/Code toggle · Select (element-pick) toggle · history back/forward · a read-only path bar · responsive-viewport cycle · refresh · Versions dropdown trigger · Publish. | `import { ArtifactToolbar } from "@working-theory/ui/chrome"` |
262
+ | `Banner` | Site-wide announcement and consent banner chrome. *(weak)* | `import { Banner } from "@working-theory/ui/chrome"` |
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` |
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` |
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. | `import { DocsSidebar } from "@working-theory/ui/chrome"` |
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"` |
267
+ | `FloatingCta` | Persistent fixed corner action pill. *(weak)* | `import { FloatingCta } from "@working-theory/ui/chrome"` |
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"` |
269
+ | `Nav` | Primary navigation server component with locale-aware links. Three layout variants supported via `navAlignment`. Flyout (mega-menu) items: the desktop link list is ALWAYS a single SectionNav render path — there is no Path A/B fork. | `import { Nav } from "@working-theory/ui/chrome"` |
270
+ | `NavMobileMenu` | 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). *(weak)* | internal — compose from `packages/ui/src/chrome/NavMobileMenu.tsx` |
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` |
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"` |
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"` |
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 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"` |
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` |
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"` |
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"` |
278
+
279
+ ---
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`. | `import { InvoiceDetail } from "@working-theory/ui/panels"` |
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 (8)
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
+ | `AdminShell` | @deprecated; use PortalShell with your own navItems. Internal admin dashboard layout shell. Thin composition of AppShell + SidebarNav. Converged from the hand-rolled layout in the prior MVP to match the AppShell pattern established by WorkspaceShell. | `import { AdminShell } from "@working-theory/templates/shells"` |
398
+ | `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"` |
399
+ | `ArtifactEditorShell` | Chat + artifact-canvas split-view slot-frame. Recomposes the ploy.ai Ploy Editor capture: a chat-driven artifact editor whose split view is LEFT = chat pane (conversation + composer) and RIGHT = artifact canvas (toolbar + preview/code), behind a drag-resizable divider. A blank session is chat-only, full width, until an artifact exists — then the canvas panel slides in. | `import { ArtifactEditorShell } from "@working-theory/templates/shells"` |
400
+ | `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)* | `import { BlogShell } from "@working-theory/templates/shells"` |
401
+ | `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)* | `import { DocsShell } from "@working-theory/templates/shells"` |
402
+ | `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"` |
403
+ | `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 WorkspaceShell. *(weak)* | `import { PortalShell } from "@working-theory/templates/shells"` |
404
+ | `WorkspaceShell` | Application sidebar shell (thin AppShell composition);. Props are intentionally identical to the old DashboardShellProps — no additions beyond what AppShell provides — so any fork using DashboardShell can swap the import without changes. *(weak)* | `import { WorkspaceShell } from "@working-theory/templates/shells"` |
405
+
406
+ ---
407
+
408
+ ## Weak descriptions
409
+
410
+ These 30 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.
411
+
412
+ | Component | Tier | What the source gives us |
413
+ | --- | --- | --- |
414
+ | `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. |
415
+ | `AgentContextCard` | blocks | Capability-bearing block that renders agent provenance. RSC note: no hooks or browser APIs — server-renderable by default. |
416
+ | `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`. |
417
+ | `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. |
418
+ | `SinglePriceCard` | blocks | 2-column split card for the Pricing 'single-price-with-details' variant. |
419
+ | `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. |
420
+ | `Banner` | chrome | Site-wide announcement and consent banner chrome. |
421
+ | `BannerConsentIsland` | chrome | 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). |
422
+ | `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. |
423
+ | `FloatingCta` | chrome | Persistent fixed corner action pill. |
424
+ | `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). |
425
+ | `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.). |
426
+ | `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. |
427
+ | `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. |
428
+ | `CopyButton` | primitives | CopyButton Primitive. |
429
+ | `Delta` | primitives | Sign-driven semantic indicator for numeric change. |
430
+ | `Dialog` | primitives | Modal overlay composed from @radix-ui/react-dialog. |
431
+ | `MoneyAmount` | primitives | Locale-aware currency display. |
432
+ | `SplitButton` | primitives | A main action button paired with a dropdown trigger. |
433
+ | `StatusBadge` | primitives | Colored circle + glyph status indicator. |
434
+ | `ThemeToggle` | primitives | Stateful 3-state theme owner. |
435
+ | `Toast` | primitives | Radix-backed transient notification system. |
436
+ | `Toggle` | primitives | Toggle Primitive. |
437
+ | `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. |
438
+ | `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. |
439
+ | `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. |
440
+ | `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. |
441
+ | `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). |
442
+ | `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 WorkspaceShell. |
443
+ | `WorkspaceShell` | shells | Application sidebar shell (thin AppShell composition);. Props are intentionally identical to the old DashboardShellProps — no additions beyond what AppShell provides — so any fork using DashboardShell can swap the import without changes. |
444
+
445
+ ---
446
+
447
+ ## Undescribed components
448
+
449
+ 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.
450
+
451
+ | Component | Tier | Source |
452
+ | --- | --- | --- |
453
+ | `Container` | primitives | `packages/ui/src/primitives/Container.tsx` |
454
+ | `Heading` | primitives | `packages/ui/src/primitives/Heading.tsx` |
455
+ | `Link` | primitives | `packages/ui/src/primitives/Link.tsx` |
456
+ | `Text` | primitives | `packages/ui/src/primitives/Text.tsx` |