@titan-design/react-ui 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/README.md +46 -47
  2. package/dist/bodymap.js +768 -701
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +770 -703
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1319 -216
  7. package/dist/index.d.ts +1319 -216
  8. package/dist/index.js +5996 -4498
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +5773 -4357
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
  13. package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1435 -1428
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1443 -1436
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +195 -134
  21. package/dist/theme/index.d.ts +195 -134
  22. package/dist/theme/index.js +215 -300
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +202 -296
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +62 -5
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +62 -5
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +73 -5
  31. package/dist/theme/tokens.d.ts +73 -5
  32. package/dist/theme/tokens.js +55 -7
  33. package/dist/theme/tokens.js.map +1 -1
  34. package/dist/theme/tokens.mjs +55 -8
  35. package/dist/theme/tokens.mjs.map +1 -1
  36. package/docs/audits/2026-09-08-critique-addenda.md +51 -0
  37. package/docs/audits/2026-09-08-library-critique.md +212 -0
  38. package/docs/library-roadmap.md +99 -0
  39. package/package.json +1 -1
  40. package/src/arch/arch-graph.freshness.test.ts +52 -0
  41. package/src/arch/arch-graph.json +5021 -1617
  42. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  43. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  44. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  45. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  46. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  48. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  49. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  51. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  52. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  54. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  55. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  57. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  58. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  60. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  61. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
  63. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  64. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  66. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  67. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  69. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  70. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  71. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  73. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  74. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  76. package/src/components/custom/ActiveWork/README.md +305 -0
  77. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  78. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  80. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  81. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  82. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  83. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  84. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  86. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  87. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  88. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  90. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  91. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  92. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  93. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  94. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  95. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  96. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  97. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  98. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  99. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  100. package/src/components/custom/ActiveWork/index.ts +19 -0
  101. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  102. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  103. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  104. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  105. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
  106. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  107. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  108. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  109. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  110. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  111. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  112. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  113. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  116. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  117. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  119. package/src/components/custom/Fatigue/README.md +40 -3
  120. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  121. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  122. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  123. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  124. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  125. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  126. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  127. package/src/components/custom/Fatigue/index.ts +17 -5
  128. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  129. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  130. package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
  131. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  132. package/src/components/custom/Gauge/Gauge.tsx +4 -1
  133. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  134. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  135. package/src/components/custom/Metric/Metric.tsx +5 -20
  136. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  137. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  138. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  139. package/src/components/custom/Prose/README.md +58 -0
  140. package/src/components/custom/Prose/index.ts +1 -0
  141. package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
  142. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  143. package/src/components/custom/Scatter/Scatter.tsx +116 -14
  144. package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
  145. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  146. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  147. package/src/components/custom/Table/Table.stories.tsx +98 -15
  148. package/src/components/custom/Table/Table.test.tsx +273 -86
  149. package/src/components/custom/Table/Table.tsx +159 -67
  150. package/src/components/custom/Table/column-fit.test.ts +75 -0
  151. package/src/components/custom/Table/column-fit.ts +116 -0
  152. package/src/components/custom/Table/index.ts +9 -0
  153. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  154. package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
  155. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  156. package/src/components/custom/Treemap/Treemap.tsx +7 -2
  157. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  158. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  159. package/src/components/custom/Typography/Typography.tsx +6 -0
  160. package/src/components/custom/Typography/index.ts +1 -8
  161. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
  162. package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
  163. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  164. package/src/components/custom/Workout/BaseBadge.tsx +3 -0
  165. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  166. package/src/components/custom/Workout/BodyMap.tsx +3 -1
  167. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
  168. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  169. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
  170. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
  171. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  172. package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
  173. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  174. package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
  175. package/src/components/custom/Workout/DeviationBar.tsx +21 -16
  176. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
  177. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
  178. package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
  179. package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
  180. package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
  181. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
  182. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  183. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  184. package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
  185. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
  186. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  187. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  188. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  189. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  190. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  191. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  192. package/src/components/custom/Workout/IntensityBar.tsx +4 -2
  193. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  194. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  195. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  196. package/src/components/custom/Workout/MesoCard.tsx +12 -9
  197. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  198. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  199. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  200. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  201. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  202. package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
  203. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  204. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  205. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  206. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  207. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
  208. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  209. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  210. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  211. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  212. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  213. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
  214. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  215. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  216. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  217. package/src/components/custom/Workout/README.md +11 -6
  218. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  219. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  220. package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
  221. package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
  222. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  223. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  224. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  225. package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
  226. package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
  227. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  228. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  229. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  230. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  231. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  232. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  233. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  234. package/src/components/custom/Workout/SetBar.tsx +38 -12
  235. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  236. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  237. package/src/components/custom/Workout/SetRow.tsx +61 -23
  238. package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
  239. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  240. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  241. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  242. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  243. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  244. package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
  245. package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
  246. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  247. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  248. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  249. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  250. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  251. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  252. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  253. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  254. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
  255. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  256. package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
  257. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  258. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  259. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  260. package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
  261. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  262. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  263. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  264. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
  265. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
  266. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
  267. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  268. package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
  269. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  270. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  271. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  272. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  273. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  274. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  275. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  276. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  277. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  278. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  279. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  280. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  281. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  282. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  283. package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
  284. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  285. package/src/components/custom/Workout/index.ts +5 -0
  286. package/src/components/custom/Workout/metricText.stories.tsx +6 -5
  287. package/src/components/custom/Workout/metricText.tsx +4 -0
  288. package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
  289. package/src/components/custom/charts/README.md +61 -0
  290. package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
  291. package/src/components/custom/charts/SetBarChart.tsx +42 -4
  292. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  293. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  294. package/src/components/custom/charts/SparkBars.tsx +85 -0
  295. package/src/components/custom/charts/index.ts +3 -0
  296. package/src/components/custom/index.ts +3 -0
  297. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  298. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  299. package/src/components/custom/stepper/Stepper.tsx +13 -28
  300. package/src/components/icons/icons.stories.tsx +1 -1
  301. package/src/components/icons/icons.tsx +51 -0
  302. package/src/components/shell/AppShell.stories.tsx +150 -0
  303. package/src/components/shell/AppShell.test.tsx +70 -0
  304. package/src/components/shell/AppShell.tsx +90 -0
  305. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  306. package/src/components/shell/BrandLockup.test.tsx +34 -1
  307. package/src/components/shell/BrandLockup.tsx +27 -11
  308. package/src/components/shell/NavItem.stories.tsx +4 -4
  309. package/src/components/shell/NavItem.test.tsx +17 -0
  310. package/src/components/shell/NavItem.tsx +17 -5
  311. package/src/components/shell/README.md +89 -26
  312. package/src/components/shell/SideNav.stories.tsx +38 -7
  313. package/src/components/shell/SideNav.test.tsx +16 -8
  314. package/src/components/shell/SideNav.tsx +17 -17
  315. package/src/components/shell/TopBar.stories.tsx +44 -19
  316. package/src/components/shell/TopBar.test.tsx +34 -12
  317. package/src/components/shell/TopBar.tsx +61 -40
  318. package/src/components/shell/brands.tsx +66 -0
  319. package/src/components/shell/index.ts +9 -8
  320. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  321. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  322. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  323. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  324. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  325. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  326. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  327. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  328. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  329. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  330. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  331. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  332. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  333. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  334. package/src/components/shell/workout/index.ts +9 -0
  335. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  336. package/src/components/ui/README.md +110 -0
  337. package/src/components/ui/alert/Alert.stories.tsx +1 -1
  338. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  339. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  340. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  341. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  342. package/src/components/ui/avatar/Avatar.tsx +2 -10
  343. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  344. package/src/components/ui/badge/Badge.test.tsx +19 -3
  345. package/src/components/ui/badge/Badge.tsx +48 -55
  346. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  347. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  348. package/src/components/ui/button/Button.stories.tsx +46 -12
  349. package/src/components/ui/button/Button.tsx +32 -25
  350. package/src/components/ui/card/Card.stories.tsx +90 -94
  351. package/src/components/ui/card/Card.test.tsx +80 -6
  352. package/src/components/ui/card/Card.tsx +150 -203
  353. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  354. package/src/components/ui/checkbox/Checkbox.tsx +6 -26
  355. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  356. package/src/components/ui/chip/Chip.test.tsx +10 -6
  357. package/src/components/ui/chip/Chip.tsx +76 -91
  358. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  359. package/src/components/ui/collapse/Collapse.tsx +6 -11
  360. package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
  361. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  362. package/src/components/ui/data-row/DataRow.tsx +18 -7
  363. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  364. package/src/components/ui/divider/Divider.tsx +1 -5
  365. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  366. package/src/components/ui/drawer/Drawer.tsx +13 -30
  367. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  368. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  369. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  370. package/src/components/ui/form-field/FormField.tsx +10 -46
  371. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  372. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  373. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  374. package/src/components/ui/help-tip/index.ts +7 -1
  375. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  376. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  377. package/src/components/ui/icon-box/IconBox.tsx +2 -12
  378. package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
  379. package/src/components/ui/indicator/Indicator.tsx +20 -14
  380. package/src/components/ui/input/Input.stories.tsx +3 -11
  381. package/src/components/ui/input/Input.test.tsx +2 -10
  382. package/src/components/ui/input/Input.tsx +10 -25
  383. package/src/components/ui/input/index.ts +7 -1
  384. package/src/components/ui/link/Link.stories.tsx +19 -7
  385. package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
  386. package/src/components/ui/list-item/ListItem.tsx +2 -9
  387. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  388. package/src/components/ui/menu/Menu.test.tsx +2 -11
  389. package/src/components/ui/menu/Menu.tsx +12 -14
  390. package/src/components/ui/menu/index.ts +8 -1
  391. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  392. package/src/components/ui/modal/Modal.tsx +29 -19
  393. package/src/components/ui/pill/Pill.stories.tsx +58 -23
  394. package/src/components/ui/pill/Pill.test.tsx +101 -3
  395. package/src/components/ui/pill/Pill.tsx +164 -49
  396. package/src/components/ui/pill/index.ts +1 -1
  397. package/src/components/ui/popover/Popover.stories.tsx +5 -7
  398. package/src/components/ui/popover/Popover.test.tsx +1 -6
  399. package/src/components/ui/popover/Popover.tsx +20 -15
  400. package/src/components/ui/popover/index.ts +7 -1
  401. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  402. package/src/components/ui/progress/Progress.test.tsx +1 -5
  403. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  404. package/src/components/ui/radio/Radio.test.tsx +6 -2
  405. package/src/components/ui/radio/Radio.tsx +23 -22
  406. package/src/components/ui/section/Section.stories.tsx +5 -14
  407. package/src/components/ui/section/Section.test.tsx +1 -6
  408. package/src/components/ui/section/Section.tsx +1 -3
  409. package/src/components/ui/section/index.ts +1 -5
  410. package/src/components/ui/select/Select.stories.tsx +3 -13
  411. package/src/components/ui/select/Select.test.tsx +2 -11
  412. package/src/components/ui/select/Select.tsx +14 -14
  413. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  414. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  415. package/src/components/ui/skeleton/index.ts +1 -7
  416. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  417. package/src/components/ui/spinner/Spinner.tsx +1 -4
  418. package/src/components/ui/stack/Stack.stories.tsx +1 -1
  419. package/src/components/ui/stack/Stack.tsx +1 -1
  420. package/src/components/ui/surface/Surface.stories.tsx +17 -5
  421. package/src/components/ui/surface/Surface.test.tsx +88 -28
  422. package/src/components/ui/surface/Surface.tsx +37 -87
  423. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  424. package/src/components/ui/surface/index.ts +8 -0
  425. package/src/components/ui/surface/resolveSurface.ts +98 -0
  426. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  427. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  428. package/src/components/ui/switch/Switch.tsx +7 -6
  429. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  430. package/src/components/ui/tabs/Tabs.tsx +7 -22
  431. package/src/components/ui/tabs/index.ts +1 -7
  432. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  433. package/src/components/ui/tile/Tile.tsx +3 -0
  434. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  435. package/src/components/ui/toast/Toast.test.tsx +2 -8
  436. package/src/components/ui/toast/Toast.tsx +43 -53
  437. package/src/components/ui/toast/index.ts +0 -1
  438. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  439. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  440. package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
  441. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  442. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  443. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  444. package/src/components/ui/tooltip/index.ts +1 -1
  445. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  446. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  447. package/src/components/ui/trigger/index.ts +2 -0
  448. package/src/stories/PresetShowcase.stories.tsx +100 -47
  449. package/src/test/no-device-internals.test.ts +3 -3
  450. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  451. package/src/theme/ColorPalettes.stories.tsx +62 -45
  452. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  453. package/src/theme/Depth.stories.tsx +132 -65
  454. package/src/theme/DepthCalibration.stories.tsx +23 -21
  455. package/src/theme/ThemeProvider.test.tsx +4 -4
  456. package/src/theme/barrel.ts +7 -6
  457. package/src/theme/color-stories.coverage.test.ts +1 -1
  458. package/src/theme/color-utils.ts +41 -29
  459. package/src/theme/config.completeness.test.ts +1 -1
  460. package/src/theme/config.ts +28 -0
  461. package/src/theme/elevation.test.ts +82 -56
  462. package/src/theme/elevation.ts +77 -561
  463. package/src/theme/global.css +30 -2
  464. package/src/theme/grey-ramp.test.ts +24 -8
  465. package/src/theme/lift.test.ts +39 -0
  466. package/src/theme/lift.ts +102 -0
  467. package/src/theme/materials.test.ts +5 -2
  468. package/src/theme/materials.ts +38 -4
  469. package/src/theme/native-theming-guard.test.ts +5 -5
  470. package/src/theme/presets/apply.ts +4 -0
  471. package/src/theme/presets/audiobook.ts +5 -2
  472. package/src/theme/presets/default.ts +4 -0
  473. package/src/theme/presets/index.ts +14 -1
  474. package/src/theme/presets/types.ts +1 -1
  475. package/src/theme/semantic-contrast.test.ts +13 -4
  476. package/src/theme/status-distinctness.test.ts +66 -0
  477. package/src/theme/surface-planes.test.ts +37 -0
  478. package/src/theme/surface-planes.ts +68 -0
  479. package/src/theme/token-export-guard.test.ts +1 -3
  480. package/src/theme/tokens/primitives.test.ts +15 -7
  481. package/src/theme/tokens/primitives.ts +65 -33
  482. package/src/theme/tokens/semantic.ts +71 -37
  483. package/src/theme/wash-ladder.test.ts +58 -0
  484. package/src/theme/workout-tokens.ts +1 -7
  485. package/src/types/jest-axe.d.ts +2 -6
  486. package/src/types/raw-md.d.ts +5 -0
  487. package/src/utils/colors.ts +4 -4
  488. package/src/utils/form.ts +1 -3
  489. package/src/utils/index.ts +2 -7
  490. package/src/utils/number-format.ts +17 -0
  491. package/src/utils/workout-format.ts +15 -6
  492. package/src/web-jsx/jsx-runtime.ts +1 -5
  493. package/tailwind.config.js +5 -0
  494. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  495. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  496. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  497. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  498. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  499. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  500. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  501. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  502. package/src/components/shell/DashboardShell.tsx +0 -75
  503. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  504. package/src/theme/elevation.stories.tsx +0 -346
  505. package/src/utils/useTheme.ts +0 -72
  506. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  507. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  508. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  509. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
