@titan-design/react-ui 0.12.1 → 0.13.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 (509) hide show
  1. package/README.md +46 -47
  2. package/dist/bodymap.js +768 -701
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +770 -703
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1319 -216
  7. package/dist/index.d.ts +1319 -216
  8. package/dist/index.js +5996 -4498
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +5773 -4357
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
  13. package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1435 -1428
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1443 -1436
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +195 -134
  21. package/dist/theme/index.d.ts +195 -134
  22. package/dist/theme/index.js +215 -300
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +202 -296
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +62 -5
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +62 -5
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +73 -5
  31. package/dist/theme/tokens.d.ts +73 -5
  32. package/dist/theme/tokens.js +55 -7
  33. package/dist/theme/tokens.js.map +1 -1
  34. package/dist/theme/tokens.mjs +55 -8
  35. package/dist/theme/tokens.mjs.map +1 -1
  36. package/docs/audits/2026-09-08-critique-addenda.md +51 -0
  37. package/docs/audits/2026-09-08-library-critique.md +212 -0
  38. package/docs/library-roadmap.md +99 -0
  39. package/package.json +1 -1
  40. package/src/arch/arch-graph.freshness.test.ts +52 -0
  41. package/src/arch/arch-graph.json +5021 -1617
  42. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  43. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  44. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  45. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  46. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  48. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  49. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  51. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  52. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  54. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  55. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  57. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  58. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  60. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  61. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
  63. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  64. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  66. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  67. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  69. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  70. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  71. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  73. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  74. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  76. package/src/components/custom/ActiveWork/README.md +305 -0
  77. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  78. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  80. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  81. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  82. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  83. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  84. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  86. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  87. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  88. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  90. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  91. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  92. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  93. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  94. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  95. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  96. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  97. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  98. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  99. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  100. package/src/components/custom/ActiveWork/index.ts +19 -0
  101. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  102. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  103. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  104. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  105. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
  106. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  107. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  108. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  109. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  110. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  111. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  112. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  113. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  116. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  117. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  119. package/src/components/custom/Fatigue/README.md +40 -3
  120. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  121. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  122. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  123. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  124. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  125. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  126. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  127. package/src/components/custom/Fatigue/index.ts +17 -5
  128. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  129. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  130. package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
  131. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  132. package/src/components/custom/Gauge/Gauge.tsx +4 -1
  133. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  134. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  135. package/src/components/custom/Metric/Metric.tsx +5 -20
  136. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  137. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  138. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  139. package/src/components/custom/Prose/README.md +58 -0
  140. package/src/components/custom/Prose/index.ts +1 -0
  141. package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
  142. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  143. package/src/components/custom/Scatter/Scatter.tsx +116 -14
  144. package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
  145. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  146. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  147. package/src/components/custom/Table/Table.stories.tsx +98 -15
  148. package/src/components/custom/Table/Table.test.tsx +273 -86
  149. package/src/components/custom/Table/Table.tsx +159 -67
  150. package/src/components/custom/Table/column-fit.test.ts +75 -0
  151. package/src/components/custom/Table/column-fit.ts +116 -0
  152. package/src/components/custom/Table/index.ts +9 -0
  153. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  154. package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
  155. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  156. package/src/components/custom/Treemap/Treemap.tsx +7 -2
  157. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  158. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  159. package/src/components/custom/Typography/Typography.tsx +6 -0
  160. package/src/components/custom/Typography/index.ts +1 -8
  161. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
  162. package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
  163. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  164. package/src/components/custom/Workout/BaseBadge.tsx +3 -0
  165. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  166. package/src/components/custom/Workout/BodyMap.tsx +3 -1
  167. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
  168. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  169. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
  170. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
  171. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  172. package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
  173. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  174. package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
  175. package/src/components/custom/Workout/DeviationBar.tsx +21 -16
  176. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
  177. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
  178. package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
  179. package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
  180. package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
  181. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
  182. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  183. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  184. package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
  185. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
  186. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  187. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  188. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  189. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  190. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  191. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  192. package/src/components/custom/Workout/IntensityBar.tsx +4 -2
  193. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  194. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  195. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  196. package/src/components/custom/Workout/MesoCard.tsx +12 -9
  197. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  198. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  199. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  200. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  201. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  202. package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
  203. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  204. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  205. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  206. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  207. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
  208. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  209. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  210. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  211. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  212. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  213. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
  214. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  215. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  216. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  217. package/src/components/custom/Workout/README.md +11 -6
  218. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  219. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  220. package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
  221. package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
  222. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  223. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  224. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  225. package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
  226. package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
  227. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  228. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  229. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  230. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  231. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  232. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  233. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  234. package/src/components/custom/Workout/SetBar.tsx +38 -12
  235. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  236. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  237. package/src/components/custom/Workout/SetRow.tsx +61 -23
  238. package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
  239. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  240. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  241. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  242. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  243. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  244. package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
  245. package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
  246. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  247. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  248. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  249. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  250. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  251. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  252. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  253. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  254. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
  255. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  256. package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
  257. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  258. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  259. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  260. package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
  261. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  262. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  263. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  264. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
  265. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
  266. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
  267. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  268. package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
  269. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  270. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  271. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  272. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  273. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  274. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  275. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  276. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  277. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  278. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  279. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  280. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  281. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  282. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  283. package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
  284. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  285. package/src/components/custom/Workout/index.ts +5 -0
  286. package/src/components/custom/Workout/metricText.stories.tsx +6 -5
  287. package/src/components/custom/Workout/metricText.tsx +4 -0
  288. package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
  289. package/src/components/custom/charts/README.md +61 -0
  290. package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
  291. package/src/components/custom/charts/SetBarChart.tsx +42 -4
  292. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  293. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  294. package/src/components/custom/charts/SparkBars.tsx +85 -0
  295. package/src/components/custom/charts/index.ts +3 -0
  296. package/src/components/custom/index.ts +3 -0
  297. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  298. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  299. package/src/components/custom/stepper/Stepper.tsx +13 -28
  300. package/src/components/icons/icons.stories.tsx +1 -1
  301. package/src/components/icons/icons.tsx +51 -0
  302. package/src/components/shell/AppShell.stories.tsx +150 -0
  303. package/src/components/shell/AppShell.test.tsx +70 -0
  304. package/src/components/shell/AppShell.tsx +90 -0
  305. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  306. package/src/components/shell/BrandLockup.test.tsx +34 -1
  307. package/src/components/shell/BrandLockup.tsx +27 -11
  308. package/src/components/shell/NavItem.stories.tsx +4 -4
  309. package/src/components/shell/NavItem.test.tsx +17 -0
  310. package/src/components/shell/NavItem.tsx +17 -5
  311. package/src/components/shell/README.md +89 -26
  312. package/src/components/shell/SideNav.stories.tsx +38 -7
  313. package/src/components/shell/SideNav.test.tsx +16 -8
  314. package/src/components/shell/SideNav.tsx +17 -17
  315. package/src/components/shell/TopBar.stories.tsx +44 -19
  316. package/src/components/shell/TopBar.test.tsx +34 -12
  317. package/src/components/shell/TopBar.tsx +61 -40
  318. package/src/components/shell/brands.tsx +66 -0
  319. package/src/components/shell/index.ts +9 -8
  320. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  321. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  322. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  323. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  324. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  325. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  326. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  327. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  328. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  329. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  330. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  331. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  332. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  333. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  334. package/src/components/shell/workout/index.ts +9 -0
  335. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  336. package/src/components/ui/README.md +110 -0
  337. package/src/components/ui/alert/Alert.stories.tsx +1 -1
  338. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  339. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  340. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  341. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  342. package/src/components/ui/avatar/Avatar.tsx +2 -10
  343. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  344. package/src/components/ui/badge/Badge.test.tsx +19 -3
  345. package/src/components/ui/badge/Badge.tsx +48 -55
  346. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  347. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  348. package/src/components/ui/button/Button.stories.tsx +46 -12
  349. package/src/components/ui/button/Button.tsx +32 -25
  350. package/src/components/ui/card/Card.stories.tsx +90 -94
  351. package/src/components/ui/card/Card.test.tsx +80 -6
  352. package/src/components/ui/card/Card.tsx +150 -203
  353. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  354. package/src/components/ui/checkbox/Checkbox.tsx +6 -26
  355. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  356. package/src/components/ui/chip/Chip.test.tsx +10 -6
  357. package/src/components/ui/chip/Chip.tsx +76 -91
  358. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  359. package/src/components/ui/collapse/Collapse.tsx +6 -11
  360. package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
  361. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  362. package/src/components/ui/data-row/DataRow.tsx +18 -7
  363. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  364. package/src/components/ui/divider/Divider.tsx +1 -5
  365. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  366. package/src/components/ui/drawer/Drawer.tsx +13 -30
  367. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  368. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  369. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  370. package/src/components/ui/form-field/FormField.tsx +10 -46
  371. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  372. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  373. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  374. package/src/components/ui/help-tip/index.ts +7 -1
  375. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  376. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  377. package/src/components/ui/icon-box/IconBox.tsx +2 -12
  378. package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
  379. package/src/components/ui/indicator/Indicator.tsx +20 -14
  380. package/src/components/ui/input/Input.stories.tsx +3 -11
  381. package/src/components/ui/input/Input.test.tsx +2 -10
  382. package/src/components/ui/input/Input.tsx +10 -25
  383. package/src/components/ui/input/index.ts +7 -1
  384. package/src/components/ui/link/Link.stories.tsx +19 -7
  385. package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
  386. package/src/components/ui/list-item/ListItem.tsx +2 -9
  387. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  388. package/src/components/ui/menu/Menu.test.tsx +2 -11
  389. package/src/components/ui/menu/Menu.tsx +12 -14
  390. package/src/components/ui/menu/index.ts +8 -1
  391. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  392. package/src/components/ui/modal/Modal.tsx +29 -19
  393. package/src/components/ui/pill/Pill.stories.tsx +58 -23
  394. package/src/components/ui/pill/Pill.test.tsx +101 -3
  395. package/src/components/ui/pill/Pill.tsx +164 -49
  396. package/src/components/ui/pill/index.ts +1 -1
  397. package/src/components/ui/popover/Popover.stories.tsx +5 -7
  398. package/src/components/ui/popover/Popover.test.tsx +1 -6
  399. package/src/components/ui/popover/Popover.tsx +20 -15
  400. package/src/components/ui/popover/index.ts +7 -1
  401. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  402. package/src/components/ui/progress/Progress.test.tsx +1 -5
  403. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  404. package/src/components/ui/radio/Radio.test.tsx +6 -2
  405. package/src/components/ui/radio/Radio.tsx +23 -22
  406. package/src/components/ui/section/Section.stories.tsx +5 -14
  407. package/src/components/ui/section/Section.test.tsx +1 -6
  408. package/src/components/ui/section/Section.tsx +1 -3
  409. package/src/components/ui/section/index.ts +1 -5
  410. package/src/components/ui/select/Select.stories.tsx +3 -13
  411. package/src/components/ui/select/Select.test.tsx +2 -11
  412. package/src/components/ui/select/Select.tsx +14 -14
  413. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  414. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  415. package/src/components/ui/skeleton/index.ts +1 -7
  416. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  417. package/src/components/ui/spinner/Spinner.tsx +1 -4
  418. package/src/components/ui/stack/Stack.stories.tsx +1 -1
  419. package/src/components/ui/stack/Stack.tsx +1 -1
  420. package/src/components/ui/surface/Surface.stories.tsx +17 -5
  421. package/src/components/ui/surface/Surface.test.tsx +88 -28
  422. package/src/components/ui/surface/Surface.tsx +37 -87
  423. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  424. package/src/components/ui/surface/index.ts +8 -0
  425. package/src/components/ui/surface/resolveSurface.ts +98 -0
  426. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  427. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  428. package/src/components/ui/switch/Switch.tsx +7 -6
  429. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  430. package/src/components/ui/tabs/Tabs.tsx +7 -22
  431. package/src/components/ui/tabs/index.ts +1 -7
  432. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  433. package/src/components/ui/tile/Tile.tsx +3 -0
  434. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  435. package/src/components/ui/toast/Toast.test.tsx +2 -8
  436. package/src/components/ui/toast/Toast.tsx +43 -53
  437. package/src/components/ui/toast/index.ts +0 -1
  438. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  439. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  440. package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
  441. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  442. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  443. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  444. package/src/components/ui/tooltip/index.ts +1 -1
  445. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  446. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  447. package/src/components/ui/trigger/index.ts +2 -0
  448. package/src/stories/PresetShowcase.stories.tsx +100 -47
  449. package/src/test/no-device-internals.test.ts +3 -3
  450. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  451. package/src/theme/ColorPalettes.stories.tsx +62 -45
  452. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  453. package/src/theme/Depth.stories.tsx +132 -65
  454. package/src/theme/DepthCalibration.stories.tsx +23 -21
  455. package/src/theme/ThemeProvider.test.tsx +4 -4
  456. package/src/theme/barrel.ts +7 -6
  457. package/src/theme/color-stories.coverage.test.ts +1 -1
  458. package/src/theme/color-utils.ts +41 -29
  459. package/src/theme/config.completeness.test.ts +1 -1
  460. package/src/theme/config.ts +28 -0
  461. package/src/theme/elevation.test.ts +82 -56
  462. package/src/theme/elevation.ts +77 -561
  463. package/src/theme/global.css +30 -2
  464. package/src/theme/grey-ramp.test.ts +24 -8
  465. package/src/theme/lift.test.ts +39 -0
  466. package/src/theme/lift.ts +102 -0
  467. package/src/theme/materials.test.ts +5 -2
  468. package/src/theme/materials.ts +38 -4
  469. package/src/theme/native-theming-guard.test.ts +5 -5
  470. package/src/theme/presets/apply.ts +4 -0
  471. package/src/theme/presets/audiobook.ts +5 -2
  472. package/src/theme/presets/default.ts +4 -0
  473. package/src/theme/presets/index.ts +14 -1
  474. package/src/theme/presets/types.ts +1 -1
  475. package/src/theme/semantic-contrast.test.ts +13 -4
  476. package/src/theme/status-distinctness.test.ts +66 -0
  477. package/src/theme/surface-planes.test.ts +37 -0
  478. package/src/theme/surface-planes.ts +68 -0
  479. package/src/theme/token-export-guard.test.ts +1 -3
  480. package/src/theme/tokens/primitives.test.ts +15 -7
  481. package/src/theme/tokens/primitives.ts +65 -33
  482. package/src/theme/tokens/semantic.ts +71 -37
  483. package/src/theme/wash-ladder.test.ts +58 -0
  484. package/src/theme/workout-tokens.ts +1 -7
  485. package/src/types/jest-axe.d.ts +2 -6
  486. package/src/types/raw-md.d.ts +5 -0
  487. package/src/utils/colors.ts +4 -4
  488. package/src/utils/form.ts +1 -3
  489. package/src/utils/index.ts +2 -7
  490. package/src/utils/number-format.ts +17 -0
  491. package/src/utils/workout-format.ts +15 -6
  492. package/src/web-jsx/jsx-runtime.ts +1 -5
  493. package/tailwind.config.js +5 -0
  494. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  495. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  496. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  497. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  498. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  499. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  500. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  501. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  502. package/src/components/shell/DashboardShell.tsx +0 -75
  503. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  504. package/src/theme/elevation.stories.tsx +0 -346
  505. package/src/utils/useTheme.ts +0 -72
  506. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  507. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  508. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  509. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
