@titan-design/react-ui 0.12.0 → 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 +1320 -215
  7. package/dist/index.d.ts +1320 -215
  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 +202 -1042
  21. package/dist/theme/index.d.ts +202 -1042
  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 +972 -0
  31. package/dist/theme/tokens.d.ts +972 -0
  32. package/dist/theme/tokens.js +904 -0
  33. package/dist/theme/tokens.js.map +1 -0
  34. package/dist/theme/tokens.mjs +880 -0
  35. package/dist/theme/tokens.mjs.map +1 -0
  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 +7 -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 +12 -7
  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 +90 -27
  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 +24 -22
  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 +102 -0
  480. package/src/theme/tokens/primitives.test.ts +15 -7
  481. package/src/theme/tokens/primitives.ts +67 -35
  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
package/dist/pages.js CHANGED
@@ -11,6 +11,7 @@ var tailwindMerge = require('tailwind-merge');
11
11
  // src/theme/tokens/primitives.ts
12
12
  var primitiveColors = {
13
13
  white: "#FFFFFF"};
14
+ var alertRedVivid = "#FF4757";
14
15
  var greyRamp = {
15
16
  50: "#F9F6F3",
16
17
  // L*97.0 W6
@@ -161,11 +162,7 @@ var WORKOUT_TOKENS = {
161
162
  intensity: {
162
163
  // matches status-error
163
164
  over2: primitiveRamps.red[700],
164
- over3: primitiveRamps.red[800]},
165
- // Placeholder strip
166
- placeholder: {
167
- fill: "#3A3A3A"
168
- }};
165
+ over3: primitiveRamps.red[800]}};
169
166
 
170
167
  // src/theme/tokens/semantic.ts