package/dist/bodymap.js CHANGED
@@ -19,6 +19,7 @@ function cn(...inputs) {
19
19
  // src/theme/tokens/primitives.ts
20
20
  var primitiveColors = {
21
21
  white: "#FFFFFF"};
22
+ var alertRedVivid = "#FF4757";
22
23
  var greyRamp = {
23
24
  50: "#F9F6F3",
24
25
  // L*97.0 W6
@@ -141,12 +142,16 @@ var semanticColorsLight = {
141
142
  "brand-primary-light": primitiveRamps.orange[300],
142
143
  "brand-primary-dark": primitiveRamps.orange[500],
143
144
  "brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
145
+ "brand-primary-muted": "rgba(255, 121, 0, 0.30)",
146
+ "brand-primary-strong": "rgba(255, 121, 0, 0.50)",
144
147
  "brand-primary-hover": primitiveRamps.orange[500],
145
148
  "brand-primary-active": primitiveRamps.orange[600],
146
149
  "brand-secondary": primitiveRamps.cyan[600],
147
150
  "brand-secondary-light": primitiveRamps.cyan[500],
148
151
  "brand-secondary-dark": primitiveRamps.cyan[700],
149
152
  "brand-secondary-subtle": "rgba(48, 123, 155, 0.08)",
153
+ "brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
154
+ "brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
150
155
  "brand-secondary-hover": primitiveRamps.cyan[700],
151
156
  "brand-secondary-active": primitiveRamps.cyan[800],
152
157
  // Text on brand backgrounds (on-*)
@@ -157,6 +162,8 @@ var semanticColorsLight = {
157
162
  "status-success-light": primitiveRamps.green[200],
158
163
  "status-success-dark": primitiveRamps.green[600],
159
164
  "status-success-subtle": primitiveRamps.green[50],
165
+ "status-success-muted": "rgba(46, 213, 115, 0.30)",
166
+ "status-success-strong": "rgba(46, 213, 115, 0.50)",
160
167
  // Live-session accent — its OWN role, decoupled from success so the two can diverge
161
168
  "status-live": primitiveRamps.green[300],
162
169
  "status-live-muted": primitiveRamps.green[500],
@@ -164,19 +171,27 @@ var semanticColorsLight = {
164
171
  "status-error-light": primitiveRamps.red[500],
165
172
  "status-error-dark": primitiveRamps.red[700],
166
173
  "status-error-subtle": primitiveRamps.red[50],
167
- "status-error-vivid": primitiveRamps.red[600],
168
- // vivid alert red
174
+ "status-error-muted": "rgba(209, 67, 67, 0.30)",
175
+ "status-error-strong": "rgba(209, 67, 67, 0.50)",
176
+ "status-error-vivid": alertRedVivid,
177
+ // NOT red[600], that is status-error
169
178
  "status-error-vivid-light": primitiveRamps.red[500],
170
179
  "status-error-vivid-dark": primitiveRamps.red[700],
171
180
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
181
+ "status-error-vivid-muted": "rgba(255, 71, 87, 0.30)",
182
+ "status-error-vivid-strong": "rgba(255, 71, 87, 0.50)",
172
183
  "status-warning": primitiveRamps.amber[300],
173
184
  "status-warning-light": primitiveRamps.amber[200],
174
185
  "status-warning-dark": primitiveRamps.amber[500],
175
186
  "status-warning-subtle": primitiveRamps.amber[50],
187
+ "status-warning-muted": "rgba(249, 180, 21, 0.30)",
188
+ "status-warning-strong": "rgba(249, 180, 21, 0.50)",
176
189
  "status-info": primitiveRamps.blue[500],
177
190
  "status-info-light": primitiveRamps.blue[300],
178
191
  "status-info-dark": primitiveRamps.blue[600],
179
192
  "status-info-subtle": primitiveRamps.blue[50],
193
+ "status-info-muted": "rgba(33, 150, 243, 0.30)",
194
+ "status-info-strong": "rgba(33, 150, 243, 0.50)",
180
195
  // Text on status backgrounds (on-status-*)
181
196
  "on-status-success": primitiveColors.white,
182
197
  "on-status-error": primitiveColors.white,
@@ -271,7 +286,7 @@ var semanticColorsLight = {
271
286
  "interactive-disabled": "rgba(55, 65, 81, 0.12)",
272
287
  "interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
273
288
  // Divider
274
- "divider": "#E8E9EB",
289
+ divider: "#E8E9EB",
275
290
  // Avatar default
276
291
  "avatar-background": greyRamp[600],
277
292
  "avatar-text": primitiveColors.white
@@ -282,12 +297,16 @@ var semanticColorsDark = {
282
297
  "brand-primary-light": primitiveRamps.orange[300],
283
298
  "brand-primary-dark": primitiveRamps.orange[500],
284
299
  "brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
300
+ "brand-primary-muted": "rgba(255, 121, 0, 0.30)",
301
+ "brand-primary-strong": "rgba(255, 121, 0, 0.50)",
285
302
  "brand-primary-hover": primitiveRamps.orange[300],
286
303
  "brand-primary-active": primitiveRamps.orange[200],
287
304
  "brand-secondary": primitiveRamps.cyan[600],
288
305
  "brand-secondary-light": primitiveRamps.cyan[500],
289
306
  "brand-secondary-dark": primitiveRamps.cyan[700],
290
307
  "brand-secondary-subtle": "rgba(48, 123, 155, 0.12)",
308
+ "brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
309
+ "brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
291
310
  "brand-secondary-hover": primitiveRamps.cyan[500],
292
311
  "brand-secondary-active": primitiveRamps.cyan[400],
293
312
  // Text on brand backgrounds
@@ -298,6 +317,8 @@ var semanticColorsDark = {
298
317
  "status-success-light": primitiveRamps.green[200],
299
318
  "status-success-dark": primitiveRamps.green[600],
300
319
  "status-success-subtle": "rgba(46, 213, 115, 0.12)",
320
+ "status-success-muted": "rgba(46, 213, 115, 0.30)",
321
+ "status-success-strong": "rgba(46, 213, 115, 0.50)",
301
322
  // Live-session accent — its OWN role, decoupled from success so the two can diverge
302
323
  "status-live": primitiveRamps.green[300],
303
324
  "status-live-muted": primitiveRamps.green[500],
@@ -305,18 +326,26 @@ var semanticColorsDark = {
305
326
  "status-error-light": primitiveRamps.red[500],
306
327
  "status-error-dark": primitiveRamps.red[700],
307
328
  "status-error-subtle": "rgba(209, 67, 67, 0.12)",
308
- "status-error-vivid": primitiveRamps.red[600],
329
+ "status-error-muted": "rgba(209, 67, 67, 0.30)",
330
+ "status-error-strong": "rgba(209, 67, 67, 0.50)",
331
+ "status-error-vivid": alertRedVivid,
309
332
  "status-error-vivid-light": primitiveRamps.red[500],
310
333
  "status-error-vivid-dark": primitiveRamps.red[700],
311
334
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
335
+ "status-error-vivid-muted": "rgba(255, 71, 87, 0.30)",
336
+ "status-error-vivid-strong": "rgba(255, 71, 87, 0.50)",
312
337
  "status-warning": primitiveRamps.amber[300],
313
338
  "status-warning-light": primitiveRamps.amber[200],
314
339
  "status-warning-dark": primitiveRamps.amber[500],
315
340
  "status-warning-subtle": "rgba(249, 180, 21, 0.12)",
341
+ "status-warning-muted": "rgba(249, 180, 21, 0.30)",
342
+ "status-warning-strong": "rgba(249, 180, 21, 0.50)",
316
343
  "status-info": primitiveRamps.blue[500],
317
344
  "status-info-light": primitiveRamps.blue[300],
318
345
  "status-info-dark": primitiveRamps.blue[600],
319
346
  "status-info-subtle": "rgba(33, 150, 243, 0.12)",
347
+ "status-info-muted": "rgba(33, 150, 243, 0.30)",
348
+ "status-info-strong": "rgba(33, 150, 243, 0.50)",
320
349
  // Text on status backgrounds
321
350
  "on-status-success": primitiveColors.white,
322
351
  "on-status-error": primitiveColors.white,
@@ -456,7 +485,7 @@ var semanticColorsDark = {
456
485
  "interactive-disabled": "rgba(255, 255, 255, 0.12)",
457
486
  "interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
458
487
  // Divider
459
- "divider": "rgba(255, 255, 255, 0.09)",
488
+ divider: "rgba(255, 255, 255, 0.09)",
460
489
  // Avatar default
461
490
  "avatar-background": greyRamp[700],
462
491
  "avatar-text": primitiveColors.white
@@ -470,6 +499,150 @@ function resolveColor(token, mode = "dark") {
470
499
  return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
471
500
  }
472
501
 
502
+ // src/theme/color-utils.ts
503
+ function hexToRgb(hex) {
504
+ const cleaned = hex.replace("#", "");
505
+ let r, g, b;
506
+ if (cleaned.length === 3) {
507
+ r = parseInt(cleaned[0] + cleaned[0], 16);
508
+ g = parseInt(cleaned[1] + cleaned[1], 16);
509
+ b = parseInt(cleaned[2] + cleaned[2], 16);
510
+ } else if (cleaned.length === 6) {
511
+ r = parseInt(cleaned.slice(0, 2), 16);
512
+ g = parseInt(cleaned.slice(2, 4), 16);
513
+ b = parseInt(cleaned.slice(4, 6), 16);
514
+ } else {
515
+ return null;
516
+ }
517
+ return { r, g, b };
518
+ }
519
+
520
+ // src/theme/materials.ts
521
+ var c = getSemanticColors("dark");
522
+ function insetWell(tone = c["surface-input"]) {
523
+ return {
524
+ backgroundColor: tone,
525
+ boxShadow: "inset 0 2px 6px rgba(0,0,0,0.55), inset 0 -1px 0 rgba(255,255,255,0.12)"
526
+ };
527
+ }
528
+ var FLOATING_LIFT_MIN = 4;
529
+ var LIFT_RIM_ALPHA = { dark: 0.12, light: 0.9 };
530
+ var AMBIENT = {
531
+ 1: [
532
+ { y: 1, blur: 2, alpha: 0.35 },
533
+ { y: 2, blur: 6, alpha: 0.3 }
534
+ ],
535
+ 2: [
536
+ { y: 1, blur: 2, alpha: 0.35 },
537
+ { y: 4, blur: 12, alpha: 0.32 }
538
+ ],
539
+ 3: [
540
+ { y: 2, blur: 4, alpha: 0.35 },
541
+ { y: 8, blur: 22, alpha: 0.35 }
542
+ ],
543
+ 4: [
544
+ { y: 1, blur: 2, alpha: 0.35 },
545
+ { y: 10, blur: 24, alpha: 0.3 },
546
+ { y: 24, blur: 48, alpha: 0.2 }
547
+ ],
548
+ 5: [
549
+ { y: 2, blur: 4, alpha: 0.4 },
550
+ { y: 16, blur: 32, alpha: 0.35 },
551
+ { y: 32, blur: 64, alpha: 0.25 }
552
+ ]
553
+ };
554
+ var AMBIENT_ALPHA_SCALE = { dark: 1, light: 0.4 };
555
+ function ambientLayers(step, mode) {
556
+ const scale = AMBIENT_ALPHA_SCALE[mode];
557
+ return AMBIENT[step].map(
558
+ ({ y, blur, alpha: alpha2 }) => `0 ${y}px ${blur}px rgba(0,0,0,${(alpha2 * scale).toFixed(2)})`
559
+ );
560
+ }
561
+ function liftShadow(step, mode = "dark", opts = {}) {
562
+ const rim = opts.rim ?? LIFT_RIM_ALPHA[mode];
563
+ const layers = ambientLayers(step, mode);
564
+ if (rim > 0) layers.unshift(`inset 0 1px 0 rgba(255,255,255,${rim.toFixed(2)})`);
565
+ return layers.join(", ");
566
+ }
567
+ function liftStyle(step, mode = "dark", opts = {}) {
568
+ const deepest = AMBIENT[step][AMBIENT[step].length - 1];
569
+ return reactNative.Platform.select({
570
+ web: { boxShadow: liftShadow(step, mode, opts) },
571
+ default: {
572
+ shadowColor: "#000",
573
+ shadowOffset: { width: 0, height: Math.round(deepest.y / 2) },
574
+ shadowOpacity: deepest.alpha * AMBIENT_ALPHA_SCALE[mode],
575
+ shadowRadius: deepest.blur / 2,
576
+ elevation: step
577
+ }
578
+ });
579
+ }
580
+
581
+ // src/theme/surface-planes.ts
582
+ var SURFACE_LEVEL_TOKEN = {
583
+ frame: "background-frame",
584
+ background: "background-base",
585
+ base: "surface-base",
586
+ elevated: "surface-elevated",
587
+ raised: "surface-raised",
588
+ overlay: "surface-overlay"
589
+ };
590
+ var PLANE_ORDER = [
591
+ "frame",
592
+ "background",
593
+ "base",
594
+ "elevated",
595
+ "raised",
596
+ "overlay"
597
+ ];
598
+ function surfaceBackground(level, mode) {
599
+ return getSemanticColors(mode)[SURFACE_LEVEL_TOKEN[level]];
600
+ }
601
+ function stepPlane(from, delta) {
602
+ const index = PLANE_ORDER.indexOf(from);
603
+ const clamped = Math.min(PLANE_ORDER.length - 1, Math.max(0, index + delta));
604
+ return PLANE_ORDER[clamped];
605
+ }
606
+ function pressedLevel(parent) {
607
+ return stepPlane(parent, -1);
608
+ }
609
+ function raisedLevel(parent, steps) {
610
+ return stepPlane(parent, Math.max(0, steps));
611
+ }
612
+
613
+ // src/theme/elevation.ts
614
+ var FLOATING_ELEVATION_MIN = FLOATING_LIFT_MIN;
615
+ function getPressedRecessShadow(fillColor, _mode = "dark") {
616
+ const { boxShadow } = insetWell(fillColor);
617
+ return reactNative.Platform.select({
618
+ web: { boxShadow },
619
+ default: {}
620
+ });
621
+ }
622
+ var glowConfig = {
623
+ tight: { blur: 4, spread: 0, opacity: 0.4 },
624
+ subtle: { blur: 12, spread: 0, opacity: 0.25 },
625
+ medium: { blur: 20, spread: 2, opacity: 0.4 },
626
+ strong: { blur: 30, spread: 4, opacity: 0.55 }
627
+ };
628
+ function getGlowShadow(color, intensity = "medium") {
629
+ const config = glowConfig[intensity];
630
+ const rgb = hexToRgb(color);
631
+ if (!rgb) return {};
632
+ return reactNative.Platform.select({
633
+ web: {
634
+ boxShadow: `0 0 ${config.blur}px ${config.spread}px rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${config.opacity})`
635
+ },
636
+ default: {
637
+ shadowColor: color,
638
+ shadowOffset: { width: 0, height: 0 },
639
+ shadowOpacity: config.opacity,
640
+ shadowRadius: config.blur / 2,
641
+ elevation: 0
642
+ }
643
+ });
644
+ }
645
+
473
646
  // src/theme/workout-tokens.ts
474
647
  var WORKOUT_TOKENS = {
475
648
  // BodyMap volume heatmap — the canonical `divergingScale` (under → optimal →
@@ -797,7 +970,8 @@ function BodyMap({
797
970
  alignSelf: "center",
798
971
  transform: [{ scale }]
799
972
  },
800
- glowColor ? { boxShadow: `0 0 14px 2px ${glowColor}` } : void 0
973
+ // The highlight halo is emphasis, not depth.
974
+ glowColor ? getGlowShadow(glowColor, "medium") : void 0
801
975
  ],
802
976
  "aria-hidden": true,
803
977
  accessibilityElementsHidden: true,
@@ -959,6 +1133,17 @@ var colorStyles = {
959
1133
  info: "bg-status-info",
960
1134
  "error-vivid": "bg-status-error-vivid"
961
1135
  };
1136
+ var t = getSemanticColors("dark");
1137
+ var glowColors = {
1138
+ default: greyRamp[500],
1139
+ primary: t["brand-primary"],
1140
+ success: t["status-success"],
1141
+ live: t["status-live"],
1142
+ error: t["status-error"],
1143
+ warning: t["status-warning"],
1144
+ info: t["status-info"],
1145
+ "error-vivid": t["status-error-vivid"]
1146
+ };
962
1147
  function Indicator({
963
1148
  size = "sm",
964
1149
  color = "default",
@@ -996,11 +1181,7 @@ function Indicator({
996
1181
  )
997
1182
  ] });
998
1183
  }
999
- const dynamicStyle = {
1000
- ...typeof style === "object" ? style : {},
1001
- ...colorStyle ?? {},
1002
- ...glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}
1003
- };
1184
+ const glowStyle = glow ? getGlowShadow(customColor ?? glowColors[color], "subtle") : null;
1004
1185
  return /* @__PURE__ */ jsx(
1005
1186
  reactNative.View,
1006
1187
  {
@@ -1010,54 +1191,165 @@ function Indicator({
1010
1191
  colorClass,
1011
1192
  pulseMode === "opacity" && "animate-pulse",
1012
1193
  ring && "border-2 border-background-base",
1013
- glow && !customColor && (color === "success" || color === "live") && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
1014
- glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
1015
- glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
1016
- glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
1017
- glow && !customColor && color === "error-vivid" && "shadow-[0_0_6px_rgba(255,71,87,0.6)]",
1018
1194
  className
1019
1195
  ),
1020
- style: Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style,
1196
+ style: [style, colorStyle, glowStyle],
1021
1197
  ...props
1022
1198
  }
1023
1199
  );
1024
1200
  }
1025
-
1026
- // src/components/ui/badge/Badge.tsx
1027
- var variantColorStyles = {
1201
+ var colorToTone = {
1202
+ default: "neutral",
1203
+ primary: "brand",
1204
+ secondary: "brand-secondary",
1205
+ success: "success",
1206
+ error: "error",
1207
+ warning: "warning",
1208
+ info: "info"
1209
+ };
1210
+ var toneStyles = {
1028
1211
  solid: {
1029
- default: "bg-hairline-strong text-text-inverse",
1030
- primary: "bg-brand-primary text-text-inverse",
1031
- secondary: "bg-brand-secondary text-text-inverse",
1032
- success: "bg-status-success text-text-inverse",
1033
- error: "bg-status-error text-text-inverse",
1034
- warning: "bg-status-warning text-text-inverse",
1035
- info: "bg-status-info text-text-inverse"
1212
+ neutral: "bg-hairline-strong border-transparent text-text-inverse",
1213
+ brand: "bg-brand-primary border-transparent text-text-inverse",
1214
+ "brand-secondary": "bg-brand-secondary border-transparent text-text-inverse",
1215
+ success: "bg-status-success border-transparent text-text-inverse",
1216
+ warning: "bg-status-warning border-transparent text-text-inverse",
1217
+ error: "bg-status-error border-transparent text-text-inverse",
1218
+ info: "bg-status-info border-transparent text-text-inverse"
1036
1219
  },
1037
1220
  subtle: {
1038
- default: "bg-surface-raised text-text-secondary",
1039
- primary: "bg-brand-primary-subtle text-brand-primary",
1040
- secondary: "bg-brand-secondary-subtle text-brand-secondary",
1041
- success: "bg-status-success-subtle text-status-success",
1042
- error: "bg-status-error-subtle text-status-error",
1043
- warning: "bg-status-warning-subtle text-status-warning",
1044
- info: "bg-status-info-subtle text-status-info"
1221
+ // Alpha-white rather than a ramp step: a pill sits on whatever plane its
1222
+ // host is, and an alpha fill composites by the same amount on all of them.
1223
+ // A `surface-*` fill would vanish on the plane it names. Borderless like the
1224
+ // six coloured tones — the fill carries the capsule, not a ring.
1225
+ neutral: "bg-hairline-subtle border-transparent text-text-secondary",
1226
+ brand: "bg-brand-primary-subtle border-transparent text-brand-primary",
1227
+ "brand-secondary": "bg-brand-secondary-subtle border-transparent text-brand-secondary",
1228
+ success: "bg-status-success-subtle border-transparent text-status-success",
1229
+ warning: "bg-status-warning-subtle border-transparent text-status-warning",
1230
+ error: "bg-status-error-subtle border-transparent text-status-error",
1231
+ info: "bg-status-info-subtle border-transparent text-status-info"
1045
1232
  },
1046
1233
  outline: {
1047
- default: "border border-hairline-strong text-text-secondary",
1048
- primary: "border border-brand-primary text-brand-primary",
1049
- secondary: "border border-brand-secondary text-brand-secondary",
1050
- success: "border border-status-success text-status-success",
1051
- error: "border border-status-error text-status-error",
1052
- warning: "border border-status-warning text-status-warning",
1053
- info: "border border-status-info text-status-info"
1234
+ neutral: "border-hairline text-text-secondary",
1235
+ brand: "border-brand-primary text-brand-primary",
1236
+ "brand-secondary": "border-brand-secondary text-brand-secondary",
1237
+ success: "border-status-success text-status-success",
1238
+ warning: "border-status-warning text-status-warning",
1239
+ error: "border-status-error text-status-error",
1240
+ info: "border-status-info text-status-info"
1054
1241
  }
1055
1242
  };
1243
+ var dotToneStyles = {
1244
+ neutral: "bg-text-tertiary",
1245
+ brand: "bg-brand-primary",
1246
+ "brand-secondary": "bg-brand-secondary",
1247
+ success: "bg-status-success",
1248
+ warning: "bg-status-warning",
1249
+ error: "bg-status-error",
1250
+ info: "bg-status-info"
1251
+ };
1056
1252
  var sizeStyles2 = {
1057
- sm: "px-1.5 py-0.5 text-xs",
1058
- md: "px-2 py-0.5 text-xs",
1059
- lg: "px-2.5 py-1 text-sm"
1253
+ xs: { container: "px-1 py-px", text: "text-3xs" },
1254
+ sm: { container: "px-2 py-0.5", text: "text-2xs" },
1255
+ md: { container: "px-2.5 py-1", text: "text-xs" },
1256
+ lg: { container: "px-3 py-1.5", text: "text-sm" },
1257
+ xl: { container: "px-4 py-2", text: "text-base" }
1258
+ };
1259
+ function PillDot({ tone, testID }) {
1260
+ return /* @__PURE__ */ jsx(
1261
+ reactNative.View,
1262
+ {
1263
+ className: cn("w-1.5 h-1.5 rounded-full shrink-0", dotToneStyles[tone]),
1264
+ accessibilityElementsHidden: true,
1265
+ testID: testID ? `${testID}-dot` : "pill-dot"
1266
+ }
1267
+ );
1268
+ }
1269
+ function containerClasses(p, tone) {
1270
+ return cn(
1271
+ "flex-row items-center gap-1 border self-start shrink-0",
1272
+ p.rounded === false ? "rounded" : "rounded-full",
1273
+ toneStyles[p.variant ?? "subtle"][tone],
1274
+ sizeStyles2[p.size ?? "sm"].container,
1275
+ p.isDisabled && "opacity-50",
1276
+ p.className
1277
+ );
1278
+ }
1279
+ function PillContent({ tone, ...p }) {
1280
+ const textClasses = cn(
1281
+ "font-heading font-semibold text-inherit",
1282
+ sizeStyles2[p.size ?? "sm"].text,
1283
+ p.textClassName
1284
+ );
1285
+ const slot = p.leading ?? p.leftElement;
1286
+ return /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
1287
+ slot === "dot" ? /* @__PURE__ */ jsx(PillDot, { tone: p.dotTone ?? tone, testID: p.testID }) : slot,
1288
+ typeof p.children === "string" ? /* @__PURE__ */ jsx(reactNative.Text, { className: textClasses, children: p.children }) : p.children,
1289
+ p.trailing
1290
+ ] });
1291
+ }
1292
+ function Pill(props) {
1293
+ const {
1294
+ variant,
1295
+ tone,
1296
+ color,
1297
+ size,
1298
+ rounded,
1299
+ leading,
1300
+ dotTone,
1301
+ leftElement,
1302
+ trailing,
1303
+ onPress,
1304
+ isDisabled,
1305
+ className,
1306
+ textClassName,
1307
+ children,
1308
+ ...viewProps
1309
+ } = props;
1310
+ const resolvedTone = tone ?? (color ? colorToTone[color] : "neutral");
1311
+ const classes = containerClasses(props, resolvedTone);
1312
+ const content = /* @__PURE__ */ jsx(PillContent, { ...props, tone: resolvedTone });
1313
+ if (onPress) {
1314
+ return /* @__PURE__ */ jsx(
1315
+ reactNative.Pressable,
1316
+ {
1317
+ onPress,
1318
+ disabled: isDisabled,
1319
+ accessibilityRole: "button",
1320
+ className: classes,
1321
+ ...viewProps,
1322
+ children: content
1323
+ }
1324
+ );
1325
+ }
1326
+ return /* @__PURE__ */ jsx(reactNative.View, { className: classes, ...viewProps, children: content });
1327
+ }
1328
+
1329
+ // src/components/ui/badge/Badge.tsx
1330
+ var colorToTone2 = {
1331
+ default: "neutral",
1332
+ primary: "brand",
1333
+ secondary: "brand-secondary",
1334
+ success: "success",
1335
+ error: "error",
1336
+ warning: "warning",
1337
+ info: "info"
1338
+ };
1339
+ var sizeStyles3 = {
1340
+ sm: "px-1.5 py-0.5",
1341
+ md: "px-2 py-0.5",
1342
+ lg: "px-2.5 py-1"
1060
1343
  };
1344
+ var textSizeStyles = {
1345
+ sm: "text-xs",
1346
+ md: "text-xs",
1347
+ lg: "text-sm"
1348
+ };
1349
+ function dotIndicatorColor(color, dotColor) {
1350
+ if (dotColor) return dotColor;
1351
+ return color === "default" || color === "secondary" ? "default" : color;
1352
+ }
1061
1353
  function Badge({
1062
1354
  variant = "subtle",
1063
1355
  color = "default",
@@ -1068,31 +1360,116 @@ function Badge({
1068
1360
  children,
1069
1361
  ...props
1070
1362
  }) {
1071
- return /* @__PURE__ */ jsxs(
1072
- reactNative.View,
1363
+ return /* @__PURE__ */ jsx(
1364
+ Pill,
1073
1365
  {
1366
+ variant,
1367
+ tone: colorToTone2[color],
1368
+ leading: dot ? /* @__PURE__ */ jsx(Indicator, { size: "xs", color: dotIndicatorColor(color, dotColor), className: "mr-0.5" }) : void 0,
1074
1369
  className: cn(
1075
- "inline-flex items-center justify-center rounded-full font-medium",
1076
- variantColorStyles[variant][color],
1077
- sizeStyles2[size],
1370
+ "justify-center self-auto gap-0",
1371
+ variant === "outline" ? "border" : "border-0",
1372
+ sizeStyles3[size],
1078
1373
  className
1079
1374
  ),
1375
+ textClassName: cn("font-sans font-medium", textSizeStyles[size]),
1080
1376
  ...props,
1081
- children: [
1082
- dot && /* @__PURE__ */ jsx(
1083
- Indicator,
1084
- {
1085
- size: "xs",
1086
- color: dotColor ?? (color === "default" || color === "secondary" ? "default" : color),
1087
- className: "mr-0.5"
1088
- }
1089
- ),
1090
- typeof children === "string" ? /* @__PURE__ */ jsx(reactNative.Text, { className: "text-inherit font-medium", children }) : children
1091
- ]
1377
+ children
1378
+ }
1379
+ );
1380
+ }
1381
+ var variantStyles = {
1382
+ h1: "font-heading text-5xl font-bold leading-tight",
1383
+ h2: "font-heading text-4xl font-bold leading-tight",
1384
+ h3: "font-heading text-3xl font-bold leading-tight",
1385
+ h4: "font-heading text-2xl font-bold leading-tight",
1386
+ h5: "font-heading text-xl font-semibold leading-tight",
1387
+ h6: "font-heading text-lg font-semibold leading-tight",
1388
+ body1: "font-body text-base font-normal leading-normal",
1389
+ body2: "font-body text-sm font-normal leading-normal",
1390
+ subtitle1: "font-body text-base font-medium leading-relaxed",
1391
+ subtitle2: "font-body text-sm font-medium leading-normal",
1392
+ caption: "font-body text-xs font-normal leading-loose",
1393
+ overline: "font-body text-xs font-semibold uppercase tracking-widest leading-relaxed",
1394
+ button: "font-sans text-sm font-semibold leading-relaxed",
1395
+ // Monospace technical readouts (clocks, ids, metrics) and their all-caps label form.
1396
+ mono: "font-mono text-xs font-normal leading-normal",
1397
+ monoLabel: "font-mono text-xs font-bold uppercase tracking-wide leading-normal",
1398
+ // The sans (Inter) label pair: 10px for dense table/column headers, 12px bold for
1399
+ // badge and row labels. `overline` is the 12px font-body form of the same idea.
1400
+ microLabel: "font-sans text-2xs font-semibold uppercase tracking-widest leading-normal",
1401
+ boldLabel: "font-sans text-xs font-bold leading-normal"
1402
+ };
1403
+ var colorStyles2 = {
1404
+ primary: "text-text-primary",
1405
+ secondary: "text-text-secondary",
1406
+ tertiary: "text-text-tertiary",
1407
+ disabled: "text-text-disabled",
1408
+ inverse: "text-text-inverse",
1409
+ success: "text-status-success",
1410
+ error: "text-status-error",
1411
+ warning: "text-status-warning",
1412
+ info: "text-status-info",
1413
+ inherit: ""
1414
+ // No color class, inherit from parent
1415
+ };
1416
+ var alignStyles = {
1417
+ left: "text-left",
1418
+ center: "text-center",
1419
+ right: "text-right",
1420
+ justify: "text-justify"
1421
+ };
1422
+ var headingVariants = ["h1", "h2", "h3", "h4", "h5", "h6"];
1423
+ var marginBottomStyles = {
1424
+ none: "",
1425
+ sm: "mb-1",
1426
+ md: "mb-2",
1427
+ lg: "mb-4"
1428
+ };
1429
+ function Typography({
1430
+ variant = "body1",
1431
+ color = "primary",
1432
+ align,
1433
+ truncate = false,
1434
+ noWrap = false,
1435
+ // deprecated, kept for backward compatibility
1436
+ marginBottom,
1437
+ gutterBottom = false,
1438
+ // deprecated, kept for backward compatibility
1439
+ maxLines,
1440
+ className,
1441
+ children,
1442
+ ...props
1443
+ }) {
1444
+ const isHeading = headingVariants.includes(variant);
1445
+ const shouldTruncate = truncate || noWrap;
1446
+ const mb = marginBottom || (gutterBottom ? "md" : "none");
1447
+ let numLines;
1448
+ if (maxLines) {
1449
+ numLines = maxLines;
1450
+ } else if (shouldTruncate) {
1451
+ numLines = 1;
1452
+ }
1453
+ return /* @__PURE__ */ jsx(
1454
+ reactNative.Text,
1455
+ {
1456
+ accessibilityRole: isHeading ? "header" : "text",
1457
+ numberOfLines: numLines,
1458
+ className: cn(
1459
+ variantStyles[variant],
1460
+ color !== "inherit" && colorStyles2[color],
1461
+ align && alignStyles[align],
1462
+ shouldTruncate && "truncate",
1463
+ marginBottomStyles[mb],
1464
+ className
1465
+ ),
1466
+ ...props,
1467
+ children
1092
1468
  }
1093
1469
  );
1094
1470
  }
1095
- var BRAND_PRIMARY2 = getSemanticColors("dark")["brand-primary"];
1471
+
1472
+ // src/components/custom/Workout/Sparkline.tsx
1096
1473
  function normalizeData(data, height) {
1097
1474
  if (data.length === 0) return [];
1098
1475
  const min = Math.min(...data);
@@ -1129,7 +1506,7 @@ function Sparkline({
1129
1506
  }
1130
1507
  );
1131
1508
  }
1132
- const resolvedColor = color ?? BRAND_PRIMARY2;
1509
+ const resolvedColor = color ?? resolveColor("brand-primary");
1133
1510
  const normalized = normalizeData(data, height);
1134
1511
  const stepX = data.length > 1 ? width / (data.length - 1) : 0;
1135
1512
  const dotSize = 3;
@@ -1169,14 +1546,19 @@ function Sparkline({
1169
1546
  ],
1170
1547
  accessibilityElementsHidden: true,
1171
1548
  testID: `sparkline-reference-${i}`,
1172
- children: line.label && /* @__PURE__ */ jsx(
1173
- reactNative.Text,
1549
+ children: line.label && // `3xs` (9px) is the scale floor; the label was 7px, which is off it
1550
+ // entirely (TOKENS.md §4). The line box stays unpinned, as the raw
1551
+ // <Text> this replaced was, so the absolute offset still lands.
1552
+ /* @__PURE__ */ jsx(
1553
+ Typography,
1174
1554
  {
1555
+ variant: "caption",
1556
+ color: "inherit",
1557
+ className: "text-3xs leading-[normal]",
1175
1558
  style: {
1176
1559
  position: "absolute",
1177
1560
  right: 0,
1178
1561
  top: -10,
1179
- fontSize: 7,
1180
1562
  color: line.color,
1181
1563
  opacity: 1
1182
1564
  },
@@ -1245,9 +1627,9 @@ function Sparkline({
1245
1627
  }
1246
1628
 
1247
1629
  // src/components/custom/Workout/BodyMapDetailPanel.tsx
1248
- var t = getSemanticColors("dark");
1249
- var BRAND_PRIMARY3 = t["brand-primary"];
1250
- var VOLUME_GRADIENT = `linear-gradient(90deg, ${t["status-info"]} 0%, ${t["status-success"]} 50%, ${t["status-error"]} 100%)`;
1630
+ var t2 = getSemanticColors("dark");
1631
+ var BRAND_PRIMARY2 = t2["brand-primary"];
1632
+ var VOLUME_GRADIENT = `linear-gradient(90deg, ${t2["status-info"]} 0%, ${t2["status-success"]} 50%, ${t2["status-error"]} 100%)`;
1251
1633
  var SLIDE_OFFSET = 400;
1252
1634
  var BACKDROP_OPACITY = 0.4;
1253
1635
  var STATUS_BADGE_COLOR = {
@@ -1312,7 +1694,14 @@ function BodyMapDetailPanel({
1312
1694
  return /* @__PURE__ */ jsxs(
1313
1695
  reactNative.View,
1314
1696
  {
1315
- style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, justifyContent: "flex-end" },
1697
+ style: {
1698
+ position: "absolute",
1699
+ top: 0,
1700
+ left: 0,
1701
+ right: 0,
1702
+ bottom: 0,
1703
+ justifyContent: "flex-end"
1704
+ },
1316
1705
  testID: "body-map-detail-panel-root",
1317
1706
  children: [
1318
1707
  /* @__PURE__ */ jsx(
@@ -1447,8 +1836,22 @@ function BodyMapDetailPanel({
1447
1836
  style: { marginBottom: 6 },
1448
1837
  accessibilityElementsHidden: true,
1449
1838
  children: [
1450
- /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-tertiary", style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" }, children: `MEV ${landmarks.mev}` }),
1451
- /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-tertiary", style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" }, children: `MRV ${landmarks.mrv}` })
1839
+ /* @__PURE__ */ jsx(
1840
+ reactNative.Text,
1841
+ {
1842
+ className: "text-text-tertiary",
1843
+ style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" },
1844
+ children: `MEV ${landmarks.mev}`
1845
+ }
1846
+ ),
1847
+ /* @__PURE__ */ jsx(
1848
+ reactNative.Text,
1849
+ {
1850
+ className: "text-text-tertiary",
1851
+ style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" },
1852
+ children: `MRV ${landmarks.mrv}`
1853
+ }
1854
+ )
1452
1855
  ]
1453
1856
  }
1454
1857
  ),
@@ -1483,7 +1886,8 @@ function BodyMapDetailPanel({
1483
1886
  height: 14,
1484
1887
  borderRadius: 7,
1485
1888
  borderWidth: 2,
1486
- boxShadow: "0 0 4px rgba(0,0,0,0.5)"
1889
+ // A knob resting on the volume bar: lift, with the ring as its edge.
1890
+ ...liftStyle(1, "dark", { rim: 0 })
1487
1891
  },
1488
1892
  accessibilityElementsHidden: true,
1489
1893
  testID: "body-map-detail-panel-volume-marker"
@@ -1566,7 +1970,12 @@ function BodyMapDetailPanel({
1566
1970
  reactNative.Text,
1567
1971
  {
1568
1972
  className: "text-text-primary",
1569
- style: { flex: 1, fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "600" },
1973
+ style: {
1974
+ flex: 1,
1975
+ fontSize: 13,
1976
+ fontFamily: "Inter, sans-serif",
1977
+ fontWeight: "600"
1978
+ },
1570
1979
  testID: `body-map-detail-panel-contributing-${index}-name`,
1571
1980
  children: exercise.name
1572
1981
  }
@@ -1610,7 +2019,12 @@ function BodyMapDetailPanel({
1610
2019
  reactNative.Text,
1611
2020
  {
1612
2021
  className: "text-text-primary",
1613
- style: { flex: 1, fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "600" },
2022
+ style: {
2023
+ flex: 1,
2024
+ fontSize: 13,
2025
+ fontFamily: "Inter, sans-serif",
2026
+ fontWeight: "600"
2027
+ },
1614
2028
  testID: `body-map-detail-panel-upcoming-${index}-name`,
1615
2029
  children: exercise.name
1616
2030
  }
@@ -1645,7 +2059,18 @@ function BodyMapDetailPanel({
1645
2059
  borderColor: "rgba(255,121,0,0.3)"
1646
2060
  },
1647
2061
  testID: "body-map-detail-panel-view-exercises",
1648
- children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "700", color: BRAND_PRIMARY3 }, children: "View exercises" })
2062
+ children: /* @__PURE__ */ jsx(
2063
+ reactNative.Text,
2064
+ {
2065
+ style: {
2066
+ fontSize: 13,
2067
+ fontFamily: "Inter, sans-serif",
2068
+ fontWeight: "700",
2069
+ color: BRAND_PRIMARY2
2070
+ },
2071
+ children: "View exercises"
2072
+ }
2073
+ )
1649
2074
  }
1650
2075
  )
1651
2076
  ]
@@ -1658,439 +2083,81 @@ function BodyMapDetailPanel({
1658
2083
  }
1659
2084
  );
1660
2085
  }
1661
-
1662
- // src/theme/color-utils.ts
1663
- function hexToRgb(hex) {
1664
- const cleaned = hex.replace("#", "");
1665
- let r, g, b;
1666
- if (cleaned.length === 3) {
1667
- r = parseInt(cleaned[0] + cleaned[0], 16);
1668
- g = parseInt(cleaned[1] + cleaned[1], 16);
1669
- b = parseInt(cleaned[2] + cleaned[2], 16);
1670
- } else if (cleaned.length === 6) {
1671
- r = parseInt(cleaned.slice(0, 2), 16);
1672
- g = parseInt(cleaned.slice(2, 4), 16);
1673
- b = parseInt(cleaned.slice(4, 6), 16);
1674
- } else {
1675
- return null;
1676
- }
1677
- return { r, g, b };
1678
- }
1679
- function rgbToHsv(r, g, b) {
1680
- const rNorm = r / 255;
1681
- const gNorm = g / 255;
1682
- const bNorm = b / 255;
1683
- const max = Math.max(rNorm, gNorm, bNorm);
1684
- const min = Math.min(rNorm, gNorm, bNorm);
1685
- const delta = max - min;
1686
- const v = max;
1687
- const s = max === 0 ? 0 : delta / max;
1688
- let h = 0;
1689
- if (delta !== 0) {
1690
- if (max === rNorm) {
1691
- h = 60 * ((gNorm - bNorm) / delta % 6);
1692
- } else if (max === gNorm) {
1693
- h = 60 * ((bNorm - rNorm) / delta + 2);
1694
- } else {
1695
- h = 60 * ((rNorm - gNorm) / delta + 4);
1696
- }
1697
- }
1698
- if (h < 0) h += 360;
1699
- return { h, s, v };
1700
- }
1701
- function hsvToRgb(h, s, v) {
1702
- const c = v * s;
1703
- const x = c * (1 - Math.abs(h / 60 % 2 - 1));
1704
- const m = v - c;
1705
- let rPrime, gPrime, bPrime;
1706
- if (h >= 0 && h < 60) {
1707
- rPrime = c;
1708
- gPrime = x;
1709
- bPrime = 0;
1710
- } else if (h >= 60 && h < 120) {
1711
- rPrime = x;
1712
- gPrime = c;
1713
- bPrime = 0;
1714
- } else if (h >= 120 && h < 180) {
1715
- rPrime = 0;
1716
- gPrime = c;
1717
- bPrime = x;
1718
- } else if (h >= 180 && h < 240) {
1719
- rPrime = 0;
1720
- gPrime = x;
1721
- bPrime = c;
1722
- } else if (h >= 240 && h < 300) {
1723
- rPrime = x;
1724
- gPrime = 0;
1725
- bPrime = c;
1726
- } else {
1727
- rPrime = c;
1728
- gPrime = 0;
1729
- bPrime = x;
1730
- }
1731
- return {
1732
- r: Math.round((rPrime + m) * 255),
1733
- g: Math.round((gPrime + m) * 255),
1734
- b: Math.round((bPrime + m) * 255)
1735
- };
2086
+ var DEFAULT_CONTEXT = { mode: "dark", level: "base" };
2087
+ var SurfaceContext = react.createContext(DEFAULT_CONTEXT);
2088
+ function useSurface() {
2089
+ return react.useContext(SurfaceContext);
1736
2090
  }
1737
- function rgbToHex(r, g, b) {
1738
- const toHex = (n) => {
1739
- const clamped = Math.max(0, Math.min(255, Math.round(n)));
1740
- return clamped.toString(16).padStart(2, "0");
1741
- };
1742
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
1743
- }
1744
- function lighten(hex, amount = 0.1) {
1745
- const rgb = hexToRgb(hex);
1746
- if (!rgb) return hex;
1747
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1748
- const newV = Math.min(1, hsv.v + amount);
1749
- const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
1750
- return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
1751
- }
1752
- var elevationSystem = {
1753
- // Deep inset (recessed input fields, deeply pressed buttons)
1754
- [-2]: {
1755
- name: "deep-inset",
1756
- colorAdjustment: 0,
1757
- shadowIntensity: "strong",
1758
- shadowStyle: "pressed",
1759
- description: "Deeply recessed elements (e.g., input fields, deeply pressed buttons)"
1760
- },
1761
- // Shallow inset (pressed buttons, sunken panels)
1762
- [-1]: {
1763
- name: "inset",
1764
- colorAdjustment: 0,
1765
- shadowIntensity: "medium",
1766
- shadowStyle: "pressed",
1767
- description: "Shallow inset elements (e.g., pressed buttons, sunken panels within cards)"
1768
- },
1769
- // Base level (page background, default surface)
1770
- [0]: {
1771
- name: "base",
1772
- colorAdjustment: 0,
1773
- shadowIntensity: "subtle",
1774
- shadowStyle: "raised",
1775
- description: "Base surface level (page background, default containers)"
1776
- },
1777
- // Level 1: Subtle elevation (outline cards, subtle containers)
1778
- [1]: {
1779
- name: "subtle",
1780
- // The whole ladder was re-spaced in TD-07.16. It used to run
1781
- // 0.01/0.02/0.04/0.06/0.08, where the first step was ~2 RGB values — under
1782
- // the perceptual floor, so level 1 existed in the type system and nowhere on
1783
- // screen. With drop-shadow now gated off below FLOATING_ELEVATION_MIN, TONE
1784
- // is the only thing separating 0-3, so every step has to actually land.
1785
- // Even 0.025 spacing, verified in elevation.test.ts as ΔL* > 1 per step.
1786
- colorAdjustment: 0.025,
1787
- shadowIntensity: "subtle",
1788
- shadowStyle: "raised",
1789
- description: "Subtle elevation (outline cards, subtle containers)"
1790
- },
1791
- // Level 2: Standard elevation (default cards, buttons)
1792
- [2]: {
1793
- name: "standard",
1794
- colorAdjustment: 0.05,
1795
- shadowIntensity: "medium",
1796
- shadowStyle: "raised",
1797
- description: "Standard elevation (default cards, raised buttons)"
1798
- },
1799
- // Level 3: Prominent elevation (important cards, modals)
1800
- [3]: {
1801
- name: "prominent",
1802
- colorAdjustment: 0.075,
1803
- shadowIntensity: "strong",
1804
- shadowStyle: "raised",
1805
- description: "Prominent elevation (important cards, modals, dropdowns)"
1806
- },
1807
- // Level 4: High elevation (overlays, popovers)
1808
- [4]: {
1809
- name: "high",
1810
- colorAdjustment: 0.1,
1811
- shadowIntensity: "strong",
1812
- shadowStyle: "raised",
1813
- description: "High elevation (overlays, popovers, tooltips)"
1814
- },
1815
- // Level 5: Floating (toasts, floating action buttons)
1816
- [5]: {
1817
- name: "floating",
1818
- colorAdjustment: 0.13,
1819
- shadowIntensity: "strong",
1820
- shadowStyle: "raised",
1821
- description: "Floating elevation (toasts, floating action buttons, highest z-index)"
1822
- }
1823
- };
1824
- function calculateRimLightColor(baseColor, level) {
1825
- const rgb = hexToRgb(baseColor);
1826
- if (!rgb) {
1827
- return "rgba(255, 255, 255, 0.5)";
1828
- }
1829
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1830
- const isLight = hsv.v > 0.6;
1831
- const isSaturated = hsv.s > 0.3;
1832
- const absLevel = Math.abs(level);
1833
- const opacityBoost = Math.max(0, (absLevel - 1) * 0.05);
1834
- if (isSaturated) {
1835
- const rimLightValue = 0.95;
1836
- const rimLightRgb = hsvToRgb(hsv.h, hsv.s * 0.3, rimLightValue);
1837
- const baseOpacity = isLight ? 0.9 : 0.5;
1838
- const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
1839
- return `rgba(${rimLightRgb.r}, ${rimLightRgb.g}, ${rimLightRgb.b}, ${finalOpacity.toFixed(2)})`;
1840
- } else {
1841
- const baseOpacity = isLight ? 0.9 : 0.12;
1842
- const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
1843
- return `rgba(255, 255, 255, ${finalOpacity.toFixed(2)})`;
1844
- }
2091
+ function recessDepth(inherited, planesDown, mode) {
2092
+ let plane = inherited.level;
2093
+ for (let i = 0; i < planesDown; i++) plane = pressedLevel(plane);
2094
+ const backgroundColor = surfaceBackground(plane, mode);
2095
+ return { plane, backgroundColor, depthStyle: getPressedRecessShadow(backgroundColor, mode) };
1845
2096
  }
1846
- function calculateDarkShadowColors(surfaceColor) {
1847
- const rgb = hexToRgb(surfaceColor);
1848
- if (!rgb) {
1849
- return {
1850
- dark: "rgba(0, 0, 0, 0.3)",
1851
- darker: "rgba(0, 0, 0, 0.4)"
1852
- };
2097
+ function resolveSurfaceDepth(inherited, props) {
2098
+ const mode = props.theme ?? inherited.mode;
2099
+ const elevation = props.elevation ?? 0;
2100
+ if (props.pressed || elevation < 0) {
2101
+ const down = props.pressed ? 1 : -elevation;
2102
+ return { mode, step: 0, lifted: false, ...recessDepth(inherited, down, mode) };
1853
2103
  }
1854
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1855
- const isLight = hsv.v > 0.6;
1856
- const isSaturated = hsv.s > 0.3;
1857
- if (isSaturated) {
1858
- const darkShadowValue = 0.15;
1859
- const darkShadowRgb = hsvToRgb(hsv.h, hsv.s, darkShadowValue);
1860
- if (isLight) {
1861
- return {
1862
- dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.3)`,
1863
- darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.4)`
1864
- };
1865
- } else {
1866
- return {
1867
- dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.5)`,
1868
- darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.6)`
1869
- };
1870
- }
1871
- } else {
1872
- if (isLight) {
1873
- return {
1874
- dark: "rgba(0, 0, 0, 0.2)",
1875
- darker: "rgba(0, 0, 0, 0.3)"
1876
- };
1877
- } else {
1878
- return {
1879
- dark: "rgba(0, 0, 0, 0.5)",
1880
- darker: "rgba(0, 0, 0, 0.6)"
1881
- };
1882
- }
1883
- }
1884
- }
1885
- function getRimLightConfig() {
1886
- return {
1887
- offset: 1,
1888
- // Fixed 1px for crisp rim
1889
- blur: 1
1890
- // Tight blur for crisp edge
1891
- };
1892
- }
1893
- var elevationSurfaceCache = /* @__PURE__ */ new Map();
1894
- var MAX_CACHE_SIZE = 100;
1895
- function getCacheKey(baseColor, level, theme) {
1896
- return `${baseColor}-${level}-${theme}`;
2104
+ const step = props.level != null ? 0 : props.raise ?? elevation;
2105
+ const floating = step >= FLOATING_ELEVATION_MIN;
2106
+ const plane = props.level ?? (floating ? "overlay" : raisedLevel(inherited.level, step));
2107
+ const lifted = props.lift ?? step > 0;
2108
+ const liftStep = Math.max(1, Math.min(5, step));
2109
+ const depthStyle = lifted ? liftStyle(liftStep, mode, props.liftOptions) : {};
2110
+ return { mode, plane, backgroundColor: surfaceBackground(plane, mode), depthStyle, step, lifted };
1897
2111
  }
1898
- function calculateElevationSurface(baseColor, level, theme) {
1899
- const config = elevationSystem[level];
1900
- if (config.colorAdjustment === 0) {
1901
- return baseColor;
1902
- }
1903
- if (level < 0) {
1904
- return baseColor;
1905
- }
1906
- return lighten(baseColor, config.colorAdjustment);
1907
- }
1908
- function getElevationSurface(baseColor, level, theme) {
1909
- const cacheKey = getCacheKey(baseColor, level, theme);
1910
- if (elevationSurfaceCache.has(cacheKey)) {
1911
- return elevationSurfaceCache.get(cacheKey);
1912
- }
1913
- const result = calculateElevationSurface(baseColor, level);
1914
- if (elevationSurfaceCache.size >= MAX_CACHE_SIZE) {
1915
- const firstKey = elevationSurfaceCache.keys().next().value;
1916
- elevationSurfaceCache.delete(firstKey);
1917
- }
1918
- elevationSurfaceCache.set(cacheKey, result);
1919
- return result;
1920
- }
1921
- var elevationShadowCache = /* @__PURE__ */ new Map();
1922
- var MAX_SHADOW_CACHE_SIZE = 50;
1923
- function getShadowCacheKey(baseColor, level, theme, isHovered) {
1924
- return `${baseColor}-${level}-${theme}-${isHovered}`;
1925
- }
1926
- function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
1927
- const config = elevationSystem[level];
1928
- if (level === 0) {
1929
- return {};
1930
- }
1931
- const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
1932
- const rimLightColor = calculateRimLightColor(baseColor, level);
1933
- const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
1934
- const intensityConfig = {
1935
- subtle: { offset: 1, blur: 2 },
1936
- medium: { offset: 2, blur: 4 },
1937
- strong: { offset: 2, blur: 5 }
1938
- };
1939
- const { offset, blur } = intensityConfig[config.shadowIntensity];
1940
- const rimConfig = getRimLightConfig();
1941
- if (config.shadowStyle === "pressed") {
1942
- if (isHovered) {
1943
- const hoverOffset = Math.max(1, Math.round(offset / 2));
1944
- const hoverBlur = Math.max(1, Math.round(blur / 2));
1945
- return reactNative.Platform.select({
1946
- web: {
1947
- boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
1948
- },
1949
- default: {
1950
- shadowOpacity: 0,
1951
- elevation: 0
1952
- }
1953
- });
1954
- }
1955
- return reactNative.Platform.select({
1956
- web: {
1957
- boxShadow: `inset ${offset}px ${offset}px ${blur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
1958
- },
1959
- default: {
1960
- shadowOpacity: 0,
1961
- elevation: 0
1962
- }
1963
- });
1964
- } else {
1965
- if (isHovered) {
1966
- const hoverOffset = Math.max(1, Math.round(offset / 2));
1967
- const hoverBlur = Math.max(1, Math.round(blur / 2));
1968
- return reactNative.Platform.select({
1969
- web: {
1970
- boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
1971
- },
1972
- default: {
1973
- shadowColor: "#000",
1974
- shadowOffset: { width: hoverOffset, height: hoverOffset },
1975
- shadowOpacity: 0.2,
1976
- shadowRadius: hoverBlur / 2,
1977
- elevation: hoverOffset
1978
- }
1979
- });
1980
- }
1981
- return reactNative.Platform.select({
1982
- web: {
1983
- boxShadow: `${offset}px ${offset}px ${blur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
1984
- },
1985
- default: {
1986
- shadowColor: "#000",
1987
- shadowOffset: { width: offset, height: offset },
1988
- shadowOpacity: 0.3,
1989
- shadowRadius: blur / 2,
1990
- elevation: offset
1991
- }
1992
- });
1993
- }
1994
- }
1995
- var FLOATING_ELEVATION_MIN = 4;
1996
- function getElevationShadow(baseColor, level, theme, isHovered = false) {
1997
- const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
1998
- if (elevationShadowCache.has(cacheKey)) {
1999
- return elevationShadowCache.get(cacheKey);
2000
- }
2001
- const result = level > 0 && level < FLOATING_ELEVATION_MIN ? {} : calculateElevationShadow(baseColor, level, theme, isHovered);
2002
- if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
2003
- const firstKey = elevationShadowCache.keys().next().value;
2004
- elevationShadowCache.delete(firstKey);
2005
- }
2006
- elevationShadowCache.set(cacheKey, result);
2007
- return result;
2008
- }
2009
- function getBaseSurfaceColor(theme) {
2010
- return theme === "light" ? semanticColorsLight["surface-raised"] : semanticColorsDark["surface-elevated"];
2011
- }
2012
- var componentElevationRanges = {
2013
- button: {
2014
- allowed: [2],
2015
- default: 2,
2016
- hover: 3
2017
- },
2018
- card: {
2019
- allowed: [1, 2, 3],
2020
- default: 2,
2021
- hover: 3
2022
- },
2023
- input: {
2024
- allowed: [-2, -1, 0],
2025
- default: -1
2026
- },
2027
- overlay: {
2028
- allowed: [4, 5],
2029
- default: 4
2030
- }
2031
- };
2032
- function getValidatedElevation(component, requested) {
2033
- const range = componentElevationRanges[component];
2034
- if (range.allowed.includes(requested)) {
2035
- return requested;
2036
- }
2037
- const sorted = [...range.allowed].sort((a, b) => a - b);
2038
- if (requested < sorted[0]) return sorted[0];
2039
- if (requested > sorted[sorted.length - 1]) return sorted[sorted.length - 1];
2040
- return sorted.reduce(
2041
- (prev, curr) => Math.abs(curr - requested) < Math.abs(prev - requested) ? curr : prev
2112
+ function useResolvedSurface(props) {
2113
+ const inherited = useSurface();
2114
+ const { level, raise, elevation, pressed, lift, liftOptions, theme } = props;
2115
+ return react.useMemo(
2116
+ () => resolveSurfaceDepth(inherited, {
2117
+ level,
2118
+ raise,
2119
+ elevation,
2120
+ pressed,
2121
+ lift,
2122
+ liftOptions,
2123
+ theme
2124
+ }),
2125
+ [inherited, level, raise, elevation, pressed, lift, liftOptions, theme]
2042
2126
  );
2043
2127
  }
2044
- function getTheme() {
2045
- if (typeof document === "undefined") return "dark";
2046
- return document.documentElement.classList.contains("light") ? "light" : "dark";
2047
- }
2048
- var listeners = [];
2049
- function subscribe(listener) {
2050
- listeners = [...listeners, listener];
2051
- if (typeof document !== "undefined" && listeners.length === 1) {
2052
- const observer = new MutationObserver((mutations) => {
2053
- for (const mutation of mutations) {
2054
- if (mutation.type === "attributes" && mutation.attributeName === "class") {
2055
- listeners.forEach((l) => l());
2056
- }
2057
- }
2058
- });
2059
- observer.observe(document.documentElement, {
2060
- attributes: true,
2061
- attributeFilter: ["class"]
2062
- });
2063
- subscribe._observer = observer;
2064
- }
2065
- return () => {
2066
- listeners = listeners.filter((l) => l !== listener);
2067
- if (listeners.length === 0 && subscribe._observer) {
2068
- subscribe._observer.disconnect();
2069
- subscribe._observer = null;
2070
- }
2071
- };
2072
- }
2073
- function getSnapshot() {
2074
- return getTheme();
2075
- }
2076
- function getServerSnapshot() {
2077
- return "dark";
2078
- }
2079
- function useTheme() {
2080
- return react.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2081
- }
2082
2128
 
2083
2129
  // src/components/ui/card/Card.tsx
2084
- var variantStyles = {
2130
+ var EDGE_CLASS = {
2085
2131
  elevated: "",
2086
- // Will be set dynamically via elevation system
2087
- outline: "border-2 border-hairline-strong",
2088
- // Thicker border with stronger contrast
2132
+ accent: "",
2089
2133
  filled: "",
2090
- // Will be set dynamically via elevation system
2091
- accent: "border border-hairline",
2134
+ outline: "border border-hairline-strong",
2092
2135
  subtle: "border border-hairline-subtle"
2093
2136
  };
2137
+ var LIFTED = {
2138
+ elevated: true,
2139
+ accent: true,
2140
+ filled: false,
2141
+ outline: false,
2142
+ subtle: false
2143
+ };
2144
+ var STAYS_ON_HOST = {
2145
+ elevated: false,
2146
+ accent: false,
2147
+ filled: false,
2148
+ outline: true,
2149
+ subtle: true
2150
+ };
2151
+ function useCardDepth(variant, elevation, hovered) {
2152
+ const raise = STAYS_ON_HOST[variant] ? void 0 : elevation;
2153
+ const resolved = useResolvedSurface({ raise, lift: LIFTED[variant] });
2154
+ const depthStyle = react.useMemo(() => {
2155
+ if (!hovered || !LIFTED[variant]) return resolved.depthStyle;
2156
+ const hoverStep = Math.min(3, resolved.step + 1);
2157
+ return liftStyle(hoverStep, resolved.mode);
2158
+ }, [hovered, variant, resolved]);
2159
+ return { ...resolved, depthStyle };
2160
+ }
2094
2161
  function Card({
2095
2162
  variant = "elevated",
2096
2163
  elevation = 2,
@@ -2111,89 +2178,54 @@ function Card({
2111
2178
  }) {
2112
2179
  const isClickable = isInteractive || !!onPress;
2113
2180
  const [isHovered, setIsHovered] = react.useState(false);
2114
- const theme = useTheme();
2115
- const elevationLevel = react.useMemo(() => {
2116
- const validated = getValidatedElevation("card", elevation);
2117
- if (variant === "outline" || variant === "accent" || variant === "subtle") {
2118
- return 1;
2119
- }
2120
- return validated;
2121
- }, [variant, elevation]);
2122
- const baseColor = react.useMemo(() => getBaseSurfaceColor(theme), [theme]);
2123
- const surfaceColor = react.useMemo(() => {
2124
- if ((variant === "outline" || variant === "accent") && theme === "light") {
2125
- return "#FAFAFA";
2126
- }
2127
- if (variant === "subtle") {
2128
- return getElevationSurface(baseColor, 0, theme);
2129
- }
2130
- return getElevationSurface(baseColor, elevationLevel, theme);
2131
- }, [baseColor, elevationLevel, theme, variant]);
2132
- const shadowStyle = react.useMemo(() => {
2133
- const shouldHover = isHovered && isClickable;
2134
- return getElevationShadow(baseColor, elevationLevel, theme, shouldHover);
2135
- }, [baseColor, elevationLevel, theme, isHovered, isClickable]);
2136
- const cardContent = isLoading ? /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
2137
- skeletonHasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
2138
- /* @__PURE__ */ jsx(reactNative.View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
2139
- /* @__PURE__ */ jsx(reactNative.View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
2140
- ] }),
2141
- /* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: skeletonContentLines }).map((_, i) => /* @__PURE__ */ jsx(
2142
- reactNative.View,
2143
- {
2144
- className: cn(
2145
- "h-4 bg-interactive-disabled rounded",
2146
- i < skeletonContentLines - 1 ? "mb-2 w-full" : "w-4/5"
2147
- )
2148
- },
2149
- i
2150
- )) }),
2151
- skeletonHasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(reactNative.View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
2152
- ] }) : children;
2181
+ const depth = useCardDepth(variant, elevation, isHovered && isClickable);
2153
2182
  const baseClassName = cn(
2154
2183
  "rounded-lg overflow-hidden relative",
2155
- // Apply variant styles, but only use default border color if no custom borderColor
2156
- variant === "outline" ? borderColor ? "border-2" : variantStyles[variant] : variantStyles[variant],
2157
- // Remove Tailwind shadow classes - we're using elevation shadows via style prop
2184
+ borderColor ? "border" : EDGE_CLASS[variant],
2158
2185
  isClickable && "web:cursor-pointer web:transition-all web:duration-150",
2159
2186
  isClickable && "web:hover:-translate-y-0.5 active:scale-[0.99]",
2160
2187
  isLoading && "pointer-events-none animate-pulse",
2161
2188
  className
2162
2189
  );
2163
- const accentStyle = react.useMemo(() => variant === "accent" ? {
2164
- borderLeftWidth: accentWidth ?? 3,
2165
- borderLeftColor: accentColor ?? "var(--color-brand-primary)"
2166
- } : {}, [variant, accentWidth, accentColor]);
2167
2190
  const mergedStyle = react.useMemo(() => {
2168
- const elevationStyle = {
2169
- backgroundColor: bgColor || surfaceColor,
2191
+ const own = {
2192
+ backgroundColor: bgColor || depth.backgroundColor,
2170
2193
  borderRadius: 8,
2171
2194
  overflow: "hidden",
2172
- ...shadowStyle,
2173
- ...accentStyle
2195
+ ...depth.depthStyle
2174
2196
  };
2175
- if (borderColor) {
2176
- elevationStyle.borderColor = borderColor;
2197
+ if (variant === "accent") {
2198
+ own.borderLeftWidth = accentWidth ?? 3;
2199
+ own.borderLeftColor = accentColor ?? "var(--color-brand-primary)";
2177
2200
  }
2178
- if (!style) return elevationStyle;
2179
- return [elevationStyle, style];
2180
- }, [style, surfaceColor, shadowStyle, borderColor, bgColor, accentStyle]);
2181
- if (isClickable) {
2182
- return /* @__PURE__ */ jsx(
2183
- reactNative.Pressable,
2184
- {
2185
- onPress,
2186
- onHoverIn: () => setIsHovered(true),
2187
- onHoverOut: () => setIsHovered(false),
2188
- accessibilityRole: "button",
2189
- className: baseClassName,
2190
- style: mergedStyle,
2191
- ...props,
2192
- children: cardContent
2193
- }
2194
- );
2195
- }
2196
- return /* @__PURE__ */ jsx(reactNative.View, { className: baseClassName, style: mergedStyle, ...props, children: cardContent });
2201
+ if (borderColor) own.borderColor = borderColor;
2202
+ return style ? [own, style] : own;
2203
+ }, [style, depth, bgColor, borderColor, variant, accentWidth, accentColor]);
2204
+ const context = react.useMemo(
2205
+ () => ({ mode: depth.mode, level: depth.plane }),
2206
+ [depth.mode, depth.plane]
2207
+ );
2208
+ const content = isLoading ? /* @__PURE__ */ jsx(
2209
+ SkeletonBody,
2210
+ {
2211
+ hasHeader: skeletonHasHeader,
2212
+ hasFooter: skeletonHasFooter,
2213
+ contentLines: skeletonContentLines
2214
+ }
2215
+ ) : children;
2216
+ return /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: context, children: isClickable ? /* @__PURE__ */ jsx(
2217
+ reactNative.Pressable,
2218
+ {
2219
+ onPress,
2220
+ onHoverIn: () => setIsHovered(true),
2221
+ onHoverOut: () => setIsHovered(false),
2222
+ accessibilityRole: "button",
2223
+ className: baseClassName,
2224
+ style: mergedStyle,
2225
+ ...props,
2226
+ children: content
2227
+ }
2228
+ ) : /* @__PURE__ */ jsx(reactNative.View, { className: baseClassName, style: mergedStyle, ...props, children: content }) });
2197
2229
  }
2198
2230
  function CardHeader({ children, className }) {
2199
2231
  return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-6 py-6", className), children });
@@ -2204,60 +2236,122 @@ function CardContent({ children, className }) {
2204
2236
  function CardFooter({ children, className }) {
2205
2237
  return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
2206
2238
  }
2207
- var t2 = getSemanticColors("dark");
2208
- var solidVariantColors = {
2209
- success: t2["status-success"],
2210
- warning: t2["status-warning"],
2211
- error: t2["status-error"],
2212
- neutral: greyRamp[500]
2213
- };
2214
- var ringVariantStyles = {
2215
- "on-track": {
2216
- backgroundColor: "rgba(46,213,115,0.15)",
2217
- borderWidth: 1,
2218
- borderColor: "rgba(46,213,115,0.3)"
2219
- },
2220
- deviation: {
2221
- backgroundColor: "rgba(245,158,11,0.15)",
2222
- borderWidth: 1,
2223
- borderColor: "rgba(245,158,11,0.25)"
2224
- },
2225
- future: {
2226
- backgroundColor: "rgba(107,114,128,0.1)",
2227
- borderWidth: 1,
2228
- borderStyle: "dashed",
2229
- borderColor: "rgba(107,114,128,0.2)"
2239
+ function SkeletonBody({ hasHeader, hasFooter, contentLines }) {
2240
+ return /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
2241
+ hasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
2242
+ /* @__PURE__ */ jsx(reactNative.View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
2243
+ /* @__PURE__ */ jsx(reactNative.View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
2244
+ ] }),
2245
+ /* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: contentLines }).map((_, i) => /* @__PURE__ */ jsx(
2246
+ reactNative.View,
2247
+ {
2248
+ className: cn(
2249
+ "h-4 bg-interactive-disabled rounded",
2250
+ i < contentLines - 1 ? "mb-2 w-full" : "w-4/5"
2251
+ )
2252
+ },
2253
+ i
2254
+ )) }),
2255
+ hasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(reactNative.View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
2256
+ ] });
2257
+ }
2258
+
2259
+ // src/utils/colors.ts
2260
+ function alpha(color, opacity) {
2261
+ const clampedOpacity = Math.max(0, Math.min(1, opacity));
2262
+ if (color.startsWith("#")) {
2263
+ const hex = color.slice(1);
2264
+ let r, g, b;
2265
+ if (hex.length === 3) {
2266
+ r = parseInt(hex[0] + hex[0], 16);
2267
+ g = parseInt(hex[1] + hex[1], 16);
2268
+ b = parseInt(hex[2] + hex[2], 16);
2269
+ } else if (hex.length === 6) {
2270
+ r = parseInt(hex.slice(0, 2), 16);
2271
+ g = parseInt(hex.slice(2, 4), 16);
2272
+ b = parseInt(hex.slice(4, 6), 16);
2273
+ } else {
2274
+ return color;
2275
+ }
2276
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
2277
+ }
2278
+ const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
2279
+ if (rgbMatch) {
2280
+ const [, r, g, b] = rgbMatch;
2281
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
2230
2282
  }
2283
+ const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
2284
+ if (rgbaMatch) {
2285
+ const [, r, g, b] = rgbaMatch;
2286
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
2287
+ }
2288
+ return color;
2289
+ }
2290
+
2291
+ // src/components/custom/Workout/StatusDot.tsx
2292
+ var solidFillToken = {
2293
+ success: "status-success",
2294
+ warning: "status-warning",
2295
+ error: "status-error",
2296
+ neutral: "text-tertiary"
2231
2297
  };
2232
- var glowStyles = {
2233
- success: { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
2234
- warning: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
2235
- error: { boxShadow: "0 0 4px rgba(239,68,68,0.4)" },
2236
- neutral: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" },
2237
- "on-track": { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
2238
- deviation: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
2239
- future: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" }
2298
+ var ringWashToken = {
2299
+ "on-track": { fill: "status-success-subtle", border: "status-success-muted" },
2300
+ deviation: { fill: "status-warning-subtle", border: "status-warning-muted" }
2240
2301
  };
2302
+ var FUTURE_FILL = alpha(greyRamp[500], 0.1);
2303
+ var FUTURE_BORDER = alpha(greyRamp[500], 0.2);
2304
+ var glyphToken = {
2305
+ success: "text-inverse",
2306
+ warning: "text-inverse",
2307
+ error: "text-inverse",
2308
+ neutral: "text-inverse",
2309
+ "on-track": "status-success",
2310
+ deviation: "status-warning",
2311
+ future: "text-tertiary"
2312
+ };
2313
+ var glowColors2 = {
2314
+ success: semanticColorsDark["status-success"],
2315
+ warning: semanticColorsDark["status-warning"],
2316
+ error: semanticColorsDark["status-error"],
2317
+ neutral: greyRamp[500],
2318
+ "on-track": semanticColorsDark["status-success"],
2319
+ deviation: semanticColorsDark["status-warning"],
2320
+ future: greyRamp[500]
2321
+ };
2322
+ var glowStyles = Object.fromEntries(
2323
+ Object.entries(glowColors2).map(([variant, color]) => [variant, getGlowShadow(color, "subtle")])
2324
+ );
2241
2325
  var iconChars = {
2242
2326
  check: "\u2713",
2243
2327
  exclamation: "!",
2244
2328
  dash: "\u2014"
2245
2329
  };
2246
- var iconColors = {
2247
- success: "#0A5C52",
2248
- warning: "#6B4000",
2249
- error: "#5C1A1A",
2250
- neutral: greyRamp[200],
2251
- "on-track": t2["status-success"],
2252
- deviation: t2["status-warning"],
2253
- future: greyRamp[500]
2254
- };
2255
2330
  var sizeDimensions = {
2256
2331
  sm: { size: 8, showIcon: false },
2257
2332
  md: { size: 18, showIcon: true }
2258
2333
  };
2259
2334
  function isSolidVariant(variant) {
2260
- return variant in solidVariantColors;
2335
+ return variant in solidFillToken;
2336
+ }
2337
+ function ringStyle(variant) {
2338
+ if (variant === "future") {
2339
+ return {
2340
+ backgroundColor: FUTURE_FILL,
2341
+ borderWidth: 1,
2342
+ borderStyle: "dashed",
2343
+ borderColor: FUTURE_BORDER
2344
+ };
2345
+ }
2346
+ if (variant === "on-track" || variant === "deviation") {
2347
+ const tokens = ringWashToken[variant];
2348
+ return {
2349
+ backgroundColor: resolveColor(tokens.fill),
2350
+ borderWidth: 1,
2351
+ borderColor: resolveColor(tokens.border)
2352
+ };
2353
+ }
2354
+ return void 0;
2261
2355
  }
2262
2356
  function StatusDot({
2263
2357
  variant,
@@ -2270,7 +2364,7 @@ function StatusDot({
2270
2364
  }) {
2271
2365
  const config = sizeDimensions[size];
2272
2366
  const solid = isSolidVariant(variant);
2273
- const ring = ringVariantStyles[variant];
2367
+ const ring = ringStyle(variant);
2274
2368
  const glowStyle = glow ? glowStyles[variant] : null;
2275
2369
  const dot = /* @__PURE__ */ jsx(
2276
2370
  reactNative.View,
@@ -2284,22 +2378,22 @@ function StatusDot({
2284
2378
  justifyContent: "center",
2285
2379
  flexShrink: 0
2286
2380
  },
2287
- solid ? { backgroundColor: solidVariantColors[variant] } : void 0,
2288
- ring ? ring : void 0,
2381
+ solid ? { backgroundColor: resolveColor(solidFillToken[variant]) } : void 0,
2382
+ ring,
2289
2383
  glowStyle ? glowStyle : void 0
2290
2384
  ],
2291
2385
  accessibilityRole: "image",
2292
2386
  accessibilityLabel: `${variant} status`,
2293
2387
  testID: "status-dot",
2294
- children: config.showIcon && icon && /* @__PURE__ */ jsx(
2295
- reactNative.Text,
2388
+ children: config.showIcon && icon && // The glyph was 11px/900, off the type scale (TOKENS.md §4); `boldLabel` is
2389
+ // the 12px sans label step and `font-black` keeps the original weight.
2390
+ /* @__PURE__ */ jsx(
2391
+ Typography,
2296
2392
  {
2297
- style: {
2298
- fontSize: 11,
2299
- lineHeight: 11,
2300
- fontWeight: "900",
2301
- color: iconColors[variant]
2302
- },
2393
+ variant: "boldLabel",
2394
+ color: "inherit",
2395
+ className: "font-black leading-none",
2396
+ style: { color: resolveColor(glyphToken[variant]) },
2303
2397
  accessibilityElementsHidden: true,
2304
2398
  children: iconChars[icon]
2305
2399
  }
@@ -2317,9 +2411,11 @@ function StatusDot({
2317
2411
  children: [
2318
2412
  /* @__PURE__ */ jsx(reactNative.View, { accessibilityElementsHidden: true, children: dot }),
2319
2413
  /* @__PURE__ */ jsx(
2320
- reactNative.Text,
2414
+ Typography,
2321
2415
  {
2322
- style: { fontSize: 12, lineHeight: 16, color: greyRamp[400] },
2416
+ variant: "caption",
2417
+ color: "secondary",
2418
+ className: "leading-4",
2323
2419
  accessibilityElementsHidden: true,
2324
2420
  children: label
2325
2421
  }
@@ -2335,13 +2431,13 @@ var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
2335
2431
 
2336
2432
  // src/components/custom/Workout/MesoStatusCard.tsx
2337
2433
  var t3 = getSemanticColors("dark");
2338
- var BRAND_PRIMARY4 = t3["brand-primary"];
2434
+ var BRAND_PRIMARY3 = t3["brand-primary"];
2339
2435
  var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
2340
2436
  var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
2341
2437
  var SUCCESS = t3["status-success"];
2342
2438
  var WARNING = t3["status-warning"];
2343
2439
  var ERROR = t3["status-error"];
2344
- var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY4, BRAND_PRIMARY_LIGHT];
2440
+ var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY3, BRAND_PRIMARY_LIGHT];
2345
2441
  var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
2346
2442
  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%)";
2347
2443
  var STATUS_VARIANTS = {
@@ -2366,15 +2462,7 @@ function renderCoachingText(text, highlights) {
2366
2462
  if (escaped.length === 0) return text;
2367
2463
  const regex = new RegExp(`(${escaped.join("|")})`, "g");
2368
2464
  return text.split(regex).map(
2369
- (part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(
2370
- reactNative.Text,
2371
- {
2372
- className: "text-text-primary",
2373
- style: { fontWeight: "700" },
2374
- children: part
2375
- },
2376
- `${part}-${index}`
2377
- ) : /* @__PURE__ */ jsx(react.Fragment, { children: part }, `t-${index}`)
2465
+ (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}`)
2378
2466
  );
2379
2467
  }
2380
2468
  function StatusPill({ badge }) {
@@ -2459,41 +2547,34 @@ function Gauge({ gauge }) {
2459
2547
  "aria-valuemax": 100,
2460
2548
  testID: "meso-status-card-gauge",
2461
2549
  children: [
2462
- /* @__PURE__ */ jsxs(
2463
- reactNative.View,
2464
- {
2465
- className: "flex-row items-center justify-between",
2466
- accessibilityElementsHidden: true,
2467
- children: [
2468
- /* @__PURE__ */ jsx(
2469
- reactNative.Text,
2470
- {
2471
- className: "text-text-secondary",
2472
- style: {
2473
- fontSize: 10,
2474
- fontFamily: "Inter, sans-serif",
2475
- fontWeight: "500",
2476
- letterSpacing: 0.5,
2477
- textTransform: "uppercase"
2478
- },
2479
- children: gauge.label
2480
- }
2481
- ),
2482
- gauge.sublabel != null && /* @__PURE__ */ jsx(
2483
- reactNative.Text,
2484
- {
2485
- className: "text-text-tertiary",
2486
- style: {
2487
- fontSize: 10,
2488
- fontFamily: "Inter, sans-serif",
2489
- fontWeight: "500"
2490
- },
2491
- children: gauge.sublabel
2492
- }
2493
- )
2494
- ]
2495
- }
2496
- ),
2550
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center justify-between", accessibilityElementsHidden: true, children: [
2551
+ /* @__PURE__ */ jsx(
2552
+ reactNative.Text,
2553
+ {
2554
+ className: "text-text-secondary",
2555
+ style: {
2556
+ fontSize: 10,
2557
+ fontFamily: "Inter, sans-serif",
2558
+ fontWeight: "500",
2559
+ letterSpacing: 0.5,
2560
+ textTransform: "uppercase"
2561
+ },
2562
+ children: gauge.label
2563
+ }
2564
+ ),
2565
+ gauge.sublabel != null && /* @__PURE__ */ jsx(
2566
+ reactNative.Text,
2567
+ {
2568
+ className: "text-text-tertiary",
2569
+ style: {
2570
+ fontSize: 10,
2571
+ fontFamily: "Inter, sans-serif",
2572
+ fontWeight: "500"
2573
+ },
2574
+ children: gauge.sublabel
2575
+ }
2576
+ )
2577
+ ] }),
2497
2578
  /* @__PURE__ */ jsxs(
2498
2579
  reactNative.View,
2499
2580
  {
@@ -2534,7 +2615,8 @@ function Gauge({ gauge }) {
2534
2615
  borderRadius: 9999,
2535
2616
  borderWidth: 2,
2536
2617
  backgroundColor: markerColor,
2537
- boxShadow: "0 0 4px rgba(0,0,0,0.5)"
2618
+ // A knob resting on the gauge: lift, with the ring as its edge.
2619
+ ...liftStyle(1, "dark", { rim: 0 })
2538
2620
  },
2539
2621
  testID: "meso-status-card-gauge-marker"
2540
2622
  }
@@ -2586,30 +2668,23 @@ function MesoStatusCard({
2586
2668
  ),
2587
2669
  /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 14, gap: 14 }, testID: "meso-status-card-body", children: [
2588
2670
  /* @__PURE__ */ jsxs(reactNative.View, { testID: "meso-status-card-header", children: [
2589
- /* @__PURE__ */ jsxs(
2590
- reactNative.View,
2591
- {
2592
- className: "flex-row items-center justify-between",
2593
- style: { gap: 8 },
2594
- children: [
2595
- /* @__PURE__ */ jsx(
2596
- reactNative.Text,
2597
- {
2598
- className: "text-text-primary",
2599
- style: {
2600
- flexShrink: 1,
2601
- fontSize: 15,
2602
- fontFamily: '"Space Grotesk", sans-serif',
2603
- fontWeight: "700"
2604
- },
2605
- testID: "meso-status-card-name",
2606
- children: mesoName
2607
- }
2608
- ),
2609
- /* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
2610
- ]
2611
- }
2612
- ),
2671
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center justify-between", style: { gap: 8 }, children: [
2672
+ /* @__PURE__ */ jsx(
2673
+ reactNative.Text,
2674
+ {
2675
+ className: "text-text-primary",
2676
+ style: {
2677
+ flexShrink: 1,
2678
+ fontSize: 15,
2679
+ fontFamily: '"Space Grotesk", sans-serif',
2680
+ fontWeight: "700"
2681
+ },
2682
+ testID: "meso-status-card-name",
2683
+ children: mesoName
2684
+ }
2685
+ ),
2686
+ /* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
2687
+ ] }),
2613
2688
  /* @__PURE__ */ jsx(
2614
2689
  reactNative.Text,
2615
2690
  {
@@ -2624,15 +2699,7 @@ function MesoStatusCard({
2624
2699
  }
2625
2700
  )
2626
2701
  ] }),
2627
- metrics.length > 0 && /* @__PURE__ */ jsx(
2628
- reactNative.View,
2629
- {
2630
- className: "flex-row flex-wrap",
2631
- style: { gap: 8 },
2632
- testID: "meso-status-card-metrics",
2633
- children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell, { metric }, `${metric.label}-${index}`))
2634
- }
2635
- ),
2702
+ 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(MetricCell, { metric }, `${metric.label}-${index}`)) }),
2636
2703
  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}`)) }),
2637
2704
  coaching != null && /* @__PURE__ */ jsx(
2638
2705
  reactNative.View,