@@ -0,0 +1,212 @@
1
+ # titan-design `packages/ui` — deep critique and fix roadmap
2
+
3
+ Reviewed on `main` at 4267d69, 2026-09-08. Read-only. Gates on main: `tsc` 0 errors, prettier clean, eslint 0 errors / 81 warnings, targeted depth tests 115/115 pass.
4
+ Scope: 191 story files, 170 test files (~2,196 `it()`), 143 shipped component files (38 `ui/` dirs, 96 `custom/` files, 9 `shell/`).
5
+
6
+ ---
7
+
8
+ ## A. Executive findings (ranked by impact on cohesive application of the fundamentals)
9
+
10
+ **1. The foundations are sound, but only ~3 families consume them; Workout (the largest family, 54 components) is frozen to the pre-ramp era.**
11
+ Workout carries 39 files with module-scope `const t = getSemanticColors('dark')` (55 such constants repo-wide, 71 call sites in components), 149 literal `fontSize:` values, 81 `rgba(` literals, 34 raw hex, 31 files setting `backgroundColor:` inline, 16 inline `boxShadow`, 12 files indexing `greyRamp[...]` directly, 19 raw `<Text>` and zero `Typography`. It is the family with the highest drift and the highest consumer count. Only ActiveWork, Prose and charts are held to the token-pure lint (`eslint.config.js:215-219`); Workout is exempt from every rule except the ratchet.
12
+
13
+ **2. `Card` is not on the surface system at all.** It reads theme from a DOM class observer (`utils/useTheme.ts`, its only consumer is `Card.tsx:96,373`), never touches `SurfaceContext`, derives its fill from the deleted-tomorrow `lighten()` ladder, and writes `backgroundColor` into `style` (`Card.tsx:190`) so a caller's `bg-*` class is discarded. `filled` and `elevated` are byte-identical (`Card.tsx:46-52`), `outline`/`accent`/`subtle` silently clamp to level 1 or 0 (`Card.tsx:102-104,117-119`), and light mode is a hard-coded `#FAFAFA` (`Card.tsx:115`). 13 shipped files import it. No test covers the className override (`Card.test.tsx` asserts variants render, not what they render).
14
+
15
+ **3. Four container primitives compete and none is the default.** `Card` (13 consumers), `Surface` (3 shipped: DashboardShell, SessionHeader, SessionRail), `Tile` (3, hand-rolls `bg-surface-raised` + 10px uppercase label), `Section` (0). ActiveWork lists set `bg-surface-raised` on plain `View`s for selection (`SessionListItem.tsx:138`, `FileActivityRow.tsx:96`) because no primitive expresses "one plane up". The north-star §5b asked for exactly one un-misconfigurable `<Card>`; the repo has four ways and 58 loose `bg-surface-*` classes across 25 families.
16
+
17
+ **4. Twelve pill-shaped components.** `Pill`, `Badge`, `Chip`, `BaseBadge`, `StatusPill`, `WorkoutPill`, `SessionStatePill`, `WeightBadge`, `PrBadge`, `MuscleGroupChip`, `SeverityLabel`, `CoChangeChip`. In-repo consumers: Pill 6, Badge 2, SeverityLabel 2, the rest 0-1. `Chip.tsx:38-41` styles with `bg-neutral-600`/`text-neutral-700` (Tailwind's default cool grey, since the config is in `extend` mode) plus `text-white` ×7; `WorkoutPill.tsx` carries 10 `rgba(` literals. Five Workout badges are titled under `Components/Atoms/*` while the family's other 49 stories sit under `Workout/*`.
18
+
19
+ **5. Storybook has no single tree.** Nine top-level groups (Components 487 entries, Workout 326, Lab 125, Custom 54, Foundations 40, ActiveWork 30, Shell 27, Pages 16, Docs 1). ActiveWork alone is split four ways (`ActiveWork/*` 7, `Custom/ActiveWork/*` 11, `Components/Molecules/Eyebrow`, `Lab/ActiveWork/*` 6 stale duplicates of the hardened readers). Eight `Lab/`-titled story files live in shipped dirs (`Workout/S3*.stories.tsx` ×5, `ExerciseCardUnified`, `RowInventory`, `shell/SessionRailSpecimen`) and therefore publish to npm, because `package.json` `files` only excludes `src/lab`. Three titles use `·`, which `gotchas.md #8` says mangles story ids. 833 story exports across ~140 component story files (Input 15, Card 14, Alert 14) against the skill's "one Default args story + controls".
20
+
21
+ **6. Every governance signal is inert or stale.** Zero of 191 story files carry a `status:` tag; all 1,106 Storybook entries read `status:review`, so the sidebar filter MATURITY.md is built around slices nothing. `arch-graph.json` was last regenerated 2026-07-09 (91 components; now ~143), omits the entire ActiveWork family, `Tile`, `SetBarChart`, `SparkBars`, `LiveFatigueCard`, `MarkdownProse`, and its `dead` list names `Pill` (6 consumers today), `Tooltip` (8), `Modal`, `Collapse`, `SideNav`, `TopBar`. The workflow skill's Gate 1 requires a current graph. `REJECTED.md` has 3 entries; the Storybook has 10 archived directions with none.
22
+
23
+ **7. Colour math is copied, not shared.** `hexToRgb` ×4 (`theme/color-utils.ts:27`, `Fatigue/fatigue-tokens.ts:133`, `lab/north-star/fatigue-lab-shared.tsx:262`, `lab/archive/GrindingLine…:205`), `mixHex` ×4, `perceivedLuminance` ×3 (`materials.ts:87`, `lab/north-star/surfaces.ts:15`, `DualGhostLine…:45`), `lstar` ×3 (all in tests/lab, none exported from theme though the north-star makes ΔL\* the sanctioned metric), `parseHex` (`materials.ts:69`) beside `hexToRgb`. `lab/north-star/surfaces.ts` is a verbatim fork of `materials.ts` (`paperSheet`/`insetWell`/`grainForTone`) and `DualGhostLine` has a third copy.
24
+
25
+ **8. `ui/*` atoms cannot use `Typography` because it lives in `custom/`.** 81 raw `<Text>` in `ui/*`, 0 `Typography`; `CardTitle`, `SectionHeader` (`Section.tsx:29`), `Menu.tsx:210`, `Tile` all hand-roll heading/eyebrow styles. `Eyebrow` exists but only ActiveWork uses it. The tier order (ui → custom) forbids the fix the skill prescribes.
26
+
27
+ **9. 185 functions exceed 30 lines (29 exceed 100).** Workout 78, ui 31. Top: `BodyMapDetailPanel` 371, `StrengthTrendChart` 368, `CapacityBandChart` 328, `VelocityStrip` 313 (file is 1,468 lines), `Autocomplete` 204, `Tooltip` 161, `Card` 136, `calculateElevationShadow` 91. Two story-only kits ship as components: `Workout/velocity-story-kit.tsx` (438 lines) and `Workout/setHeadingKit.tsx` (364 lines, raw HTML `<div>`, 15 hex literals, no tests, no stories).
28
+
29
+ **10. Tests pin implementation and skip a11y where the rules say they must not.** 16 component test files have no `axe` (all four shell sub-parts, six Fatigue, five Workout pages, TimerReadout) despite CLAUDE.md's "every component test file must include an accessibility test". 43 assertions compare to literal hex (`Surface.test.tsx:79,97-100,139-140` pins `#2C2A28`/`#31302F`, so the depth change breaks them by design, not by behaviour). Comments describe deleted code: `SessionRail.stories.tsx:40` cites `neumorphicShadows`, `utils/colors.ts:4` cites `shadows.ts`, `SurfaceContext.ts:19-20` lists pre-re-space hexes, `Surface.tsx:27-35,63,90` documents the lighten model, `elevation.ts:19` says light from upper-right while the offsets are top-left.
30
+
31
+ ---
32
+
33
+ ## B. Competing systems and operator questions
34
+
35
+ | # | Pair | What each does / who uses it | Question for the operator |
36
+ |---|---|---|---|
37
+ | 1 | `Card` vs `Surface` vs `Tile` vs `Section` | Card: lighten ladder + 5 variants, 13 consumers. Surface: named planes + on-surface context, 3 shipped. Tile: bare View + `bg-surface-raised`, 3. Section: 0. | Is `Card` the only content container app code may use (Surface reserved for shell roots; Tile becomes a Card preset; Section deleted)? |
38
+ | 2 | numeric `elevation` vs named `level` | `elevation=` 15 uses (Card + Surface stories); `level=` 31 uses. Both public. | After the depth fix, does the public API expose only named planes plus a relative "one up", with numeric elevation internal? |
39
+ | 3 | 12 pill/badge/chip components | Pill 6 consumers, Badge 2, SeverityLabel 2, others 0-1. Three token-impure. | One `Pill` primitive (tone/size/icon/dot slots) with domain pills as thin wrappers, or keep domain pills as separate components? |
40
+ | 4 | `Divider` vs hairline border classes | Divider 5 consumers; 21 hand-rolled `h-px`/`border-t border-hairline` rules in 9 families; 56 `border-hairline*` uses. | Is every rule a `Divider`, with `border-hairline` reserved for the opt-in `outline` edge? |
41
+ | 5 | `Tooltip` vs `HelpTip` vs `Popover` | Tooltip 8 consumers, HelpTip 0 (+ `LabelWithHelp`), Popover 1. HelpTip is a Tooltip preset. | Delete HelpTip, or keep it as a documented Tooltip preset? |
42
+ | 6 | `useTheme` (DOM observer) vs `SurfaceContext`/`ThemeProvider` | useTheme: Card only. Context: Surface, Typography-adjacent, charts. | Is the Surface/ThemeProvider context the single theme source, so `utils/useTheme.ts` is deleted? |
43
+ | 7 | `getSemanticColors('dark')` constants vs `resolveColor` vs `className` tokens | 55 module constants (Workout 39, Fatigue 9); resolveColor in 14 files. TOKENS.md calls it a "known migration". | Are Workout and Fatigue dark-only by design (document and exempt) or must they be theme-correct (migrate 55 files)? |
44
+ | 8 | colour math ×5 modules | `theme/color-utils` (HSV), `utils/colors` (`alpha`, 137 call sites), `materials` (`parseHex`, Rec.601 luminance), `fatigue-tokens` (`mixHex`), `SetBarChart` (`mixHex`), 3 lab forks, 3 test `lstar`. | One `theme/color-math` module with CIELAB L\* as the sanctioned metric, everything else re-exported or deleted? |
45
+ | 9 | `Typography` (custom) vs raw `<Text>` in `ui/*` | 81 raw Text in ui, 0 Typography. Tier order forbids the import. | Move `Typography` (and `Eyebrow`) into `ui/` so atoms compose it, or exempt `ui/*` from the Typography rule? |
46
+ | 10 | `Indicator` vs `StatusDot` | 6 vs 5 consumers. Skill 03 says "standardize on Indicator"; `Fatigue/README.md:41` says fatigue lights are `StatusDot`. Contradiction is live. | Which dot survives? |
47
+ | 11 | `Metric` vs `MetricCell` vs `MetricTiles`+`Tile` vs Gauge value | Four label-over-value lockups; Metric 3 consumers, MetricCell 3, MetricTiles 1. | One stat primitive with `size`/`align`/`trend`, or keep Workout's `MetricCell` separate? |
48
+ | 12 | `materials.ts` vs `lab/north-star/surfaces.ts` fork vs elevation shadows | materials: 4 shipped call sites. Fork: lab only. Depth decision 2 makes paperSheet's rim the default. | Is `paperSheet` still hero-only (materials header) once every lifted plane carries the rim, or does it collapse into the depth recipe? |
49
+ | 13 | Formatters | `utils/number-format` (2), `utils/workout-format` (7), `ActiveWork/format-time` (2), `DateTime.formatDateTime`, 8 local `formatX` in components, 14 `toFixed`. | One `utils/format` module per domain (number / time / workout), with components forbidden from local formatters? |
50
+ | 14 | Storybook groups ×9 | Components/Atoms\|Molecules\|Organisms\|DataViz\|Charts, Custom/, Workout/, ActiveWork/, Pages/, Docs/, Shell/, Foundations/, Lab/. | Approve the target tree in §C-E4, or name a different top level for domain families? |
51
+ | 15 | Lint mechanisms ×3 | `titan/no-raw-color` ratchet (baseline JSON, 0 errors), family-scoped `no-restricted-syntax` errors (3 families), shell/icons warn. | One mechanism: extend the per-family error block to every family and retire the baseline, or keep the ratchet and delete the scoped blocks? |
52
+ | 16 | Light mode | `semantic.ts` defines a full light map; Workout has 1 file that mentions light; Card hard-codes light hex. | Is light mode a supported target for every family, or only for `ui/*` + Foundations? |
53
+
54
+ ---
55
+
56
+ ## C. Epics and task lists
57
+
58
+ Sizes: S ≤ half a day, M ≤ 2 days, L > 2 days. "Depends" refers to epic.task ids or operator questions Q#.
59
+
60
+ ### E1. Depth correction (in flight, aw-depth) — blast-radius inventory
61
+
62
+ Everything below is what the four depth decisions touch. Nothing in E2-E6 may edit these files until E1 lands.
63
+
64
+ **Consumers by family (shipped source, excluding tests/stories):**
65
+
66
+ | Family | `<Card>` | `<Surface>` | `bg-surface-*` | inline `boxShadow` | tailwind `shadow-*` | materials |
67
+ |---|---|---|---|---|---|---|
68
+ | ActiveWork | 6 files (CoChangeChip filled; FileActivityDetail subtle; FileHistoryExplorer subtle; InitiativeCard accent/outline; PortfolioOverview filled; SessionDetail outline) | 0 | 2 (SessionListItem:138, FileActivityRow:96) | 0 | 0 | `insetWell()` FileActivityDetail:124 |
69
+ | Workout | 4 (MesoCard outline e2 + borderColor + style boxShadow:191; MesoStatusCard outline e1 + borderColor; ReadinessCheck outline e2; WorkoutCard accent e1 + bgColor) | 2 (SessionHeader level=background; SessionRail level=elevated + `insetWell(surface-base)`:137) | 14 files | 16 lines (StatusDot:55-61 ×7 glows; DeviationBar:75; MesoStatusCard:275; BodyMapDetailPanel:337; BodyMap:200; ZoneTrack:241; IntensityBar:181; PrHistoryModal:84; setHeadingKit:308) | 0 | SessionRail |
70
+ | Fatigue | 0 | 0 | 0 | 0 | 0 | `barPaper` LiveFatigueCard:58 |
71
+ | charts | 0 | 0 (uses `useSurface`) | 0 | 0 | 0 | `barPaper` SetBarChart:494 |
72
+ | shell | 0 | 1 (DashboardShell:67 level=base) | 2 | 0 | 0 | 0 |
73
+ | ui/* floating overlays | — | — | 14 files | Indicator:92 glow; ToolbarButton:264 | 13 files: autocomplete, drawer, help-tip, indicator (5 arbitrary glow shadows), menu, modal, popover, select, switch, tabs, toast, toolbar-button, tooltip (`shadow-lg` ×9, `-sm` ×2, `-xl`, `-2xl`) | 0 |
74
+ | theme stories | — | 4 | 1 | 10 | 0 | Depth.stories:130-141, DepthCalibration:396-588 (+ local `Card` at :480) |
75
+ | lab | 21 story uses of Card | 0 | 2 | 12 | 0 | 17 call sites + 2 forks |
76
+
77
+ Prop-form totals across all files: `variant=` outline 19 / filled 16 / subtle 5 / accent 2 / elevated 1; Card `elevation=` {1}×2 {2}×6 {3}×3; `CardInset` −1×3 −2×3 (stories/tests only); Surface `level=` background 14 / base 9 / raised 5 / elevated 3; `elevation={2}` ×5, `{3}` ×1; `pressed` ×23. Elevation helpers (`getElevationSurface/Shadow`, `getBaseSurfaceColor`, `getValidatedElevation`, `getPressedRecessShadow`, `getGlowShadow`) are called only from `Card.tsx` and `Surface.tsx`; the blast radius of deleting `lighten()` is contained to those two files plus `elevation.test.ts` and `Depth*.stories.tsx`.
78
+
79
+ Tasks (for aw-depth's plan, not a redesign):
80
+ - **E1.1** Card reads `useSurface()` and resolves parent+1; delete `utils/useTheme.ts`. Files: `Card.tsx`, `utils/useTheme.ts`, `utils/index.ts`. S. Done when: no `useTheme` import remains and `Card` inside `<Surface level="base">` renders `surface-elevated`.
81
+ - **E1.2** Fix className/style precedence bug + regression test. Files: `Card.tsx:187-205`, `Card.test.tsx`. S. Done when: `<Card className="bg-surface-raised">` computed background is greyRamp[875] in jsdom.
82
+ - **E1.3** Collapse variants: `filled` = `elevated`; `outline` becomes opt-in edge, not a level clamp. `Card.tsx:46-52,102-104`. Depends Q1. S.
83
+ - **E1.4** Floating overlays (13 ui files) move from `shadow-lg` + `border-hairline` to the level-4/5 recipe. M. Done when: `grep -rE "shadow-(sm|md|lg|xl|2xl)" src/components/ui` = 0.
84
+ - **E1.5** Replace hex pins in `Surface.test.tsx`, `surface.contract.test.ts`, `elevation.test.ts` with `greyRamp[...]` references. S.
85
+ - **E1.6** Purge stale comments: `Surface.tsx:27-35,63,90`, `SurfaceContext.ts:19-20`, `SessionRail.stories.tsx:40`, `utils/colors.ts:4`, `elevation.ts:19`, `gotchas.md` "Neumorphic depth" section, `SessionRail.tsx:16-17`. S.
86
+ - **E1.7** Delete `lab/north-star/surfaces.ts` fork and `DualGhostLine` local copies; point lab at `theme/materials`. S.
87
+ - **E1.8** Decide glow shadows (StatusDot ×7, Indicator, MesoCard, BodyMap, ZoneTrack, IntensityBar, PrHistoryModal): they are emphasis, not depth. Route through `getGlowShadow` or leave. Depends on aw-depth. S.
88
+ - **E1.9** Rewrite `Foundations/Depth` and `Depth Calibration` to the new model; delete DepthCalibration's local `Card`. M.
89
+
90
+ ### E2. One container, one pill, one dot (depends E1; Q1, Q3, Q4, Q5, Q10, Q11)
91
+ - **E2.1** `Card` becomes the sole content container: fold `Tile` into a `Card` stat preset, delete `Section`/`SectionHeader` (0 consumers) or make `SectionHeader` compose `Eyebrow`. M.
92
+ - **E2.2** Replace loose `bg-surface-*` on `View`s with the container (58 sites, 25 families; start ActiveWork 2, shell 2, ui 14). L.
93
+ - **E2.3** `Pill` gains `tone`/`size`/`leading` slots; `Badge`, `Chip`, `BaseBadge`, `StatusPill`, `WorkoutPill`, `WeightBadge`, `PrBadge`, `MuscleGroupChip`, `SeverityLabel`, `SessionStatePill`, `CoChangeChip` become wrappers or are deleted per Q3. L. Done when: `Chip.tsx` has no `neutral-*`/`text-white`, and each survivor's story is titled under the same parent.
94
+ - **E2.4** `Divider` everywhere: replace 21 hand-rolled rules. S.
95
+ - **E2.5** `Indicator` vs `StatusDot`: migrate the loser's 5-6 consumers; fix `Fatigue/README.md:41`. M.
96
+ - **E2.6** `HelpTip` → Tooltip preset or delete. S.
97
+ - **E2.7** Stat lockup: `Metric` absorbs `MetricCell` + `MetricTiles`. M.
98
+
99
+ ### E3. Port Workout and Fatigue onto the foundations (depends E1; Q7, Q8, Q9, Q15, Q16)
100
+ - **E3.1** Move `Typography` + `Eyebrow` to `ui/`; leave re-export shims in `custom/`. S.
101
+ - **E3.2** `theme/color-math.ts`: single `hexToRgb`, `mixHex`, `alpha`, `lstar`, `deltaL`; delete 4 duplicate `hexToRgb`, 4 `mixHex`, 3 `perceivedLuminance`, 3 test `lstar`. M.
102
+ - **E3.3** Workout: replace 39 module-scope `getSemanticColors('dark')` with `resolveColor`/`useOnSurfaceColor` (or document dark-only per Q7). L.
103
+ - **E3.4** Workout: 149 literal `fontSize:` → `Typography` variants; 19 raw `<Text>`. L. Files ranked by count: ReadinessCheck 7, TempoDisplay 10, ExerciseCard 5, VelocityStrip 4.
104
+ - **E3.5** Fatigue: 9 module constants, 9 `fontSize:`, local `hexToRgb/mixHex`. M.
105
+ - **E3.6** `ui/*`: 81 raw `<Text>` → `Typography`; `Button` 6× `#ffffff` + `text-white`, `Alert` `bg-black`, `Tooltip` `bg-neutral-800`, `Spinner` hex. M.
106
+ - **E3.7** Lint: add every family to the token-pure error block (or per Q15 keep only the ratchet); delete `raw-color-baseline.json` when it reaches zero; update TOKENS.md §6 to list Prose and `no-raw-color`. S.
107
+ - **E3.8** Delete `Workout/velocity-story-kit.tsx` and `setHeadingKit.tsx` from `components/` (move to `src/lab/` or into the stories that use them). S.
108
+
109
+ ### E4. Storybook reorganisation (independent of E1; Q14)
110
+ Target tree:
111
+ ```
112
+ Foundations/{Color,Typography,Icons,Depth,Spacing,Choosing Tokens}
113
+ Components/Atoms|Molecules|Organisms/<Name> (ui/* only, one Default + controls)
114
+ Custom/<Family>/<Name> (ActiveWork, Workout, Fatigue, Charts, Prose, DataViz)
115
+ Shell/<Name>
116
+ Pages/<Name>
117
+ Lab/<Family>/<Name> (src/lab only; status:lab)
118
+ Docs/Architecture
119
+ ```
120
+ - **E4.1** Retitle: `ActiveWork/*` and `Components/Molecules/Eyebrow` → `Custom/ActiveWork/*`; `Workout/*` and the 5 Workout atoms under `Components/Atoms/*` → `Custom/Workout/*`; `Workout/Fatigue/*` → `Custom/Fatigue/*`; `Components/Charts|DataViz` → `Custom/Charts`. Fix `Composes` links. M.
121
+ - **E4.2** Move the 8 `Lab/`-titled files out of `components/` into `src/lab/` (or delete: `S3*` explorations are superseded by hardened SessionRail). S.
122
+ - **E4.3** Delete duplicates: `Lab/ActiveWork/*` (6), `Lab/Components/{Ghost Spark,Velocity Hero,Verdict Hero}` (3), `Lab/Archive/Surface` vs `Lab/North Star/1 · Surface System`. Record each in REJECTED.md. S.
123
+ - **E4.4** Rename `·` titles to ASCII; normalise spaces vs PascalCase within a family (`Initiative Reader` vs `InitiativeBrief`). S.
124
+ - **E4.5** Add `tags: ['autodocs']` to the 11 hardened ActiveWork stories and the 43 other files without it; add a `Composes` line to the 142 story files lacking one (ui/* first). M.
125
+ - **E4.6** Decorators compose `<Surface>`; today 0 do and ~30 hand-roll `backgroundColor`/`bg-*` (`SessionRail.stories.tsx:26-29` also uses `#6B7280`). M.
126
+ - **E4.7** Thin per-state stories to one `Default` + controls where the skill says so (Input 15, Card 14, Alert 14, Toast 13). M.
127
+
128
+ ### E5. Governance refresh (independent)
129
+ - **E5.1** Regenerate `arch-graph.json` via `scripts/arch-graph.mjs`; add a CI check that fails when the graph is older than the newest `index.ts`. S.
130
+ - **E5.2** REJECTED.md entries for: Fable Directions, Feature Explorations, Foundations (superseded), Screen Prototypes, Shell Specimens, Curves ×2, Grinding Line, Rep Breakdown, Hero Tempo, retired `inset` level, `tonalFill`/`ditherTile`, `data-1..10`. S.
131
+ - **E5.3** Apply `status:` tags: `status:lab` on every `src/lab` story, `status:candidate` on ported items, and run the MATURITY review session for `ui/*` (MATURITY says "~52 primitives"; there are 38). M. Depends E4.
132
+ - **E5.4** README per family for ui/*, ActiveWork (exists), Fatigue (exists, fix StatusDot line), charts, Prose. M.
133
+ - **E5.5** Update the skill: `gotchas.md` cites `neumorphicShadows`/`shadows.ts`/`charcoal`/`neutral-100` (none exist); `06-lint-guardrails.md` predates the ratchet. S.
134
+
135
+ ### E6. Code quality floor (independent)
136
+ - **E6.1** Split the 29 functions over 100 lines (start with the four charts >300 lines and `VelocityStrip.tsx` 1,468 lines). L.
137
+ - **E6.2** eslint warnings 81 → 0 (39 unused-vars, 37 explicit-any; `elevation.ts` 5, `useTheme.ts` 4). S.
138
+ - **E6.3** `axe` in the 16 test files lacking it. S.
139
+ - **E6.4** Dead-export decision after external-consumer check (brief D1): 40+ components with 0 in-repo consumers. Delete or mark `status:candidate`. M. Depends D1.
140
+ - **E6.5** Delete the 18 gitignored `tmp-*.mjs` in the package root. S.
141
+
142
+ Sequencing: E1 → (E2, E3) in parallel; E4, E5, E6 can start now on files E1 does not list. E5.3 waits for E4.1 so tags land on final titles.
143
+
144
+ ---
145
+
146
+ ## D. Follow-on research briefs (read-only explorer)
147
+
148
+ **D1. External consumers of the barrel.** Path: the voltras-mcp SPA and the mobile app checkouts (locate via `active-work paths`). For each name in `packages/ui/src/components/ui/index.ts` and `custom/index.ts`, count imports from `@titan-design/react-ui`. Output: table name → external files. Purpose: settle E6.4 and Q3/Q5/Q11 with real usage, since in-repo counts show 40+ zero-consumer exports.
149
+
150
+ **D2. Workout per-file token audit.** Path: `packages/ui/src/components/custom/Workout/*.tsx` (exclude tests/stories). For each file count: `getSemanticColors(`, `fontSize:`, `#[0-9a-f]{6}`, `rgba(`, `<Text`, `greyRamp[`, `primitiveRamps`, `boxShadow`, `backgroundColor:`, functions >30 lines. Rank; propose the port order for E3.3-E3.4 (smallest, most-consumed first).
151
+
152
+ **D3. Story duplicate and lab audit against the live index.** `curl localhost:6006/index.json`; group entries by component import path; list titles whose component is also rendered under another title; list every `Lab/` entry whose `importPath` is under `src/components`. Output: delete/move list for E4.2-E4.3.
153
+
154
+ **D4. Test quality sample.** For 20 test files chosen by highest `toHaveStyle(` count, classify each `it()` as behaviour / implementation / smoke. Count assertions on literal hex or pixel values that would break under a token re-space. Output: list for E1.5 beyond the three files already named.
155
+
156
+ **D5. Theme presets liveness.** Path: `src/theme/presets/*`, `src/stories/ThemePresets.stories.tsx`, `PresetShowcase.stories.tsx`. Does anything outside stories call `applyPreset`? Does `audiobook.ts` reference retired tokens? Output: keep / move to Lab / delete recommendation and a REJECTED.md draft.
157
+
158
+ **D6. Light-mode reality.** Render `Pages/*` and `Custom/Workout/*` docs pages with the Storybook theme toggle set to light (Playwright, do not restart the server). Screenshot 10; list components whose fills or text stay dark-frozen. Output: evidence for Q16.
159
+
160
+ ---
161
+
162
+ ## E. Evidence appendix (run from `packages/ui`; zsh needs `bash -c` or `noglob` for `--include`)
163
+
164
+ ```
165
+ # story titles → tree tally
166
+ grep -rnoE "^\s*title:\s*['\"][^'\"]+['\"]" src --include='*.stories.tsx' | perl -pe 's/^([^:]+):(\d+):\s*title:\s*[\x27"]([^\x27"]+)[\x27"]/$3\t$1:$2/' | sort
167
+ → 191 meta titles; top-level: Components 54 files, Workout 53, Lab 37, Custom 14, Shell 10, Foundations 9, ActiveWork 7, Pages 5, Docs 1
168
+ curl -s localhost:6006/index.json → 1106 entries (969 stories, 137 docs); all tagged status:review
169
+ grep -rlE "status:[a-z]+" src --include='*.stories.tsx' | wc -l → 0
170
+ grep -rLE "'autodocs'" src --include='*.stories.tsx' | wc -l → 54 ; grep -rlE "Composes" … → 49
171
+ grep -rnE "title: 'Lab/" src/components --include='*.stories.tsx' → 8 files
172
+
173
+ # depth inventory (SRC = *.ts/*.tsx minus tests/stories)
174
+ grep -rlE "<Card[ >]" src $SRC → ActiveWork 6 (+Card.tsx), Workout 4 ; imports of Card: 13 shipped files
175
+ grep -rhoE "<Card[^>]*variant=\"[a-z]+\"" src --include='*.tsx' → outline 19, filled 16, subtle 5, accent 2, elevated 1
176
+ grep -rhoE "bg-surface-[a-z]+" src $SRC | sort | uniq -c → elevated 28, raised 22, base 6, input 2 (58; 118 incl stories)
177
+ grep -rnE "boxShadow" src $SRC | grep -v ^src/theme → Workout 16, lab 12, ui 2
178
+ grep -rhoE "\bshadow-(sm|md|lg|xl|2xl|inner|\[[^]]*\])" src $SRC → 13 ui files
179
+ grep -rnE "paperSheet\(|insetWell\(|barPaper\(|grainForTone\(" src → 4 shipped call sites, 17 lab, 2 forks
180
+ grep -rnE "getElevationShadow|getElevationSurface|getBaseSurfaceColor|getValidatedElevation" src | grep -v ^src/theme → Card.tsx, Surface.tsx only
181
+ grep -rhoE "border(-[trblxy])?-hairline(-[a-z]+)?" src $SRC → default 38, strong 13, subtle 5
182
+
183
+ # drift
184
+ grep -rnE "^const [a-zA-Z_]+ = getSemanticColors\('dark'\)" src $SRC | wc -l → 55 (Workout 39, Fatigue 9)
185
+ grep -rE "getSemanticColors\(" src/components src/lab $SRC | wc -l → 71
186
+ grep -rnE "fontSize: [0-9]" src $SRC → Workout 149, lab/surface 56, lab/north-star 28, Fatigue 9
187
+ grep -rnoE "#[0-9a-fA-F]{6}\b" src $SRC | grep -v ^src/theme → lab/surface 63, Workout 34, ui 21
188
+ grep -rnoE "rgba\(" src $SRC | grep -v ^src/theme → Workout 81, lab/surface 31
189
+ raw <Text vs <Typography per dir → ui 81/0, Workout 19/0, ActiveWork 0/47, Table 9/0
190
+ grep -rnE "neutral" src/components/ui/chip/Chip.tsx → lines 38-41 ; tailwind.config.js:7 `extend:`
191
+ grep -rnE "^(export )?function (hexToRgb|mixHex|perceivedLuminance|lstar|parseHex)" src → 4/4/3/3/1 copies
192
+
193
+ # consumers (files in src/components + src/lab rendering <X, excluding own file)
194
+ Pill 6, Badge 2, Chip 0, BaseBadge 0, StatusPill 1, WorkoutPill 0, WeightBadge 0, PrBadge 1, MuscleGroupChip 0, SeverityLabel 2, CoChangeChip 1
195
+ Card 4 (+9 more via import), Surface 3, Tile 3, Section 0, Stack 0, HStack 2
196
+ Indicator 6, StatusDot 5, Tooltip 8, HelpTip 0, Popover 1, Divider 5, Eyebrow 8, Typography 22
197
+ Metric 3, MetricCell 3, MetricTiles 1
198
+
199
+ # code quality
200
+ TypeScript-AST scan (scratchpad longfn.mjs) → 185 functions >30 lines in 114 files; 29 >100
201
+ pnpm exec eslint src/ -f json → 0 errors, 81 warnings (no-unused-vars 39, no-explicit-any 37, no-restricted-syntax 4)
202
+ grep -rL "axe(" $(find src/components -name '*.test.tsx') | wc -l → 16 of 139
203
+ grep -rE "toHaveStyle\([^)]*#[0-9a-fA-F]" src --include='*.test.tsx' | wc -l → 43
204
+ grep -rnE "\b(TODO|FIXME|HACK)\b" src → 1 (a test name) ; commented-out code candidates → 0
205
+ ls tmp-*.mjs | wc -l → 18 (gitignored)
206
+
207
+ # governance
208
+ git log -1 --format='%cs %h' -- packages/ui/src/arch/arch-graph.json → 2026-07-09 bc3aeb4 ; components 91, edges 72, no timestamp field
209
+ node -e "…summary.dead" → Autocomplete, Avatar, Breadcrumbs, Chip, Collapse, HelpTip, IconBox, Link, Menu, Modal, Pill, ReadinessCheck, SideNav, Skeleton, Spinner, Stepper, Switch, Tabs, Toast, ToolbarButton, Tooltip, TopBar, Treemap
210
+ REJECTED.md → 3 entries, last 2026-07-27 ; MATURITY.md → 2026-09-03 ; TOKENS.md → 2026-08-29
211
+ gates: pnpm exec tsc --noEmit → 0 ; prettier --check → clean ; vitest (card, surface, elevation, materials, grey-ramp) → 115 passed
212
+ ```
@@ -0,0 +1,99 @@
1
+ # Library roadmap — decided 2026-09-08
2
+
3
+ The operator reviewed a deep critique of `packages/ui` (attached as
4
+ `docs/audits/2026-09-08-library-critique.md`) and answered its sixteen
5
+ competing-system questions. This file is the record. When a change touches
6
+ one of these areas, it follows the decision here or reopens it explicitly.
7
+
8
+ ## Standing policies
9
+
10
+ **Colour.** Every colour used anywhere comes from a colour ramp (`greyRamp`,
11
+ the OKLCH ramps in `theme/tokens/primitives.ts`). Semantic tokens and palettes
12
+ reference ramp steps; components use only semantic tokens. No file declares
13
+ its own colour. The eslint token-purity error block extends to every family;
14
+ the raw-colour baseline (`titan/no-raw-color`) shrinks per PR and is deleted at
15
+ zero. Workout and Fatigue are not dark-only by design: they become theme-correct.
16
+
17
+ **Consumers.** We own every downstream consumer of `@titan-design/react-ui`
18
+ (audiobook, source-linked; voltras-mcp; agent-chat, tokens only; voltras
19
+ mobile; codewatch; two stale forks). Breaking changes are allowed. A component
20
+ being retired is marked `@deprecated` in code first so no new usage appears,
21
+ and each consumer gets a follow-up task to migrate.
22
+
23
+ **Depth.** See Foundations/Depth. Tone plus lift (rim 0.12, ambient shadow
24
+ scaled by planes crossed) on every raised plane; floating surfaces carry the
25
+ rim and no hairline ring; lift sparingly, inset inside cards; light mode is
26
+ deferred to its own pass.
27
+
28
+ ## Decisions (critique §B)
29
+
30
+ | # | Question | Decision |
31
+ |---|---|---|
32
+ | 1 | Container | `Card` is the only content container. `Surface` is for shell roots (shell, page, rail). `Tile` becomes a Card stat preset. `Section`/`SectionHeader` become Card presets (voltras mobile uses them), not deleted. |
33
+ | 2 | numeric vs named elevation | Both public: `level` is absolute for shell roots, `raise`/`elevation` are relative. Landed in #166. |
34
+ | 3 | Pills | One `Pill` primitive (tone / size / leading slot). `Badge`, `Chip`, `StatusPill`, `PrBadge`, `MuscleGroupChip` survive as thin presets (external users). `BaseBadge`, `WorkoutPill`, `SessionStatePill`, `WeightBadge`, `SeverityLabel`, `CoChangeChip` fold in or are deleted. |
35
+ | 4 | Divider | Every rule is a `Divider`. `border-hairline*` is legal only on Card `outline`/`subtle`, Table rules, and input borders. |
36
+ | 5 | HelpTip | Delete `HelpTip` and `LabelWithHelp`; a Tooltip story shows the pattern. |
37
+ | 6 | Theme source | `SurfaceContext`/`ThemeProvider` only. `utils/useTheme.ts` is deleted (Card no longer uses it after #166). |
38
+ | 7 | Workout/Fatigue dark-only? | No. Full theme-correct port (E3), in the batches below. |
39
+ | 8 | Colour math | One `theme/color-math.ts` with CIELAB L* as the sanctioned metric; duplicate `hexToRgb` ×4, `mixHex` ×4, luminance ×3, test `lstar` ×3 deleted. |
40
+ | 9 | Typography | `Typography` and `Eyebrow` move into `ui/`; re-export shims stay in `custom/`. |
41
+ | 10 | Dot | `Indicator` survives. `StatusDot`'s consumers migrate; its inline glows route through `getGlowShadow`. Fatigue README corrected. |
42
+ | 11 | Metric | One `Metric` with size / align / trend. `MetricTiles` becomes a preset (one external site); `MetricCell` deleted (no consumers). |
43
+ | 12 | paperSheet | Stays hero-only. Cards use the lift (rim 0.12); grain is not on ordinary cards. |
44
+ | 13 | Formatters | `utils/format/{number,time,workout}`. No component-local `formatX` or inline `toFixed`; lint enforces after migration. |
45
+ | 14 | Storybook tree | Six groups: `Foundations/` · `Components/Atoms|Molecules|Organisms/` (ui/* only) · `Custom/<Family>/` · `Shell/` · `Pages/` · `Lab/<Family>/` (src/lab only). |
46
+ | 15 | Lint | One mechanism: the per-family token-purity error block, extended everywhere; baseline retired at zero. |
47
+ | 16 | Light mode | Deferred. Task filed. Not a target for any family until the dark port is done. |
48
+
49
+ ## Epics, in order
50
+
51
+ **E1 · Depth follow-ups** (after #166; starts now)
52
+ - 13 `ui/*` overlays (autocomplete, drawer, help-tip, indicator, menu, modal, popover, select, switch, tabs, toast, toolbar-button, tooltip) move from Tailwind `shadow-*` + hairline ring to the floating lift recipe. Done when `grep -rE "shadow-(sm|md|lg|xl|2xl)" src/components/ui` is empty.
53
+ - Delete `utils/useTheme.ts`.
54
+ - Replace literal-hex pins in `Surface.test.tsx`, `surface.contract.test.ts`, `Card.test.tsx`, `elevation.test.ts` with `greyRamp[...]` references.
55
+ - Purge stale comments: `SessionRail.stories.tsx:40`, `utils/colors.ts:4`, `SessionRail.tsx:16-17`, the skill's `gotchas.md` "Neumorphic depth" section.
56
+ - Delete the `lab/north-star/surfaces.ts` fork and `DualGhostLine`'s local copies; point lab at `theme/materials`.
57
+ - Glow shadows (StatusDot ×7, Indicator, MesoCard, BodyMap, ZoneTrack, IntensityBar, PrHistoryModal) route through `getGlowShadow`.
58
+
59
+ **E4 · Storybook reorganisation** (can run beside E1 on non-overlapping files)
60
+ - Retitle onto the six-group tree; fix `Composes` links.
61
+ - Move the 8 `Lab/`-titled files out of `src/components` (they publish to npm today).
62
+ - Delete duplicate `Lab/ActiveWork/*` (6), `Lab/Components/*` (3), `Lab/Archive/Surface`, each with a REJECTED.md entry.
63
+ - ASCII titles; one naming convention per family.
64
+ - `autodocs` + a `Composes` line on every hardened story; decorators compose `<Surface level="base">`.
65
+ - Thin per-state stories to Default + controls (Input 15, Card 14, Alert 14, Toast 13).
66
+
67
+ **E5 · Governance refresh** (after E4 so tags land on final titles)
68
+ - Regenerate `arch-graph.json`; CI fails when it is older than the newest `index.ts`.
69
+ - REJECTED.md backfill for the ten archived directions plus retired `inset`, `tonalFill`/`ditherTile`, `data-1..10`.
70
+ - `status:` tags; MATURITY review for `ui/*` (38 primitives, not 52).
71
+ - READMEs for `ui/*`, charts, Prose; fix Fatigue README's StatusDot line.
72
+ - Update the workflow skill's `gotchas.md` and `06-lint-guardrails.md`.
73
+
74
+ **E2 · Consolidation** (decisions 1, 3, 4, 5, 10, 11)
75
+ - Card as sole container; Tile and Section as presets; loose `bg-surface-*` Views (58 sites) onto Card.
76
+ - Pill primitive + presets; `Chip` loses `neutral-*`/`text-white`.
77
+ - Divider everywhere (21 rules). Indicator over StatusDot. Metric absorbs MetricTiles; MetricCell deleted. HelpTip deleted.
78
+ - Each retired export: `@deprecated` first, then a consumer-update task per downstream repo.
79
+
80
+ **E3 · Port Workout and Fatigue** (decisions 7, 8, 9, 13, 15)
81
+ - Typography + Eyebrow into `ui/`; `theme/color-math.ts`; `utils/format/*`.
82
+ - Workout batches from the 2026-09-08 audit, smallest drift and most consumers first:
83
+ - B1 (S): MetricCell, SetStrip, SetTableHeader, SetsRepsLoad, ExerciseHeading, ExerciseIndicator, ExerciseCardHeading, PrBadge.
84
+ - B2 (M): SegmentedBar, MuscleGroupChip, PlaceholderStrip, ScheduleTiles, StatusPill, SupersetWrapper, MesoProgressBar, Sparkline, VolumeLandmarkBar, SessionHeader, WeekRow, WorkoutCard.
85
+ - B3 (M): StatusDot (6 cross-family consumers), WeightBadge (the one render-path `getSemanticColors('dark')` bug, lines 46 and 105), ExerciseCard, SetRow, SetBar, WorkoutPill.
86
+ - B4 (M/L): InputBar, PrHistoryModal, RestTimer, SessionRail, BodyMap (the pattern to copy: three correct `resolveColor` calls; one leftover module constant), MesoCard.
87
+ - B5 (L): MesoStatusCard (drift 40, highest), TempoDisplay, BodyMapDetailPanel, StrengthTrendChart, ZoneTrack, CapacityBandChart, IntensityBar, ReadinessCheck, the five page organisms, VelocityStrip (1,468 lines).
88
+ - Fatigue: 9 module constants, local colour math.
89
+ - `ui/*`: 81 raw `Text` onto Typography; Button `#ffffff`, Alert `bg-black`, Tooltip `bg-neutral-800`, Spinner hex.
90
+ - Lint: every family in the error block; delete `raw-color-baseline.json` at zero.
91
+ - Move `velocity-story-kit.tsx` and `setHeadingKit.tsx` out of `components/`.
92
+
93
+ **E6 · Code-quality floor** (independent)
94
+ - Split the 29 functions over 100 lines (four charts >300 lines; VelocityStrip).
95
+ - eslint warnings 81 → 0. `axe` in the 16 test files lacking it. Delete the 18 gitignored `tmp-*.mjs`.
96
+
97
+ ## Consumer follow-ups (one task per repo when E2 lands)
98
+
99
+ audiobook/frontend (Badge, Chip, StatusPill) · voltras-mcp (Pill, Badge, PrBadge, MuscleGroupChip, MetricTiles, StatusPill type) · voltras mobile (Card, Metric, Section, SectionHeader, `getSemanticColors`/`alpha`) · codewatch (Badge, Metric) · voltras-mcp-wave0 and codewatch-wt-c76 (stale forks: retire or repoint).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@titan-design/react-ui",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "Cross-platform design system built on Gluestack UI",
5
5
  "author": "Henry Jewkes",
6
6
  "license": "MIT",
@@ -0,0 +1,52 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+ import { describe, expect, it } from 'vitest'
5
+ // @ts-expect-error — plain-ESM build tooling, shared with scripts/arch-graph.mjs
6
+ import { componentBarrelHash } from '../../scripts/barrel-hash.mjs'
7
+ import graph from './arch-graph.json'
8
+
9
+ const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
10
+ const REPO_ROOT = path.resolve(PKG_ROOT, '../..')
11
+
12
+ describe('arch-graph.json freshness', () => {
13
+ it('records the barrel hash it was generated from', () => {
14
+ expect(graph.componentBarrelHash).toMatch(/^sha256:[0-9a-f]{64}$/)
15
+ })
16
+
17
+ it('matches the current component barrels', () => {
18
+ expect(
19
+ graph.componentBarrelHash,
20
+ 'arch-graph.json is stale: a component barrel changed since it was generated. ' +
21
+ 'Run `pnpm arch:graph -- --reindex` from the repo root and commit the result.'
22
+ ).toBe(componentBarrelHash(PKG_ROOT))
23
+ })
24
+
25
+ it('tallies every configured consumer, so none can be silently scored as zero usage', () => {
26
+ const configured = graph.summary.consumers.map((c) => c.name)
27
+ for (const component of graph.components) {
28
+ expect(
29
+ Object.keys(component.xproj)
30
+ .filter((k) => k !== 'total')
31
+ .sort(),
32
+ `${component.name}.xproj is missing a configured consumer. A consumer absent from ` +
33
+ 'the tally scores 0 usage, which lands its components on the `dead` list.'
34
+ ).toEqual([...configured].sort())
35
+ }
36
+ })
37
+
38
+ // The consumer list is committed precisely so every machine computes the same
39
+ // `dead` verdicts. Adding a consumer without regenerating leaves a graph that
40
+ // looks authoritative and is wrong about the repo that was just added.
41
+ it('was generated from the committed consumer list', () => {
42
+ const shared = JSON.parse(
43
+ readFileSync(path.join(REPO_ROOT, 'scripts/arch.config.json'), 'utf8')
44
+ ) as { consumers: { name: string }[] }
45
+
46
+ expect(
47
+ graph.summary.consumers.map((c) => c.name).sort(),
48
+ 'arch-graph.json was generated from a different consumer set than ' +
49
+ 'scripts/arch.config.json. Run `pnpm arch:graph -- --reindex` and commit the result.'
50
+ ).toEqual(shared.consumers.map((c) => c.name).sort())
51
+ })
52
+ })