171
168
  var semanticColorsLight = {
@@ -174,12 +171,16 @@ var semanticColorsLight = {
174
171
  "brand-primary-light": primitiveRamps.orange[300],
175
172
  "brand-primary-dark": primitiveRamps.orange[500],
176
173
  "brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
174
+ "brand-primary-muted": "rgba(255, 121, 0, 0.30)",
175
+ "brand-primary-strong": "rgba(255, 121, 0, 0.50)",
177
176
  "brand-primary-hover": primitiveRamps.orange[500],
178
177
  "brand-primary-active": primitiveRamps.orange[600],
179
178
  "brand-secondary": primitiveRamps.cyan[600],
180
179
  "brand-secondary-light": primitiveRamps.cyan[500],
181
180
  "brand-secondary-dark": primitiveRamps.cyan[700],
182
181
  "brand-secondary-subtle": "rgba(48, 123, 155, 0.08)",
182
+ "brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
183
+ "brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
183
184
  "brand-secondary-hover": primitiveRamps.cyan[700],
184
185
  "brand-secondary-active": primitiveRamps.cyan[800],
185
186
  // Text on brand backgrounds (on-*)
@@ -190,6 +191,8 @@ var semanticColorsLight = {
190
191
  "status-success-light": primitiveRamps.green[200],
191
192
  "status-success-dark": primitiveRamps.green[600],
192
193
  "status-success-subtle": primitiveRamps.green[50],
194
+ "status-success-muted": "rgba(46, 213, 115, 0.30)",
195
+ "status-success-strong": "rgba(46, 213, 115, 0.50)",
193
196
  // Live-session accent — its OWN role, decoupled from success so the two can diverge
194
197
  "status-live": primitiveRamps.green[300],
195
198
  "status-live-muted": primitiveRamps.green[500],
@@ -197,19 +200,27 @@ var semanticColorsLight = {
197
200
  "status-error-light": primitiveRamps.red[500],
198
201
  "status-error-dark": primitiveRamps.red[700],
199
202
  "status-error-subtle": primitiveRamps.red[50],
200
- "status-error-vivid": primitiveRamps.red[600],
201
- // vivid alert red
203
+ "status-error-muted": "rgba(209, 67, 67, 0.30)",
204
+ "status-error-strong": "rgba(209, 67, 67, 0.50)",
205
+ "status-error-vivid": alertRedVivid,
206
+ // NOT red[600], that is status-error
202
207
  "status-error-vivid-light": primitiveRamps.red[500],
203
208
  "status-error-vivid-dark": primitiveRamps.red[700],
204
209
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
210
+ "status-error-vivid-muted": "rgba(255, 71, 87, 0.30)",
211
+ "status-error-vivid-strong": "rgba(255, 71, 87, 0.50)",
205
212
  "status-warning": primitiveRamps.amber[300],
206
213
  "status-warning-light": primitiveRamps.amber[200],
207
214
  "status-warning-dark": primitiveRamps.amber[500],
208
215
  "status-warning-subtle": primitiveRamps.amber[50],
216
+ "status-warning-muted": "rgba(249, 180, 21, 0.30)",
217
+ "status-warning-strong": "rgba(249, 180, 21, 0.50)",
209
218
  "status-info": primitiveRamps.blue[500],
210
219
  "status-info-light": primitiveRamps.blue[300],
211
220
  "status-info-dark": primitiveRamps.blue[600],
212
221
  "status-info-subtle": primitiveRamps.blue[50],
222
+ "status-info-muted": "rgba(33, 150, 243, 0.30)",
223
+ "status-info-strong": "rgba(33, 150, 243, 0.50)",
213
224
  // Text on status backgrounds (on-status-*)
214
225
  "on-status-success": primitiveColors.white,
215
226
  "on-status-error": primitiveColors.white,
@@ -304,7 +315,7 @@ var semanticColorsLight = {
304
315
  "interactive-disabled": "rgba(55, 65, 81, 0.12)",
305
316
  "interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
306
317
  // Divider
307
- "divider": "#E8E9EB",
318
+ divider: "#E8E9EB",
308
319
  // Avatar default
309
320
  "avatar-background": greyRamp[600],
310
321
  "avatar-text": primitiveColors.white
@@ -315,12 +326,16 @@ var semanticColorsDark = {
315
326
  "brand-primary-light": primitiveRamps.orange[300],
316
327
  "brand-primary-dark": primitiveRamps.orange[500],
317
328
  "brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
329
+ "brand-primary-muted": "rgba(255, 121, 0, 0.30)",
330
+ "brand-primary-strong": "rgba(255, 121, 0, 0.50)",
318
331
  "brand-primary-hover": primitiveRamps.orange[300],
319
332
  "brand-primary-active": primitiveRamps.orange[200],
320
333
  "brand-secondary": primitiveRamps.cyan[600],
321
334
  "brand-secondary-light": primitiveRamps.cyan[500],
322
335
  "brand-secondary-dark": primitiveRamps.cyan[700],
323
336
  "brand-secondary-subtle": "rgba(48, 123, 155, 0.12)",
337
+ "brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
338
+ "brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
324
339
  "brand-secondary-hover": primitiveRamps.cyan[500],
325
340
  "brand-secondary-active": primitiveRamps.cyan[400],
326
341
  // Text on brand backgrounds
@@ -331,6 +346,8 @@ var semanticColorsDark = {
331
346
  "status-success-light": primitiveRamps.green[200],
332
347
  "status-success-dark": primitiveRamps.green[600],
333
348
  "status-success-subtle": "rgba(46, 213, 115, 0.12)",
349
+ "status-success-muted": "rgba(46, 213, 115, 0.30)",
350
+ "status-success-strong": "rgba(46, 213, 115, 0.50)",
334
351
  // Live-session accent — its OWN role, decoupled from success so the two can diverge
335
352
  "status-live": primitiveRamps.green[300],
336
353
  "status-live-muted": primitiveRamps.green[500],
@@ -338,18 +355,26 @@ var semanticColorsDark = {
338
355
  "status-error-light": primitiveRamps.red[500],
339
356
  "status-error-dark": primitiveRamps.red[700],
340
357
  "status-error-subtle": "rgba(209, 67, 67, 0.12)",
341
- "status-error-vivid": primitiveRamps.red[600],
358
+ "status-error-muted": "rgba(209, 67, 67, 0.30)",
359
+ "status-error-strong": "rgba(209, 67, 67, 0.50)",
360
+ "status-error-vivid": alertRedVivid,
342
361
  "status-error-vivid-light": primitiveRamps.red[500],
343
362
  "status-error-vivid-dark": primitiveRamps.red[700],
344
363
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
364
+ "status-error-vivid-muted": "rgba(255, 71, 87, 0.30)",
365
+ "status-error-vivid-strong": "rgba(255, 71, 87, 0.50)",
345
366
  "status-warning": primitiveRamps.amber[300],
346
367
  "status-warning-light": primitiveRamps.amber[200],
347
368
  "status-warning-dark": primitiveRamps.amber[500],
348
369
  "status-warning-subtle": "rgba(249, 180, 21, 0.12)",
370
+ "status-warning-muted": "rgba(249, 180, 21, 0.30)",
371
+ "status-warning-strong": "rgba(249, 180, 21, 0.50)",
349
372
  "status-info": primitiveRamps.blue[500],
350
373
  "status-info-light": primitiveRamps.blue[300],
351
374
  "status-info-dark": primitiveRamps.blue[600],
352
375
  "status-info-subtle": "rgba(33, 150, 243, 0.12)",
376
+ "status-info-muted": "rgba(33, 150, 243, 0.30)",
377
+ "status-info-strong": "rgba(33, 150, 243, 0.50)",
353
378
  // Text on status backgrounds
354
379
  "on-status-success": primitiveColors.white,
355
380
  "on-status-error": primitiveColors.white,
@@ -489,7 +514,7 @@ var semanticColorsDark = {
489
514
  "interactive-disabled": "rgba(255, 255, 255, 0.12)",
490
515
  "interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
491
516
  // Divider
492
- "divider": "rgba(255, 255, 255, 0.09)",
517
+ divider: "rgba(255, 255, 255, 0.09)",
493
518
  // Avatar default
494
519
  "avatar-background": greyRamp[700],
495
520
  "avatar-text": primitiveColors.white
@@ -515,79 +540,6 @@ function hexToRgb(hex) {
515
540
  }
516
541
  return { r, g, b };
517
542
  }
518
- function rgbToHsv(r, g, b) {
519
- const rNorm = r / 255;
520
- const gNorm = g / 255;
521
- const bNorm = b / 255;
522
- const max = Math.max(rNorm, gNorm, bNorm);
523
- const min = Math.min(rNorm, gNorm, bNorm);
524
- const delta = max - min;
525
- const v = max;
526
- const s = max === 0 ? 0 : delta / max;
527
- let h = 0;
528
- if (delta !== 0) {
529
- if (max === rNorm) {
530
- h = 60 * ((gNorm - bNorm) / delta % 6);
531
- } else if (max === gNorm) {
532
- h = 60 * ((bNorm - rNorm) / delta + 2);
533
- } else {
534
- h = 60 * ((rNorm - gNorm) / delta + 4);
535
- }
536
- }
537
- if (h < 0) h += 360;
538
- return { h, s, v };
539
- }
540
- function hsvToRgb(h, s, v) {
541
- const c2 = v * s;
542
- const x = c2 * (1 - Math.abs(h / 60 % 2 - 1));
543
- const m = v - c2;
544
- let rPrime, gPrime, bPrime;
545
- if (h >= 0 && h < 60) {
546
- rPrime = c2;
547
- gPrime = x;
548
- bPrime = 0;
549
- } else if (h >= 60 && h < 120) {
550
- rPrime = x;
551
- gPrime = c2;
552
- bPrime = 0;
553
- } else if (h >= 120 && h < 180) {
554
- rPrime = 0;
555
- gPrime = c2;
556
- bPrime = x;
557
- } else if (h >= 180 && h < 240) {
558
- rPrime = 0;
559
- gPrime = x;
560
- bPrime = c2;
561
- } else if (h >= 240 && h < 300) {
562
- rPrime = x;
563
- gPrime = 0;
564
- bPrime = c2;
565
- } else {
566
- rPrime = c2;
567
- gPrime = 0;
568
- bPrime = x;
569
- }
570
- return {
571
- r: Math.round((rPrime + m) * 255),
572
- g: Math.round((gPrime + m) * 255),
573
- b: Math.round((bPrime + m) * 255)
574
- };
575
- }
576
- function rgbToHex(r, g, b) {
577
- const toHex = (n) => {
578
- const clamped = Math.max(0, Math.min(255, Math.round(n)));
579
- return clamped.toString(16).padStart(2, "0");
580
- };
581
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
582
- }
583
- function lighten(hex, amount = 0.1) {
584
- const rgb = hexToRgb(hex);
585
- if (!rgb) return hex;
586
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
587
- const newV = Math.min(1, hsv.v + amount);
588
- const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
589
- return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
590
- }
591
543
 
592
544
  // src/utils/colors.ts
593
545
  function alpha(color, opacity) {
@@ -634,6 +586,17 @@ function formatVelocity(velocity) {
634
586
  function roundTempo(tempo) {
635
587
  return tempo.map((v) => Math.round(v * 10) / 10);
636
588
  }
589
+ function formatRepsRange(repsLow, repsHigh) {
590
+ if (repsLow != null && repsHigh != null) {
591
+ return repsLow === repsHigh ? `${repsLow}` : `${repsLow}\u2013${repsHigh}`;
592
+ }
593
+ if (repsLow != null) return `${repsLow}`;
594
+ if (repsHigh != null) return `${repsHigh}`;
595
+ return null;
596
+ }
597
+
598
+ // src/theme/materials.ts
599
+ var c = getSemanticColors("dark");
637
600
  function parseHex(hex) {
638
601
  const h = hex.replace("#", "");
639
602
  const full = h.length === 3 ? h.split("").map((ch) => ch + ch).join("") : h;
@@ -657,12 +620,20 @@ function grainForTone(baseColor) {
657
620
  const op = grainOpacityForTone(baseColor).toFixed(3);
658
621
  return `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='${op}'/%3E%3C/svg%3E")`;
659
622
  }
623
+ function insetWell(tone = c["surface-input"]) {
624
+ return {
625
+ backgroundColor: tone,
626
+ boxShadow: "inset 0 2px 6px rgba(0,0,0,0.55), inset 0 -1px 0 rgba(255,255,255,0.12)"
627
+ };
628
+ }
660
629
  function barPaper(color, flip = false) {
661
630
  return {
662
631
  backgroundImage: grainForTone(color),
663
632
  boxShadow: flip ? "0 -6px 16px rgba(0,0,0,0.45)" : "inset 0 1.5px 0 rgba(255,255,255,0.22), 0 6px 16px rgba(0,0,0,0.45)"
664
633
  };
665
634
  }
635
+
636
+ // src/theme/surface-planes.ts
666
637
  var SURFACE_LEVEL_TOKEN = {
667
638
  frame: "background-frame",
668
639
  background: "background-base",
@@ -671,6 +642,30 @@ var SURFACE_LEVEL_TOKEN = {
671
642
  raised: "surface-raised",
672
643
  overlay: "surface-overlay"
673
644
  };
645
+ var PLANE_ORDER = [
646
+ "frame",
647
+ "background",
648
+ "base",
649
+ "elevated",
650
+ "raised",
651
+ "overlay"
652
+ ];
653
+ function surfaceBackground(level, mode) {
654
+ return getSemanticColors(mode)[SURFACE_LEVEL_TOKEN[level]];
655
+ }
656
+ function stepPlane(from, delta) {
657
+ const index = PLANE_ORDER.indexOf(from);
658
+ const clamped = Math.min(PLANE_ORDER.length - 1, Math.max(0, index + delta));
659
+ return PLANE_ORDER[clamped];
660
+ }
661
+ function pressedLevel(parent) {
662
+ return stepPlane(parent, -1);
663
+ }
664
+ function raisedLevel(parent, steps) {
665
+ return stepPlane(parent, Math.max(0, steps));
666
+ }
667
+
668
+ // src/components/ui/surface/SurfaceContext.ts
674
669
  var ON_SURFACE_TOKEN = {
675
670
  primary: "text-primary",
676
671
  secondary: "text-secondary",
@@ -687,9 +682,6 @@ function useSurfaceMode() {
687
682
  function useOnSurfaceColor(role = "primary") {
688
683
  return getSemanticColors(useSurfaceMode())[ON_SURFACE_TOKEN[role]];
689
684
  }
690
- function surfaceBackground(level, mode) {
691
- return getSemanticColors(mode)[SURFACE_LEVEL_TOKEN[level]];
692
- }
693
685
  var ANIMATION_EASING = reactNative.Easing.bezier(0.22, 1, 0.36, 1);
694
686
  var PEAK_OVERSHOOT = 1.12;
695
687
  function getReducedMotionPreference() {
@@ -763,14 +755,14 @@ var jsx = wrapJsx(jsxRuntime.jsx);
763
755
  var jsxs = wrapJsx(jsxRuntime.jsxs);
764
756
 
765
757
  // src/components/custom/charts/SetBarChart.tsx
766
- function mixHex(a, b, t12) {
758
+ function mixHex(a, b, t7) {
767
759
  const parse = (h) => {
768
760
  const s = h.replace("#", "");
769
761
  return [parseInt(s.slice(0, 2), 16), parseInt(s.slice(2, 4), 16), parseInt(s.slice(4, 6), 16)];
770
762
  };
771
763
  const [ar, ag, ab] = parse(a);
772
764
  const [br, bg, bb] = parse(b);
773
- const ch = (x, y) => Math.round(x + (y - x) * t12).toString(16).padStart(2, "0");
765
+ const ch = (x, y) => Math.round(x + (y - x) * t7).toString(16).padStart(2, "0");
774
766
  return `#${ch(ar, br)}${ch(ag, bg)}${ch(ab, bb)}`;
775
767
  }
776
768
  var VARIABLE_FILL = primitiveRamps.cyan[900];
@@ -783,6 +775,13 @@ function scaleDenominator(scale, maxValue) {
783
775
  function valueLabelFontSize(height) {
784
776
  return Math.round(Math.max(8, Math.min(12, height * 0.11)));
785
777
  }
778
+ var LABEL_GLYPH_WIDTH_RATIO = 0.62;
779
+ function estimateValueLabelWidth(text, fontSize) {
780
+ return text.length * fontSize * LABEL_GLYPH_WIDTH_RATIO;
781
+ }
782
+ function shouldFlipEdgeLabel(roomPx, labelWidthPx) {
783
+ return labelWidthPx / 2 > roomPx;
784
+ }
786
785
  var SET_BAR_DEFAULT_HEIGHT = 220;
787
786
  var LABEL_ROW_HEIGHT = 16;
788
787
  var LABEL_GAP = 3;
@@ -826,6 +825,7 @@ function SetBarChart({
826
825
  flat = false,
827
826
  showValueLabels: showValueLabelsProp = false,
828
827
  formatValue: formatValue2 = String,
828
+ flipEdgeLabel = false,
829
829
  todoVariant = "solid",
830
830
  minColumns,
831
831
  renderReference,
@@ -941,6 +941,12 @@ function SetBarChart({
941
941
  }) : isLive ? liveGrowth.interpolate({ inputRange: [0, 1], outputRange: [0, barHeight(value)] }) : barHeight(value);
942
942
  const ownLabel = showValueLabels && !renderBarOverlay && showBarLabel(repIndex);
943
943
  const labelBottom = (expandProgress ? valueBarHeight(best) : barHeight(best)) + LABEL_GAP;
944
+ const isLastCell = i === cells.length - 1;
945
+ const labelText = formatValue2(value);
946
+ const flipLabel = flipEdgeLabel && isLastCell && shouldFlipEdgeLabel(
947
+ barWidth / 2,
948
+ estimateValueLabelWidth(labelText, valueLabelFontSize(height))
949
+ );
944
950
  return /* @__PURE__ */ jsxs(reactNative.View, { accessibilityElementsHidden: renderBarOverlay == null, style: column, children: [
945
951
  ownLabel && // All labels pin to one aligned row JUST ABOVE THE PEAK BAR (not the container top),
946
952
  // in the muted on-surface-secondary tone — so the row hugs the bars, no floating void.
@@ -950,9 +956,8 @@ function SetBarChart({
950
956
  style: {
951
957
  position: "absolute",
952
958
  bottom: labelBottom,
953
- left: 0,
954
- right: 0,
955
- alignItems: "center",
959
+ ...flipLabel ? { right: 0 } : { left: 0, right: 0 },
960
+ alignItems: flipLabel ? "flex-end" : "center",
956
961
  ...expandProgress ? { opacity: expandProgress } : null
957
962
  },
958
963
  pointerEvents: "none",
@@ -962,7 +967,7 @@ function SetBarChart({
962
967
  className: "text-text-secondary",
963
968
  style: [{ fontSize: valueLabelFontSize(height), fontWeight: "700" }, flipStyle],
964
969
  testID: `${testIDPrefix}-label-${repIndex}`,
965
- children: formatValue2(value)
970
+ children: labelText
966
971
  }
967
972
  )
968
973
  }
@@ -1457,6 +1462,7 @@ function VelocityStrip({
1457
1462
  label,
1458
1463
  showValueLabels: true,
1459
1464
  formatValue: formatVelocity,
1465
+ flipEdgeLabel: columnSlots != null,
1460
1466
  renderReference: (g) => velocityReferenceOverlay(g, lossBandsOn),
1461
1467
  hideBaseline: true,
1462
1468
  testID: "velocity-strip-hero",
@@ -1661,8 +1667,12 @@ function VelocityStrip({
1661
1667
  function cn(...inputs) {
1662
1668
  return tailwindMerge.twMerge(clsx.clsx(inputs));
1663
1669
  }
1670
+ function resolveColor(token, mode = "dark") {
1671
+ return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
1672
+ }
1664
1673
 
1665
1674
  // src/components/custom/Workout/PlaceholderStrip.tsx
1675
+ var RAIL_TOKEN = "border-prominent";
1666
1676
  function SingleStrip({
1667
1677
  width,
1668
1678
  className,
@@ -1675,7 +1685,7 @@ function SingleStrip({
1675
1685
  style: [
1676
1686
  {
1677
1687
  height: 3,
1678
- backgroundColor: WORKOUT_TOKENS.placeholder.fill,
1688
+ backgroundColor: resolveColor(RAIL_TOKEN),
1679
1689
  borderRadius: 2,
1680
1690
  opacity: 0.5
1681
1691
  },
@@ -1712,7 +1722,7 @@ function SegmentedStrip({
1712
1722
  style: {
1713
1723
  flex: 1,
1714
1724
  height: 3,
1715
- backgroundColor: WORKOUT_TOKENS.placeholder.fill,
1725
+ backgroundColor: resolveColor(RAIL_TOKEN),
1716
1726
  borderRadius: 1,
1717
1727
  minWidth: 4
1718
1728
  },
@@ -1724,11 +1734,7 @@ function SegmentedStrip({
1724
1734
  }
1725
1735
  );
1726
1736
  }
1727
- function PlaceholderStrip({
1728
- mode = "single",
1729
- segments,
1730
- ...props
1731
- }) {
1737
+ function PlaceholderStrip({ mode = "single", segments, ...props }) {
1732
1738
  if (mode === "segmented") {
1733
1739
  return /* @__PURE__ */ jsx(SegmentedStrip, { segments, ...props });
1734
1740
  }
@@ -1887,9 +1893,98 @@ function BaseBadge({
1887
1893
  }
1888
1894
  return badge;
1889
1895
  }
1896
+ var variantStyles = {
1897
+ h1: "font-heading text-5xl font-bold leading-tight",
1898
+ h2: "font-heading text-4xl font-bold leading-tight",
1899
+ h3: "font-heading text-3xl font-bold leading-tight",
1900
+ h4: "font-heading text-2xl font-bold leading-tight",
1901
+ h5: "font-heading text-xl font-semibold leading-tight",
1902
+ h6: "font-heading text-lg font-semibold leading-tight",
1903
+ body1: "font-body text-base font-normal leading-normal",
1904
+ body2: "font-body text-sm font-normal leading-normal",
1905
+ subtitle1: "font-body text-base font-medium leading-relaxed",
1906
+ subtitle2: "font-body text-sm font-medium leading-normal",
1907
+ caption: "font-body text-xs font-normal leading-loose",
1908
+ overline: "font-body text-xs font-semibold uppercase tracking-widest leading-relaxed",
1909
+ button: "font-sans text-sm font-semibold leading-relaxed",
1910
+ // Monospace technical readouts (clocks, ids, metrics) and their all-caps label form.
1911
+ mono: "font-mono text-xs font-normal leading-normal",
1912
+ monoLabel: "font-mono text-xs font-bold uppercase tracking-wide leading-normal",
1913
+ // The sans (Inter) label pair: 10px for dense table/column headers, 12px bold for
1914
+ // badge and row labels. `overline` is the 12px font-body form of the same idea.
1915
+ microLabel: "font-sans text-2xs font-semibold uppercase tracking-widest leading-normal",
1916
+ boldLabel: "font-sans text-xs font-bold leading-normal"
1917
+ };
1918
+ var colorStyles = {
1919
+ primary: "text-text-primary",
1920
+ secondary: "text-text-secondary",
1921
+ tertiary: "text-text-tertiary",
1922
+ disabled: "text-text-disabled",
1923
+ inverse: "text-text-inverse",
1924
+ success: "text-status-success",
1925
+ error: "text-status-error",
1926
+ warning: "text-status-warning",
1927
+ info: "text-status-info",
1928
+ inherit: ""
1929
+ // No color class, inherit from parent
1930
+ };
1931
+ var alignStyles = {
1932
+ left: "text-left",
1933
+ center: "text-center",
1934
+ right: "text-right",
1935
+ justify: "text-justify"
1936
+ };
1937
+ var headingVariants = ["h1", "h2", "h3", "h4", "h5", "h6"];
1938
+ var marginBottomStyles = {
1939
+ none: "",
1940
+ sm: "mb-1",
1941
+ md: "mb-2",
1942
+ lg: "mb-4"
1943
+ };
1944
+ function Typography({
1945
+ variant = "body1",
1946
+ color = "primary",
1947
+ align,
1948
+ truncate = false,
1949
+ noWrap = false,
1950
+ // deprecated, kept for backward compatibility
1951
+ marginBottom,
1952
+ gutterBottom = false,
1953
+ // deprecated, kept for backward compatibility
1954
+ maxLines,
1955
+ className,
1956
+ children,
1957
+ ...props
1958
+ }) {
1959
+ const isHeading = headingVariants.includes(variant);
1960
+ const shouldTruncate = truncate || noWrap;
1961
+ const mb = marginBottom || (gutterBottom ? "md" : "none");
1962
+ let numLines;
1963
+ if (maxLines) {
1964
+ numLines = maxLines;
1965
+ } else if (shouldTruncate) {
1966
+ numLines = 1;
1967
+ }
1968
+ return /* @__PURE__ */ jsx(
1969
+ reactNative.Text,
1970
+ {
1971
+ accessibilityRole: isHeading ? "header" : "text",
1972
+ numberOfLines: numLines,
1973
+ className: cn(
1974
+ variantStyles[variant],
1975
+ color !== "inherit" && colorStyles[color],
1976
+ align && alignStyles[align],
1977
+ shouldTruncate && "truncate",
1978
+ marginBottomStyles[mb],
1979
+ className
1980
+ ),
1981
+ ...props,
1982
+ children
1983
+ }
1984
+ );
1985
+ }
1890
1986
 
1891
1987
  // src/components/custom/Workout/PrBadge.tsx
1892
- var BRAND_PRIMARY = getSemanticColors("dark")["brand-primary"];
1893
1988
  var typeLabels = {
1894
1989
  e1rm: "PR e1RM",
1895
1990
  weight: "PR Weight",
@@ -1906,6 +2001,7 @@ function PrBadge({
1906
2001
  ...props
1907
2002
  }) {
1908
2003
  const resolvedLabel = labelProp ?? typeLabels[type];
2004
+ const brandPrimary = resolveColor("brand-primary");
1909
2005
  const [scale] = react.useState(() => new reactNative.Animated.Value(animate ? 0.8 : 1));
1910
2006
  const [opacity] = react.useState(() => new reactNative.Animated.Value(animate ? 0 : 1));
1911
2007
  react.useEffect(() => {
@@ -1933,7 +2029,7 @@ function PrBadge({
1933
2029
  accessibilityLabel: `Personal record: ${resolvedLabel}`,
1934
2030
  testID: "pr-badge-star",
1935
2031
  ...props,
1936
- children: /* @__PURE__ */ jsx(StarIcon, { size: 14, color: BRAND_PRIMARY, fill: BRAND_PRIMARY, strokeWidth: 2 })
2032
+ children: /* @__PURE__ */ jsx(StarIcon, { size: 14, color: brandPrimary, fill: brandPrimary, strokeWidth: 2 })
1937
2033
  }
1938
2034
  ) : /* @__PURE__ */ jsx(
1939
2035
  BaseBadge,
@@ -1943,14 +2039,11 @@ function PrBadge({
1943
2039
  accessibilityLabel: `Personal record: ${resolvedLabel}`,
1944
2040
  ...props,
1945
2041
  children: /* @__PURE__ */ jsxs(
1946
- reactNative.Text,
2042
+ Typography,
1947
2043
  {
1948
- style: {
1949
- fontSize: 12,
1950
- color: BRAND_PRIMARY,
1951
- fontWeight: "700",
1952
- fontFamily: "Inter, sans-serif"
1953
- },
2044
+ variant: "boldLabel",
2045
+ color: "inherit",
2046
+ className: "leading-[normal] text-brand-primary",
1954
2047
  children: [
1955
2048
  "\u2605",
1956
2049
  " ",
@@ -1961,28 +2054,15 @@ function PrBadge({
1961
2054
  }
1962
2055
  );
1963
2056
  if (animate) {
1964
- return /* @__PURE__ */ jsx(
1965
- reactNative.Animated.View,
1966
- {
1967
- style: { transform: [{ scale }], opacity },
1968
- testID: "pr-badge-animated",
1969
- children: badge
1970
- }
1971
- );
2057
+ return /* @__PURE__ */ jsx(reactNative.Animated.View, { style: { transform: [{ scale }], opacity }, testID: "pr-badge-animated", children: badge });
1972
2058
  }
1973
2059
  return badge;
1974
2060
  }
1975
- var DARK = getSemanticColors("dark");
1976
- var TEXT_ACTIVE = DARK["text-primary"];
1977
- var TEXT_MUTED = DARK["text-secondary"];
2061
+ var TEXT_ACTIVE = "text-primary";
2062
+ var TEXT_MUTED = "text-secondary";
1978
2063
  var COL = { set: 36, reps: 44, load: 56, rpe: 36 };
1979
- var cellText = { fontFamily: "Inter, sans-serif", fontSize: 13, fontWeight: "600" };
1980
- var typeBadge = {
1981
- fontSize: 10,
1982
- fontWeight: "700",
1983
- fontFamily: "Inter, sans-serif",
1984
- color: WORKOUT_TOKENS.scale.orange,
1985
- backgroundColor: "rgba(255,165,2,0.12)",
2064
+ var CELL_CLASS = "font-semibold leading-[normal]";
2065
+ var typeBadgeStyle = {
1986
2066
  paddingVertical: 1,
1987
2067
  paddingHorizontal: 5,
1988
2068
  borderRadius: 3,
@@ -2043,7 +2123,8 @@ function RowStrip({ set }) {
2043
2123
  }
2044
2124
  function SetRow(set) {
2045
2125
  const live = set.state === "live";
2046
- const valueColor = live ? TEXT_ACTIVE : TEXT_MUTED;
2126
+ const valueColor = resolveColor(live ? TEXT_ACTIVE : TEXT_MUTED);
2127
+ const mutedColor = resolveColor(TEXT_MUTED);
2047
2128
  const rpe = set.state === "todo" ? null : set.rpe;
2048
2129
  return /* @__PURE__ */ jsxs(
2049
2130
  reactNative.View,
@@ -2053,10 +2134,60 @@ function SetRow(set) {
2053
2134
  testID: "set-row",
2054
2135
  children: [
2055
2136
  /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { justifyContent: "space-between" }, children: [
2056
- /* @__PURE__ */ jsx(Cell, { width: COL.set, testID: "set-row-set-number", children: set.setType ? /* @__PURE__ */ jsx(reactNative.Text, { style: typeBadge, testID: "set-row-type-badge", children: set.setType }) : /* @__PURE__ */ jsx(reactNative.Text, { style: { ...cellText, color: valueColor, fontWeight: live ? "700" : "600" }, children: set.setNumber }) }),
2057
- /* @__PURE__ */ jsx(Cell, { width: COL.reps, testID: "set-row-reps", children: /* @__PURE__ */ jsx(reactNative.Text, { style: { ...cellText, color: valueColor }, children: displayReps(set) }) }),
2058
- /* @__PURE__ */ jsx(Cell, { width: COL.load, testID: "set-row-weight", children: /* @__PURE__ */ jsx(reactNative.Text, { style: { ...cellText, color: valueColor }, children: roundWeight(displayWeight(set)) }) }),
2059
- /* @__PURE__ */ jsx(Cell, { width: COL.rpe, testID: "set-row-rpe", children: /* @__PURE__ */ jsx(reactNative.Text, { style: { ...cellText, color: TEXT_MUTED }, children: rpe != null ? roundRpe(rpe) : "\u2014" }) })
2137
+ /* @__PURE__ */ jsx(Cell, { width: COL.set, testID: "set-row-set-number", children: set.setType ? /* @__PURE__ */ jsx(
2138
+ Typography,
2139
+ {
2140
+ variant: "boldLabel",
2141
+ color: "inherit",
2142
+ className: "text-2xs leading-[normal]",
2143
+ style: {
2144
+ ...typeBadgeStyle,
2145
+ color: resolveColor("brand-primary"),
2146
+ backgroundColor: resolveColor("brand-primary-subtle")
2147
+ },
2148
+ testID: "set-row-type-badge",
2149
+ children: set.setType
2150
+ }
2151
+ ) : /* @__PURE__ */ jsx(
2152
+ Typography,
2153
+ {
2154
+ variant: "boldLabel",
2155
+ color: "inherit",
2156
+ className: live ? "font-bold leading-[normal]" : CELL_CLASS,
2157
+ style: { color: valueColor },
2158
+ children: set.setNumber
2159
+ }
2160
+ ) }),
2161
+ /* @__PURE__ */ jsx(Cell, { width: COL.reps, testID: "set-row-reps", children: /* @__PURE__ */ jsx(
2162
+ Typography,
2163
+ {
2164
+ variant: "boldLabel",
2165
+ color: "inherit",
2166
+ className: CELL_CLASS,
2167
+ style: { color: valueColor },
2168
+ children: displayReps(set)
2169
+ }
2170
+ ) }),
2171
+ /* @__PURE__ */ jsx(Cell, { width: COL.load, testID: "set-row-weight", children: /* @__PURE__ */ jsx(
2172
+ Typography,
2173
+ {
2174
+ variant: "boldLabel",
2175
+ color: "inherit",
2176
+ className: CELL_CLASS,
2177
+ style: { color: valueColor },
2178
+ children: roundWeight(displayWeight(set))
2179
+ }
2180
+ ) }),
2181
+ /* @__PURE__ */ jsx(Cell, { width: COL.rpe, testID: "set-row-rpe", children: /* @__PURE__ */ jsx(
2182
+ Typography,
2183
+ {
2184
+ variant: "boldLabel",
2185
+ color: "inherit",
2186
+ className: CELL_CLASS,
2187
+ style: { color: mutedColor },
2188
+ children: rpe != null ? roundRpe(rpe) : "\u2014"
2189
+ }
2190
+ ) })
2060
2191
  ] }),
2061
2192
  /* @__PURE__ */ jsx(reactNative.View, { style: { marginTop: live ? 6 : 4 }, testID: "set-row-strip", children: /* @__PURE__ */ jsx(RowStrip, { set }) })
2062
2193
  ]
@@ -2064,6 +2195,7 @@ function SetRow(set) {
2064
2195
  );
2065
2196
  }
2066
2197
  var PREV_COLUMN = { label: "PREV", width: void 0 };
2198
+ var COLUMN_LABEL = "leading-[normal]";
2067
2199
  function buildColumns(unit, showPrevious) {
2068
2200
  return [
2069
2201
  { label: "SET", width: 36 },
@@ -2102,20 +2234,7 @@ function SetTableHeader({
2102
2234
  gap: 8
2103
2235
  },
2104
2236
  ...isFlex ? { className: "flex-1" } : {},
2105
- children: /* @__PURE__ */ jsx(
2106
- reactNative.Text,
2107
- {
2108
- className: "text-text-tertiary",
2109
- style: {
2110
- fontSize: 10,
2111
- fontWeight: "600",
2112
- fontFamily: "Inter, sans-serif",
2113
- textTransform: "uppercase",
2114
- letterSpacing: 0.8
2115
- },
2116
- children: label
2117
- }
2118
- )
2237
+ children: /* @__PURE__ */ jsx(Typography, { variant: "microLabel", color: "tertiary", className: COLUMN_LABEL, children: label })
2119
2238
  },
2120
2239
  label
2121
2240
  );
@@ -2141,7 +2260,6 @@ function MetricCell({ children, color, fontSize = 11 }) {
2141
2260
  }
2142
2261
 
2143
2262
  // src/components/custom/Workout/SetsRepsLoad.tsx
2144
- var t2 = getSemanticColors("dark");
2145
2263
  var TIMES = "\xD7";
2146
2264
  var AT = "@";
2147
2265
  function SetsRepsLoad({
@@ -2153,8 +2271,8 @@ function SetsRepsLoad({
2153
2271
  className,
2154
2272
  ...props
2155
2273
  }) {
2156
- const value = t2["text-primary"];
2157
- const sep = t2["text-tertiary"];
2274
+ const value = useOnSurfaceColor("primary");
2275
+ const sep = useOnSurfaceColor("tertiary");
2158
2276
  return /* @__PURE__ */ jsxs(
2159
2277
  reactNative.View,
2160
2278
  {
@@ -2174,19 +2292,19 @@ function SetsRepsLoad({
2174
2292
  }
2175
2293
  );
2176
2294
  }
2177
- var t3 = getSemanticColors("dark");
2295
+ var t2 = getSemanticColors("dark");
2178
2296
  var INTER = "Inter, sans-serif";
2179
2297
  var TEXT_TERTIARY = "#6B7280";
2180
- var STATUS_ERROR = t3["status-error"];
2181
- var STATUS_SUCCESS = t3["status-success"];
2182
- var STATUS_WARNING = t3["status-warning"];
2298
+ var STATUS_ERROR = t2["status-error"];
2299
+ var STATUS_SUCCESS = t2["status-success"];
2300
+ var STATUS_WARNING = t2["status-warning"];
2183
2301
  var ON_TARGET_MS = 100;
2184
2302
  function getTempoFillPct(elapsedMs, targetMs) {
2185
2303
  if (!targetMs) return 100;
2186
2304
  return Math.min(100, elapsedMs / targetMs * 100);
2187
2305
  }
2188
2306
  function activeNumberTone(elapsedMs, targetMs) {
2189
- if (targetMs == null) return t3["text-primary"];
2307
+ if (targetMs == null) return t2["text-primary"];
2190
2308
  const remainingMs = targetMs - elapsedMs;
2191
2309
  if (remainingMs > ON_TARGET_MS) return STATUS_WARNING;
2192
2310
  if (remainingMs >= -ON_TARGET_MS) return STATUS_SUCCESS;
@@ -2338,7 +2456,7 @@ function TempoDisplay({
2338
2456
  style: {
2339
2457
  flexDirection: "row",
2340
2458
  alignItems: "center",
2341
- backgroundColor: t3["surface-raised"],
2459
+ backgroundColor: t2["surface-raised"],
2342
2460
  paddingHorizontal: chromePadX,
2343
2461
  paddingVertical: chromePadY,
2344
2462
  borderRadius: chromeRadius
@@ -2353,7 +2471,7 @@ function TempoDisplay({
2353
2471
  fontSize: labelFont,
2354
2472
  fontWeight: "500",
2355
2473
  // Live-muted green while a rep is running, tertiary at rest.
2356
- color: live ? t3["status-live-muted"] : TEXT_TERTIARY,
2474
+ color: live ? t2["status-live-muted"] : TEXT_TERTIARY,
2357
2475
  letterSpacing: 0.5,
2358
2476
  textTransform: "uppercase",
2359
2477
  marginRight: Math.round(fontSize * 0.5)
@@ -2411,7 +2529,7 @@ function TempoDisplay({
2411
2529
  reactNative.View,
2412
2530
  {
2413
2531
  style: {
2414
- backgroundColor: t3["surface-overlay"],
2532
+ backgroundColor: t2["surface-overlay"],
2415
2533
  borderRadius: 6,
2416
2534
  paddingVertical: 8,
2417
2535
  paddingHorizontal: 12,
@@ -2464,17 +2582,17 @@ function TempoDisplay({
2464
2582
  }
2465
2583
  );
2466
2584
  }
2467
- var t4 = getSemanticColors("dark");
2468
2585
  var INDICATOR_CONFIG = {
2469
- imbalance: { Icon: ScaleIcon, color: t4["status-error"], label: "Left/right imbalance" },
2470
- overshoot: { Icon: AlertTriangleIcon, color: t4["status-error"], label: "Load overshoot" },
2471
- "velocity-loss": { Icon: TrendingDownIcon, color: t4["status-warning"], label: "Velocity loss" },
2472
- "missed-reps": { Icon: CircleSlashIcon, color: t4["status-warning"], label: "Missed reps" },
2473
- pr: { Icon: AwardIcon, color: t4["status-success"], label: "Personal record" },
2474
- info: { Icon: InfoIcon, color: t4["status-info"], label: "More info" }
2586
+ imbalance: { Icon: ScaleIcon, token: "status-error", label: "Left/right imbalance" },
2587
+ overshoot: { Icon: AlertTriangleIcon, token: "status-error", label: "Load overshoot" },
2588
+ "velocity-loss": { Icon: TrendingDownIcon, token: "status-warning", label: "Velocity loss" },
2589
+ "missed-reps": { Icon: CircleSlashIcon, token: "status-warning", label: "Missed reps" },
2590
+ pr: { Icon: AwardIcon, token: "status-success", label: "Personal record" },
2591
+ info: { Icon: InfoIcon, token: "status-info", label: "More info" }
2475
2592
  };
2476
2593
  function ExerciseIndicator({ kind, onPress, className, ...props }) {
2477
- const { Icon, color, label } = INDICATOR_CONFIG[kind];
2594
+ const { Icon, token, label } = INDICATOR_CONFIG[kind];
2595
+ const color = resolveColor(token);
2478
2596
  const chip = /* @__PURE__ */ jsx(
2479
2597
  reactNative.View,
2480
2598
  {
@@ -2529,10 +2647,10 @@ function ExerciseHeading({
2529
2647
  testID: "exercise-card-header",
2530
2648
  children: [
2531
2649
  /* @__PURE__ */ jsx(
2532
- reactNative.Text,
2650
+ Typography,
2533
2651
  {
2534
- className: "text-text-primary",
2535
- style: { fontSize: 14, fontFamily: '"Space Grotesk", sans-serif', fontWeight: "700" },
2652
+ variant: "boldLabel",
2653
+ className: "font-heading text-sm leading-[normal]",
2536
2654
  testID: "exercise-card-name",
2537
2655
  children: name
2538
2656
  }
@@ -2661,12 +2779,12 @@ function SegmentedBar({
2661
2779
 
2662
2780
  // src/components/custom/Workout/SetBar.tsx
2663
2781
  var SET_STRIP_ZONES = {
2664
- slow: primitiveRamps.red[600],
2665
- moderate: primitiveRamps.orange[400],
2666
- fast: primitiveRamps.amber[300],
2667
- fastest: primitiveRamps.green[300]
2782
+ slow: WORKOUT_TOKENS.scale.red,
2783
+ moderate: WORKOUT_TOKENS.scale.orange,
2784
+ fast: WORKOUT_TOKENS.scale.yellow,
2785
+ fastest: WORKOUT_TOKENS.scale.green
2668
2786
  };
2669
- var TODO_COLOR = greyRamp[900];
2787
+ var TODO_COLOR = resolveColor("border-prominent");
2670
2788
  var SET_STRIP_VARIABLE_COLOR = primitiveRamps.cyan[900];
2671
2789
  var NOTCH_GAP = 2;
2672
2790
  var CLUSTER_GAP = 3;
@@ -2780,6 +2898,10 @@ function describeSets(sets) {
2780
2898
  const upcoming = sets.filter((s) => setCategory(s) === "upcoming").length;
2781
2899
  return `Set progress: ${done} done, ${active} in progress, ${upcoming} upcoming`;
2782
2900
  }
2901
+ function repsRangeLabel(set) {
2902
+ if (set.status !== "todo" && set.status !== "active") return null;
2903
+ return formatRepsRange(set.repsLow, set.repsHigh);
2904
+ }
2783
2905
  function SetStrip({ sets, height = 8, className, ...props }) {
2784
2906
  return /* @__PURE__ */ jsx(
2785
2907
  reactNative.View,
@@ -2790,7 +2912,22 @@ function SetStrip({ sets, height = 8, className, ...props }) {
2790
2912
  accessibilityLabel: describeSets(sets),
2791
2913
  testID: "set-strip",
2792
2914
  ...props,
2793
- children: sets.map((set, i) => /* @__PURE__ */ jsx(SetBar, { set, height }, i))
2915
+ children: sets.map((set, i) => {
2916
+ const label = repsRangeLabel(set);
2917
+ if (label == null) return /* @__PURE__ */ jsx(SetBar, { set, height }, i);
2918
+ return /* @__PURE__ */ jsxs(reactNative.View, { style: { flex: 1, minWidth: 0, position: "relative" }, children: [
2919
+ /* @__PURE__ */ jsx(
2920
+ reactNative.Text,
2921
+ {
2922
+ className: "text-text-secondary text-2xs font-semibold text-center",
2923
+ style: { position: "absolute", bottom: height + 3, left: 0, right: 0 },
2924
+ testID: "set-strip-reps-label",
2925
+ children: label
2926
+ }
2927
+ ),
2928
+ /* @__PURE__ */ jsx(SetBar, { set, height })
2929
+ ] }, i);
2930
+ })
2794
2931
  }
2795
2932
  );
2796
2933
  }
@@ -2902,28 +3039,24 @@ function CollapsedCard({
2902
3039
  children: [
2903
3040
  /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", testID: "exercise-card-header", children: [
2904
3041
  /* @__PURE__ */ jsx(
2905
- reactNative.Text,
3042
+ Typography,
2906
3043
  {
2907
- className: "text-text-primary",
2908
- style: {
2909
- fontSize: 14,
2910
- fontFamily: '"Space Grotesk", sans-serif',
2911
- fontWeight: "700"
2912
- },
3044
+ variant: "h6",
3045
+ color: "primary",
3046
+ className: "text-sm font-bold leading-[normal]",
2913
3047
  testID: "exercise-card-name",
2914
3048
  children: name
2915
3049
  }
2916
3050
  ),
2917
3051
  /* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
2918
- summary && /* @__PURE__ */ jsx(
2919
- reactNative.Text,
3052
+ summary && /* The demo's "body" face is Inter, which is the library's `font-sans`
3053
+ (the mapping B1 established for PrBadge), not Typography's `font-body`. */
3054
+ /* @__PURE__ */ jsx(
3055
+ Typography,
2920
3056
  {
2921
- className: "text-text-secondary",
2922
- style: {
2923
- fontSize: 12,
2924
- fontFamily: "Inter, sans-serif",
2925
- marginRight: 8
2926
- },
3057
+ variant: "caption",
3058
+ color: "secondary",
3059
+ className: "font-sans mr-2 leading-[normal]",
2927
3060
  testID: "exercise-card-summary",
2928
3061
  children: formatSummary(summary)
2929
3062
  }
@@ -2957,8 +3090,6 @@ function CollapsedCard({
2957
3090
  }
2958
3091
  );
2959
3092
  }
2960
- var DARK2 = getSemanticColors("dark");
2961
- var BODY_DIVIDER = DARK2["hairline-subtle"];
2962
3093
  function deriveHeaderSetStates(sets) {
2963
3094
  return sets.map((set) => {
2964
3095
  switch (set.state) {
@@ -3019,7 +3150,11 @@ function ExpandedCard({
3019
3150
  /* @__PURE__ */ jsxs(
3020
3151
  reactNative.View,
3021
3152
  {
3022
- style: { borderTopWidth: 1, borderTopColor: BODY_DIVIDER, paddingBottom: 6 },
3153
+ style: {
3154
+ borderTopWidth: 1,
3155
+ borderTopColor: resolveColor("hairline-subtle"),
3156
+ paddingBottom: 6
3157
+ },
3023
3158
  testID: "exercise-card-body",
3024
3159
  children: [
3025
3160
  /* @__PURE__ */ jsx(SetTableHeader, { unit, showPrevious: false, testID: "exercise-card-column-headers" }),
@@ -3054,45 +3189,36 @@ function UpcomingCard({
3054
3189
  testID: "exercise-card",
3055
3190
  children: /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", children: [
3056
3191
  /* @__PURE__ */ jsx(
3057
- reactNative.Text,
3192
+ Typography,
3058
3193
  {
3059
- className: "text-text-primary",
3060
- style: {
3061
- flexShrink: 0,
3062
- fontSize: 14,
3063
- fontFamily: '"Space Grotesk", sans-serif',
3064
- fontWeight: "700"
3065
- },
3194
+ variant: "h6",
3195
+ color: "primary",
3196
+ className: "shrink-0 text-sm font-bold leading-[normal]",
3066
3197
  testID: "exercise-card-name",
3067
3198
  children: name
3068
3199
  }
3069
3200
  ),
3070
3201
  prescription && /* @__PURE__ */ jsx(
3071
- reactNative.Text,
3202
+ Typography,
3072
3203
  {
3073
- className: "text-text-secondary",
3074
- numberOfLines: 1,
3075
- style: {
3076
- flexShrink: 1,
3077
- fontSize: 12,
3078
- fontFamily: "Inter, sans-serif",
3079
- marginLeft: 8
3080
- },
3204
+ variant: "caption",
3205
+ color: "secondary",
3206
+ maxLines: 1,
3207
+ className: "font-sans shrink ml-2 leading-[normal]",
3081
3208
  testID: "exercise-card-prescription",
3082
3209
  children: prescription
3083
3210
  }
3084
3211
  ),
3085
3212
  /* @__PURE__ */ jsx(reactNative.View, { className: "flex-1", style: { minWidth: 8 } }),
3086
- previousBest && /* @__PURE__ */ jsx(
3087
- reactNative.Text,
3213
+ previousBest && /* 11px is off the type scale; `2xs` (10px) is the step below, as B2's
3214
+ WorkoutCard date took for the same size. */
3215
+ /* @__PURE__ */ jsx(
3216
+ Typography,
3088
3217
  {
3089
- className: "text-text-tertiary",
3090
- numberOfLines: 1,
3091
- style: {
3092
- flexShrink: 1,
3093
- fontSize: 11,
3094
- fontFamily: "Inter, sans-serif"
3095
- },
3218
+ variant: "caption",
3219
+ color: "tertiary",
3220
+ maxLines: 1,
3221
+ className: "font-sans shrink text-2xs leading-[normal]",
3096
3222
  testID: "exercise-card-previous-best",
3097
3223
  children: previousBest
3098
3224
  }
@@ -3119,12 +3245,7 @@ function ExerciseCard({
3119
3245
  if (upcoming) return /* @__PURE__ */ jsx(UpcomingCard, { ...rest, onToggle });
3120
3246
  return isExpanded ? /* @__PURE__ */ jsx(ExpandedCard, { ...rest, onToggle }) : /* @__PURE__ */ jsx(CollapsedCard, { ...rest, onToggle });
3121
3247
  }
3122
- function resolveColor(token, mode = "dark") {
3123
- return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
3124
- }
3125
-
3126
- // src/components/custom/Workout/InputBar.tsx
3127
- var BRAND_PRIMARY2 = getSemanticColors("dark")["brand-primary"];
3248
+ var BRAND_PRIMARY = getSemanticColors("dark")["brand-primary"];
3128
3249
  var INPUT_CLASSNAME = "bg-surface-raised border-hairline-strong text-text-primary";
3129
3250
  var inputStyle = {
3130
3251
  fontSize: 14,
@@ -3253,7 +3374,7 @@ function InputBar({
3253
3374
  onPress: onRecord,
3254
3375
  disabled: !canRecord,
3255
3376
  style: ({ pressed }) => ({
3256
- backgroundColor: BRAND_PRIMARY2,
3377
+ backgroundColor: BRAND_PRIMARY,
3257
3378
  borderRadius: 8,
3258
3379
  paddingVertical: 10,
3259
3380
  paddingHorizontal: 16,
@@ -3487,7 +3608,7 @@ function CircularTimer({
3487
3608
  }
3488
3609
 
3489
3610
  // src/components/custom/Workout/RestTimer.tsx
3490
- var BRAND_PRIMARY3 = getSemanticColors("dark")["brand-primary"];
3611
+ var BRAND_PRIMARY2 = getSemanticColors("dark")["brand-primary"];
3491
3612
  var RING_DEFAULT_SIZE = 180;
3492
3613
  function RestActions({ onAddTime, onSkip }) {
3493
3614
  return /* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row", gap: 8 }, children: [
@@ -3534,7 +3655,7 @@ function RestActions({ onAddTime, onSkip }) {
3534
3655
  fontSize: 11,
3535
3656
  fontFamily: "Inter, sans-serif",
3536
3657
  fontWeight: "600",
3537
- color: BRAND_PRIMARY3
3658
+ color: BRAND_PRIMARY2
3538
3659
  },
3539
3660
  children: "Skip"
3540
3661
  }
@@ -3709,7 +3830,7 @@ function RestTimer({
3709
3830
  {
3710
3831
  style: {
3711
3832
  height: "100%",
3712
- backgroundColor: BRAND_PRIMARY3,
3833
+ backgroundColor: BRAND_PRIMARY2,
3713
3834
  borderRadius: 2,
3714
3835
  width: `${progressPct}%`
3715
3836
  },
@@ -3723,23 +3844,16 @@ function RestTimer({
3723
3844
  }
3724
3845
  );
3725
3846
  }
3726
- var DEFAULTS = {
3727
- label: "SS",
3728
- color: getSemanticColors("dark")["brand-primary"],
3729
- bgBase: getSemanticColors("dark")["background-base"]
3730
- };
3731
- function SupersetWrapper({
3732
- label = DEFAULTS.label,
3733
- color = DEFAULTS.color,
3734
- children
3735
- }) {
3847
+ var DEFAULT_LABEL = "SS";
3848
+ function SupersetWrapper({ label = DEFAULT_LABEL, color, children }) {
3849
+ const rail = color ?? resolveColor("brand-primary");
3736
3850
  return /* @__PURE__ */ jsxs(
3737
3851
  reactNative.View,
3738
3852
  {
3739
3853
  style: {
3740
3854
  position: "relative",
3741
3855
  borderLeftWidth: 3,
3742
- borderLeftColor: color,
3856
+ borderLeftColor: rail,
3743
3857
  paddingLeft: 8,
3744
3858
  marginHorizontal: 12,
3745
3859
  marginBottom: 8,
@@ -3750,21 +3864,18 @@ function SupersetWrapper({
3750
3864
  testID: "superset-wrapper",
3751
3865
  children: [
3752
3866
  /* @__PURE__ */ jsx(
3753
- reactNative.Text,
3867
+ Typography,
3754
3868
  {
3869
+ variant: "microLabel",
3870
+ color: "inverse",
3755
3871
  style: {
3756
3872
  position: "absolute",
3757
3873
  top: -1,
3758
3874
  left: -3,
3759
- fontSize: 9,
3760
- fontFamily: "Inter, sans-serif",
3761
- fontWeight: "700",
3762
- backgroundColor: color,
3763
- color: DEFAULTS.bgBase,
3875
+ backgroundColor: rail,
3764
3876
  paddingVertical: 2,
3765
3877
  paddingHorizontal: 6,
3766
3878
  borderBottomRightRadius: 4,
3767
- letterSpacing: 0.5,
3768
3879
  zIndex: 2
3769
3880
  },
3770
3881
  testID: "superset-label",
@@ -3778,7 +3889,7 @@ function SupersetWrapper({
3778
3889
  }
3779
3890
 
3780
3891
  // src/components/custom/Workout/ActiveWorkoutPage.tsx
3781
- var BRAND_PRIMARY4 = getSemanticColors("dark")["brand-primary"];
3892
+ var BRAND_PRIMARY3 = getSemanticColors("dark")["brand-primary"];
3782
3893
  function countCompletedSets(exercise) {
3783
3894
  if (exercise.setVelocities != null) return exercise.setVelocities.length;
3784
3895
  if (exercise.status === "completed") return exercise.totalPlannedSets;
@@ -3892,7 +4003,7 @@ function WorkoutHeader({
3892
4003
  fontSize: 15,
3893
4004
  fontFamily: '"Space Grotesk", sans-serif',
3894
4005
  fontWeight: "700",
3895
- color: BRAND_PRIMARY4,
4006
+ color: BRAND_PRIMARY3,
3896
4007
  fontVariant: ["tabular-nums"]
3897
4008
  },
3898
4009
  children: `${progress.completedExercises}/${progress.totalExercises}`
@@ -3926,7 +4037,7 @@ function WorkoutHeader({
3926
4037
  style: {
3927
4038
  height: "100%",
3928
4039
  width: `${Math.round(progress.fraction * 100)}%`,
3929
- backgroundColor: BRAND_PRIMARY4,
4040
+ backgroundColor: BRAND_PRIMARY3,
3930
4041
  borderRadius: 2
3931
4042
  },
3932
4043
  testID: "active-workout-page-progress-fill"
@@ -4060,348 +4171,159 @@ function ActiveWorkoutPage({
4060
4171
  }
4061
4172
  );
4062
4173
  }
4063
- var elevationSystem = {
4064
- // Deep inset (recessed input fields, deeply pressed buttons)
4065
- [-2]: {
4066
- name: "deep-inset",
4067
- colorAdjustment: 0,
4068
- shadowIntensity: "strong",
4069
- shadowStyle: "pressed",
4070
- description: "Deeply recessed elements (e.g., input fields, deeply pressed buttons)"
4071
- },
4072
- // Shallow inset (pressed buttons, sunken panels)
4073
- [-1]: {
4074
- name: "inset",
4075
- colorAdjustment: 0,
4076
- shadowIntensity: "medium",
4077
- shadowStyle: "pressed",
4078
- description: "Shallow inset elements (e.g., pressed buttons, sunken panels within cards)"
4079
- },
4080
- // Base level (page background, default surface)
4081
- [0]: {
4082
- name: "base",
4083
- colorAdjustment: 0,
4084
- shadowIntensity: "subtle",
4085
- shadowStyle: "raised",
4086
- description: "Base surface level (page background, default containers)"
4087
- },
4088
- // Level 1: Subtle elevation (outline cards, subtle containers)
4089
- [1]: {
4090
- name: "subtle",
4091
- // The whole ladder was re-spaced in TD-07.16. It used to run
4092
- // 0.01/0.02/0.04/0.06/0.08, where the first step was ~2 RGB values — under
4093
- // the perceptual floor, so level 1 existed in the type system and nowhere on
4094
- // screen. With drop-shadow now gated off below FLOATING_ELEVATION_MIN, TONE
4095
- // is the only thing separating 0-3, so every step has to actually land.
4096
- // Even 0.025 spacing, verified in elevation.test.ts as ΔL* > 1 per step.
4097
- colorAdjustment: 0.025,
4098
- shadowIntensity: "subtle",
4099
- shadowStyle: "raised",
4100
- description: "Subtle elevation (outline cards, subtle containers)"
4101
- },
4102
- // Level 2: Standard elevation (default cards, buttons)
4103
- [2]: {
4104
- name: "standard",
4105
- colorAdjustment: 0.05,
4106
- shadowIntensity: "medium",
4107
- shadowStyle: "raised",
4108
- description: "Standard elevation (default cards, raised buttons)"
4109
- },
4110
- // Level 3: Prominent elevation (important cards, modals)
4111
- [3]: {
4112
- name: "prominent",
4113
- colorAdjustment: 0.075,
4114
- shadowIntensity: "strong",
4115
- shadowStyle: "raised",
4116
- description: "Prominent elevation (important cards, modals, dropdowns)"
4117
- },
4118
- // Level 4: High elevation (overlays, popovers)
4119
- [4]: {
4120
- name: "high",
4121
- colorAdjustment: 0.1,
4122
- shadowIntensity: "strong",
4123
- shadowStyle: "raised",
4124
- description: "High elevation (overlays, popovers, tooltips)"
4125
- },
4126
- // Level 5: Floating (toasts, floating action buttons)
4127
- [5]: {
4128
- name: "floating",
4129
- colorAdjustment: 0.13,
4130
- shadowIntensity: "strong",
4131
- shadowStyle: "raised",
4132
- description: "Floating elevation (toasts, floating action buttons, highest z-index)"
4133
- }
4174
+ var FLOATING_LIFT_MIN = 4;
4175
+ var LIFT_RIM_ALPHA = { dark: 0.12, light: 0.9 };
4176
+ var AMBIENT = {
4177
+ 1: [
4178
+ { y: 1, blur: 2, alpha: 0.35 },
4179
+ { y: 2, blur: 6, alpha: 0.3 }
4180
+ ],
4181
+ 2: [
4182
+ { y: 1, blur: 2, alpha: 0.35 },
4183
+ { y: 4, blur: 12, alpha: 0.32 }
4184
+ ],
4185
+ 3: [
4186
+ { y: 2, blur: 4, alpha: 0.35 },
4187
+ { y: 8, blur: 22, alpha: 0.35 }
4188
+ ],
4189
+ 4: [
4190
+ { y: 1, blur: 2, alpha: 0.35 },
4191
+ { y: 10, blur: 24, alpha: 0.3 },
4192
+ { y: 24, blur: 48, alpha: 0.2 }
4193
+ ],
4194
+ 5: [
4195
+ { y: 2, blur: 4, alpha: 0.4 },
4196
+ { y: 16, blur: 32, alpha: 0.35 },
4197
+ { y: 32, blur: 64, alpha: 0.25 }
4198
+ ]
4134
4199
  };
4135
- function calculateRimLightColor(baseColor, level) {
4136
- const rgb = hexToRgb(baseColor);
4137
- if (!rgb) {
4138
- return "rgba(255, 255, 255, 0.5)";
4139
- }
4140
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
4141
- const isLight = hsv.v > 0.6;
4142
- const isSaturated = hsv.s > 0.3;
4143
- const absLevel = Math.abs(level);
4144
- const opacityBoost = Math.max(0, (absLevel - 1) * 0.05);
4145
- if (isSaturated) {
4146
- const rimLightValue = 0.95;
4147
- const rimLightRgb = hsvToRgb(hsv.h, hsv.s * 0.3, rimLightValue);
4148
- const baseOpacity = isLight ? 0.9 : 0.5;
4149
- const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
4150
- return `rgba(${rimLightRgb.r}, ${rimLightRgb.g}, ${rimLightRgb.b}, ${finalOpacity.toFixed(2)})`;
4151
- } else {
4152
- const baseOpacity = isLight ? 0.9 : 0.12;
4153
- const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
4154
- return `rgba(255, 255, 255, ${finalOpacity.toFixed(2)})`;
4155
- }
4200
+ var AMBIENT_ALPHA_SCALE = { dark: 1, light: 0.4 };
4201
+ function ambientLayers(step, mode) {
4202
+ const scale = AMBIENT_ALPHA_SCALE[mode];
4203
+ return AMBIENT[step].map(
4204
+ ({ y, blur, alpha: alpha2 }) => `0 ${y}px ${blur}px rgba(0,0,0,${(alpha2 * scale).toFixed(2)})`
4205
+ );
4156
4206
  }
4157
- function calculateDarkShadowColors(surfaceColor) {
4158
- const rgb = hexToRgb(surfaceColor);
4159
- if (!rgb) {
4160
- return {
4161
- dark: "rgba(0, 0, 0, 0.3)",
4162
- darker: "rgba(0, 0, 0, 0.4)"
4163
- };
4164
- }
4165
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
4166
- const isLight = hsv.v > 0.6;
4167
- const isSaturated = hsv.s > 0.3;
4168
- if (isSaturated) {
4169
- const darkShadowValue = 0.15;
4170
- const darkShadowRgb = hsvToRgb(hsv.h, hsv.s, darkShadowValue);
4171
- if (isLight) {
4172
- return {
4173
- dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.3)`,
4174
- darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.4)`
4175
- };
4176
- } else {
4177
- return {
4178
- dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.5)`,
4179
- darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.6)`
4180
- };
4181
- }
4182
- } else {
4183
- if (isLight) {
4184
- return {
4185
- dark: "rgba(0, 0, 0, 0.2)",
4186
- darker: "rgba(0, 0, 0, 0.3)"
4187
- };
4188
- } else {
4189
- return {
4190
- dark: "rgba(0, 0, 0, 0.5)",
4191
- darker: "rgba(0, 0, 0, 0.6)"
4192
- };
4207
+ function liftShadow(step, mode = "dark", opts = {}) {
4208
+ const rim = opts.rim ?? LIFT_RIM_ALPHA[mode];
4209
+ const layers = ambientLayers(step, mode);
4210
+ if (rim > 0) layers.unshift(`inset 0 1px 0 rgba(255,255,255,${rim.toFixed(2)})`);
4211
+ return layers.join(", ");
4212
+ }
4213
+ function liftStyle(step, mode = "dark", opts = {}) {
4214
+ const deepest = AMBIENT[step][AMBIENT[step].length - 1];
4215
+ return reactNative.Platform.select({
4216
+ web: { boxShadow: liftShadow(step, mode, opts) },
4217
+ default: {
4218
+ shadowColor: "#000",
4219
+ shadowOffset: { width: 0, height: Math.round(deepest.y / 2) },
4220
+ shadowOpacity: deepest.alpha * AMBIENT_ALPHA_SCALE[mode],
4221
+ shadowRadius: deepest.blur / 2,
4222
+ elevation: step
4193
4223
  }
4194
- }
4195
- }
4196
- function getRimLightConfig() {
4197
- return {
4198
- offset: 1,
4199
- // Fixed 1px for crisp rim
4200
- blur: 1
4201
- // Tight blur for crisp edge
4202
- };
4203
- }
4204
- var elevationSurfaceCache = /* @__PURE__ */ new Map();
4205
- var MAX_CACHE_SIZE = 100;
4206
- function getCacheKey(baseColor, level, theme) {
4207
- return `${baseColor}-${level}-${theme}`;
4224
+ });
4208
4225
  }
4209
- function calculateElevationSurface(baseColor, level, theme) {
4210
- const config = elevationSystem[level];
4211
- if (config.colorAdjustment === 0) {
4212
- return baseColor;
4213
- }
4214
- if (level < 0) {
4215
- return baseColor;
4216
- }
4217
- return lighten(baseColor, config.colorAdjustment);
4226
+ var FLOATING_ELEVATION_MIN = FLOATING_LIFT_MIN;
4227
+ function getPressedRecessShadow(fillColor, _mode = "dark") {
4228
+ const { boxShadow } = insetWell(fillColor);
4229
+ return reactNative.Platform.select({
4230
+ web: { boxShadow },
4231
+ default: {}
4232
+ });
4218
4233
  }
4219
- function getElevationSurface(baseColor, level, theme) {
4220
- const cacheKey = getCacheKey(baseColor, level, theme);
4221
- if (elevationSurfaceCache.has(cacheKey)) {
4222
- return elevationSurfaceCache.get(cacheKey);
4223
- }
4224
- const result = calculateElevationSurface(baseColor, level);
4225
- if (elevationSurfaceCache.size >= MAX_CACHE_SIZE) {
4226
- const firstKey = elevationSurfaceCache.keys().next().value;
4227
- elevationSurfaceCache.delete(firstKey);
4228
- }
4229
- elevationSurfaceCache.set(cacheKey, result);
4230
- return result;
4231
- }
4232
- var elevationShadowCache = /* @__PURE__ */ new Map();
4233
- var MAX_SHADOW_CACHE_SIZE = 50;
4234
- function getShadowCacheKey(baseColor, level, theme, isHovered) {
4235
- return `${baseColor}-${level}-${theme}-${isHovered}`;
4236
- }
4237
- function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
4238
- const config = elevationSystem[level];
4239
- if (level === 0) {
4240
- return {};
4241
- }
4242
- const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
4243
- const rimLightColor = calculateRimLightColor(baseColor, level);
4244
- const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
4245
- const intensityConfig = {
4246
- subtle: { offset: 1, blur: 2 },
4247
- medium: { offset: 2, blur: 4 },
4248
- strong: { offset: 2, blur: 5 }
4249
- };
4250
- const { offset, blur } = intensityConfig[config.shadowIntensity];
4251
- const rimConfig = getRimLightConfig();
4252
- if (config.shadowStyle === "pressed") {
4253
- if (isHovered) {
4254
- const hoverOffset = Math.max(1, Math.round(offset / 2));
4255
- const hoverBlur = Math.max(1, Math.round(blur / 2));
4256
- return reactNative.Platform.select({
4257
- web: {
4258
- boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
4259
- },
4260
- default: {
4261
- shadowOpacity: 0,
4262
- elevation: 0
4263
- }
4264
- });
4265
- }
4266
- return reactNative.Platform.select({
4267
- web: {
4268
- boxShadow: `inset ${offset}px ${offset}px ${blur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
4269
- },
4270
- default: {
4271
- shadowOpacity: 0,
4272
- elevation: 0
4273
- }
4274
- });
4275
- } else {
4276
- if (isHovered) {
4277
- const hoverOffset = Math.max(1, Math.round(offset / 2));
4278
- const hoverBlur = Math.max(1, Math.round(blur / 2));
4279
- return reactNative.Platform.select({
4280
- web: {
4281
- boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
4282
- },
4283
- default: {
4284
- shadowColor: "#000",
4285
- shadowOffset: { width: hoverOffset, height: hoverOffset },
4286
- shadowOpacity: 0.2,
4287
- shadowRadius: hoverBlur / 2,
4288
- elevation: hoverOffset
4289
- }
4290
- });
4234
+ var glowConfig = {
4235
+ tight: { blur: 4, spread: 0, opacity: 0.4 },
4236
+ subtle: { blur: 12, spread: 0, opacity: 0.25 },
4237
+ medium: { blur: 20, spread: 2, opacity: 0.4 },
4238
+ strong: { blur: 30, spread: 4, opacity: 0.55 }
4239
+ };
4240
+ function getGlowShadow(color, intensity = "medium") {
4241
+ const config = glowConfig[intensity];
4242
+ const rgb = hexToRgb(color);
4243
+ if (!rgb) return {};
4244
+ return reactNative.Platform.select({
4245
+ web: {
4246
+ boxShadow: `0 0 ${config.blur}px ${config.spread}px rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${config.opacity})`
4247
+ },
4248
+ default: {
4249
+ shadowColor: color,
4250
+ shadowOffset: { width: 0, height: 0 },
4251
+ shadowOpacity: config.opacity,
4252
+ shadowRadius: config.blur / 2,
4253
+ elevation: 0
4291
4254
  }
4292
- return reactNative.Platform.select({
4293
- web: {
4294
- boxShadow: `${offset}px ${offset}px ${blur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
4295
- },
4296
- default: {
4297
- shadowColor: "#000",
4298
- shadowOffset: { width: offset, height: offset },
4299
- shadowOpacity: 0.3,
4300
- shadowRadius: blur / 2,
4301
- elevation: offset
4302
- }
4303
- });
4304
- }
4305
- }
4306
- var FLOATING_ELEVATION_MIN = 4;
4307
- function getElevationShadow(baseColor, level, theme, isHovered = false) {
4308
- const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
4309
- if (elevationShadowCache.has(cacheKey)) {
4310
- return elevationShadowCache.get(cacheKey);
4311
- }
4312
- const result = level > 0 && level < FLOATING_ELEVATION_MIN ? {} : calculateElevationShadow(baseColor, level, theme, isHovered);
4313
- if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
4314
- const firstKey = elevationShadowCache.keys().next().value;
4315
- elevationShadowCache.delete(firstKey);
4316
- }
4317
- elevationShadowCache.set(cacheKey, result);
4318
- return result;
4319
- }
4320
- function getBaseSurfaceColor(theme) {
4321
- return theme === "light" ? semanticColorsLight["surface-raised"] : semanticColorsDark["surface-elevated"];
4255
+ });
4322
4256
  }
4323
- var componentElevationRanges = {
4324
- button: {
4325
- allowed: [2],
4326
- default: 2,
4327
- hover: 3
4328
- },
4329
- card: {
4330
- allowed: [1, 2, 3],
4331
- default: 2,
4332
- hover: 3
4333
- },
4334
- input: {
4335
- allowed: [-2, -1, 0],
4336
- default: -1
4337
- },
4338
- overlay: {
4339
- allowed: [4, 5],
4340
- default: 4
4257
+ function recessDepth(inherited, planesDown, mode) {
4258
+ let plane = inherited.level;
4259
+ for (let i = 0; i < planesDown; i++) plane = pressedLevel(plane);
4260
+ const backgroundColor = surfaceBackground(plane, mode);
4261
+ return { plane, backgroundColor, depthStyle: getPressedRecessShadow(backgroundColor, mode) };
4262
+ }
4263
+ function resolveSurfaceDepth(inherited, props) {
4264
+ const mode = props.theme ?? inherited.mode;
4265
+ const elevation = props.elevation ?? 0;
4266
+ if (props.pressed || elevation < 0) {
4267
+ const down = props.pressed ? 1 : -elevation;
4268
+ return { mode, step: 0, lifted: false, ...recessDepth(inherited, down, mode) };
4341
4269
  }
4342
- };
4343
- function getValidatedElevation(component, requested) {
4344
- const range = componentElevationRanges[component];
4345
- if (range.allowed.includes(requested)) {
4346
- return requested;
4347
- }
4348
- const sorted = [...range.allowed].sort((a, b) => a - b);
4349
- if (requested < sorted[0]) return sorted[0];
4350
- if (requested > sorted[sorted.length - 1]) return sorted[sorted.length - 1];
4351
- return sorted.reduce(
4352
- (prev, curr) => Math.abs(curr - requested) < Math.abs(prev - requested) ? curr : prev
4270
+ const step = props.level != null ? 0 : props.raise ?? elevation;
4271
+ const floating = step >= FLOATING_ELEVATION_MIN;
4272
+ const plane = props.level ?? (floating ? "overlay" : raisedLevel(inherited.level, step));
4273
+ const lifted = props.lift ?? step > 0;
4274
+ const liftStep = Math.max(1, Math.min(5, step));
4275
+ const depthStyle = lifted ? liftStyle(liftStep, mode, props.liftOptions) : {};
4276
+ return { mode, plane, backgroundColor: surfaceBackground(plane, mode), depthStyle, step, lifted };
4277
+ }
4278
+ function useResolvedSurface(props) {
4279
+ const inherited = useSurface();
4280
+ const { level, raise, elevation, pressed, lift, liftOptions, theme } = props;
4281
+ return react.useMemo(
4282
+ () => resolveSurfaceDepth(inherited, {
4283
+ level,
4284
+ raise,
4285
+ elevation,
4286
+ pressed,
4287
+ lift,
4288
+ liftOptions,
4289
+ theme
4290
+ }),
4291
+ [inherited, level, raise, elevation, pressed, lift, liftOptions, theme]
4353
4292
  );
4354
4293
  }
4355
- function getTheme() {
4356
- if (typeof document === "undefined") return "dark";
4357
- return document.documentElement.classList.contains("light") ? "light" : "dark";
4358
- }
4359
- var listeners = [];
4360
- function subscribe(listener) {
4361
- listeners = [...listeners, listener];
4362
- if (typeof document !== "undefined" && listeners.length === 1) {
4363
- const observer = new MutationObserver((mutations) => {
4364
- for (const mutation of mutations) {
4365
- if (mutation.type === "attributes" && mutation.attributeName === "class") {
4366
- listeners.forEach((l) => l());
4367
- }
4368
- }
4369
- });
4370
- observer.observe(document.documentElement, {
4371
- attributes: true,
4372
- attributeFilter: ["class"]
4373
- });
4374
- subscribe._observer = observer;
4375
- }
4376
- return () => {
4377
- listeners = listeners.filter((l) => l !== listener);
4378
- if (listeners.length === 0 && subscribe._observer) {
4379
- subscribe._observer.disconnect();
4380
- subscribe._observer = null;
4381
- }
4382
- };
4383
- }
4384
- function getSnapshot() {
4385
- return getTheme();
4386
- }
4387
- function getServerSnapshot() {
4388
- return "dark";
4389
- }
4390
- function useTheme() {
4391
- return react.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
4392
- }
4393
4294
 
4394
4295
  // src/components/ui/card/Card.tsx
4395
- var variantStyles = {
4296
+ var EDGE_CLASS = {
4396
4297
  elevated: "",
4397
- // Will be set dynamically via elevation system
4398
- outline: "border-2 border-hairline-strong",
4399
- // Thicker border with stronger contrast
4298
+ accent: "",
4400
4299
  filled: "",
4401
- // Will be set dynamically via elevation system
4402
- accent: "border border-hairline",
4300
+ outline: "border border-hairline-strong",
4403
4301
  subtle: "border border-hairline-subtle"
4404
4302
  };
4303
+ var LIFTED = {
4304
+ elevated: true,
4305
+ accent: true,
4306
+ filled: false,
4307
+ outline: false,
4308
+ subtle: false
4309
+ };
4310
+ var STAYS_ON_HOST = {
4311
+ elevated: false,
4312
+ accent: false,
4313
+ filled: false,
4314
+ outline: true,
4315
+ subtle: true
4316
+ };
4317
+ function useCardDepth(variant, elevation, hovered) {
4318
+ const raise = STAYS_ON_HOST[variant] ? void 0 : elevation;
4319
+ const resolved = useResolvedSurface({ raise, lift: LIFTED[variant] });
4320
+ const depthStyle = react.useMemo(() => {
4321
+ if (!hovered || !LIFTED[variant]) return resolved.depthStyle;
4322
+ const hoverStep = Math.min(3, resolved.step + 1);
4323
+ return liftStyle(hoverStep, resolved.mode);
4324
+ }, [hovered, variant, resolved]);
4325
+ return { ...resolved, depthStyle };
4326
+ }
4405
4327
  function Card({
4406
4328
  variant = "elevated",
4407
4329
  elevation = 2,
@@ -4422,89 +4344,54 @@ function Card({
4422
4344
  }) {
4423
4345
  const isClickable = isInteractive || !!onPress;
4424
4346
  const [isHovered, setIsHovered] = react.useState(false);
4425
- const theme = useTheme();
4426
- const elevationLevel = react.useMemo(() => {
4427
- const validated = getValidatedElevation("card", elevation);
4428
- if (variant === "outline" || variant === "accent" || variant === "subtle") {
4429
- return 1;
4430
- }
4431
- return validated;
4432
- }, [variant, elevation]);
4433
- const baseColor = react.useMemo(() => getBaseSurfaceColor(theme), [theme]);
4434
- const surfaceColor = react.useMemo(() => {
4435
- if ((variant === "outline" || variant === "accent") && theme === "light") {
4436
- return "#FAFAFA";
4437
- }
4438
- if (variant === "subtle") {
4439
- return getElevationSurface(baseColor, 0, theme);
4440
- }
4441
- return getElevationSurface(baseColor, elevationLevel, theme);
4442
- }, [baseColor, elevationLevel, theme, variant]);
4443
- const shadowStyle = react.useMemo(() => {
4444
- const shouldHover = isHovered && isClickable;
4445
- return getElevationShadow(baseColor, elevationLevel, theme, shouldHover);
4446
- }, [baseColor, elevationLevel, theme, isHovered, isClickable]);
4447
- const cardContent = isLoading ? /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
4448
- skeletonHasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
4449
- /* @__PURE__ */ jsx(reactNative.View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
4450
- /* @__PURE__ */ jsx(reactNative.View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
4451
- ] }),
4452
- /* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: skeletonContentLines }).map((_, i) => /* @__PURE__ */ jsx(
4453
- reactNative.View,
4454
- {
4455
- className: cn(
4456
- "h-4 bg-interactive-disabled rounded",
4457
- i < skeletonContentLines - 1 ? "mb-2 w-full" : "w-4/5"
4458
- )
4459
- },
4460
- i
4461
- )) }),
4462
- skeletonHasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(reactNative.View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
4463
- ] }) : children;
4347
+ const depth = useCardDepth(variant, elevation, isHovered && isClickable);
4464
4348
  const baseClassName = cn(
4465
4349
  "rounded-lg overflow-hidden relative",
4466
- // Apply variant styles, but only use default border color if no custom borderColor
4467
- variant === "outline" ? borderColor ? "border-2" : variantStyles[variant] : variantStyles[variant],
4468
- // Remove Tailwind shadow classes - we're using elevation shadows via style prop
4350
+ borderColor ? "border" : EDGE_CLASS[variant],
4469
4351
  isClickable && "web:cursor-pointer web:transition-all web:duration-150",
4470
4352
  isClickable && "web:hover:-translate-y-0.5 active:scale-[0.99]",
4471
4353
  isLoading && "pointer-events-none animate-pulse",
4472
4354
  className
4473
4355
  );
4474
- const accentStyle = react.useMemo(() => variant === "accent" ? {
4475
- borderLeftWidth: accentWidth ?? 3,
4476
- borderLeftColor: accentColor ?? "var(--color-brand-primary)"
4477
- } : {}, [variant, accentWidth, accentColor]);
4478
4356
  const mergedStyle = react.useMemo(() => {
4479
- const elevationStyle = {
4480
- backgroundColor: bgColor || surfaceColor,
4357
+ const own = {
4358
+ backgroundColor: bgColor || depth.backgroundColor,
4481
4359
  borderRadius: 8,
4482
4360
  overflow: "hidden",
4483
- ...shadowStyle,
4484
- ...accentStyle
4361
+ ...depth.depthStyle
4485
4362
  };
4486
- if (borderColor) {
4487
- elevationStyle.borderColor = borderColor;
4363
+ if (variant === "accent") {
4364
+ own.borderLeftWidth = accentWidth ?? 3;
4365
+ own.borderLeftColor = accentColor ?? "var(--color-brand-primary)";
4488
4366
  }
4489
- if (!style) return elevationStyle;
4490
- return [elevationStyle, style];
4491
- }, [style, surfaceColor, shadowStyle, borderColor, bgColor, accentStyle]);
4492
- if (isClickable) {
4493
- return /* @__PURE__ */ jsx(
4494
- reactNative.Pressable,
4495
- {
4496
- onPress,
4497
- onHoverIn: () => setIsHovered(true),
4498
- onHoverOut: () => setIsHovered(false),
4499
- accessibilityRole: "button",
4500
- className: baseClassName,
4501
- style: mergedStyle,
4502
- ...props,
4503
- children: cardContent
4504
- }
4505
- );
4506
- }
4507
- return /* @__PURE__ */ jsx(reactNative.View, { className: baseClassName, style: mergedStyle, ...props, children: cardContent });
4367
+ if (borderColor) own.borderColor = borderColor;
4368
+ return style ? [own, style] : own;
4369
+ }, [style, depth, bgColor, borderColor, variant, accentWidth, accentColor]);
4370
+ const context = react.useMemo(
4371
+ () => ({ mode: depth.mode, level: depth.plane }),
4372
+ [depth.mode, depth.plane]
4373
+ );
4374
+ const content = isLoading ? /* @__PURE__ */ jsx(
4375
+ SkeletonBody,
4376
+ {
4377
+ hasHeader: skeletonHasHeader,
4378
+ hasFooter: skeletonHasFooter,
4379
+ contentLines: skeletonContentLines
4380
+ }
4381
+ ) : children;
4382
+ return /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: context, children: isClickable ? /* @__PURE__ */ jsx(
4383
+ reactNative.Pressable,
4384
+ {
4385
+ onPress,
4386
+ onHoverIn: () => setIsHovered(true),
4387
+ onHoverOut: () => setIsHovered(false),
4388
+ accessibilityRole: "button",
4389
+ className: baseClassName,
4390
+ style: mergedStyle,
4391
+ ...props,
4392
+ children: content
4393
+ }
4394
+ ) : /* @__PURE__ */ jsx(reactNative.View, { className: baseClassName, style: mergedStyle, ...props, children: content }) });
4508
4395
  }
4509
4396
  function CardHeader({ children, className }) {
4510
4397
  return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-6 py-6", className), children });
@@ -4515,60 +4402,88 @@ function CardContent({ children, className }) {
4515
4402
  function CardFooter({ children, className }) {
4516
4403
  return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
4517
4404
  }
4518
- var t5 = getSemanticColors("dark");
4519
- var solidVariantColors = {
4520
- success: t5["status-success"],
4521
- warning: t5["status-warning"],
4522
- error: t5["status-error"],
4523
- neutral: greyRamp[500]
4405
+ function SkeletonBody({ hasHeader, hasFooter, contentLines }) {
4406
+ return /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
4407
+ hasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
4408
+ /* @__PURE__ */ jsx(reactNative.View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
4409
+ /* @__PURE__ */ jsx(reactNative.View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
4410
+ ] }),
4411
+ /* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: contentLines }).map((_, i) => /* @__PURE__ */ jsx(
4412
+ reactNative.View,
4413
+ {
4414
+ className: cn(
4415
+ "h-4 bg-interactive-disabled rounded",
4416
+ i < contentLines - 1 ? "mb-2 w-full" : "w-4/5"
4417
+ )
4418
+ },
4419
+ i
4420
+ )) }),
4421
+ hasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(reactNative.View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
4422
+ ] });
4423
+ }
4424
+ var solidFillToken = {
4425
+ success: "status-success",
4426
+ warning: "status-warning",
4427
+ error: "status-error",
4428
+ neutral: "text-tertiary"
4524
4429
  };
4525
- var ringVariantStyles = {
4526
- "on-track": {
4527
- backgroundColor: "rgba(46,213,115,0.15)",
4528
- borderWidth: 1,
4529
- borderColor: "rgba(46,213,115,0.3)"
4530
- },
4531
- deviation: {
4532
- backgroundColor: "rgba(245,158,11,0.15)",
4533
- borderWidth: 1,
4534
- borderColor: "rgba(245,158,11,0.25)"
4535
- },
4536
- future: {
4537
- backgroundColor: "rgba(107,114,128,0.1)",
4538
- borderWidth: 1,
4539
- borderStyle: "dashed",
4540
- borderColor: "rgba(107,114,128,0.2)"
4541
- }
4430
+ var ringWashToken = {
4431
+ "on-track": { fill: "status-success-subtle", border: "status-success-muted" },
4432
+ deviation: { fill: "status-warning-subtle", border: "status-warning-muted" }
4542
4433
  };
4543
- var glowStyles = {
4544
- success: { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
4545
- warning: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
4546
- error: { boxShadow: "0 0 4px rgba(239,68,68,0.4)" },
4547
- neutral: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" },
4548
- "on-track": { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
4549
- deviation: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
4550
- future: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" }
4434
+ var FUTURE_FILL = alpha(greyRamp[500], 0.1);
4435
+ var FUTURE_BORDER = alpha(greyRamp[500], 0.2);
4436
+ var glyphToken = {
4437
+ success: "text-inverse",
4438
+ warning: "text-inverse",
4439
+ error: "text-inverse",
4440
+ neutral: "text-inverse",
4441
+ "on-track": "status-success",
4442
+ deviation: "status-warning",
4443
+ future: "text-tertiary"
4551
4444
  };
4445
+ var glowColors = {
4446
+ success: semanticColorsDark["status-success"],
4447
+ warning: semanticColorsDark["status-warning"],
4448
+ error: semanticColorsDark["status-error"],
4449
+ neutral: greyRamp[500],
4450
+ "on-track": semanticColorsDark["status-success"],
4451
+ deviation: semanticColorsDark["status-warning"],
4452
+ future: greyRamp[500]
4453
+ };
4454
+ var glowStyles = Object.fromEntries(
4455
+ Object.entries(glowColors).map(([variant, color]) => [variant, getGlowShadow(color, "subtle")])
4456
+ );
4552
4457
  var iconChars = {
4553
4458
  check: "\u2713",
4554
4459
  exclamation: "!",
4555
4460
  dash: "\u2014"
4556
4461
  };
4557
- var iconColors = {
4558
- success: "#0A5C52",
4559
- warning: "#6B4000",
4560
- error: "#5C1A1A",
4561
- neutral: greyRamp[200],
4562
- "on-track": t5["status-success"],
4563
- deviation: t5["status-warning"],
4564
- future: greyRamp[500]
4565
- };
4566
4462
  var sizeDimensions = {
4567
4463
  sm: { size: 8, showIcon: false },
4568
4464
  md: { size: 18, showIcon: true }
4569
4465
  };
4570
4466
  function isSolidVariant(variant) {
4571
- return variant in solidVariantColors;
4467
+ return variant in solidFillToken;
4468
+ }
4469
+ function ringStyle(variant) {
4470
+ if (variant === "future") {
4471
+ return {
4472
+ backgroundColor: FUTURE_FILL,
4473
+ borderWidth: 1,
4474
+ borderStyle: "dashed",
4475
+ borderColor: FUTURE_BORDER
4476
+ };
4477
+ }
4478
+ if (variant === "on-track" || variant === "deviation") {
4479
+ const tokens = ringWashToken[variant];
4480
+ return {
4481
+ backgroundColor: resolveColor(tokens.fill),
4482
+ borderWidth: 1,
4483
+ borderColor: resolveColor(tokens.border)
4484
+ };
4485
+ }
4486
+ return void 0;
4572
4487
  }
4573
4488
  function StatusDot({
4574
4489
  variant,
@@ -4581,7 +4496,7 @@ function StatusDot({
4581
4496
  }) {
4582
4497
  const config = sizeDimensions[size];
4583
4498
  const solid = isSolidVariant(variant);
4584
- const ring = ringVariantStyles[variant];
4499
+ const ring = ringStyle(variant);
4585
4500
  const glowStyle = glow ? glowStyles[variant] : null;
4586
4501
  const dot = /* @__PURE__ */ jsx(
4587
4502
  reactNative.View,
@@ -4595,22 +4510,22 @@ function StatusDot({
4595
4510
  justifyContent: "center",
4596
4511
  flexShrink: 0
4597
4512
  },
4598
- solid ? { backgroundColor: solidVariantColors[variant] } : void 0,
4599
- ring ? ring : void 0,
4513
+ solid ? { backgroundColor: resolveColor(solidFillToken[variant]) } : void 0,
4514
+ ring,
4600
4515
  glowStyle ? glowStyle : void 0
4601
4516
  ],
4602
4517
  accessibilityRole: "image",
4603
4518
  accessibilityLabel: `${variant} status`,
4604
4519
  testID: "status-dot",
4605
- children: config.showIcon && icon && /* @__PURE__ */ jsx(
4606
- reactNative.Text,
4520
+ children: config.showIcon && icon && // The glyph was 11px/900, off the type scale (TOKENS.md §4); `boldLabel` is
4521
+ // the 12px sans label step and `font-black` keeps the original weight.
4522
+ /* @__PURE__ */ jsx(
4523
+ Typography,
4607
4524
  {
4608
- style: {
4609
- fontSize: 11,
4610
- lineHeight: 11,
4611
- fontWeight: "900",
4612
- color: iconColors[variant]
4613
- },
4525
+ variant: "boldLabel",
4526
+ color: "inherit",
4527
+ className: "font-black leading-none",
4528
+ style: { color: resolveColor(glyphToken[variant]) },
4614
4529
  accessibilityElementsHidden: true,
4615
4530
  children: iconChars[icon]
4616
4531
  }
@@ -4628,9 +4543,11 @@ function StatusDot({
4628
4543
  children: [
4629
4544
  /* @__PURE__ */ jsx(reactNative.View, { accessibilityElementsHidden: true, children: dot }),
4630
4545
  /* @__PURE__ */ jsx(
4631
- reactNative.Text,
4546
+ Typography,
4632
4547
  {
4633
- style: { fontSize: 12, lineHeight: 16, color: greyRamp[400] },
4548
+ variant: "caption",
4549
+ color: "secondary",
4550
+ className: "leading-4",
4634
4551
  accessibilityElementsHidden: true,
4635
4552
  children: label
4636
4553
  }
@@ -4646,14 +4563,14 @@ var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
4646
4563
  var WORKOUT_PILL_DELOAD = primitiveRamps.magenta[600];
4647
4564
 
4648
4565
  // src/components/custom/Workout/MesoStatusCard.tsx
4649
- var t6 = getSemanticColors("dark");
4650
- var BRAND_PRIMARY5 = t6["brand-primary"];
4566
+ var t3 = getSemanticColors("dark");
4567
+ var BRAND_PRIMARY4 = t3["brand-primary"];
4651
4568
  var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
4652
4569
  var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
4653
- var SUCCESS = t6["status-success"];
4654
- var WARNING = t6["status-warning"];
4655
- var ERROR = t6["status-error"];
4656
- var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY5, BRAND_PRIMARY_LIGHT];
4570
+ var SUCCESS = t3["status-success"];
4571
+ var WARNING = t3["status-warning"];
4572
+ var ERROR = t3["status-error"];
4573
+ var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY4, BRAND_PRIMARY_LIGHT];
4657
4574
  var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
4658
4575
  var GAUGE_GRADIENT = "linear-gradient(90deg, rgba(46,213,115,0.25) 0%, rgba(249,180,21,0.25) 50%, rgba(209,67,67,0.25) 100%)";
4659
4576
  var STATUS_VARIANTS = {
@@ -4678,15 +4595,7 @@ function renderCoachingText(text, highlights) {
4678
4595
  if (escaped.length === 0) return text;
4679
4596
  const regex = new RegExp(`(${escaped.join("|")})`, "g");
4680
4597
  return text.split(regex).map(
4681
- (part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(
4682
- reactNative.Text,
4683
- {
4684
- className: "text-text-primary",
4685
- style: { fontWeight: "700" },
4686
- children: part
4687
- },
4688
- `${part}-${index}`
4689
- ) : /* @__PURE__ */ jsx(react.Fragment, { children: part }, `t-${index}`)
4598
+ (part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-primary", style: { fontWeight: "700" }, children: part }, `${part}-${index}`) : /* @__PURE__ */ jsx(react.Fragment, { children: part }, `t-${index}`)
4690
4599
  );
4691
4600
  }
4692
4601
  function StatusPill({ badge }) {
@@ -4771,41 +4680,34 @@ function Gauge({ gauge }) {
4771
4680
  "aria-valuemax": 100,
4772
4681
  testID: "meso-status-card-gauge",
4773
4682
  children: [
4774
- /* @__PURE__ */ jsxs(
4775
- reactNative.View,
4776
- {
4777
- className: "flex-row items-center justify-between",
4778
- accessibilityElementsHidden: true,
4779
- children: [
4780
- /* @__PURE__ */ jsx(
4781
- reactNative.Text,
4782
- {
4783
- className: "text-text-secondary",
4784
- style: {
4785
- fontSize: 10,
4786
- fontFamily: "Inter, sans-serif",
4787
- fontWeight: "500",
4788
- letterSpacing: 0.5,
4789
- textTransform: "uppercase"
4790
- },
4791
- children: gauge.label
4792
- }
4793
- ),
4794
- gauge.sublabel != null && /* @__PURE__ */ jsx(
4795
- reactNative.Text,
4796
- {
4797
- className: "text-text-tertiary",
4798
- style: {
4799
- fontSize: 10,
4800
- fontFamily: "Inter, sans-serif",
4801
- fontWeight: "500"
4802
- },
4803
- children: gauge.sublabel
4804
- }
4805
- )
4806
- ]
4807
- }
4808
- ),
4683
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center justify-between", accessibilityElementsHidden: true, children: [
4684
+ /* @__PURE__ */ jsx(
4685
+ reactNative.Text,
4686
+ {
4687
+ className: "text-text-secondary",
4688
+ style: {
4689
+ fontSize: 10,
4690
+ fontFamily: "Inter, sans-serif",
4691
+ fontWeight: "500",
4692
+ letterSpacing: 0.5,
4693
+ textTransform: "uppercase"
4694
+ },
4695
+ children: gauge.label
4696
+ }
4697
+ ),
4698
+ gauge.sublabel != null && /* @__PURE__ */ jsx(
4699
+ reactNative.Text,
4700
+ {
4701
+ className: "text-text-tertiary",
4702
+ style: {
4703
+ fontSize: 10,
4704
+ fontFamily: "Inter, sans-serif",
4705
+ fontWeight: "500"
4706
+ },
4707
+ children: gauge.sublabel
4708
+ }
4709
+ )
4710
+ ] }),
4809
4711
  /* @__PURE__ */ jsxs(
4810
4712
  reactNative.View,
4811
4713
  {
@@ -4846,7 +4748,8 @@ function Gauge({ gauge }) {
4846
4748
  borderRadius: 9999,
4847
4749
  borderWidth: 2,
4848
4750
  backgroundColor: markerColor,
4849
- boxShadow: "0 0 4px rgba(0,0,0,0.5)"
4751
+ // A knob resting on the gauge: lift, with the ring as its edge.
4752
+ ...liftStyle(1, "dark", { rim: 0 })
4850
4753
  },
4851
4754
  testID: "meso-status-card-gauge-marker"
4852
4755
  }
@@ -4898,30 +4801,23 @@ function MesoStatusCard({
4898
4801
  ),
4899
4802
  /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 14, gap: 14 }, testID: "meso-status-card-body", children: [
4900
4803
  /* @__PURE__ */ jsxs(reactNative.View, { testID: "meso-status-card-header", children: [
4901
- /* @__PURE__ */ jsxs(
4902
- reactNative.View,
4903
- {
4904
- className: "flex-row items-center justify-between",
4905
- style: { gap: 8 },
4906
- children: [
4907
- /* @__PURE__ */ jsx(
4908
- reactNative.Text,
4909
- {
4910
- className: "text-text-primary",
4911
- style: {
4912
- flexShrink: 1,
4913
- fontSize: 15,
4914
- fontFamily: '"Space Grotesk", sans-serif',
4915
- fontWeight: "700"
4916
- },
4917
- testID: "meso-status-card-name",
4918
- children: mesoName
4919
- }
4920
- ),
4921
- /* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
4922
- ]
4923
- }
4924
- ),
4804
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center justify-between", style: { gap: 8 }, children: [
4805
+ /* @__PURE__ */ jsx(
4806
+ reactNative.Text,
4807
+ {
4808
+ className: "text-text-primary",
4809
+ style: {
4810
+ flexShrink: 1,
4811
+ fontSize: 15,
4812
+ fontFamily: '"Space Grotesk", sans-serif',
4813
+ fontWeight: "700"
4814
+ },
4815
+ testID: "meso-status-card-name",
4816
+ children: mesoName
4817
+ }
4818
+ ),
4819
+ /* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
4820
+ ] }),
4925
4821
  /* @__PURE__ */ jsx(
4926
4822
  reactNative.Text,
4927
4823
  {
@@ -4936,15 +4832,7 @@ function MesoStatusCard({
4936
4832
  }
4937
4833
  )
4938
4834
  ] }),
4939
- metrics.length > 0 && /* @__PURE__ */ jsx(
4940
- reactNative.View,
4941
- {
4942
- className: "flex-row flex-wrap",
4943
- style: { gap: 8 },
4944
- testID: "meso-status-card-metrics",
4945
- children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell2, { metric }, `${metric.label}-${index}`))
4946
- }
4947
- ),
4835
+ metrics.length > 0 && /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row flex-wrap", style: { gap: 8 }, testID: "meso-status-card-metrics", children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell2, { metric }, `${metric.label}-${index}`)) }),
4948
4836
  gauges.length > 0 && /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 12 }, testID: "meso-status-card-gauges", children: gauges.map((gauge, index) => /* @__PURE__ */ jsx(Gauge, { gauge }, `${gauge.label}-${index}`)) }),
4949
4837
  coaching != null && /* @__PURE__ */ jsx(
4950
4838
  reactNative.View,
@@ -5010,7 +4898,7 @@ function MesoStatusCard({
5010
4898
  );
5011
4899
  }
5012
4900
  var sem = getSemanticColors("dark");
5013
- var BRAND_PRIMARY6 = sem["brand-primary"];
4901
+ var BRAND_PRIMARY5 = sem["brand-primary"];
5014
4902
  var PROJECTION_LINE_COLOR = resolveColor("text-tertiary");
5015
4903
  var STATUS_SUCCESS2 = sem["status-success"];
5016
4904
  var STATUS_ERROR2 = sem["status-error"];
@@ -5023,8 +4911,8 @@ var ERROR_PILL_BORDER = "rgba(209,67,67,0.20)";
5023
4911
  var PLOT_LEFT = 26;
5024
4912
  var TOOLTIP_WIDTH = 124;
5025
4913
  function timeOf(dateStr) {
5026
- const t12 = Date.parse(dateStr);
5027
- return Number.isNaN(t12) ? 0 : t12;
4914
+ const t7 = Date.parse(dateStr);
4915
+ return Number.isNaN(t7) ? 0 : t7;
5028
4916
  }
5029
4917
  function formatValue(value) {
5030
4918
  return `${Math.round(value)}`;
@@ -5065,9 +4953,7 @@ function buildGeometry(data, projection, boundaries, width, height) {
5065
4953
  point,
5066
4954
  index
5067
4955
  }));
5068
- const tickValues = Array.from(
5069
- new Set([yMax, (yMin + yMax) / 2, yMin].map((v) => Math.round(v)))
5070
- );
4956
+ const tickValues = Array.from(new Set([yMax, (yMin + yMax) / 2, yMin].map((v) => Math.round(v))));
5071
4957
  const gridLines = tickValues.map((v) => ({ y: toY(v), label: formatValue(v) }));
5072
4958
  return {
5073
4959
  hasData: true,
@@ -5156,10 +5042,7 @@ function StrengthTrendChart({
5156
5042
  () => buildGeometry(data, projection, mesoBoundaries, width, height),
5157
5043
  [data, projection, mesoBoundaries, width, height]
5158
5044
  );
5159
- const trend = react.useMemo(
5160
- () => computeTrend(data, mesoBoundaries),
5161
- [data, mesoBoundaries]
5162
- );
5045
+ const trend = react.useMemo(() => computeTrend(data, mesoBoundaries), [data, mesoBoundaries]);
5163
5046
  const [reveal] = react.useState(() => new reactNative.Animated.Value(animateOnMount ? 0 : 1));
5164
5047
  const [selected, setSelected] = react.useState(null);
5165
5048
  react.useEffect(() => {
@@ -5196,7 +5079,14 @@ function StrengthTrendChart({
5196
5079
  alignItems: "center",
5197
5080
  justifyContent: "center"
5198
5081
  },
5199
- children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-tertiary", style: { fontSize: 12, fontFamily: "Inter, sans-serif" }, children: "No strength data yet" })
5082
+ children: /* @__PURE__ */ jsx(
5083
+ reactNative.Text,
5084
+ {
5085
+ className: "text-text-tertiary",
5086
+ style: { fontSize: 12, fontFamily: "Inter, sans-serif" },
5087
+ children: "No strength data yet"
5088
+ }
5089
+ )
5200
5090
  }
5201
5091
  )
5202
5092
  }
@@ -5207,316 +5097,333 @@ function StrengthTrendChart({
5207
5097
  outputRange: [0, width]
5208
5098
  });
5209
5099
  const selectedCoord = selected != null ? geometry.actual[selected] : void 0;
5210
- return /* @__PURE__ */ jsxs(
5211
- reactNative.View,
5212
- {
5213
- style: { width },
5214
- className: cn(className),
5215
- testID: "strength-trend-chart",
5216
- ...props,
5217
- children: [
5218
- /* @__PURE__ */ jsxs(reactNative.View, { style: { width, height, position: "relative" }, children: [
5219
- /* @__PURE__ */ jsxs(
5220
- reactNative.View,
5221
- {
5222
- style: { position: "absolute", top: 0, left: 0, width, height },
5223
- accessibilityRole: "image",
5224
- accessibilityLabel: ariaLabel,
5225
- testID: "strength-trend-chart-canvas",
5226
- children: [
5227
- geometry.gridLines.map((line, i) => /* @__PURE__ */ jsx(
5228
- reactNative.View,
5229
- {
5230
- accessibilityElementsHidden: true,
5231
- testID: "strength-trend-chart-gridline",
5232
- style: {
5233
- position: "absolute",
5234
- left: PLOT_LEFT,
5235
- right: 0,
5236
- top: line.y,
5237
- height: 1,
5238
- backgroundColor: GRID_LINE
5239
- },
5240
- children: /* @__PURE__ */ jsx(
5241
- reactNative.Text,
5242
- {
5243
- className: "text-text-tertiary",
5244
- style: {
5245
- position: "absolute",
5246
- left: -PLOT_LEFT,
5247
- top: -6,
5248
- width: PLOT_LEFT - 4,
5249
- textAlign: "right",
5250
- fontSize: 9,
5251
- fontFamily: "Inter, sans-serif"
5252
- },
5253
- children: line.label
5254
- }
5255
- )
5256
- },
5257
- `grid-${i}`
5258
- )),
5259
- geometry.boundaries.map((boundary, i) => /* @__PURE__ */ jsx(
5260
- reactNative.View,
5261
- {
5262
- accessibilityElementsHidden: true,
5263
- testID: "strength-trend-chart-meso-boundary",
5264
- style: {
5265
- position: "absolute",
5266
- left: boundary.x,
5267
- top: 0,
5268
- width: 0,
5269
- height,
5270
- borderLeftWidth: 1,
5271
- borderStyle: "dashed",
5272
- borderLeftColor: "rgba(255,255,255,0.10)"
5273
- }
5274
- },
5275
- `boundary-${i}`
5276
- )),
5277
- /* @__PURE__ */ jsx(
5278
- reactNative.Animated.View,
5100
+ return /* @__PURE__ */ jsxs(reactNative.View, { style: { width }, className: cn(className), testID: "strength-trend-chart", ...props, children: [
5101
+ /* @__PURE__ */ jsxs(reactNative.View, { style: { width, height, position: "relative" }, children: [
5102
+ /* @__PURE__ */ jsxs(
5103
+ reactNative.View,
5104
+ {
5105
+ style: { position: "absolute", top: 0, left: 0, width, height },
5106
+ accessibilityRole: "image",
5107
+ accessibilityLabel: ariaLabel,
5108
+ testID: "strength-trend-chart-canvas",
5109
+ children: [
5110
+ geometry.gridLines.map((line, i) => /* @__PURE__ */ jsx(
5111
+ reactNative.View,
5112
+ {
5113
+ accessibilityElementsHidden: true,
5114
+ testID: "strength-trend-chart-gridline",
5115
+ style: {
5116
+ position: "absolute",
5117
+ left: PLOT_LEFT,
5118
+ right: 0,
5119
+ top: line.y,
5120
+ height: 1,
5121
+ backgroundColor: GRID_LINE
5122
+ },
5123
+ children: /* @__PURE__ */ jsx(
5124
+ reactNative.Text,
5279
5125
  {
5126
+ className: "text-text-tertiary",
5280
5127
  style: {
5281
5128
  position: "absolute",
5282
- top: 0,
5283
- left: 0,
5284
- width: revealWidth,
5285
- height,
5286
- overflow: "hidden"
5129
+ left: -PLOT_LEFT,
5130
+ top: -6,
5131
+ width: PLOT_LEFT - 4,
5132
+ textAlign: "right",
5133
+ fontSize: 9,
5134
+ fontFamily: "Inter, sans-serif"
5287
5135
  },
5288
- testID: "strength-trend-chart-reveal",
5289
- children: /* @__PURE__ */ jsxs(reactNative.View, { style: { width, height, position: "absolute", top: 0, left: 0 }, children: [
5290
- /* @__PURE__ */ jsx(
5291
- ChartLine,
5292
- {
5293
- coords: geometry.projection,
5294
- color: PROJECTION_LINE_COLOR,
5295
- strokeWidth: 2,
5296
- dashed: true,
5297
- testID: "strength-trend-chart-projection-segment"
5298
- }
5299
- ),
5300
- /* @__PURE__ */ jsx(
5301
- ChartLine,
5302
- {
5303
- coords: geometry.actual,
5304
- color: BRAND_PRIMARY6,
5305
- strokeWidth: 2.5,
5306
- testID: "strength-trend-chart-actual-segment"
5307
- }
5308
- )
5309
- ] })
5136
+ children: line.label
5310
5137
  }
5311
- ),
5312
- geometry.actual.map(
5313
- (c2) => c2.point.isPR ? /* @__PURE__ */ jsx(
5314
- reactNative.Text,
5315
- {
5316
- accessibilityElementsHidden: true,
5317
- testID: "strength-trend-chart-pr-star",
5318
- style: {
5319
- position: "absolute",
5320
- left: c2.x - 7,
5321
- top: c2.y - 20,
5322
- fontSize: 12,
5323
- color: STATUS_WARNING2
5324
- },
5325
- children: "\u2605"
5326
- },
5327
- `star-${c2.index}`
5328
- ) : null
5329
5138
  )
5330
- ]
5331
- }
5332
- ),
5333
- /* @__PURE__ */ jsx(
5334
- reactNative.View,
5335
- {
5336
- style: { position: "absolute", top: 0, left: 0, width, height },
5337
- testID: "strength-trend-chart-points",
5338
- children: geometry.actual.map((c2) => {
5339
- const label = c2.point.sessionLabel ?? c2.point.date;
5340
- return /* @__PURE__ */ jsx(
5341
- reactNative.Pressable,
5342
- {
5343
- testID: "strength-trend-chart-point",
5344
- accessibilityRole: "button",
5345
- accessibilityLabel: `${label}: ${formatValue(c2.point.e1rm)} ${unit}${c2.point.isPR ? ", personal record" : ""}`,
5346
- onPress: () => {
5347
- setSelected(c2.index);
5348
- onPointPress?.(c2.point);
5349
- },
5350
- style: {
5351
- position: "absolute",
5352
- left: c2.x - 4,
5353
- top: c2.y - 4,
5354
- width: 8,
5355
- height: 8,
5356
- borderRadius: 1,
5357
- backgroundColor: BRAND_PRIMARY6
5139
+ },
5140
+ `grid-${i}`
5141
+ )),
5142
+ geometry.boundaries.map((boundary, i) => /* @__PURE__ */ jsx(
5143
+ reactNative.View,
5144
+ {
5145
+ accessibilityElementsHidden: true,
5146
+ testID: "strength-trend-chart-meso-boundary",
5147
+ style: {
5148
+ position: "absolute",
5149
+ left: boundary.x,
5150
+ top: 0,
5151
+ width: 0,
5152
+ height,
5153
+ borderLeftWidth: 1,
5154
+ borderStyle: "dashed",
5155
+ borderLeftColor: "rgba(255,255,255,0.10)"
5156
+ }
5157
+ },
5158
+ `boundary-${i}`
5159
+ )),
5160
+ /* @__PURE__ */ jsx(
5161
+ reactNative.Animated.View,
5162
+ {
5163
+ style: {
5164
+ position: "absolute",
5165
+ top: 0,
5166
+ left: 0,
5167
+ width: revealWidth,
5168
+ height,
5169
+ overflow: "hidden"
5170
+ },
5171
+ testID: "strength-trend-chart-reveal",
5172
+ children: /* @__PURE__ */ jsxs(reactNative.View, { style: { width, height, position: "absolute", top: 0, left: 0 }, children: [
5173
+ /* @__PURE__ */ jsx(
5174
+ ChartLine,
5175
+ {
5176
+ coords: geometry.projection,
5177
+ color: PROJECTION_LINE_COLOR,
5178
+ strokeWidth: 2,
5179
+ dashed: true,
5180
+ testID: "strength-trend-chart-projection-segment"
5358
5181
  }
5182
+ ),
5183
+ /* @__PURE__ */ jsx(
5184
+ ChartLine,
5185
+ {
5186
+ coords: geometry.actual,
5187
+ color: BRAND_PRIMARY5,
5188
+ strokeWidth: 2.5,
5189
+ testID: "strength-trend-chart-actual-segment"
5190
+ }
5191
+ )
5192
+ ] })
5193
+ }
5194
+ ),
5195
+ geometry.actual.map(
5196
+ (c2) => c2.point.isPR ? /* @__PURE__ */ jsx(
5197
+ reactNative.Text,
5198
+ {
5199
+ accessibilityElementsHidden: true,
5200
+ testID: "strength-trend-chart-pr-star",
5201
+ style: {
5202
+ position: "absolute",
5203
+ left: c2.x - 7,
5204
+ top: c2.y - 20,
5205
+ fontSize: 12,
5206
+ color: STATUS_WARNING2
5359
5207
  },
5360
- `point-${c2.index}`
5361
- );
5362
- })
5363
- }
5364
- ),
5365
- selectedCoord && /* @__PURE__ */ jsxs(
5366
- reactNative.View,
5367
- {
5368
- testID: "strength-trend-chart-tooltip",
5369
- accessibilityElementsHidden: true,
5370
- className: "bg-surface-elevated border-hairline-strong",
5371
- style: {
5372
- position: "absolute",
5373
- left: Math.max(
5374
- 0,
5375
- Math.min(width - TOOLTIP_WIDTH, selectedCoord.x - TOOLTIP_WIDTH / 2)
5376
- ),
5377
- top: Math.max(0, selectedCoord.y - 52),
5378
- maxWidth: TOOLTIP_WIDTH,
5379
- borderWidth: 1,
5380
- borderRadius: 8,
5381
- paddingVertical: 8,
5382
- paddingHorizontal: 10
5208
+ children: "\u2605"
5209
+ },
5210
+ `star-${c2.index}`
5211
+ ) : null
5212
+ )
5213
+ ]
5214
+ }
5215
+ ),
5216
+ /* @__PURE__ */ jsx(
5217
+ reactNative.View,
5218
+ {
5219
+ style: { position: "absolute", top: 0, left: 0, width, height },
5220
+ testID: "strength-trend-chart-points",
5221
+ children: geometry.actual.map((c2) => {
5222
+ const label = c2.point.sessionLabel ?? c2.point.date;
5223
+ return /* @__PURE__ */ jsx(
5224
+ reactNative.Pressable,
5225
+ {
5226
+ testID: "strength-trend-chart-point",
5227
+ accessibilityRole: "button",
5228
+ accessibilityLabel: `${label}: ${formatValue(c2.point.e1rm)} ${unit}${c2.point.isPR ? ", personal record" : ""}`,
5229
+ onPress: () => {
5230
+ setSelected(c2.index);
5231
+ onPointPress?.(c2.point);
5232
+ },
5233
+ style: {
5234
+ position: "absolute",
5235
+ left: c2.x - 4,
5236
+ top: c2.y - 4,
5237
+ width: 8,
5238
+ height: 8,
5239
+ borderRadius: 1,
5240
+ backgroundColor: BRAND_PRIMARY5
5241
+ }
5383
5242
  },
5384
- children: [
5385
- /* @__PURE__ */ jsx(
5386
- reactNative.Text,
5387
- {
5388
- className: "text-text-tertiary",
5389
- style: {
5390
- fontSize: 10,
5391
- fontFamily: "Inter, sans-serif"
5392
- },
5393
- children: selectedCoord.point.sessionLabel ?? selectedCoord.point.date
5394
- }
5395
- ),
5396
- /* @__PURE__ */ jsx(
5397
- reactNative.Text,
5398
- {
5399
- className: "text-text-primary",
5400
- style: {
5401
- marginTop: 2,
5402
- fontSize: 13,
5403
- fontFamily: "Inter, sans-serif",
5404
- fontWeight: "700"
5405
- },
5406
- children: `${formatValue(selectedCoord.point.e1rm)} ${unit}`
5407
- }
5408
- ),
5409
- selected != null && selected > 0 && /* @__PURE__ */ jsx(
5410
- reactNative.Text,
5411
- {
5412
- style: {
5413
- marginTop: 1,
5414
- fontSize: 10,
5415
- fontFamily: "Inter, sans-serif",
5416
- color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS2 : STATUS_ERROR2
5417
- },
5418
- children: `${selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? "+" : "-"}${Math.abs(
5419
- selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm
5420
- ).toFixed(1)} ${unit}`
5421
- }
5422
- )
5423
- ]
5424
- }
5425
- )
5426
- ] }),
5427
- geometry.boundaries.length > 0 && /* @__PURE__ */ jsx(
5428
- reactNative.View,
5429
- {
5430
- style: { width, height: 14, position: "relative", marginTop: 2 },
5431
- accessibilityElementsHidden: true,
5432
- testID: "strength-trend-chart-axis",
5433
- children: geometry.boundaries.map((boundary, i) => /* @__PURE__ */ jsx(
5243
+ `point-${c2.index}`
5244
+ );
5245
+ })
5246
+ }
5247
+ ),
5248
+ selectedCoord && /* @__PURE__ */ jsxs(
5249
+ reactNative.View,
5250
+ {
5251
+ testID: "strength-trend-chart-tooltip",
5252
+ accessibilityElementsHidden: true,
5253
+ className: "bg-surface-elevated border-hairline-strong",
5254
+ style: {
5255
+ position: "absolute",
5256
+ left: Math.max(
5257
+ 0,
5258
+ Math.min(width - TOOLTIP_WIDTH, selectedCoord.x - TOOLTIP_WIDTH / 2)
5259
+ ),
5260
+ top: Math.max(0, selectedCoord.y - 52),
5261
+ maxWidth: TOOLTIP_WIDTH,
5262
+ borderWidth: 1,
5263
+ borderRadius: 8,
5264
+ paddingVertical: 8,
5265
+ paddingHorizontal: 10
5266
+ },
5267
+ children: [
5268
+ /* @__PURE__ */ jsx(
5434
5269
  reactNative.Text,
5435
5270
  {
5436
- testID: "strength-trend-chart-axis-label",
5437
5271
  className: "text-text-tertiary",
5438
5272
  style: {
5439
- position: "absolute",
5440
- left: boundary.x - 24,
5441
- width: 48,
5442
- textAlign: "center",
5443
5273
  fontSize: 10,
5444
5274
  fontFamily: "Inter, sans-serif"
5445
5275
  },
5446
- children: boundary.label
5447
- },
5448
- `axis-${i}`
5449
- ))
5450
- }
5451
- ),
5452
- /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row", style: { marginTop: 8 }, children: /* @__PURE__ */ jsx(
5453
- reactNative.View,
5454
- {
5455
- testID: "strength-trend-chart-trend-pill",
5456
- accessibilityLabel: `Strength trend: ${trendText}`,
5457
- style: {
5458
- paddingVertical: 3,
5459
- paddingHorizontal: 8,
5460
- borderRadius: 4,
5461
- borderWidth: 1,
5462
- backgroundColor: trend.positive ? SUCCESS_PILL_BG : ERROR_PILL_BG,
5463
- borderColor: trend.positive ? SUCCESS_PILL_BORDER : ERROR_PILL_BORDER
5464
- },
5465
- children: /* @__PURE__ */ jsx(
5276
+ children: selectedCoord.point.sessionLabel ?? selectedCoord.point.date
5277
+ }
5278
+ ),
5279
+ /* @__PURE__ */ jsx(
5280
+ reactNative.Text,
5281
+ {
5282
+ className: "text-text-primary",
5283
+ style: {
5284
+ marginTop: 2,
5285
+ fontSize: 13,
5286
+ fontFamily: "Inter, sans-serif",
5287
+ fontWeight: "700"
5288
+ },
5289
+ children: `${formatValue(selectedCoord.point.e1rm)} ${unit}`
5290
+ }
5291
+ ),
5292
+ selected != null && selected > 0 && /* @__PURE__ */ jsx(
5466
5293
  reactNative.Text,
5467
5294
  {
5468
5295
  style: {
5469
- fontSize: 11,
5296
+ marginTop: 1,
5297
+ fontSize: 10,
5470
5298
  fontFamily: "Inter, sans-serif",
5471
- fontWeight: "600",
5472
- color: trend.positive ? STATUS_SUCCESS2 : STATUS_ERROR2
5299
+ color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS2 : STATUS_ERROR2
5473
5300
  },
5474
- children: trendText
5301
+ children: `${selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? "+" : "-"}${Math.abs(
5302
+ selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm
5303
+ ).toFixed(1)} ${unit}`
5475
5304
  }
5476
5305
  )
5477
- }
5478
- ) }),
5479
- /* @__PURE__ */ jsxs(
5480
- reactNative.View,
5306
+ ]
5307
+ }
5308
+ )
5309
+ ] }),
5310
+ geometry.boundaries.length > 0 && /* @__PURE__ */ jsx(
5311
+ reactNative.View,
5312
+ {
5313
+ style: { width, height: 14, position: "relative", marginTop: 2 },
5314
+ accessibilityElementsHidden: true,
5315
+ testID: "strength-trend-chart-axis",
5316
+ children: geometry.boundaries.map((boundary, i) => /* @__PURE__ */ jsx(
5317
+ reactNative.Text,
5481
5318
  {
5482
- className: "flex-row items-center",
5483
- style: { marginTop: 8, gap: 14 },
5484
- testID: "strength-trend-chart-legend",
5485
- children: [
5486
- /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
5487
- /* @__PURE__ */ jsx(reactNative.View, { style: { width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY6 } }),
5488
- /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Actual" })
5489
- ] }),
5490
- /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
5491
- /* @__PURE__ */ jsx(
5492
- reactNative.View,
5493
- {
5494
- style: {
5495
- width: 14,
5496
- height: 0,
5497
- borderTopWidth: 2,
5498
- borderStyle: "dashed",
5499
- borderTopColor: PROJECTION_LINE_COLOR
5500
- }
5501
- }
5502
- ),
5503
- /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Projected" })
5504
- ] }),
5505
- /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
5506
- /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, color: STATUS_WARNING2 }, children: "\u2605" }),
5507
- /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "PR" })
5508
- ] })
5509
- ]
5319
+ testID: "strength-trend-chart-axis-label",
5320
+ className: "text-text-tertiary",
5321
+ style: {
5322
+ position: "absolute",
5323
+ left: boundary.x - 24,
5324
+ width: 48,
5325
+ textAlign: "center",
5326
+ fontSize: 10,
5327
+ fontFamily: "Inter, sans-serif"
5328
+ },
5329
+ children: boundary.label
5330
+ },
5331
+ `axis-${i}`
5332
+ ))
5333
+ }
5334
+ ),
5335
+ /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row", style: { marginTop: 8 }, children: /* @__PURE__ */ jsx(
5336
+ reactNative.View,
5337
+ {
5338
+ testID: "strength-trend-chart-trend-pill",
5339
+ accessibilityLabel: `Strength trend: ${trendText}`,
5340
+ style: {
5341
+ paddingVertical: 3,
5342
+ paddingHorizontal: 8,
5343
+ borderRadius: 4,
5344
+ borderWidth: 1,
5345
+ backgroundColor: trend.positive ? SUCCESS_PILL_BG : ERROR_PILL_BG,
5346
+ borderColor: trend.positive ? SUCCESS_PILL_BORDER : ERROR_PILL_BORDER
5347
+ },
5348
+ children: /* @__PURE__ */ jsx(
5349
+ reactNative.Text,
5350
+ {
5351
+ style: {
5352
+ fontSize: 11,
5353
+ fontFamily: "Inter, sans-serif",
5354
+ fontWeight: "600",
5355
+ color: trend.positive ? STATUS_SUCCESS2 : STATUS_ERROR2
5356
+ },
5357
+ children: trendText
5510
5358
  }
5511
5359
  )
5512
- ]
5513
- }
5514
- );
5360
+ }
5361
+ ) }),
5362
+ /* @__PURE__ */ jsxs(
5363
+ reactNative.View,
5364
+ {
5365
+ className: "flex-row items-center",
5366
+ style: { marginTop: 8, gap: 14 },
5367
+ testID: "strength-trend-chart-legend",
5368
+ children: [
5369
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
5370
+ /* @__PURE__ */ jsx(
5371
+ reactNative.View,
5372
+ {
5373
+ style: { width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY5 }
5374
+ }
5375
+ ),
5376
+ /* @__PURE__ */ jsx(
5377
+ reactNative.Text,
5378
+ {
5379
+ className: "text-text-secondary",
5380
+ style: { fontSize: 10, fontFamily: "Inter, sans-serif" },
5381
+ children: "Actual"
5382
+ }
5383
+ )
5384
+ ] }),
5385
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
5386
+ /* @__PURE__ */ jsx(
5387
+ reactNative.View,
5388
+ {
5389
+ style: {
5390
+ width: 14,
5391
+ height: 0,
5392
+ borderTopWidth: 2,
5393
+ borderStyle: "dashed",
5394
+ borderTopColor: PROJECTION_LINE_COLOR
5395
+ }
5396
+ }
5397
+ ),
5398
+ /* @__PURE__ */ jsx(
5399
+ reactNative.Text,
5400
+ {
5401
+ className: "text-text-secondary",
5402
+ style: { fontSize: 10, fontFamily: "Inter, sans-serif" },
5403
+ children: "Projected"
5404
+ }
5405
+ )
5406
+ ] }),
5407
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
5408
+ /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, color: STATUS_WARNING2 }, children: "\u2605" }),
5409
+ /* @__PURE__ */ jsx(
5410
+ reactNative.Text,
5411
+ {
5412
+ className: "text-text-secondary",
5413
+ style: { fontSize: 10, fontFamily: "Inter, sans-serif" },
5414
+ children: "PR"
5415
+ }
5416
+ )
5417
+ ] })
5418
+ ]
5419
+ }
5420
+ )
5421
+ ] });
5515
5422
  }
5516
- var t7 = getSemanticColors("dark");
5517
- var STATUS_SUCCESS3 = t7["status-success"];
5518
- var STATUS_WARNING3 = t7["status-warning"];
5519
- var STATUS_INFO = t7["status-info"];
5423
+ var t4 = getSemanticColors("dark");
5424
+ var STATUS_SUCCESS3 = t4["status-success"];
5425
+ var STATUS_WARNING3 = t4["status-warning"];
5426
+ var STATUS_INFO = t4["status-info"];
5520
5427
  var DOT_BORDER = "#F3F4F6";
5521
5428
  var BAND_FILL = "rgba(46,213,115,0.1)";
5522
5429
  var BAND_EDGE = "rgba(46,213,115,0.45)";
@@ -5559,8 +5466,8 @@ function interpEdge(pixels, x, key) {
5559
5466
  const a = pixels[i];
5560
5467
  const b = pixels[i + 1];
5561
5468
  if (x >= a.x && x <= b.x) {
5562
- const t12 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
5563
- return a[key] + t12 * (b[key] - a[key]);
5469
+ const t7 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
5470
+ return a[key] + t7 * (b[key] - a[key]);
5564
5471
  }
5565
5472
  }
5566
5473
  return pixels[pixels.length - 1][key];
@@ -5746,18 +5653,53 @@ function CapacityBandChart({
5746
5653
  /* @__PURE__ */ jsx(
5747
5654
  reactNative.Animated.View,
5748
5655
  {
5749
- style: { position: "absolute", top: 0, left: 0, height, width: revealWidth, overflow: "hidden" },
5656
+ style: {
5657
+ position: "absolute",
5658
+ top: 0,
5659
+ left: 0,
5660
+ height,
5661
+ width: revealWidth,
5662
+ overflow: "hidden"
5663
+ },
5750
5664
  accessibilityElementsHidden: true,
5751
5665
  importantForAccessibility: "no-hide-descendants",
5752
5666
  testID: "capacity-band-chart-reveal",
5753
5667
  children: /* @__PURE__ */ jsxs(reactNative.View, { style: { width, height, position: "relative" }, children: [
5754
5668
  projection && /* @__PURE__ */ jsxs(reactNative.View, { testID: "capacity-band-chart-projection", children: [
5755
- renderColumns(buildColumns2(trainingPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
5756
- renderColumns(buildColumns2(restPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
5757
- renderEdges(buildEdges(trainingPixels, "yHigh"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
5758
- renderEdges(buildEdges(trainingPixels, "yLow"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
5759
- renderEdges(buildEdges(restPixels, "yHigh"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
5760
- renderEdges(buildEdges(restPixels, "yLow"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
5669
+ renderColumns(
5670
+ buildColumns2(trainingPixels, COLUMN_STEP),
5671
+ PROJECTION_FILL,
5672
+ "capacity-band-chart-projection-fill"
5673
+ ),
5674
+ renderColumns(
5675
+ buildColumns2(restPixels, COLUMN_STEP),
5676
+ PROJECTION_FILL,
5677
+ "capacity-band-chart-projection-fill"
5678
+ ),
5679
+ renderEdges(
5680
+ buildEdges(trainingPixels, "yHigh"),
5681
+ STATUS_SUCCESS3,
5682
+ true,
5683
+ "capacity-band-chart-projection-training"
5684
+ ),
5685
+ renderEdges(
5686
+ buildEdges(trainingPixels, "yLow"),
5687
+ STATUS_SUCCESS3,
5688
+ true,
5689
+ "capacity-band-chart-projection-training"
5690
+ ),
5691
+ renderEdges(
5692
+ buildEdges(restPixels, "yHigh"),
5693
+ STATUS_INFO,
5694
+ true,
5695
+ "capacity-band-chart-projection-rest"
5696
+ ),
5697
+ renderEdges(
5698
+ buildEdges(restPixels, "yLow"),
5699
+ STATUS_INFO,
5700
+ true,
5701
+ "capacity-band-chart-projection-rest"
5702
+ ),
5761
5703
  /* @__PURE__ */ jsx(
5762
5704
  reactNative.Text,
5763
5705
  {
@@ -5892,7 +5834,7 @@ function CapacityBandChart({
5892
5834
  }
5893
5835
 
5894
5836
  // src/components/custom/Workout/ExerciseDetailPage.tsx
5895
- var BRAND_PRIMARY7 = getSemanticColors("dark")["brand-primary"];
5837
+ var BRAND_PRIMARY6 = getSemanticColors("dark")["brand-primary"];
5896
5838
  var CHART_WIDTH = 326;
5897
5839
  var CHART_HEIGHT = 150;
5898
5840
  var EXERCISE_DETAIL_TABS = [
@@ -5955,7 +5897,7 @@ function TabBar({ active, onSelect }) {
5955
5897
  alignItems: "center",
5956
5898
  paddingVertical: 10,
5957
5899
  borderBottomWidth: 2,
5958
- borderBottomColor: isActive ? BRAND_PRIMARY7 : "transparent"
5900
+ borderBottomColor: isActive ? BRAND_PRIMARY6 : "transparent"
5959
5901
  },
5960
5902
  testID: `exercise-detail-page-tab-${key}`,
5961
5903
  children: /* @__PURE__ */ jsx(
@@ -6286,7 +6228,7 @@ function ExerciseDetailPage({
6286
6228
  fontSize: 15,
6287
6229
  fontFamily: '"Space Grotesk", sans-serif',
6288
6230
  fontWeight: "700",
6289
- color: BRAND_PRIMARY7
6231
+ color: BRAND_PRIMARY6
6290
6232
  },
6291
6233
  children: `${exercise.currentE1rm} ${exercise.unit}`
6292
6234
  }
@@ -6352,11 +6294,10 @@ function ExerciseDetailPage({
6352
6294
  }
6353
6295
  );
6354
6296
  }
6355
- var BRAND_PRIMARY8 = getSemanticColors("dark")["brand-primary"];
6356
- var segmentBgColors = {
6357
- completed: "rgba(46,213,115,0.3)",
6358
- current: "rgba(255,121,0,0.5)",
6359
- upcoming: "rgba(255,255,255,0.06)"
6297
+ var segmentTrackToken = {
6298
+ completed: "status-success-muted",
6299
+ current: "brand-primary-strong",
6300
+ upcoming: "hairline-subtle"
6360
6301
  };
6361
6302
  function clampProgress(currentWeek, weekCount) {
6362
6303
  if (currentWeek == null || weekCount <= 0) return 0;
@@ -6365,6 +6306,7 @@ function clampProgress(currentWeek, weekCount) {
6365
6306
  }
6366
6307
  function MesoSegment({ meso, isActive, onPress }) {
6367
6308
  const [pressScale] = react.useState(() => new reactNative.Animated.Value(1));
6309
+ const brandPrimary = resolveColor("brand-primary");
6368
6310
  const handlePressIn = () => {
6369
6311
  reactNative.Animated.timing(pressScale, {
6370
6312
  toValue: 0.98,
@@ -6399,12 +6341,12 @@ function MesoSegment({ meso, isActive, onPress }) {
6399
6341
  height: 8,
6400
6342
  borderRadius: 4,
6401
6343
  overflow: "hidden",
6402
- backgroundColor: segmentBgColors[meso.status],
6344
+ backgroundColor: resolveColor(segmentTrackToken[meso.status]),
6403
6345
  transform: [{ scale: pressScale }]
6404
6346
  },
6405
6347
  isActive ? {
6406
6348
  borderWidth: 2,
6407
- borderColor: BRAND_PRIMARY8,
6349
+ borderColor: brandPrimary,
6408
6350
  transform: [{ scale: 1.02 }, { scale: pressScale }]
6409
6351
  } : void 0
6410
6352
  ],
@@ -6418,7 +6360,7 @@ function MesoSegment({ meso, isActive, onPress }) {
6418
6360
  top: 0,
6419
6361
  bottom: 0,
6420
6362
  width: `${progress * 100}%`,
6421
- backgroundColor: BRAND_PRIMARY8
6363
+ backgroundColor: brandPrimary
6422
6364
  },
6423
6365
  testID: `meso-segment-fill-${meso.id}`
6424
6366
  }
@@ -6465,7 +6407,7 @@ var sizeStyles = {
6465
6407
  md: "w-2 h-2",
6466
6408
  lg: "w-2.5 h-2.5"
6467
6409
  };
6468
- var colorStyles = {
6410
+ var colorStyles2 = {
6469
6411
  default: "bg-text-tertiary",
6470
6412
  primary: "bg-brand-primary",
6471
6413
  success: "bg-status-success",
@@ -6475,6 +6417,17 @@ var colorStyles = {
6475
6417
  info: "bg-status-info",
6476
6418
  "error-vivid": "bg-status-error-vivid"
6477
6419
  };
6420
+ var t5 = getSemanticColors("dark");
6421
+ var glowColors2 = {
6422
+ default: greyRamp[500],
6423
+ primary: t5["brand-primary"],
6424
+ success: t5["status-success"],
6425
+ live: t5["status-live"],
6426
+ error: t5["status-error"],
6427
+ warning: t5["status-warning"],
6428
+ info: t5["status-info"],
6429
+ "error-vivid": t5["status-error-vivid"]
6430
+ };
6478
6431
  function Indicator({
6479
6432
  size = "sm",
6480
6433
  color = "default",
@@ -6487,7 +6440,7 @@ function Indicator({
6487
6440
  ...props
6488
6441
  }) {
6489
6442
  const pulseMode = pulse === true ? "opacity" : pulse || false;
6490
- const colorClass = !customColor ? colorStyles[color] : void 0;
6443
+ const colorClass = !customColor ? colorStyles2[color] : void 0;
6491
6444
  const colorStyle = customColor ? { backgroundColor: customColor } : void 0;
6492
6445
  if (pulseMode === "ping") {
6493
6446
  return /* @__PURE__ */ jsxs(reactNative.View, { className: cn("relative", sizeStyles[size], className), style, ...props, children: [
@@ -6512,11 +6465,7 @@ function Indicator({
6512
6465
  )
6513
6466
  ] });
6514
6467
  }
6515
- const dynamicStyle = {
6516
- ...typeof style === "object" ? style : {},
6517
- ...colorStyle ?? {},
6518
- ...glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}
6519
- };
6468
+ const glowStyle = glow ? getGlowShadow(customColor ?? glowColors2[color], "subtle") : null;
6520
6469
  return /* @__PURE__ */ jsx(
6521
6470
  reactNative.View,
6522
6471
  {
@@ -6526,54 +6475,165 @@ function Indicator({
6526
6475
  colorClass,
6527
6476
  pulseMode === "opacity" && "animate-pulse",
6528
6477
  ring && "border-2 border-background-base",
6529
- glow && !customColor && (color === "success" || color === "live") && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
6530
- glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
6531
- glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
6532
- glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
6533
- glow && !customColor && color === "error-vivid" && "shadow-[0_0_6px_rgba(255,71,87,0.6)]",
6534
6478
  className
6535
6479
  ),
6536
- style: Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style,
6480
+ style: [style, colorStyle, glowStyle],
6537
6481
  ...props
6538
6482
  }
6539
6483
  );
6540
6484
  }
6541
-
6542
- // src/components/ui/badge/Badge.tsx
6543
- var variantColorStyles = {
6485
+ var colorToTone = {
6486
+ default: "neutral",
6487
+ primary: "brand",
6488
+ secondary: "brand-secondary",
6489
+ success: "success",
6490
+ error: "error",
6491
+ warning: "warning",
6492
+ info: "info"
6493
+ };
6494
+ var toneStyles = {
6544
6495
  solid: {
6545
- default: "bg-hairline-strong text-text-inverse",
6546
- primary: "bg-brand-primary text-text-inverse",
6547
- secondary: "bg-brand-secondary text-text-inverse",
6548
- success: "bg-status-success text-text-inverse",
6549
- error: "bg-status-error text-text-inverse",
6550
- warning: "bg-status-warning text-text-inverse",
6551
- info: "bg-status-info text-text-inverse"
6496
+ neutral: "bg-hairline-strong border-transparent text-text-inverse",
6497
+ brand: "bg-brand-primary border-transparent text-text-inverse",
6498
+ "brand-secondary": "bg-brand-secondary border-transparent text-text-inverse",
6499
+ success: "bg-status-success border-transparent text-text-inverse",
6500
+ warning: "bg-status-warning border-transparent text-text-inverse",
6501
+ error: "bg-status-error border-transparent text-text-inverse",
6502
+ info: "bg-status-info border-transparent text-text-inverse"
6552
6503
  },
6553
6504
  subtle: {
6554
- default: "bg-surface-raised text-text-secondary",
6555
- primary: "bg-brand-primary-subtle text-brand-primary",
6556
- secondary: "bg-brand-secondary-subtle text-brand-secondary",
6557
- success: "bg-status-success-subtle text-status-success",
6558
- error: "bg-status-error-subtle text-status-error",
6559
- warning: "bg-status-warning-subtle text-status-warning",
6560
- info: "bg-status-info-subtle text-status-info"
6505
+ // Alpha-white rather than a ramp step: a pill sits on whatever plane its
6506
+ // host is, and an alpha fill composites by the same amount on all of them.
6507
+ // A `surface-*` fill would vanish on the plane it names. Borderless like the
6508
+ // six coloured tones — the fill carries the capsule, not a ring.
6509
+ neutral: "bg-hairline-subtle border-transparent text-text-secondary",
6510
+ brand: "bg-brand-primary-subtle border-transparent text-brand-primary",
6511
+ "brand-secondary": "bg-brand-secondary-subtle border-transparent text-brand-secondary",
6512
+ success: "bg-status-success-subtle border-transparent text-status-success",
6513
+ warning: "bg-status-warning-subtle border-transparent text-status-warning",
6514
+ error: "bg-status-error-subtle border-transparent text-status-error",
6515
+ info: "bg-status-info-subtle border-transparent text-status-info"
6561
6516
  },
6562
6517
  outline: {
6563
- default: "border border-hairline-strong text-text-secondary",
6564
- primary: "border border-brand-primary text-brand-primary",
6565
- secondary: "border border-brand-secondary text-brand-secondary",
6566
- success: "border border-status-success text-status-success",
6567
- error: "border border-status-error text-status-error",
6568
- warning: "border border-status-warning text-status-warning",
6569
- info: "border border-status-info text-status-info"
6518
+ neutral: "border-hairline text-text-secondary",
6519
+ brand: "border-brand-primary text-brand-primary",
6520
+ "brand-secondary": "border-brand-secondary text-brand-secondary",
6521
+ success: "border-status-success text-status-success",
6522
+ warning: "border-status-warning text-status-warning",
6523
+ error: "border-status-error text-status-error",
6524
+ info: "border-status-info text-status-info"
6570
6525
  }
6571
6526
  };
6527
+ var dotToneStyles = {
6528
+ neutral: "bg-text-tertiary",
6529
+ brand: "bg-brand-primary",
6530
+ "brand-secondary": "bg-brand-secondary",
6531
+ success: "bg-status-success",
6532
+ warning: "bg-status-warning",
6533
+ error: "bg-status-error",
6534
+ info: "bg-status-info"
6535
+ };
6572
6536
  var sizeStyles2 = {
6573
- sm: "px-1.5 py-0.5 text-xs",
6574
- md: "px-2 py-0.5 text-xs",
6575
- lg: "px-2.5 py-1 text-sm"
6537
+ xs: { container: "px-1 py-px", text: "text-3xs" },
6538
+ sm: { container: "px-2 py-0.5", text: "text-2xs" },
6539
+ md: { container: "px-2.5 py-1", text: "text-xs" },
6540
+ lg: { container: "px-3 py-1.5", text: "text-sm" },
6541
+ xl: { container: "px-4 py-2", text: "text-base" }
6542
+ };
6543
+ function PillDot({ tone, testID }) {
6544
+ return /* @__PURE__ */ jsx(
6545
+ reactNative.View,
6546
+ {
6547
+ className: cn("w-1.5 h-1.5 rounded-full shrink-0", dotToneStyles[tone]),
6548
+ accessibilityElementsHidden: true,
6549
+ testID: testID ? `${testID}-dot` : "pill-dot"
6550
+ }
6551
+ );
6552
+ }
6553
+ function containerClasses(p, tone) {
6554
+ return cn(
6555
+ "flex-row items-center gap-1 border self-start shrink-0",
6556
+ p.rounded === false ? "rounded" : "rounded-full",
6557
+ toneStyles[p.variant ?? "subtle"][tone],
6558
+ sizeStyles2[p.size ?? "sm"].container,
6559
+ p.isDisabled && "opacity-50",
6560
+ p.className
6561
+ );
6562
+ }
6563
+ function PillContent({ tone, ...p }) {
6564
+ const textClasses = cn(
6565
+ "font-heading font-semibold text-inherit",
6566
+ sizeStyles2[p.size ?? "sm"].text,
6567
+ p.textClassName
6568
+ );
6569
+ const slot = p.leading ?? p.leftElement;
6570
+ return /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
6571
+ slot === "dot" ? /* @__PURE__ */ jsx(PillDot, { tone: p.dotTone ?? tone, testID: p.testID }) : slot,
6572
+ typeof p.children === "string" ? /* @__PURE__ */ jsx(reactNative.Text, { className: textClasses, children: p.children }) : p.children,
6573
+ p.trailing
6574
+ ] });
6575
+ }
6576
+ function Pill(props) {
6577
+ const {
6578
+ variant,
6579
+ tone,
6580
+ color,
6581
+ size,
6582
+ rounded,
6583
+ leading,
6584
+ dotTone: dotTone2,
6585
+ leftElement,
6586
+ trailing,
6587
+ onPress,
6588
+ isDisabled,
6589
+ className,
6590
+ textClassName,
6591
+ children,
6592
+ ...viewProps
6593
+ } = props;
6594
+ const resolvedTone = tone ?? (color ? colorToTone[color] : "neutral");
6595
+ const classes = containerClasses(props, resolvedTone);
6596
+ const content = /* @__PURE__ */ jsx(PillContent, { ...props, tone: resolvedTone });
6597
+ if (onPress) {
6598
+ return /* @__PURE__ */ jsx(
6599
+ reactNative.Pressable,
6600
+ {
6601
+ onPress,
6602
+ disabled: isDisabled,
6603
+ accessibilityRole: "button",
6604
+ className: classes,
6605
+ ...viewProps,
6606
+ children: content
6607
+ }
6608
+ );
6609
+ }
6610
+ return /* @__PURE__ */ jsx(reactNative.View, { className: classes, ...viewProps, children: content });
6611
+ }
6612
+
6613
+ // src/components/ui/badge/Badge.tsx
6614
+ var colorToTone2 = {
6615
+ default: "neutral",
6616
+ primary: "brand",
6617
+ secondary: "brand-secondary",
6618
+ success: "success",
6619
+ error: "error",
6620
+ warning: "warning",
6621
+ info: "info"
6576
6622
  };
6623
+ var sizeStyles3 = {
6624
+ sm: "px-1.5 py-0.5",
6625
+ md: "px-2 py-0.5",
6626
+ lg: "px-2.5 py-1"
6627
+ };
6628
+ var textSizeStyles = {
6629
+ sm: "text-xs",
6630
+ md: "text-xs",
6631
+ lg: "text-sm"
6632
+ };
6633
+ function dotIndicatorColor(color, dotColor) {
6634
+ if (dotColor) return dotColor;
6635
+ return color === "default" || color === "secondary" ? "default" : color;
6636
+ }
6577
6637
  function Badge({
6578
6638
  variant = "subtle",
6579
6639
  color = "default",
@@ -6584,56 +6644,62 @@ function Badge({
6584
6644
  children,
6585
6645
  ...props
6586
6646
  }) {
6587
- return /* @__PURE__ */ jsxs(
6588
- reactNative.View,
6647
+ return /* @__PURE__ */ jsx(
6648
+ Pill,
6589
6649
  {
6650
+ variant,
6651
+ tone: colorToTone2[color],
6652
+ leading: dot ? /* @__PURE__ */ jsx(Indicator, { size: "xs", color: dotIndicatorColor(color, dotColor), className: "mr-0.5" }) : void 0,
6590
6653
  className: cn(
6591
- "inline-flex items-center justify-center rounded-full font-medium",
6592
- variantColorStyles[variant][color],
6593
- sizeStyles2[size],
6654
+ "justify-center self-auto gap-0",
6655
+ variant === "outline" ? "border" : "border-0",
6656
+ sizeStyles3[size],
6594
6657
  className
6595
6658
  ),
6659
+ textClassName: cn("font-sans font-medium", textSizeStyles[size]),
6596
6660
  ...props,
6597
- children: [
6598
- dot && /* @__PURE__ */ jsx(
6599
- Indicator,
6600
- {
6601
- size: "xs",
6602
- color: dotColor ?? (color === "default" || color === "secondary" ? "default" : color),
6603
- className: "mr-0.5"
6604
- }
6605
- ),
6606
- typeof children === "string" ? /* @__PURE__ */ jsx(reactNative.Text, { className: "text-inherit font-medium", children }) : children
6607
- ]
6661
+ children
6608
6662
  }
6609
6663
  );
6610
6664
  }
6611
- var HAIRLINE_DEFAULT = getSemanticColors("dark")["hairline-default"];
6612
- var t8 = getSemanticColors("dark");
6613
- var statusBgColors = {
6614
- completed: "rgba(46,213,115,0.15)",
6615
- current: "rgba(255,121,0,0.15)",
6616
- next: "transparent",
6617
- upcoming: t8["surface-raised"],
6618
- missed: "rgba(209,67,67,0.1)",
6619
- deload: "rgba(186,41,150,0.15)"
6620
- };
6621
- var statusBorderStyles = {
6622
- completed: { borderWidth: 1, borderColor: "rgba(46,213,115,0.3)" },
6623
- current: { borderWidth: 1, borderColor: "rgba(255,121,0,0.3)" },
6624
- next: { borderWidth: 1, borderColor: "rgba(255,121,0,0.4)" },
6625
- upcoming: { borderWidth: 1, borderColor: HAIRLINE_DEFAULT },
6626
- missed: { borderWidth: 1, borderColor: "rgba(209,67,67,0.25)" },
6627
- deload: { borderWidth: 1, borderColor: "rgba(186,41,150,0.3)" }
6628
- };
6629
- var textColors = {
6630
- completed: t8["status-success"],
6631
- current: t8["brand-primary"],
6632
- next: t8["brand-primary"],
6633
- upcoming: greyRamp[500],
6634
- missed: "rgba(209,67,67,0.7)",
6635
- deload: WORKOUT_PILL_DELOAD
6636
- };
6665
+ var DELOAD_WASH = alpha(WORKOUT_PILL_DELOAD, 0.12);
6666
+ var DELOAD_RIM = alpha(WORKOUT_PILL_DELOAD, 0.3);
6667
+ function paintFor(status) {
6668
+ switch (status) {
6669
+ case "completed":
6670
+ return {
6671
+ background: resolveColor("status-success-subtle"),
6672
+ border: resolveColor("status-success-muted"),
6673
+ text: resolveColor("status-success")
6674
+ };
6675
+ case "current":
6676
+ return {
6677
+ background: resolveColor("brand-primary-subtle"),
6678
+ border: resolveColor("brand-primary-muted"),
6679
+ text: resolveColor("brand-primary")
6680
+ };
6681
+ case "next":
6682
+ return {
6683
+ background: "transparent",
6684
+ border: resolveColor("brand-primary-strong"),
6685
+ text: resolveColor("brand-primary")
6686
+ };
6687
+ case "upcoming":
6688
+ return {
6689
+ background: resolveColor("surface-raised"),
6690
+ border: resolveColor("hairline-default"),
6691
+ text: resolveColor("text-tertiary")
6692
+ };
6693
+ case "missed":
6694
+ return {
6695
+ background: resolveColor("status-error-subtle"),
6696
+ border: resolveColor("status-error-muted"),
6697
+ text: resolveColor("status-error-dark")
6698
+ };
6699
+ case "deload":
6700
+ return { background: DELOAD_WASH, border: DELOAD_RIM, text: WORKOUT_PILL_DELOAD };
6701
+ }
6702
+ }
6637
6703
  function usePulse2(enabled) {
6638
6704
  const [opacity] = react.useState(() => new reactNative.Animated.Value(1));
6639
6705
  react.useEffect(() => {
@@ -6675,6 +6741,8 @@ function WorkoutPill({
6675
6741
  const pulseOpacity = usePulse2(shouldPulse);
6676
6742
  const isCompleted = status === "completed";
6677
6743
  const isMissed = status === "missed";
6744
+ const paint = paintFor(status);
6745
+ const labelClass = "font-semibold leading-[normal]";
6678
6746
  const pill = /* @__PURE__ */ jsx(
6679
6747
  reactNative.Animated.View,
6680
6748
  {
@@ -6691,53 +6759,46 @@ function WorkoutPill({
6691
6759
  paddingHorizontal: 10,
6692
6760
  paddingVertical: 4,
6693
6761
  borderRadius: 6,
6694
- backgroundColor: statusBgColors[status]
6762
+ backgroundColor: paint.background,
6763
+ borderWidth: 1,
6764
+ borderColor: paint.border
6695
6765
  },
6696
- statusBorderStyles[status],
6697
6766
  highlighted ? { borderWidth: 2, transform: [{ scale: 1.02 }] } : void 0
6698
6767
  ],
6699
6768
  accessibilityLabel: onPress ? void 0 : `${name} workout, ${status}`,
6700
6769
  ...props,
6701
6770
  children: [
6702
6771
  isCompleted && /* @__PURE__ */ jsx(
6703
- reactNative.Text,
6772
+ Typography,
6704
6773
  {
6705
- style: {
6706
- fontWeight: "600",
6707
- fontFamily: '"Nunito Sans", sans-serif',
6708
- fontSize: 11,
6709
- color: textColors[status],
6710
- marginRight: 4
6711
- },
6774
+ variant: "caption",
6775
+ color: "inherit",
6776
+ className: labelClass,
6777
+ style: { color: paint.text, marginRight: 4 },
6712
6778
  accessibilityElementsHidden: true,
6713
6779
  testID: "workout-pill-check",
6714
6780
  children: "\u2713"
6715
6781
  }
6716
6782
  ),
6717
6783
  isMissed && /* @__PURE__ */ jsx(
6718
- reactNative.Text,
6784
+ Typography,
6719
6785
  {
6720
- style: {
6721
- fontWeight: "600",
6722
- fontFamily: '"Nunito Sans", sans-serif',
6723
- fontSize: 11,
6724
- color: textColors[status],
6725
- marginRight: 4
6726
- },
6786
+ variant: "caption",
6787
+ color: "inherit",
6788
+ className: labelClass,
6789
+ style: { color: paint.text, marginRight: 4 },
6727
6790
  accessibilityElementsHidden: true,
6728
6791
  testID: "workout-pill-dash",
6729
6792
  children: "\u2014"
6730
6793
  }
6731
6794
  ),
6732
6795
  /* @__PURE__ */ jsx(
6733
- reactNative.Text,
6796
+ Typography,
6734
6797
  {
6735
- style: {
6736
- fontWeight: "600",
6737
- fontFamily: '"Nunito Sans", sans-serif',
6738
- fontSize: 11,
6739
- color: textColors[status]
6740
- },
6798
+ variant: "caption",
6799
+ color: "inherit",
6800
+ className: labelClass,
6801
+ style: { color: paint.text },
6741
6802
  accessibilityElementsHidden: onPress != null,
6742
6803
  testID: "workout-pill-name",
6743
6804
  children: name
@@ -6762,19 +6823,19 @@ function WorkoutPill({
6762
6823
  }
6763
6824
  return pill;
6764
6825
  }
6765
- var t9 = getSemanticColors("dark");
6826
+ var t6 = getSemanticColors("dark");
6766
6827
  var TRACK_BG = "#333333";
6767
6828
  var LABEL_COLOR = "#6B7280";
6768
6829
  var TARGET_LINE_COLOR = "rgba(33, 150, 243, 0.5)";
6769
- var AT_TARGET_GLOW = "0 0 5px 1px rgba(33, 150, 243, 0.35), 0 0 10px 3px rgba(33, 150, 243, 0.15)";
6830
+ var AT_TARGET_GLOW = getGlowShadow(t6["status-info"], "subtle");
6770
6831
  var ZONE = {
6771
- building: t9["status-success"],
6832
+ building: t6["status-success"],
6772
6833
  // below target ramp-up
6773
- approaching: t9["status-warning"],
6834
+ approaching: t6["status-warning"],
6774
6835
  // nearing target
6775
- target: t9["brand-primary"],
6836
+ target: t6["brand-primary"],
6776
6837
  // exactly at target
6777
- over1: t9["status-error"],
6838
+ over1: t6["status-error"],
6778
6839
  // mild over-target
6779
6840
  over2: WORKOUT_TOKENS.intensity.over2,
6780
6841
  // moderate over-target
@@ -6889,7 +6950,7 @@ function IntensityBar({
6889
6950
  borderRadius: 3,
6890
6951
  backgroundColor: zone.color,
6891
6952
  zIndex: 2,
6892
- ...atTarget ? { boxShadow: AT_TARGET_GLOW } : null
6953
+ ...atTarget ? AT_TARGET_GLOW : null
6893
6954
  },
6894
6955
  testID: "intensity-fill"
6895
6956
  }
@@ -6937,7 +6998,7 @@ function IntensityBar({
6937
6998
  }
6938
6999
 
6939
7000
  // src/components/custom/Workout/WeekRow.tsx
6940
- var BRAND_PRIMARY9 = getSemanticColors("dark")["brand-primary"];
7001
+ var DELOAD_ROW_WASH = alpha(WORKOUT_PILL_DELOAD, 0.06);
6941
7002
  function WeekRow({
6942
7003
  weekNumber,
6943
7004
  totalWeeks,
@@ -6949,6 +7010,7 @@ function WeekRow({
6949
7010
  className,
6950
7011
  ...props
6951
7012
  }) {
7013
+ const brandPrimary = resolveColor("brand-primary");
6952
7014
  const rowStyle = {
6953
7015
  flexDirection: "row",
6954
7016
  alignItems: "center",
@@ -6957,12 +7019,12 @@ function WeekRow({
6957
7019
  gap: 12
6958
7020
  };
6959
7021
  if (isDeload) {
6960
- rowStyle.backgroundColor = "rgba(186,41,150,0.06)";
7022
+ rowStyle.backgroundColor = DELOAD_ROW_WASH;
6961
7023
  }
6962
7024
  if (isCurrent) {
6963
- rowStyle.backgroundColor = "rgba(255,121,0,0.04)";
7025
+ rowStyle.backgroundColor = resolveColor("brand-primary-subtle");
6964
7026
  rowStyle.borderLeftWidth = 2;
6965
- rowStyle.borderLeftColor = BRAND_PRIMARY9;
7027
+ rowStyle.borderLeftColor = brandPrimary;
6966
7028
  }
6967
7029
  return /* @__PURE__ */ jsxs(
6968
7030
  reactNative.View,
@@ -6986,22 +7048,18 @@ function WeekRow({
6986
7048
  width: 6,
6987
7049
  height: 6,
6988
7050
  borderRadius: 3,
6989
- backgroundColor: BRAND_PRIMARY9
7051
+ backgroundColor: brandPrimary
6990
7052
  },
6991
7053
  accessibilityElementsHidden: true,
6992
7054
  testID: "week-row-current-dot"
6993
7055
  }
6994
7056
  ),
6995
7057
  /* @__PURE__ */ jsx(
6996
- reactNative.Text,
7058
+ Typography,
6997
7059
  {
6998
- className: isCurrent ? void 0 : "text-text-primary",
6999
- style: {
7000
- fontSize: 13,
7001
- fontWeight: "700",
7002
- fontFamily: "Inter, sans-serif",
7003
- color: isCurrent ? BRAND_PRIMARY9 : void 0
7004
- },
7060
+ variant: "boldLabel",
7061
+ color: isCurrent ? "inherit" : "primary",
7062
+ className: isCurrent ? "text-brand-primary" : void 0,
7005
7063
  accessibilityElementsHidden: true,
7006
7064
  children: `W${weekNumber}`
7007
7065
  }
@@ -7041,12 +7099,12 @@ function WeekRow({
7041
7099
  }
7042
7100
 
7043
7101
  // src/components/custom/Workout/MesoCard.tsx
7044
- var HAIRLINE_DEFAULT2 = getSemanticColors("dark")["hairline-default"];
7045
- var BRAND_PRIMARY10 = getSemanticColors("dark")["brand-primary"];
7102
+ var HAIRLINE_DEFAULT = getSemanticColors("dark")["hairline-default"];
7103
+ var BRAND_PRIMARY7 = getSemanticColors("dark")["brand-primary"];
7046
7104
  var BRAND_PRIMARY_DARK2 = MESO_ACCENT_GRADIENT_DARK;
7047
7105
  var BRAND_PRIMARY_LIGHT2 = MESO_ACCENT_GRADIENT_LIGHT;
7048
- var BORDER_DEFAULT = HAIRLINE_DEFAULT2;
7049
- var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2, BRAND_PRIMARY10, BRAND_PRIMARY_LIGHT2];
7106
+ var BORDER_DEFAULT = HAIRLINE_DEFAULT;
7107
+ var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2, BRAND_PRIMARY7, BRAND_PRIMARY_LIGHT2];
7050
7108
  function heatmapColor(percentage) {
7051
7109
  const clamped = Math.max(0, Math.min(100, percentage));
7052
7110
  const opacity = 0.12 + clamped / 100 * 0.78;
@@ -7081,130 +7139,139 @@ function MesoCard({
7081
7139
  }, [highlighted, highlight]);
7082
7140
  const borderColor = highlight.interpolate({
7083
7141
  inputRange: [0, 1],
7084
- outputRange: [BORDER_DEFAULT, BRAND_PRIMARY10]
7142
+ outputRange: [BORDER_DEFAULT, BRAND_PRIMARY7]
7085
7143
  });
7086
- const header = /* @__PURE__ */ jsxs(reactNative.View, { style: { paddingHorizontal: 14, paddingTop: 12, paddingBottom: 10 }, testID: "meso-card-body", children: [
7087
- /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 8 }, testID: "meso-card-header", children: [
7088
- /* @__PURE__ */ jsx(
7089
- reactNative.Text,
7090
- {
7091
- className: "text-text-primary",
7092
- style: {
7093
- fontSize: 15,
7094
- fontFamily: '"Space Grotesk", sans-serif',
7095
- fontWeight: "700"
7096
- },
7097
- testID: "meso-card-name",
7098
- children: name
7099
- }
7100
- ),
7101
- /* @__PURE__ */ jsx(Badge, { variant: "subtle", color: "primary", size: "sm", testID: "meso-card-goal-badge", children: goal })
7102
- ] }),
7103
- /* @__PURE__ */ jsx(
7104
- reactNative.Text,
7105
- {
7106
- className: "text-text-secondary",
7107
- style: {
7108
- marginTop: 4,
7109
- fontSize: 12,
7110
- fontFamily: "Inter, sans-serif"
7111
- },
7112
- testID: "meso-card-subheader",
7113
- children: `${split} \xB7 ${weekRange}`
7114
- }
7115
- ),
7116
- volumeHeatmap && volumeHeatmap.length > 0 && /* @__PURE__ */ jsx(
7117
- reactNative.View,
7118
- {
7119
- className: "flex-row items-center",
7120
- style: { marginTop: 10, gap: 3 },
7121
- accessibilityElementsHidden: true,
7122
- testID: "meso-card-heatmap",
7123
- children: volumeHeatmap.map((entry) => /* @__PURE__ */ jsx(
7124
- reactNative.View,
7125
- {
7126
- style: {
7127
- flex: 1,
7128
- height: 8,
7129
- borderRadius: 2,
7130
- backgroundColor: heatmapColor(entry.percentage)
7131
- },
7132
- testID: "meso-card-heatmap-cell"
7133
- },
7134
- entry.group
7135
- ))
7136
- }
7137
- )
7138
- ] });
7139
- return /* @__PURE__ */ jsx(reactNative.Animated.View, { style: highlighted ? { transform: [{ scale: 1 }] } : void 0, testID: "meso-card-wrapper", children: /* @__PURE__ */ jsxs(
7140
- Card,
7144
+ const header = /* @__PURE__ */ jsxs(
7145
+ reactNative.View,
7141
7146
  {
7142
- variant: "outline",
7143
- elevation: 2,
7144
- borderColor: highlighted ? BRAND_PRIMARY10 : BORDER_DEFAULT,
7145
- className,
7146
- style: [
7147
- { borderColor },
7148
- highlighted ? { boxShadow: "0 0 12px 2px rgba(255,121,0,0.25)" } : void 0
7149
- ],
7150
- testID: "meso-card",
7151
- ...props,
7147
+ style: { paddingHorizontal: 14, paddingTop: 12, paddingBottom: 10 },
7148
+ testID: "meso-card-body",
7152
7149
  children: [
7150
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 8 }, testID: "meso-card-header", children: [
7151
+ /* @__PURE__ */ jsx(
7152
+ reactNative.Text,
7153
+ {
7154
+ className: "text-text-primary",
7155
+ style: {
7156
+ fontSize: 15,
7157
+ fontFamily: '"Space Grotesk", sans-serif',
7158
+ fontWeight: "700"
7159
+ },
7160
+ testID: "meso-card-name",
7161
+ children: name
7162
+ }
7163
+ ),
7164
+ /* @__PURE__ */ jsx(Badge, { variant: "subtle", color: "primary", size: "sm", testID: "meso-card-goal-badge", children: goal })
7165
+ ] }),
7153
7166
  /* @__PURE__ */ jsx(
7154
- reactNative.View,
7155
- {
7156
- className: "flex-row",
7157
- style: { position: "absolute", top: 0, left: 0, right: 0, height: 3, zIndex: 1 },
7158
- accessibilityElementsHidden: true,
7159
- testID: "meso-card-accent",
7160
- children: ACCENT_STOPS2.map((color) => /* @__PURE__ */ jsx(reactNative.View, { style: { flex: 1, backgroundColor: color } }, color))
7161
- }
7162
- ),
7163
- isExpandable ? /* @__PURE__ */ jsx(
7164
- reactNative.Pressable,
7165
- {
7166
- onPress: onToggle,
7167
- accessibilityRole: "button",
7168
- accessibilityLabel: `${name}, ${goal}, ${weekRange}`,
7169
- "aria-expanded": expanded,
7170
- testID: "meso-card-toggle",
7171
- children: header
7172
- }
7173
- ) : /* @__PURE__ */ jsx(
7174
- reactNative.View,
7167
+ reactNative.Text,
7175
7168
  {
7176
- accessibilityLabel: `${name}, ${goal}, ${weekRange}`,
7177
- testID: "meso-card-static",
7178
- children: header
7169
+ className: "text-text-secondary",
7170
+ style: {
7171
+ marginTop: 4,
7172
+ fontSize: 12,
7173
+ fontFamily: "Inter, sans-serif"
7174
+ },
7175
+ testID: "meso-card-subheader",
7176
+ children: `${split} \xB7 ${weekRange}`
7179
7177
  }
7180
7178
  ),
7181
- expanded && weeks.length > 0 && /* @__PURE__ */ jsx(
7179
+ volumeHeatmap && volumeHeatmap.length > 0 && /* @__PURE__ */ jsx(
7182
7180
  reactNative.View,
7183
7181
  {
7184
- style: { borderTopWidth: 1, borderTopColor: BORDER_DEFAULT },
7185
- testID: "meso-card-weeks",
7186
- children: weeks.map((week) => /* @__PURE__ */ jsx(
7187
- WeekRow,
7182
+ className: "flex-row items-center",
7183
+ style: { marginTop: 10, gap: 3 },
7184
+ accessibilityElementsHidden: true,
7185
+ testID: "meso-card-heatmap",
7186
+ children: volumeHeatmap.map((entry) => /* @__PURE__ */ jsx(
7187
+ reactNative.View,
7188
7188
  {
7189
- ...week,
7190
- totalWeeks: week.totalWeeks ?? totalWeeks,
7191
- isCurrent: week.isCurrent ?? week.weekNumber === currentWeek
7189
+ style: {
7190
+ flex: 1,
7191
+ height: 8,
7192
+ borderRadius: 2,
7193
+ backgroundColor: heatmapColor(entry.percentage)
7194
+ },
7195
+ testID: "meso-card-heatmap-cell"
7192
7196
  },
7193
- week.weekNumber
7197
+ entry.group
7194
7198
  ))
7195
7199
  }
7196
7200
  )
7197
7201
  ]
7198
7202
  }
7199
- ) });
7203
+ );
7204
+ return /* @__PURE__ */ jsx(
7205
+ reactNative.Animated.View,
7206
+ {
7207
+ style: highlighted ? { transform: [{ scale: 1 }] } : void 0,
7208
+ testID: "meso-card-wrapper",
7209
+ children: /* @__PURE__ */ jsxs(
7210
+ Card,
7211
+ {
7212
+ variant: "outline",
7213
+ elevation: 2,
7214
+ borderColor: highlighted ? BRAND_PRIMARY7 : BORDER_DEFAULT,
7215
+ className,
7216
+ style: [
7217
+ { borderColor },
7218
+ // Highlight is emphasis, not depth: a brand glow through the shared builder.
7219
+ highlighted ? getGlowShadow(BRAND_PRIMARY7, "subtle") : void 0
7220
+ ],
7221
+ testID: "meso-card",
7222
+ ...props,
7223
+ children: [
7224
+ /* @__PURE__ */ jsx(
7225
+ reactNative.View,
7226
+ {
7227
+ className: "flex-row",
7228
+ style: { position: "absolute", top: 0, left: 0, right: 0, height: 3, zIndex: 1 },
7229
+ accessibilityElementsHidden: true,
7230
+ testID: "meso-card-accent",
7231
+ children: ACCENT_STOPS2.map((color) => /* @__PURE__ */ jsx(reactNative.View, { style: { flex: 1, backgroundColor: color } }, color))
7232
+ }
7233
+ ),
7234
+ isExpandable ? /* @__PURE__ */ jsx(
7235
+ reactNative.Pressable,
7236
+ {
7237
+ onPress: onToggle,
7238
+ accessibilityRole: "button",
7239
+ accessibilityLabel: `${name}, ${goal}, ${weekRange}`,
7240
+ "aria-expanded": expanded,
7241
+ testID: "meso-card-toggle",
7242
+ children: header
7243
+ }
7244
+ ) : /* @__PURE__ */ jsx(reactNative.View, { accessibilityLabel: `${name}, ${goal}, ${weekRange}`, testID: "meso-card-static", children: header }),
7245
+ expanded && weeks.length > 0 && /* @__PURE__ */ jsx(
7246
+ reactNative.View,
7247
+ {
7248
+ style: { borderTopWidth: 1, borderTopColor: BORDER_DEFAULT },
7249
+ testID: "meso-card-weeks",
7250
+ children: weeks.map((week) => /* @__PURE__ */ jsx(
7251
+ WeekRow,
7252
+ {
7253
+ ...week,
7254
+ totalWeeks: week.totalWeeks ?? totalWeeks,
7255
+ isCurrent: week.isCurrent ?? week.weekNumber === currentWeek
7256
+ },
7257
+ week.weekNumber
7258
+ ))
7259
+ }
7260
+ )
7261
+ ]
7262
+ }
7263
+ )
7264
+ }
7265
+ );
7200
7266
  }
7201
- var t10 = getSemanticColors("dark");
7202
- var dotColorMap = {
7203
- untrained: greyRamp[900],
7204
- behind: t10["brand-secondary"],
7205
- ontrack: t10["status-success"],
7206
- target: t10["brand-primary"],
7207
- over: t10["status-error"]
7267
+
7268
+ // src/components/custom/Workout/MuscleGroupChip.tsx
7269
+ var dotTone = {
7270
+ untrained: "neutral",
7271
+ behind: "brand-secondary",
7272
+ ontrack: "success",
7273
+ target: "brand",
7274
+ over: "error"
7208
7275
  };
7209
7276
  function MuscleGroupChip({
7210
7277
  name,
@@ -7213,83 +7280,31 @@ function MuscleGroupChip({
7213
7280
  className,
7214
7281
  ...props
7215
7282
  }) {
7216
- const dotColor = volumeStatus ? dotColorMap[volumeStatus] : greyRamp[900];
7217
7283
  const statusLabel = volumeStatus ?? "no status";
7218
- const content = /* @__PURE__ */ jsxs(
7219
- reactNative.View,
7284
+ return /* @__PURE__ */ jsx(
7285
+ Pill,
7220
7286
  {
7221
- className: ["bg-surface-raised border-hairline", className].filter(Boolean).join(" "),
7222
- style: {
7223
- flexDirection: "row",
7224
- alignItems: "center",
7225
- borderRadius: 9999,
7226
- paddingHorizontal: 9,
7227
- paddingVertical: 3,
7228
- borderWidth: 1
7229
- },
7230
- accessibilityLabel: onPress ? void 0 : `${name}, volume status: ${statusLabel}`,
7231
- testID: "muscle-group-chip",
7287
+ tone: "neutral",
7288
+ dotTone: volumeStatus ? dotTone[volumeStatus] : "neutral",
7289
+ variant: "subtle",
7290
+ size: "md",
7291
+ leading: "dot",
7292
+ onPress,
7293
+ className: ["gap-1.5", className].filter(Boolean).join(" "),
7294
+ textClassName: "font-sans font-medium text-text-secondary",
7295
+ accessibilityLabel: `${name}, volume status: ${statusLabel}`,
7296
+ testID: onPress ? "muscle-group-chip-pressable" : "muscle-group-chip",
7232
7297
  ...props,
7233
- children: [
7234
- /* @__PURE__ */ jsx(
7235
- reactNative.View,
7236
- {
7237
- style: {
7238
- width: 6,
7239
- height: 6,
7240
- borderRadius: 9999,
7241
- marginRight: 5,
7242
- flexShrink: 0,
7243
- backgroundColor: dotColor
7244
- },
7245
- accessibilityElementsHidden: true,
7246
- testID: "muscle-group-chip-dot"
7247
- }
7248
- ),
7249
- /* @__PURE__ */ jsx(
7250
- reactNative.Text,
7251
- {
7252
- className: "text-text-secondary",
7253
- style: {
7254
- fontFamily: "Inter, sans-serif",
7255
- fontWeight: "500",
7256
- fontSize: 11
7257
- },
7258
- accessibilityElementsHidden: true,
7259
- children: name
7260
- }
7261
- )
7262
- ]
7298
+ children: name
7263
7299
  }
7264
7300
  );
7265
- if (onPress) {
7266
- return /* @__PURE__ */ jsx(
7267
- reactNative.Pressable,
7268
- {
7269
- onPress,
7270
- accessibilityRole: "button",
7271
- accessibilityLabel: `${name}, volume status: ${statusLabel}`,
7272
- testID: "muscle-group-chip-pressable",
7273
- children: content
7274
- }
7275
- );
7276
- }
7277
- return content;
7278
7301
  }
7279
7302
 
7280
7303
  // src/components/custom/Workout/WorkoutCard.tsx
7281
- var HAIRLINE_DEFAULT3 = getSemanticColors("dark")["hairline-default"];
7282
- var t11 = getSemanticColors("dark");
7283
- var COLORS = {
7284
- statusSuccess: t11["status-success"],
7285
- brandPrimary: t11["brand-primary"],
7286
- borderDefault: HAIRLINE_DEFAULT3,
7287
- brandPrimarySubtle: "rgba(255,121,0,0.06)"
7288
- };
7289
- var statusBorderColors = {
7290
- completed: COLORS.statusSuccess,
7291
- today: COLORS.brandPrimary,
7292
- upcoming: COLORS.borderDefault
7304
+ var statusAccentToken = {
7305
+ completed: "status-success",
7306
+ today: "brand-primary",
7307
+ upcoming: "hairline-default"
7293
7308
  };
7294
7309
  var volumeStatusMap = {
7295
7310
  under: "behind",
@@ -7324,41 +7339,33 @@ function WorkoutCard({
7324
7339
  const summary = /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 14 }, testID: "workout-card-body", children: [
7325
7340
  /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", testID: "workout-card-header", children: [
7326
7341
  /* @__PURE__ */ jsx(
7327
- reactNative.Text,
7342
+ Typography,
7328
7343
  {
7329
- className: "text-text-primary",
7330
- style: {
7331
- fontSize: 15,
7332
- fontFamily: '"Space Grotesk", sans-serif',
7333
- fontWeight: "700"
7334
- },
7344
+ variant: "h6",
7345
+ color: "primary",
7346
+ className: "text-base font-bold leading-[normal]",
7335
7347
  testID: "workout-card-name",
7336
7348
  children: name
7337
7349
  }
7338
7350
  ),
7339
7351
  /* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
7340
7352
  /* @__PURE__ */ jsx(
7341
- reactNative.Text,
7353
+ Typography,
7342
7354
  {
7343
- className: "text-text-tertiary",
7344
- style: {
7345
- fontSize: 11,
7346
- fontFamily: "Inter, sans-serif"
7347
- },
7355
+ variant: "caption",
7356
+ color: "tertiary",
7357
+ className: "text-2xs leading-[normal]",
7348
7358
  testID: "workout-card-date",
7349
7359
  children: date
7350
7360
  }
7351
7361
  )
7352
7362
  ] }),
7353
7363
  /* @__PURE__ */ jsx(
7354
- reactNative.Text,
7364
+ Typography,
7355
7365
  {
7356
- className: "text-text-secondary",
7357
- style: {
7358
- marginTop: 4,
7359
- fontSize: 12,
7360
- fontFamily: "Inter, sans-serif"
7361
- },
7366
+ variant: "caption",
7367
+ color: "secondary",
7368
+ className: "mt-1 leading-[normal]",
7362
7369
  testID: "workout-card-stats",
7363
7370
  children: formatStats(totalSets, totalVolume, unit, duration)
7364
7371
  }
@@ -7387,8 +7394,8 @@ function WorkoutCard({
7387
7394
  {
7388
7395
  variant: "accent",
7389
7396
  elevation: 1,
7390
- accentColor: statusBorderColors[status],
7391
- bgColor: isToday ? COLORS.brandPrimarySubtle : void 0,
7397
+ accentColor: resolveColor(statusAccentToken[status]),
7398
+ bgColor: isToday ? resolveColor("brand-primary-subtle") : void 0,
7392
7399
  className,
7393
7400
  style: isUpcoming ? { opacity: 0.6 } : void 0,
7394
7401
  testID: "workout-card",
@@ -7426,7 +7433,7 @@ function WorkoutCard({
7426
7433
  }
7427
7434
 
7428
7435
  // src/components/custom/Workout/ProgramPlanningPage.tsx
7429
- var BRAND_PRIMARY11 = getSemanticColors("dark")["brand-primary"];
7436
+ var BRAND_PRIMARY8 = getSemanticColors("dark")["brand-primary"];
7430
7437
  var WORKOUT_PILL_STATUS = {
7431
7438
  completed: "completed",
7432
7439
  today: "current",
@@ -7494,7 +7501,7 @@ function Breadcrumbs({ crumbs, onNavigate }) {
7494
7501
  fontSize: 12,
7495
7502
  fontFamily: "Inter, sans-serif",
7496
7503
  fontWeight: isLast ? "700" : "500",
7497
- color: isLast ? void 0 : BRAND_PRIMARY11
7504
+ color: isLast ? void 0 : BRAND_PRIMARY8
7498
7505
  },
7499
7506
  children: crumb.label
7500
7507
  }