@titan-design/react-ui 0.12.1 → 0.14.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 (531) hide show
  1. package/README.md +60 -47
  2. package/dist/bodymap.js +856 -736
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +858 -738
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1431 -237
  7. package/dist/index.d.ts +1431 -237
  8. package/dist/index.js +6506 -4781
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +6280 -4642
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-B1hqnGIC.d.ts → pages-CsjsUn0G.d.ts} +51 -16
  13. package/dist/{pages-CvsFqNtx.d.mts → pages-ZbT_pD_U.d.mts} +51 -16
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1919 -1937
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1927 -1945
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +225 -140
  21. package/dist/theme/index.d.ts +225 -140
  22. package/dist/theme/index.js +298 -319
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +283 -315
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +145 -24
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +145 -24
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +128 -11
  31. package/dist/theme/tokens.d.ts +128 -11
  32. package/dist/theme/tokens.js +126 -26
  33. package/dist/theme/tokens.js.map +1 -1
  34. package/dist/theme/tokens.mjs +124 -27
  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/docs/render-testing-pattern.md +130 -0
  40. package/package.json +1 -1
  41. package/src/arch/Architecture.stories.tsx +3 -1
  42. package/src/arch/arch-graph.freshness.test.ts +52 -0
  43. package/src/arch/arch-graph.json +4989 -1583
  44. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  45. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  46. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  48. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  49. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  51. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  52. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  54. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  55. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  57. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  58. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  60. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  61. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  63. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  64. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +182 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  66. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  67. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  69. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  70. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  71. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  73. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  74. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  76. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  77. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  78. package/src/components/custom/ActiveWork/README.md +305 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  80. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  81. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  82. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  83. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  84. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  86. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  87. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  88. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  90. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  91. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  92. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  93. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  94. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  95. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  96. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  97. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  98. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  99. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  100. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  101. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  102. package/src/components/custom/ActiveWork/index.ts +19 -0
  103. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  104. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  105. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  106. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  107. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +12 -6
  108. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  109. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  110. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  111. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  112. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  113. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  116. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  117. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  119. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  120. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  121. package/src/components/custom/Fatigue/README.md +40 -3
  122. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  123. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  124. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  125. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  126. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  127. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  128. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  129. package/src/components/custom/Fatigue/index.ts +17 -5
  130. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  131. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  132. package/src/components/custom/Gauge/Gauge.stories.tsx +6 -3
  133. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  134. package/src/components/custom/Gauge/Gauge.tsx +7 -2
  135. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  136. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  137. package/src/components/custom/Metric/Metric.tsx +5 -20
  138. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  139. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  140. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  141. package/src/components/custom/Prose/README.md +58 -0
  142. package/src/components/custom/Prose/index.ts +1 -0
  143. package/src/components/custom/Scatter/Scatter.stories.tsx +55 -14
  144. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  145. package/src/components/custom/Scatter/Scatter.tsx +122 -18
  146. package/src/components/custom/Sidebar/Sidebar.stories.tsx +41 -8
  147. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  148. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  149. package/src/components/custom/Table/Table.stories.tsx +99 -16
  150. package/src/components/custom/Table/Table.test.tsx +273 -86
  151. package/src/components/custom/Table/Table.tsx +159 -67
  152. package/src/components/custom/Table/column-fit.test.ts +75 -0
  153. package/src/components/custom/Table/column-fit.ts +116 -0
  154. package/src/components/custom/Table/index.ts +9 -0
  155. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  156. package/src/components/custom/Treemap/Treemap.stories.tsx +15 -12
  157. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  158. package/src/components/custom/Treemap/Treemap.tsx +11 -3
  159. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  160. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  161. package/src/components/custom/Typography/Typography.tsx +6 -0
  162. package/src/components/custom/Typography/index.ts +1 -8
  163. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +11 -2
  164. package/src/components/custom/Workout/BaseBadge.stories.tsx +27 -11
  165. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  166. package/src/components/custom/Workout/BaseBadge.tsx +6 -2
  167. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  168. package/src/components/custom/Workout/BodyMap.tsx +8 -4
  169. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +28 -6
  170. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  171. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +50 -12
  172. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +12 -9
  173. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  174. package/src/components/custom/Workout/CapacityBandChart.tsx +144 -111
  175. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  176. package/src/components/custom/Workout/DeviationBar.test.tsx +10 -4
  177. package/src/components/custom/Workout/DeviationBar.tsx +24 -16
  178. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +183 -0
  179. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +32 -18
  180. package/src/components/custom/Workout/ExerciseCard.stories.tsx +12 -11
  181. package/src/components/custom/Workout/ExerciseCard.test.tsx +52 -22
  182. package/src/components/custom/Workout/ExerciseCard.tsx +99 -183
  183. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +95 -12
  184. package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
  185. package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
  186. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  187. package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
  188. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  189. package/src/components/custom/Workout/ExerciseHeading.tsx +194 -46
  190. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +12 -9
  191. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  192. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  193. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  194. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  195. package/src/components/custom/Workout/InputBar.tsx +4 -2
  196. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  197. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  198. package/src/components/custom/Workout/IntensityBar.tsx +8 -3
  199. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  200. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  201. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  202. package/src/components/custom/Workout/MesoCard.tsx +14 -10
  203. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  204. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  205. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  206. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  207. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  208. package/src/components/custom/Workout/MesoStatusCard.tsx +20 -33
  209. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  210. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  211. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  212. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  213. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +9 -4
  214. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  215. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  216. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  217. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  218. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  219. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +16 -3
  220. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  221. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  222. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  223. package/src/components/custom/Workout/README.md +68 -17
  224. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  225. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  226. package/src/components/custom/Workout/ReadinessCheck.tsx +22 -4
  227. package/src/components/custom/Workout/RestTimer.stories.tsx +16 -4
  228. package/src/components/custom/Workout/RestTimer.tsx +4 -2
  229. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  230. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  231. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  232. package/src/components/custom/Workout/SegmentedBar.stories.tsx +21 -17
  233. package/src/components/custom/Workout/SegmentedBar.tsx +10 -5
  234. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  235. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  236. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  237. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  238. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  239. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  240. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  241. package/src/components/custom/Workout/SetBar.tsx +38 -12
  242. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  243. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  244. package/src/components/custom/Workout/SetRow.tsx +61 -23
  245. package/src/components/custom/Workout/SetStrip.stories.tsx +63 -7
  246. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  247. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  248. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  249. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  250. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  251. package/src/components/custom/Workout/SetsRepsLoad.tsx +24 -12
  252. package/src/components/custom/Workout/Sparkline.stories.tsx +14 -11
  253. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  254. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  255. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  256. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  257. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  258. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  259. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  260. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  261. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +11 -4
  262. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  263. package/src/components/custom/Workout/StrengthTrendChart.tsx +39 -36
  264. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  265. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  266. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  267. package/src/components/custom/Workout/TempoDisplay.stories.tsx +26 -10
  268. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  269. package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
  270. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  271. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  272. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +10 -6
  273. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +5 -2
  274. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +44 -1
  275. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  276. package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
  277. package/src/components/custom/Workout/VelocityStrip.tsx +26 -14
  278. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  279. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  280. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  281. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  282. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  283. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  284. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  285. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  286. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  287. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  288. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  289. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  290. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  291. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  292. package/src/components/custom/Workout/ZoneTrack.stories.tsx +10 -7
  293. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  294. package/src/components/custom/Workout/exerciseRowState.ts +29 -0
  295. package/src/components/custom/Workout/index.ts +17 -2
  296. package/src/components/custom/Workout/metricText.stories.tsx +15 -13
  297. package/src/components/custom/Workout/metricText.tsx +8 -2
  298. package/src/components/custom/Workout/setHeadingKit.tsx +219 -36
  299. package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
  300. package/src/components/custom/charts/README.md +66 -0
  301. package/src/components/custom/charts/SetBarChart.test.tsx +46 -1
  302. package/src/components/custom/charts/SetBarChart.tsx +56 -9
  303. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  304. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  305. package/src/components/custom/charts/SparkBars.tsx +85 -0
  306. package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
  307. package/src/components/custom/charts/flatBarGeometry.ts +32 -0
  308. package/src/components/custom/charts/index.ts +3 -0
  309. package/src/components/custom/index.ts +3 -0
  310. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  311. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  312. package/src/components/custom/stepper/Stepper.tsx +21 -34
  313. package/src/components/icons/icons.stories.tsx +1 -1
  314. package/src/components/icons/icons.tsx +51 -0
  315. package/src/components/shell/AppShell.stories.tsx +150 -0
  316. package/src/components/shell/AppShell.test.tsx +70 -0
  317. package/src/components/shell/AppShell.tsx +90 -0
  318. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  319. package/src/components/shell/BrandLockup.test.tsx +34 -1
  320. package/src/components/shell/BrandLockup.tsx +27 -11
  321. package/src/components/shell/NavItem.stories.tsx +4 -4
  322. package/src/components/shell/NavItem.test.tsx +17 -0
  323. package/src/components/shell/NavItem.tsx +17 -5
  324. package/src/components/shell/README.md +89 -26
  325. package/src/components/shell/SideNav.stories.tsx +38 -7
  326. package/src/components/shell/SideNav.test.tsx +16 -8
  327. package/src/components/shell/SideNav.tsx +17 -17
  328. package/src/components/shell/TopBar.stories.tsx +44 -19
  329. package/src/components/shell/TopBar.test.tsx +34 -12
  330. package/src/components/shell/TopBar.tsx +61 -40
  331. package/src/components/shell/brands.tsx +66 -0
  332. package/src/components/shell/index.ts +9 -8
  333. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  334. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  335. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  336. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  337. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  338. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  339. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  340. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  341. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  342. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  343. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  344. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  345. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  346. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  347. package/src/components/shell/workout/index.ts +9 -0
  348. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  349. package/src/components/ui/README.md +110 -0
  350. package/src/components/ui/alert/Alert.stories.tsx +15 -5
  351. package/src/components/ui/alert/Alert.tsx +24 -3
  352. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  353. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  354. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  355. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  356. package/src/components/ui/avatar/Avatar.tsx +2 -10
  357. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  358. package/src/components/ui/badge/Badge.test.tsx +19 -3
  359. package/src/components/ui/badge/Badge.tsx +48 -55
  360. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  361. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  362. package/src/components/ui/button/Button.stories.tsx +46 -12
  363. package/src/components/ui/button/Button.tsx +44 -37
  364. package/src/components/ui/card/Card.stories.tsx +90 -94
  365. package/src/components/ui/card/Card.test.tsx +80 -6
  366. package/src/components/ui/card/Card.tsx +150 -203
  367. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  368. package/src/components/ui/checkbox/Checkbox.tsx +7 -27
  369. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  370. package/src/components/ui/chip/Chip.test.tsx +10 -6
  371. package/src/components/ui/chip/Chip.tsx +76 -91
  372. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  373. package/src/components/ui/collapse/Collapse.tsx +6 -11
  374. package/src/components/ui/data-row/DataRow.stories.tsx +14 -3
  375. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  376. package/src/components/ui/data-row/DataRow.tsx +18 -7
  377. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  378. package/src/components/ui/divider/Divider.tsx +1 -5
  379. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  380. package/src/components/ui/drawer/Drawer.tsx +13 -27
  381. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  382. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  383. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  384. package/src/components/ui/form-field/FormField.tsx +10 -46
  385. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  386. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  387. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  388. package/src/components/ui/help-tip/index.ts +7 -1
  389. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  390. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  391. package/src/components/ui/icon-box/IconBox.tsx +10 -18
  392. package/src/components/ui/indicator/Indicator.stories.tsx +5 -4
  393. package/src/components/ui/indicator/Indicator.tsx +20 -14
  394. package/src/components/ui/input/Input.stories.tsx +3 -11
  395. package/src/components/ui/input/Input.test.tsx +2 -10
  396. package/src/components/ui/input/Input.tsx +10 -25
  397. package/src/components/ui/input/index.ts +7 -1
  398. package/src/components/ui/link/Link.stories.tsx +19 -7
  399. package/src/components/ui/list-item/ListItem.stories.tsx +17 -5
  400. package/src/components/ui/list-item/ListItem.tsx +2 -9
  401. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  402. package/src/components/ui/menu/Menu.test.tsx +2 -11
  403. package/src/components/ui/menu/Menu.tsx +12 -14
  404. package/src/components/ui/menu/index.ts +8 -1
  405. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  406. package/src/components/ui/modal/Modal.tsx +31 -19
  407. package/src/components/ui/pill/Pill.stories.tsx +111 -23
  408. package/src/components/ui/pill/Pill.test.tsx +101 -3
  409. package/src/components/ui/pill/Pill.tsx +168 -49
  410. package/src/components/ui/pill/index.ts +1 -1
  411. package/src/components/ui/popover/Popover.stories.tsx +6 -8
  412. package/src/components/ui/popover/Popover.test.tsx +1 -6
  413. package/src/components/ui/popover/Popover.tsx +20 -15
  414. package/src/components/ui/popover/index.ts +7 -1
  415. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  416. package/src/components/ui/progress/Progress.test.tsx +1 -5
  417. package/src/components/ui/progress/Progress.tsx +9 -6
  418. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  419. package/src/components/ui/radio/Radio.test.tsx +6 -2
  420. package/src/components/ui/radio/Radio.tsx +23 -22
  421. package/src/components/ui/section/Section.stories.tsx +12 -21
  422. package/src/components/ui/section/Section.test.tsx +1 -6
  423. package/src/components/ui/section/Section.tsx +1 -3
  424. package/src/components/ui/section/index.ts +1 -5
  425. package/src/components/ui/select/Select.stories.tsx +3 -13
  426. package/src/components/ui/select/Select.test.tsx +2 -11
  427. package/src/components/ui/select/Select.tsx +16 -15
  428. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  429. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  430. package/src/components/ui/skeleton/index.ts +1 -7
  431. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  432. package/src/components/ui/spinner/Spinner.tsx +4 -5
  433. package/src/components/ui/stack/Stack.stories.tsx +8 -8
  434. package/src/components/ui/stack/Stack.tsx +1 -1
  435. package/src/components/ui/surface/Surface.stories.tsx +92 -33
  436. package/src/components/ui/surface/Surface.test.tsx +88 -28
  437. package/src/components/ui/surface/Surface.tsx +37 -87
  438. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  439. package/src/components/ui/surface/index.ts +8 -0
  440. package/src/components/ui/surface/resolveSurface.ts +98 -0
  441. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  442. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  443. package/src/components/ui/switch/Switch.tsx +7 -6
  444. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  445. package/src/components/ui/tabs/Tabs.tsx +8 -21
  446. package/src/components/ui/tabs/index.ts +1 -7
  447. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  448. package/src/components/ui/tile/Tile.tsx +3 -0
  449. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  450. package/src/components/ui/toast/Toast.test.tsx +2 -8
  451. package/src/components/ui/toast/Toast.tsx +49 -57
  452. package/src/components/ui/toast/index.ts +0 -1
  453. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  454. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  455. package/src/components/ui/toolbar-button/ToolbarButton.tsx +38 -49
  456. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  457. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  458. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  459. package/src/components/ui/tooltip/index.ts +1 -1
  460. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  461. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  462. package/src/components/ui/trigger/index.ts +2 -0
  463. package/src/stories/PresetShowcase.stories.tsx +101 -48
  464. package/src/test/no-device-internals.test.ts +3 -3
  465. package/src/test/no-raw-color.test.ts +39 -0
  466. package/src/theme/Alpha.stories.tsx +103 -0
  467. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  468. package/src/theme/ColorPalettes.stories.tsx +62 -45
  469. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  470. package/src/theme/Depth.stories.tsx +132 -65
  471. package/src/theme/DepthCalibration.stories.tsx +23 -21
  472. package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
  473. package/src/theme/ThemeProvider.test.tsx +4 -4
  474. package/src/theme/barrel.ts +7 -6
  475. package/src/theme/color-stories.coverage.test.ts +1 -1
  476. package/src/theme/color-utils.ts +41 -29
  477. package/src/theme/config.completeness.test.ts +1 -1
  478. package/src/theme/config.ts +40 -0
  479. package/src/theme/elevation.test.ts +82 -56
  480. package/src/theme/elevation.ts +77 -561
  481. package/src/theme/global.css +45 -5
  482. package/src/theme/grey-ramp.test.ts +24 -8
  483. package/src/theme/lift.test.ts +39 -0
  484. package/src/theme/lift.ts +102 -0
  485. package/src/theme/materials.test.ts +5 -2
  486. package/src/theme/materials.ts +38 -4
  487. package/src/theme/native-theming-guard.test.ts +5 -5
  488. package/src/theme/presets/apply.ts +4 -0
  489. package/src/theme/presets/audiobook.ts +5 -2
  490. package/src/theme/presets/default.ts +4 -0
  491. package/src/theme/presets/index.ts +14 -1
  492. package/src/theme/presets/types.ts +1 -1
  493. package/src/theme/semantic-contrast.test.ts +13 -4
  494. package/src/theme/status-distinctness.test.ts +66 -0
  495. package/src/theme/subtle-tone-weight.test.ts +163 -0
  496. package/src/theme/surface-planes.test.ts +37 -0
  497. package/src/theme/surface-planes.ts +68 -0
  498. package/src/theme/tailwind-var-opacity.test.ts +163 -0
  499. package/src/theme/token-export-guard.test.ts +1 -3
  500. package/src/theme/tokens/primitives.test.ts +15 -7
  501. package/src/theme/tokens/primitives.ts +98 -33
  502. package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
  503. package/src/theme/tokens/semantic.ts +124 -54
  504. package/src/theme/wash-ladder.test.ts +58 -0
  505. package/src/theme/workout-tokens.ts +1 -7
  506. package/src/types/jest-axe.d.ts +2 -6
  507. package/src/types/raw-md.d.ts +5 -0
  508. package/src/utils/colors.alpha-adoption.test.ts +408 -0
  509. package/src/utils/colors.ts +4 -4
  510. package/src/utils/form.ts +1 -3
  511. package/src/utils/index.ts +2 -7
  512. package/src/utils/number-format.ts +17 -0
  513. package/src/utils/workout-format.ts +15 -6
  514. package/src/web-jsx/jsx-runtime.ts +1 -5
  515. package/tailwind.config.js +55 -9
  516. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  517. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  518. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  519. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  520. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  521. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  522. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  523. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  524. package/src/components/shell/DashboardShell.tsx +0 -75
  525. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  526. package/src/theme/elevation.stories.tsx +0 -346
  527. package/src/utils/useTheme.ts +0 -72
  528. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  529. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  530. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  531. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
package/dist/bodymap.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { useMemo, useState, useEffect, Fragment as Fragment$1, useSyncExternalStore } from 'react';
1
+ import { createContext, useMemo, useState, useEffect, Fragment, useContext } from 'react';
2
2
  import { Platform, Animated, Easing, View, Text, Pressable, ScrollView } from 'react-native';
3
3
  import BodyHighlighter from 'react-native-body-highlighter';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
- import { Fragment, jsx as jsx$1, jsxs as jsxs$1 } from 'react/jsx-runtime';
6
+ import { Fragment as Fragment$1, jsx as jsx$1, jsxs as jsxs$1 } from 'react/jsx-runtime';
7
7
 
8
8
  // src/components/custom/Workout/BodyMap.tsx
9
9
  function cn(...inputs) {
@@ -12,7 +12,29 @@ function cn(...inputs) {
12
12
 
13
13
  // src/theme/tokens/primitives.ts
14
14
  var primitiveColors = {
15
- white: "#FFFFFF"};
15
+ white: "#FFFFFF",
16
+ black: "#000000"};
17
+ var alertRedVivid = "#FF4757";
18
+ var resultPaletteColors = {
19
+ improve: "#4caf50",
20
+ improveDark: "#248a24",
21
+ degrade: "#ef5350",
22
+ degradeDark: "#b30000",
23
+ inconclusive: "#9E9A97"
24
+ };
25
+ var semanticPins = {
26
+ // Cool navy-black; darker and more blue-shifted than any warm greyRamp step.
27
+ textPrimaryLight: "#121828",
28
+ // Cool blue-grey; outside greyRamp's warm (R>=G>=B) scale.
29
+ textSecondaryLight: "#65748B",
30
+ // Pure neutral grey (R=G=B); no warm greyRamp step lands on it exactly.
31
+ backgroundBaseLight: "#EBEBEB",
32
+ // Near-neutral grey, kept one step off backgroundBaseLight by design.
33
+ dividerLight: "#E8E9EB",
34
+ // Periwinkle/indigo; more purple than any primitiveRamps.blue step. Shared by
35
+ // dark-mode text-link, border-focus and border-input-focus.
36
+ focusIndigoDark: "#828DF8"
37
+ };
16
38
  var greyRamp = {
17
39
  50: "#F9F6F3",
18
40
  // L*97.0 W6
@@ -46,6 +68,7 @@ var greyRamp = {
46
68
  var primitiveRamps = {
47
69
  red: {
48
70
  50: "#FFF4F4",
71
+ 400: "#F77175",
49
72
  500: "#E05254",
50
73
  600: "#D14343",
51
74
  // pin
@@ -135,22 +158,34 @@ var semanticColorsLight = {
135
158
  "brand-primary-light": primitiveRamps.orange[300],
136
159
  "brand-primary-dark": primitiveRamps.orange[500],
137
160
  "brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
161
+ "brand-primary-muted": "rgba(255, 121, 0, 0.30)",
162
+ "brand-primary-strong": "rgba(255, 121, 0, 0.50)",
138
163
  "brand-primary-hover": primitiveRamps.orange[500],
139
164
  "brand-primary-active": primitiveRamps.orange[600],
140
165
  "brand-secondary": primitiveRamps.cyan[600],
141
166
  "brand-secondary-light": primitiveRamps.cyan[500],
142
167
  "brand-secondary-dark": primitiveRamps.cyan[700],
143
168
  "brand-secondary-subtle": "rgba(48, 123, 155, 0.08)",
169
+ "brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
170
+ "brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
144
171
  "brand-secondary-hover": primitiveRamps.cyan[700],
145
172
  "brand-secondary-active": primitiveRamps.cyan[800],
146
173
  // Text on brand backgrounds (on-*)
147
174
  "on-brand-primary": primitiveColors.white,
148
175
  "on-brand-secondary": primitiveColors.white,
176
+ // Text ON a `-subtle` fill. Light mode keeps today's pairing (the base token) so
177
+ // nothing moves here: light has the same disease mirrored — a light rung on a
178
+ // near-white ramp[50] fill — but correcting it belongs with the light-mode pass
179
+ // in AW-121, not this one.
180
+ "on-brand-primary-subtle": primitiveRamps.orange[400],
181
+ "on-brand-secondary-subtle": primitiveRamps.cyan[600],
149
182
  // Status colors (status-*)
150
183
  "status-success": primitiveRamps.green[300],
151
184
  "status-success-light": primitiveRamps.green[200],
152
185
  "status-success-dark": primitiveRamps.green[600],
153
186
  "status-success-subtle": primitiveRamps.green[50],
187
+ "status-success-muted": "rgba(46, 213, 115, 0.30)",
188
+ "status-success-strong": "rgba(46, 213, 115, 0.50)",
154
189
  // Live-session accent — its OWN role, decoupled from success so the two can diverge
155
190
  "status-live": primitiveRamps.green[300],
156
191
  "status-live-muted": primitiveRamps.green[500],
@@ -158,34 +193,47 @@ var semanticColorsLight = {
158
193
  "status-error-light": primitiveRamps.red[500],
159
194
  "status-error-dark": primitiveRamps.red[700],
160
195
  "status-error-subtle": primitiveRamps.red[50],
161
- "status-error-vivid": primitiveRamps.red[600],
162
- // vivid alert red
196
+ "status-error-muted": "rgba(209, 67, 67, 0.30)",
197
+ "status-error-strong": "rgba(209, 67, 67, 0.50)",
198
+ "status-error-vivid": alertRedVivid,
199
+ // NOT red[600], that is status-error
163
200
  "status-error-vivid-light": primitiveRamps.red[500],
164
201
  "status-error-vivid-dark": primitiveRamps.red[700],
165
202
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
203
+ "status-error-vivid-muted": "rgba(255, 71, 87, 0.30)",
204
+ "status-error-vivid-strong": "rgba(255, 71, 87, 0.50)",
166
205
  "status-warning": primitiveRamps.amber[300],
167
206
  "status-warning-light": primitiveRamps.amber[200],
168
207
  "status-warning-dark": primitiveRamps.amber[500],
169
208
  "status-warning-subtle": primitiveRamps.amber[50],
209
+ "status-warning-muted": "rgba(249, 180, 21, 0.30)",
210
+ "status-warning-strong": "rgba(249, 180, 21, 0.50)",
170
211
  "status-info": primitiveRamps.blue[500],
171
212
  "status-info-light": primitiveRamps.blue[300],
172
213
  "status-info-dark": primitiveRamps.blue[600],
173
214
  "status-info-subtle": primitiveRamps.blue[50],
215
+ "status-info-muted": "rgba(33, 150, 243, 0.30)",
216
+ "status-info-strong": "rgba(33, 150, 243, 0.50)",
217
+ // Text ON a `-subtle` fill — see the on-brand-*-subtle note above.
218
+ "on-status-success-subtle": primitiveRamps.green[300],
219
+ "on-status-error-subtle": primitiveRamps.red[600],
220
+ "on-status-warning-subtle": primitiveRamps.amber[300],
221
+ "on-status-info-subtle": primitiveRamps.blue[500],
174
222
  // Text on status backgrounds (on-status-*)
175
223
  "on-status-success": primitiveColors.white,
176
224
  "on-status-error": primitiveColors.white,
177
225
  "on-status-warning": primitiveColors.white,
178
226
  "on-status-info": primitiveColors.white,
179
227
  // Result/outcome indicators (result-*)
180
- "result-improve": "#4caf50",
228
+ "result-improve": resultPaletteColors.improve,
181
229
  // Green - positive outcome
182
230
  "result-improve-light": "rgba(76, 175, 80, 0.12)",
183
- "result-improve-dark": "#248a24",
184
- "result-degrade": "#ef5350",
231
+ "result-improve-dark": resultPaletteColors.improveDark,
232
+ "result-degrade": resultPaletteColors.degrade,
185
233
  // Red - negative outcome
186
234
  "result-degrade-light": "rgba(239, 83, 80, 0.12)",
187
- "result-degrade-dark": "#b30000",
188
- "result-inconclusive": "#9E9A97",
235
+ "result-degrade-dark": resultPaletteColors.degradeDark,
236
+ "result-inconclusive": resultPaletteColors.inconclusive,
189
237
  // Gray - no clear result
190
238
  "result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
191
239
  "result-neutral": greyRamp[600],
@@ -217,8 +265,8 @@ var semanticColorsLight = {
217
265
  "data-10": discreteRainbow[22],
218
266
  // Dark Orange
219
267
  // Text colors (text-*)
220
- "text-primary": "#121828",
221
- "text-secondary": "#65748B",
268
+ "text-primary": semanticPins.textPrimaryLight,
269
+ "text-secondary": semanticPins.textSecondaryLight,
222
270
  "text-tertiary": greyRamp[400],
223
271
  "text-disabled": "rgba(55, 65, 81, 0.48)",
224
272
  "text-inverse": primitiveColors.white,
@@ -234,7 +282,7 @@ var semanticColorsLight = {
234
282
  "surface-input": greyRamp[50],
235
283
  // Input field background (filled variant)
236
284
  // Background colors (background-*)
237
- "background-base": "#EBEBEB",
285
+ "background-base": semanticPins.backgroundBaseLight,
238
286
  "background-default": primitiveColors.white,
239
287
  "background-subtle": greyRamp[50],
240
288
  // Frame/bezel chrome — top bar + side nav shell, one step below
@@ -265,7 +313,7 @@ var semanticColorsLight = {
265
313
  "interactive-disabled": "rgba(55, 65, 81, 0.12)",
266
314
  "interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
267
315
  // Divider
268
- "divider": "#E8E9EB",
316
+ divider: semanticPins.dividerLight,
269
317
  // Avatar default
270
318
  "avatar-background": greyRamp[600],
271
319
  "avatar-text": primitiveColors.white
@@ -276,54 +324,87 @@ var semanticColorsDark = {
276
324
  "brand-primary-light": primitiveRamps.orange[300],
277
325
  "brand-primary-dark": primitiveRamps.orange[500],
278
326
  "brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
327
+ "brand-primary-muted": "rgba(255, 121, 0, 0.30)",
328
+ "brand-primary-strong": "rgba(255, 121, 0, 0.50)",
279
329
  "brand-primary-hover": primitiveRamps.orange[300],
280
330
  "brand-primary-active": primitiveRamps.orange[200],
281
331
  "brand-secondary": primitiveRamps.cyan[600],
282
332
  "brand-secondary-light": primitiveRamps.cyan[500],
283
333
  "brand-secondary-dark": primitiveRamps.cyan[700],
284
- "brand-secondary-subtle": "rgba(48, 123, 155, 0.12)",
334
+ "brand-secondary-subtle": "rgba(34, 211, 238, 0.12)",
335
+ "brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
336
+ "brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
285
337
  "brand-secondary-hover": primitiveRamps.cyan[500],
286
338
  "brand-secondary-active": primitiveRamps.cyan[400],
287
339
  // Text on brand backgrounds
288
340
  "on-brand-primary": primitiveColors.white,
289
341
  "on-brand-secondary": primitiveColors.white,
342
+ // Text ON a `-subtle` fill. Its own role: `brand-primary` and friends are tuned to
343
+ // carry a white label as a solid fill, which makes the two deepest of them
344
+ // (cyan[600], red[600]) too dark to read as text on a dark plane. Levelling the
345
+ // family at rung 300 puts every tone within OKLCH L 0.769-0.813 instead of
346
+ // 0.550-0.813. Brand is deliberately left at its own orange[400] (operator, AW-133)
347
+ // so the Voltras tone never drifts; it is the one tone under AA on a raised card.
348
+ "on-brand-primary-subtle": primitiveRamps.orange[400],
349
+ "on-brand-secondary-subtle": primitiveRamps.cyan[300],
290
350
  // Status colors
291
351
  "status-success": primitiveRamps.green[300],
292
352
  "status-success-light": primitiveRamps.green[200],
293
353
  "status-success-dark": primitiveRamps.green[600],
294
354
  "status-success-subtle": "rgba(46, 213, 115, 0.12)",
355
+ "status-success-muted": "rgba(46, 213, 115, 0.30)",
356
+ "status-success-strong": "rgba(46, 213, 115, 0.50)",
295
357
  // Live-session accent — its OWN role, decoupled from success so the two can diverge
296
358
  "status-live": primitiveRamps.green[300],
297
359
  "status-live-muted": primitiveRamps.green[500],
298
360
  "status-error": primitiveRamps.red[600],
299
361
  "status-error-light": primitiveRamps.red[500],
300
362
  "status-error-dark": primitiveRamps.red[700],
301
- "status-error-subtle": "rgba(209, 67, 67, 0.12)",
302
- "status-error-vivid": primitiveRamps.red[600],
363
+ // Alpha 0.08, not the family's 0.12: error's label is red[400], a rung darker than
364
+ // its siblings so it reads RED rather than pink (rung 300 has only 0.121 chroma).
365
+ // Thinning the fill buys back the contrast that extra darkness costs. See AW-133.
366
+ "status-error-subtle": "rgba(247, 113, 117, 0.08)",
367
+ "status-error-muted": "rgba(209, 67, 67, 0.30)",
368
+ "status-error-strong": "rgba(209, 67, 67, 0.50)",
369
+ "status-error-vivid": alertRedVivid,
303
370
  "status-error-vivid-light": primitiveRamps.red[500],
304
371
  "status-error-vivid-dark": primitiveRamps.red[700],
305
372
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
373
+ "status-error-vivid-muted": "rgba(255, 71, 87, 0.30)",
374
+ "status-error-vivid-strong": "rgba(255, 71, 87, 0.50)",
306
375
  "status-warning": primitiveRamps.amber[300],
307
376
  "status-warning-light": primitiveRamps.amber[200],
308
377
  "status-warning-dark": primitiveRamps.amber[500],
309
378
  "status-warning-subtle": "rgba(249, 180, 21, 0.12)",
379
+ "status-warning-muted": "rgba(249, 180, 21, 0.30)",
380
+ "status-warning-strong": "rgba(249, 180, 21, 0.50)",
310
381
  "status-info": primitiveRamps.blue[500],
311
382
  "status-info-light": primitiveRamps.blue[300],
312
383
  "status-info-dark": primitiveRamps.blue[600],
313
- "status-info-subtle": "rgba(33, 150, 243, 0.12)",
384
+ "status-info-subtle": "rgba(120, 194, 255, 0.12)",
385
+ "status-info-muted": "rgba(33, 150, 243, 0.30)",
386
+ "status-info-strong": "rgba(33, 150, 243, 0.50)",
314
387
  // Text on status backgrounds
315
388
  "on-status-success": primitiveColors.white,
316
389
  "on-status-error": primitiveColors.white,
317
390
  "on-status-warning": primitiveColors.white,
318
391
  "on-status-info": primitiveColors.white,
392
+ // Text ON a `-subtle` fill — see the on-brand-*-subtle note above. Error is the
393
+ // second deliberate exception to the rung-300 rule (operator, AW-133): red[300]
394
+ // levelled perfectly but read PINK, because a red that light can only hold 0.121
395
+ // chroma. red[400] carries 0.165 and reads red; its fill is thinned to compensate.
396
+ "on-status-success-subtle": primitiveRamps.green[300],
397
+ "on-status-error-subtle": primitiveRamps.red[400],
398
+ "on-status-warning-subtle": primitiveRamps.amber[300],
399
+ "on-status-info-subtle": primitiveRamps.blue[300],
319
400
  // Result/outcome indicators (result-*)
320
- "result-improve": "#4caf50",
401
+ "result-improve": resultPaletteColors.improve,
321
402
  "result-improve-light": "rgba(76, 175, 80, 0.16)",
322
- "result-improve-dark": "#248a24",
323
- "result-degrade": "#ef5350",
403
+ "result-improve-dark": resultPaletteColors.improveDark,
404
+ "result-degrade": resultPaletteColors.degrade,
324
405
  "result-degrade-light": "rgba(239, 83, 80, 0.16)",
325
- "result-degrade-dark": "#b30000",
326
- "result-inconclusive": "#9E9A97",
406
+ "result-degrade-dark": resultPaletteColors.degradeDark,
407
+ "result-inconclusive": resultPaletteColors.inconclusive,
327
408
  "result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
328
409
  "result-neutral": greyRamp[400],
329
410
  // Text on result backgrounds
@@ -354,7 +435,7 @@ var semanticColorsDark = {
354
435
  "text-tertiary": greyRamp[500],
355
436
  "text-disabled": "rgba(255, 255, 255, 0.38)",
356
437
  "text-inverse": greyRamp[950],
357
- "text-link": "#828DF8",
438
+ "text-link": semanticPins.focusIndigoDark,
358
439
  "text-link-hover": primitiveRamps.blue[400],
359
440
  // Surface colors - dark backgrounds — warm-tapered DERIVED ramp (TD-surface-tokens,
360
441
  // S-1, re-spaced S-3). Shipped verbatim from `deriveSurfaceRamp()` — see
@@ -404,10 +485,10 @@ var semanticColorsDark = {
404
485
  // plane, so it keeps its job without collision.
405
486
  "border-prominent": greyRamp[800],
406
487
  // high-visibility divider
407
- "border-focus": "#828DF8",
488
+ "border-focus": semanticPins.focusIndigoDark,
408
489
  "border-input": greyRamp[700],
409
490
  "border-input-hover": greyRamp[600],
410
- "border-input-focus": "#828DF8",
491
+ "border-input-focus": semanticPins.focusIndigoDark,
411
492
  "border-input-error": primitiveRamps.red[500],
412
493
  // Alpha hairline separators — the primary separation cue (§4/S-2). Self-
413
494
  // normalizing: composites toward white by ~the same amount on ANY plane, so
@@ -450,7 +531,7 @@ var semanticColorsDark = {
450
531
  "interactive-disabled": "rgba(255, 255, 255, 0.12)",
451
532
  "interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
452
533
  // Divider
453
- "divider": "rgba(255, 255, 255, 0.09)",
534
+ divider: "rgba(255, 255, 255, 0.09)",
454
535
  // Avatar default
455
536
  "avatar-background": greyRamp[700],
456
537
  "avatar-text": primitiveColors.white
@@ -464,6 +545,182 @@ function resolveColor(token, mode = "dark") {
464
545
  return Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
465
546
  }
466
547
 
548
+ // src/theme/color-utils.ts
549
+ function hexToRgb(hex) {
550
+ const cleaned = hex.replace("#", "");
551
+ let r, g, b;
552
+ if (cleaned.length === 3) {
553
+ r = parseInt(cleaned[0] + cleaned[0], 16);
554
+ g = parseInt(cleaned[1] + cleaned[1], 16);
555
+ b = parseInt(cleaned[2] + cleaned[2], 16);
556
+ } else if (cleaned.length === 6) {
557
+ r = parseInt(cleaned.slice(0, 2), 16);
558
+ g = parseInt(cleaned.slice(2, 4), 16);
559
+ b = parseInt(cleaned.slice(4, 6), 16);
560
+ } else {
561
+ return null;
562
+ }
563
+ return { r, g, b };
564
+ }
565
+
566
+ // src/utils/colors.ts
567
+ function alpha(color, opacity) {
568
+ const clampedOpacity = Math.max(0, Math.min(1, opacity));
569
+ if (color.startsWith("#")) {
570
+ const hex = color.slice(1);
571
+ let r, g, b;
572
+ if (hex.length === 3) {
573
+ r = parseInt(hex[0] + hex[0], 16);
574
+ g = parseInt(hex[1] + hex[1], 16);
575
+ b = parseInt(hex[2] + hex[2], 16);
576
+ } else if (hex.length === 6) {
577
+ r = parseInt(hex.slice(0, 2), 16);
578
+ g = parseInt(hex.slice(2, 4), 16);
579
+ b = parseInt(hex.slice(4, 6), 16);
580
+ } else {
581
+ return color;
582
+ }
583
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
584
+ }
585
+ const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
586
+ if (rgbMatch) {
587
+ const [, r, g, b] = rgbMatch;
588
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
589
+ }
590
+ const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
591
+ if (rgbaMatch) {
592
+ const [, r, g, b] = rgbaMatch;
593
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
594
+ }
595
+ return color;
596
+ }
597
+
598
+ // src/theme/materials.ts
599
+ var c = getSemanticColors("dark");
600
+ function insetWell(tone = c["surface-input"]) {
601
+ return {
602
+ backgroundColor: tone,
603
+ boxShadow: "inset 0 2px 6px rgba(0,0,0,0.55), inset 0 -1px 0 rgba(255,255,255,0.12)"
604
+ };
605
+ }
606
+ var FLOATING_LIFT_MIN = 4;
607
+ var LIFT_RIM_ALPHA = { dark: 0.12, light: 0.9 };
608
+ var AMBIENT = {
609
+ 1: [
610
+ { y: 1, blur: 2, alpha: 0.35 },
611
+ { y: 2, blur: 6, alpha: 0.3 }
612
+ ],
613
+ 2: [
614
+ { y: 1, blur: 2, alpha: 0.35 },
615
+ { y: 4, blur: 12, alpha: 0.32 }
616
+ ],
617
+ 3: [
618
+ { y: 2, blur: 4, alpha: 0.35 },
619
+ { y: 8, blur: 22, alpha: 0.35 }
620
+ ],
621
+ 4: [
622
+ { y: 1, blur: 2, alpha: 0.35 },
623
+ { y: 10, blur: 24, alpha: 0.3 },
624
+ { y: 24, blur: 48, alpha: 0.2 }
625
+ ],
626
+ 5: [
627
+ { y: 2, blur: 4, alpha: 0.4 },
628
+ { y: 16, blur: 32, alpha: 0.35 },
629
+ { y: 32, blur: 64, alpha: 0.25 }
630
+ ]
631
+ };
632
+ var AMBIENT_ALPHA_SCALE = { dark: 1, light: 0.4 };
633
+ function ambientLayers(step, mode) {
634
+ const scale = AMBIENT_ALPHA_SCALE[mode];
635
+ return AMBIENT[step].map(
636
+ ({ y, blur, alpha: alpha2 }) => `0 ${y}px ${blur}px rgba(0,0,0,${(alpha2 * scale).toFixed(2)})`
637
+ );
638
+ }
639
+ function liftShadow(step, mode = "dark", opts = {}) {
640
+ const rim = opts.rim ?? LIFT_RIM_ALPHA[mode];
641
+ const layers = ambientLayers(step, mode);
642
+ if (rim > 0) layers.unshift(`inset 0 1px 0 rgba(255,255,255,${rim.toFixed(2)})`);
643
+ return layers.join(", ");
644
+ }
645
+ function liftStyle(step, mode = "dark", opts = {}) {
646
+ const deepest = AMBIENT[step][AMBIENT[step].length - 1];
647
+ return Platform.select({
648
+ web: { boxShadow: liftShadow(step, mode, opts) },
649
+ default: {
650
+ shadowColor: "#000",
651
+ shadowOffset: { width: 0, height: Math.round(deepest.y / 2) },
652
+ shadowOpacity: deepest.alpha * AMBIENT_ALPHA_SCALE[mode],
653
+ shadowRadius: deepest.blur / 2,
654
+ elevation: step
655
+ }
656
+ });
657
+ }
658
+
659
+ // src/theme/surface-planes.ts
660
+ var SURFACE_LEVEL_TOKEN = {
661
+ frame: "background-frame",
662
+ background: "background-base",
663
+ base: "surface-base",
664
+ elevated: "surface-elevated",
665
+ raised: "surface-raised",
666
+ overlay: "surface-overlay"
667
+ };
668
+ var PLANE_ORDER = [
669
+ "frame",
670
+ "background",
671
+ "base",
672
+ "elevated",
673
+ "raised",
674
+ "overlay"
675
+ ];
676
+ function surfaceBackground(level, mode) {
677
+ return getSemanticColors(mode)[SURFACE_LEVEL_TOKEN[level]];
678
+ }
679
+ function stepPlane(from, delta) {
680
+ const index = PLANE_ORDER.indexOf(from);
681
+ const clamped = Math.min(PLANE_ORDER.length - 1, Math.max(0, index + delta));
682
+ return PLANE_ORDER[clamped];
683
+ }
684
+ function pressedLevel(parent) {
685
+ return stepPlane(parent, -1);
686
+ }
687
+ function raisedLevel(parent, steps) {
688
+ return stepPlane(parent, Math.max(0, steps));
689
+ }
690
+
691
+ // src/theme/elevation.ts
692
+ var FLOATING_ELEVATION_MIN = FLOATING_LIFT_MIN;
693
+ function getPressedRecessShadow(fillColor, _mode = "dark") {
694
+ const { boxShadow } = insetWell(fillColor);
695
+ return Platform.select({
696
+ web: { boxShadow },
697
+ default: {}
698
+ });
699
+ }
700
+ var glowConfig = {
701
+ tight: { blur: 4, spread: 0, opacity: 0.4 },
702
+ subtle: { blur: 12, spread: 0, opacity: 0.25 },
703
+ medium: { blur: 20, spread: 2, opacity: 0.4 },
704
+ strong: { blur: 30, spread: 4, opacity: 0.55 }
705
+ };
706
+ function getGlowShadow(color, intensity = "medium") {
707
+ const config = glowConfig[intensity];
708
+ const rgb = hexToRgb(color);
709
+ if (!rgb) return {};
710
+ return Platform.select({
711
+ web: {
712
+ boxShadow: `0 0 ${config.blur}px ${config.spread}px rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${config.opacity})`
713
+ },
714
+ default: {
715
+ shadowColor: color,
716
+ shadowOffset: { width: 0, height: 0 },
717
+ shadowOpacity: config.opacity,
718
+ shadowRadius: config.blur / 2,
719
+ elevation: 0
720
+ }
721
+ });
722
+ }
723
+
467
724
  // src/theme/workout-tokens.ts
468
725
  var WORKOUT_TOKENS = {
469
726
  // BodyMap volume heatmap — the canonical `divergingScale` (under → optimal →
@@ -688,8 +945,8 @@ var jsxs = wrapJsx(jsxs$1);
688
945
  // src/components/custom/Workout/BodyMap.tsx
689
946
  var Body = BodyHighlighter.default ?? BodyHighlighter;
690
947
  var BRAND_PRIMARY = getSemanticColors("dark")["brand-primary"];
691
- var OUTLINE_FILL = "rgba(255,255,255,0.08)";
692
- var OUTLINE_BORDER = "rgba(255,255,255,0.12)";
948
+ var OUTLINE_FILL = alpha(primitiveColors.white, 0.08);
949
+ var OUTLINE_BORDER = alpha(primitiveColors.white, 0.12);
693
950
  var BODY_SCALE = 0.8;
694
951
  function buildSlugParts(data) {
695
952
  const bySlug = /* @__PURE__ */ new Map();
@@ -791,7 +1048,8 @@ function BodyMap({
791
1048
  alignSelf: "center",
792
1049
  transform: [{ scale }]
793
1050
  },
794
- glowColor ? { boxShadow: `0 0 14px 2px ${glowColor}` } : void 0
1051
+ // The highlight halo is emphasis, not depth.
1052
+ glowColor ? getGlowShadow(glowColor, "medium") : void 0
795
1053
  ],
796
1054
  "aria-hidden": true,
797
1055
  accessibilityElementsHidden: true,
@@ -864,7 +1122,7 @@ function ViewToggle({ view, onViewChange }) {
864
1122
  paddingHorizontal: 12,
865
1123
  paddingVertical: 4,
866
1124
  borderRadius: 9999,
867
- backgroundColor: active ? "rgba(255,121,0,0.16)" : "transparent",
1125
+ backgroundColor: active ? alpha(BRAND_PRIMARY, 0.16) : "transparent",
868
1126
  borderWidth: 1,
869
1127
  borderColor: active ? BRAND_PRIMARY : resolveColor("hairline-strong")
870
1128
  },
@@ -953,6 +1211,17 @@ var colorStyles = {
953
1211
  info: "bg-status-info",
954
1212
  "error-vivid": "bg-status-error-vivid"
955
1213
  };
1214
+ var t = getSemanticColors("dark");
1215
+ var glowColors = {
1216
+ default: greyRamp[500],
1217
+ primary: t["brand-primary"],
1218
+ success: t["status-success"],
1219
+ live: t["status-live"],
1220
+ error: t["status-error"],
1221
+ warning: t["status-warning"],
1222
+ info: t["status-info"],
1223
+ "error-vivid": t["status-error-vivid"]
1224
+ };
956
1225
  function Indicator({
957
1226
  size = "sm",
958
1227
  color = "default",
@@ -990,11 +1259,7 @@ function Indicator({
990
1259
  )
991
1260
  ] });
992
1261
  }
993
- const dynamicStyle = {
994
- ...typeof style === "object" ? style : {},
995
- ...colorStyle ?? {},
996
- ...glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}
997
- };
1262
+ const glowStyle = glow ? getGlowShadow(customColor ?? glowColors[color], "subtle") : null;
998
1263
  return /* @__PURE__ */ jsx(
999
1264
  View,
1000
1265
  {
@@ -1004,54 +1269,168 @@ function Indicator({
1004
1269
  colorClass,
1005
1270
  pulseMode === "opacity" && "animate-pulse",
1006
1271
  ring && "border-2 border-background-base",
1007
- glow && !customColor && (color === "success" || color === "live") && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
1008
- glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
1009
- glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
1010
- glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
1011
- glow && !customColor && color === "error-vivid" && "shadow-[0_0_6px_rgba(255,71,87,0.6)]",
1012
1272
  className
1013
1273
  ),
1014
- style: Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style,
1274
+ style: [style, colorStyle, glowStyle],
1015
1275
  ...props
1016
1276
  }
1017
1277
  );
1018
1278
  }
1019
-
1020
- // src/components/ui/badge/Badge.tsx
1021
- var variantColorStyles = {
1279
+ var colorToTone = {
1280
+ default: "neutral",
1281
+ primary: "brand",
1282
+ secondary: "brand-secondary",
1283
+ success: "success",
1284
+ error: "error",
1285
+ warning: "warning",
1286
+ info: "info"
1287
+ };
1288
+ var toneStyles = {
1022
1289
  solid: {
1023
- default: "bg-hairline-strong text-text-inverse",
1024
- primary: "bg-brand-primary text-text-inverse",
1025
- secondary: "bg-brand-secondary text-text-inverse",
1026
- success: "bg-status-success text-text-inverse",
1027
- error: "bg-status-error text-text-inverse",
1028
- warning: "bg-status-warning text-text-inverse",
1029
- info: "bg-status-info text-text-inverse"
1290
+ neutral: "bg-hairline-strong border-transparent text-text-inverse",
1291
+ brand: "bg-brand-primary border-transparent text-text-inverse",
1292
+ "brand-secondary": "bg-brand-secondary border-transparent text-text-inverse",
1293
+ success: "bg-status-success border-transparent text-text-inverse",
1294
+ warning: "bg-status-warning border-transparent text-text-inverse",
1295
+ error: "bg-status-error border-transparent text-text-inverse",
1296
+ info: "bg-status-info border-transparent text-text-inverse"
1030
1297
  },
1031
1298
  subtle: {
1032
- default: "bg-surface-raised text-text-secondary",
1033
- primary: "bg-brand-primary-subtle text-brand-primary",
1034
- secondary: "bg-brand-secondary-subtle text-brand-secondary",
1035
- success: "bg-status-success-subtle text-status-success",
1036
- error: "bg-status-error-subtle text-status-error",
1037
- warning: "bg-status-warning-subtle text-status-warning",
1038
- info: "bg-status-info-subtle text-status-info"
1299
+ // Alpha-white rather than a ramp step: a pill sits on whatever plane its
1300
+ // host is, and an alpha fill composites by the same amount on all of them.
1301
+ // A `surface-*` fill would vanish on the plane it names. Borderless like the
1302
+ // six coloured tones — the fill carries the capsule, not a ring.
1303
+ // Label comes from `on-*-subtle`, not the base tone token: the base is tuned to
1304
+ // carry a white label as a solid fill, which left error and accent unreadable
1305
+ // here (AW-133). The on-subtle tokens level the family at one weight.
1306
+ neutral: "bg-hairline-subtle border-transparent text-text-secondary",
1307
+ brand: "bg-brand-primary-subtle border-transparent text-on-brand-primary-subtle",
1308
+ "brand-secondary": "bg-brand-secondary-subtle border-transparent text-on-brand-secondary-subtle",
1309
+ success: "bg-status-success-subtle border-transparent text-on-status-success-subtle",
1310
+ warning: "bg-status-warning-subtle border-transparent text-on-status-warning-subtle",
1311
+ error: "bg-status-error-subtle border-transparent text-on-status-error-subtle",
1312
+ info: "bg-status-info-subtle border-transparent text-on-status-info-subtle"
1039
1313
  },
1040
1314
  outline: {
1041
- default: "border border-hairline-strong text-text-secondary",
1042
- primary: "border border-brand-primary text-brand-primary",
1043
- secondary: "border border-brand-secondary text-brand-secondary",
1044
- success: "border border-status-success text-status-success",
1045
- error: "border border-status-error text-status-error",
1046
- warning: "border border-status-warning text-status-warning",
1047
- info: "border border-status-info text-status-info"
1315
+ neutral: "border-hairline text-text-secondary",
1316
+ brand: "border-brand-primary text-brand-primary",
1317
+ "brand-secondary": "border-brand-secondary text-brand-secondary",
1318
+ success: "border-status-success text-status-success",
1319
+ warning: "border-status-warning text-status-warning",
1320
+ error: "border-status-error text-status-error",
1321
+ info: "border-status-info text-status-info"
1048
1322
  }
1049
1323
  };
1324
+ var dotToneStyles = {
1325
+ neutral: "bg-text-tertiary",
1326
+ brand: "bg-brand-primary",
1327
+ "brand-secondary": "bg-brand-secondary",
1328
+ success: "bg-status-success",
1329
+ warning: "bg-status-warning",
1330
+ error: "bg-status-error",
1331
+ info: "bg-status-info"
1332
+ };
1050
1333
  var sizeStyles2 = {
1051
- sm: "px-1.5 py-0.5 text-xs",
1052
- md: "px-2 py-0.5 text-xs",
1053
- lg: "px-2.5 py-1 text-sm"
1334
+ xs: { container: "px-1 py-px", text: "text-3xs" },
1335
+ sm: { container: "px-2 py-0.5", text: "text-2xs" },
1336
+ md: { container: "px-2.5 py-1", text: "text-xs" },
1337
+ lg: { container: "px-3 py-1.5", text: "text-sm" },
1338
+ xl: { container: "px-4 py-2", text: "text-base" }
1339
+ };
1340
+ function PillDot({ tone, testID }) {
1341
+ return /* @__PURE__ */ jsx(
1342
+ View,
1343
+ {
1344
+ className: cn("w-1.5 h-1.5 rounded-full shrink-0", dotToneStyles[tone]),
1345
+ accessibilityElementsHidden: true,
1346
+ testID: testID ? `${testID}-dot` : "pill-dot"
1347
+ }
1348
+ );
1349
+ }
1350
+ function containerClasses(p, tone) {
1351
+ return cn(
1352
+ "flex-row items-center gap-1 border self-start shrink-0",
1353
+ p.rounded === false ? "rounded" : "rounded-full",
1354
+ toneStyles[p.variant ?? "subtle"][tone],
1355
+ sizeStyles2[p.size ?? "sm"].container,
1356
+ p.isDisabled && "opacity-50",
1357
+ p.className
1358
+ );
1359
+ }
1360
+ function PillContent({ tone, ...p }) {
1361
+ const textClasses = cn(
1362
+ "font-heading font-semibold text-inherit",
1363
+ sizeStyles2[p.size ?? "sm"].text,
1364
+ p.textClassName
1365
+ );
1366
+ const slot = p.leading ?? p.leftElement;
1367
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1368
+ slot === "dot" ? /* @__PURE__ */ jsx(PillDot, { tone: p.dotTone ?? tone, testID: p.testID }) : slot,
1369
+ typeof p.children === "string" ? /* @__PURE__ */ jsx(Text, { className: textClasses, children: p.children }) : p.children,
1370
+ p.trailing
1371
+ ] });
1372
+ }
1373
+ function Pill(props) {
1374
+ const {
1375
+ variant,
1376
+ tone,
1377
+ color,
1378
+ size,
1379
+ rounded,
1380
+ leading,
1381
+ dotTone,
1382
+ leftElement,
1383
+ trailing,
1384
+ onPress,
1385
+ isDisabled,
1386
+ className,
1387
+ textClassName,
1388
+ children,
1389
+ ...viewProps
1390
+ } = props;
1391
+ const resolvedTone = tone ?? (color ? colorToTone[color] : "neutral");
1392
+ const classes = containerClasses(props, resolvedTone);
1393
+ const content = /* @__PURE__ */ jsx(PillContent, { ...props, tone: resolvedTone });
1394
+ if (onPress) {
1395
+ return /* @__PURE__ */ jsx(
1396
+ Pressable,
1397
+ {
1398
+ onPress,
1399
+ disabled: isDisabled,
1400
+ accessibilityRole: "button",
1401
+ className: classes,
1402
+ ...viewProps,
1403
+ children: content
1404
+ }
1405
+ );
1406
+ }
1407
+ return /* @__PURE__ */ jsx(View, { className: classes, ...viewProps, children: content });
1408
+ }
1409
+
1410
+ // src/components/ui/badge/Badge.tsx
1411
+ var colorToTone2 = {
1412
+ default: "neutral",
1413
+ primary: "brand",
1414
+ secondary: "brand-secondary",
1415
+ success: "success",
1416
+ error: "error",
1417
+ warning: "warning",
1418
+ info: "info"
1419
+ };
1420
+ var sizeStyles3 = {
1421
+ sm: "px-1.5 py-0.5",
1422
+ md: "px-2 py-0.5",
1423
+ lg: "px-2.5 py-1"
1054
1424
  };
1425
+ var textSizeStyles = {
1426
+ sm: "text-xs",
1427
+ md: "text-xs",
1428
+ lg: "text-sm"
1429
+ };
1430
+ function dotIndicatorColor(color, dotColor) {
1431
+ if (dotColor) return dotColor;
1432
+ return color === "default" || color === "secondary" ? "default" : color;
1433
+ }
1055
1434
  function Badge({
1056
1435
  variant = "subtle",
1057
1436
  color = "default",
@@ -1062,31 +1441,116 @@ function Badge({
1062
1441
  children,
1063
1442
  ...props
1064
1443
  }) {
1065
- return /* @__PURE__ */ jsxs(
1066
- View,
1444
+ return /* @__PURE__ */ jsx(
1445
+ Pill,
1067
1446
  {
1447
+ variant,
1448
+ tone: colorToTone2[color],
1449
+ leading: dot ? /* @__PURE__ */ jsx(Indicator, { size: "xs", color: dotIndicatorColor(color, dotColor), className: "mr-0.5" }) : void 0,
1068
1450
  className: cn(
1069
- "inline-flex items-center justify-center rounded-full font-medium",
1070
- variantColorStyles[variant][color],
1071
- sizeStyles2[size],
1451
+ "justify-center self-auto gap-0",
1452
+ variant === "outline" ? "border" : "border-0",
1453
+ sizeStyles3[size],
1072
1454
  className
1073
1455
  ),
1456
+ textClassName: cn("font-sans font-medium", textSizeStyles[size]),
1074
1457
  ...props,
1075
- children: [
1076
- dot && /* @__PURE__ */ jsx(
1077
- Indicator,
1078
- {
1079
- size: "xs",
1080
- color: dotColor ?? (color === "default" || color === "secondary" ? "default" : color),
1081
- className: "mr-0.5"
1082
- }
1083
- ),
1084
- typeof children === "string" ? /* @__PURE__ */ jsx(Text, { className: "text-inherit font-medium", children }) : children
1085
- ]
1458
+ children
1459
+ }
1460
+ );
1461
+ }
1462
+ var variantStyles = {
1463
+ h1: "font-heading text-5xl font-bold leading-tight",
1464
+ h2: "font-heading text-4xl font-bold leading-tight",
1465
+ h3: "font-heading text-3xl font-bold leading-tight",
1466
+ h4: "font-heading text-2xl font-bold leading-tight",
1467
+ h5: "font-heading text-xl font-semibold leading-tight",
1468
+ h6: "font-heading text-lg font-semibold leading-tight",
1469
+ body1: "font-body text-base font-normal leading-normal",
1470
+ body2: "font-body text-sm font-normal leading-normal",
1471
+ subtitle1: "font-body text-base font-medium leading-relaxed",
1472
+ subtitle2: "font-body text-sm font-medium leading-normal",
1473
+ caption: "font-body text-xs font-normal leading-loose",
1474
+ overline: "font-body text-xs font-semibold uppercase tracking-widest leading-relaxed",
1475
+ button: "font-sans text-sm font-semibold leading-relaxed",
1476
+ // Monospace technical readouts (clocks, ids, metrics) and their all-caps label form.
1477
+ mono: "font-mono text-xs font-normal leading-normal",
1478
+ monoLabel: "font-mono text-xs font-bold uppercase tracking-wide leading-normal",
1479
+ // The sans (Inter) label pair: 10px for dense table/column headers, 12px bold for
1480
+ // badge and row labels. `overline` is the 12px font-body form of the same idea.
1481
+ microLabel: "font-sans text-2xs font-semibold uppercase tracking-widest leading-normal",
1482
+ boldLabel: "font-sans text-xs font-bold leading-normal"
1483
+ };
1484
+ var colorStyles2 = {
1485
+ primary: "text-text-primary",
1486
+ secondary: "text-text-secondary",
1487
+ tertiary: "text-text-tertiary",
1488
+ disabled: "text-text-disabled",
1489
+ inverse: "text-text-inverse",
1490
+ success: "text-status-success",
1491
+ error: "text-status-error",
1492
+ warning: "text-status-warning",
1493
+ info: "text-status-info",
1494
+ inherit: ""
1495
+ // No color class, inherit from parent
1496
+ };
1497
+ var alignStyles = {
1498
+ left: "text-left",
1499
+ center: "text-center",
1500
+ right: "text-right",
1501
+ justify: "text-justify"
1502
+ };
1503
+ var headingVariants = ["h1", "h2", "h3", "h4", "h5", "h6"];
1504
+ var marginBottomStyles = {
1505
+ none: "",
1506
+ sm: "mb-1",
1507
+ md: "mb-2",
1508
+ lg: "mb-4"
1509
+ };
1510
+ function Typography({
1511
+ variant = "body1",
1512
+ color = "primary",
1513
+ align,
1514
+ truncate = false,
1515
+ noWrap = false,
1516
+ // deprecated, kept for backward compatibility
1517
+ marginBottom,
1518
+ gutterBottom = false,
1519
+ // deprecated, kept for backward compatibility
1520
+ maxLines,
1521
+ className,
1522
+ children,
1523
+ ...props
1524
+ }) {
1525
+ const isHeading = headingVariants.includes(variant);
1526
+ const shouldTruncate = truncate || noWrap;
1527
+ const mb = marginBottom || (gutterBottom ? "md" : "none");
1528
+ let numLines;
1529
+ if (maxLines) {
1530
+ numLines = maxLines;
1531
+ } else if (shouldTruncate) {
1532
+ numLines = 1;
1533
+ }
1534
+ return /* @__PURE__ */ jsx(
1535
+ Text,
1536
+ {
1537
+ accessibilityRole: isHeading ? "header" : "text",
1538
+ numberOfLines: numLines,
1539
+ className: cn(
1540
+ variantStyles[variant],
1541
+ color !== "inherit" && colorStyles2[color],
1542
+ align && alignStyles[align],
1543
+ shouldTruncate && "truncate",
1544
+ marginBottomStyles[mb],
1545
+ className
1546
+ ),
1547
+ ...props,
1548
+ children
1086
1549
  }
1087
1550
  );
1088
1551
  }
1089
- var BRAND_PRIMARY2 = getSemanticColors("dark")["brand-primary"];
1552
+
1553
+ // src/components/custom/Workout/Sparkline.tsx
1090
1554
  function normalizeData(data, height) {
1091
1555
  if (data.length === 0) return [];
1092
1556
  const min = Math.min(...data);
@@ -1123,7 +1587,7 @@ function Sparkline({
1123
1587
  }
1124
1588
  );
1125
1589
  }
1126
- const resolvedColor = color ?? BRAND_PRIMARY2;
1590
+ const resolvedColor = color ?? resolveColor("brand-primary");
1127
1591
  const normalized = normalizeData(data, height);
1128
1592
  const stepX = data.length > 1 ? width / (data.length - 1) : 0;
1129
1593
  const dotSize = 3;
@@ -1163,14 +1627,19 @@ function Sparkline({
1163
1627
  ],
1164
1628
  accessibilityElementsHidden: true,
1165
1629
  testID: `sparkline-reference-${i}`,
1166
- children: line.label && /* @__PURE__ */ jsx(
1167
- Text,
1630
+ children: line.label && // `3xs` (9px) is the scale floor; the label was 7px, which is off it
1631
+ // entirely (TOKENS.md §4). The line box stays unpinned, as the raw
1632
+ // <Text> this replaced was, so the absolute offset still lands.
1633
+ /* @__PURE__ */ jsx(
1634
+ Typography,
1168
1635
  {
1636
+ variant: "caption",
1637
+ color: "inherit",
1638
+ className: "text-3xs leading-[normal]",
1169
1639
  style: {
1170
1640
  position: "absolute",
1171
1641
  right: 0,
1172
1642
  top: -10,
1173
- fontSize: 7,
1174
1643
  color: line.color,
1175
1644
  opacity: 1
1176
1645
  },
@@ -1239,9 +1708,9 @@ function Sparkline({
1239
1708
  }
1240
1709
 
1241
1710
  // src/components/custom/Workout/BodyMapDetailPanel.tsx
1242
- var t = getSemanticColors("dark");
1243
- var BRAND_PRIMARY3 = t["brand-primary"];
1244
- var VOLUME_GRADIENT = `linear-gradient(90deg, ${t["status-info"]} 0%, ${t["status-success"]} 50%, ${t["status-error"]} 100%)`;
1711
+ var t2 = getSemanticColors("dark");
1712
+ var BRAND_PRIMARY2 = t2["brand-primary"];
1713
+ var VOLUME_GRADIENT = `linear-gradient(90deg, ${t2["status-info"]} 0%, ${t2["status-success"]} 50%, ${t2["status-error"]} 100%)`;
1245
1714
  var SLIDE_OFFSET = 400;
1246
1715
  var BACKDROP_OPACITY = 0.4;
1247
1716
  var STATUS_BADGE_COLOR = {
@@ -1306,7 +1775,14 @@ function BodyMapDetailPanel({
1306
1775
  return /* @__PURE__ */ jsxs(
1307
1776
  View,
1308
1777
  {
1309
- style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, justifyContent: "flex-end" },
1778
+ style: {
1779
+ position: "absolute",
1780
+ top: 0,
1781
+ left: 0,
1782
+ right: 0,
1783
+ bottom: 0,
1784
+ justifyContent: "flex-end"
1785
+ },
1310
1786
  testID: "body-map-detail-panel-root",
1311
1787
  children: [
1312
1788
  /* @__PURE__ */ jsx(
@@ -1318,7 +1794,7 @@ function BodyMapDetailPanel({
1318
1794
  left: 0,
1319
1795
  right: 0,
1320
1796
  bottom: 0,
1321
- backgroundColor: "#000000",
1797
+ backgroundColor: primitiveColors.black,
1322
1798
  opacity: backdrop
1323
1799
  },
1324
1800
  testID: "body-map-detail-panel-backdrop-anim",
@@ -1441,8 +1917,22 @@ function BodyMapDetailPanel({
1441
1917
  style: { marginBottom: 6 },
1442
1918
  accessibilityElementsHidden: true,
1443
1919
  children: [
1444
- /* @__PURE__ */ jsx(Text, { className: "text-text-tertiary", style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" }, children: `MEV ${landmarks.mev}` }),
1445
- /* @__PURE__ */ jsx(Text, { className: "text-text-tertiary", style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" }, children: `MRV ${landmarks.mrv}` })
1920
+ /* @__PURE__ */ jsx(
1921
+ Text,
1922
+ {
1923
+ className: "text-text-tertiary",
1924
+ style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" },
1925
+ children: `MEV ${landmarks.mev}`
1926
+ }
1927
+ ),
1928
+ /* @__PURE__ */ jsx(
1929
+ Text,
1930
+ {
1931
+ className: "text-text-tertiary",
1932
+ style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600" },
1933
+ children: `MRV ${landmarks.mrv}`
1934
+ }
1935
+ )
1446
1936
  ]
1447
1937
  }
1448
1938
  ),
@@ -1477,7 +1967,8 @@ function BodyMapDetailPanel({
1477
1967
  height: 14,
1478
1968
  borderRadius: 7,
1479
1969
  borderWidth: 2,
1480
- boxShadow: "0 0 4px rgba(0,0,0,0.5)"
1970
+ // A knob resting on the volume bar: lift, with the ring as its edge.
1971
+ ...liftStyle(1, "dark", { rim: 0 })
1481
1972
  },
1482
1973
  accessibilityElementsHidden: true,
1483
1974
  testID: "body-map-detail-panel-volume-marker"
@@ -1560,7 +2051,12 @@ function BodyMapDetailPanel({
1560
2051
  Text,
1561
2052
  {
1562
2053
  className: "text-text-primary",
1563
- style: { flex: 1, fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "600" },
2054
+ style: {
2055
+ flex: 1,
2056
+ fontSize: 13,
2057
+ fontFamily: "Inter, sans-serif",
2058
+ fontWeight: "600"
2059
+ },
1564
2060
  testID: `body-map-detail-panel-contributing-${index}-name`,
1565
2061
  children: exercise.name
1566
2062
  }
@@ -1604,7 +2100,12 @@ function BodyMapDetailPanel({
1604
2100
  Text,
1605
2101
  {
1606
2102
  className: "text-text-primary",
1607
- style: { flex: 1, fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "600" },
2103
+ style: {
2104
+ flex: 1,
2105
+ fontSize: 13,
2106
+ fontFamily: "Inter, sans-serif",
2107
+ fontWeight: "600"
2108
+ },
1608
2109
  testID: `body-map-detail-panel-upcoming-${index}-name`,
1609
2110
  children: exercise.name
1610
2111
  }
@@ -1634,12 +2135,23 @@ function BodyMapDetailPanel({
1634
2135
  paddingVertical: 10,
1635
2136
  borderRadius: 8,
1636
2137
  alignItems: "center",
1637
- backgroundColor: "rgba(255,121,0,0.12)",
2138
+ backgroundColor: alpha(BRAND_PRIMARY2, 0.12),
1638
2139
  borderWidth: 1,
1639
- borderColor: "rgba(255,121,0,0.3)"
2140
+ borderColor: alpha(BRAND_PRIMARY2, 0.3)
1640
2141
  },
1641
2142
  testID: "body-map-detail-panel-view-exercises",
1642
- children: /* @__PURE__ */ jsx(Text, { style: { fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "700", color: BRAND_PRIMARY3 }, children: "View exercises" })
2143
+ children: /* @__PURE__ */ jsx(
2144
+ Text,
2145
+ {
2146
+ style: {
2147
+ fontSize: 13,
2148
+ fontFamily: "Inter, sans-serif",
2149
+ fontWeight: "700",
2150
+ color: BRAND_PRIMARY2
2151
+ },
2152
+ children: "View exercises"
2153
+ }
2154
+ )
1643
2155
  }
1644
2156
  )
1645
2157
  ]
@@ -1652,439 +2164,81 @@ function BodyMapDetailPanel({
1652
2164
  }
1653
2165
  );
1654
2166
  }
1655
-
1656
- // src/theme/color-utils.ts
1657
- function hexToRgb(hex) {
1658
- const cleaned = hex.replace("#", "");
1659
- let r, g, b;
1660
- if (cleaned.length === 3) {
1661
- r = parseInt(cleaned[0] + cleaned[0], 16);
1662
- g = parseInt(cleaned[1] + cleaned[1], 16);
1663
- b = parseInt(cleaned[2] + cleaned[2], 16);
1664
- } else if (cleaned.length === 6) {
1665
- r = parseInt(cleaned.slice(0, 2), 16);
1666
- g = parseInt(cleaned.slice(2, 4), 16);
1667
- b = parseInt(cleaned.slice(4, 6), 16);
1668
- } else {
1669
- return null;
1670
- }
1671
- return { r, g, b };
1672
- }
1673
- function rgbToHsv(r, g, b) {
1674
- const rNorm = r / 255;
1675
- const gNorm = g / 255;
1676
- const bNorm = b / 255;
1677
- const max = Math.max(rNorm, gNorm, bNorm);
1678
- const min = Math.min(rNorm, gNorm, bNorm);
1679
- const delta = max - min;
1680
- const v = max;
1681
- const s = max === 0 ? 0 : delta / max;
1682
- let h = 0;
1683
- if (delta !== 0) {
1684
- if (max === rNorm) {
1685
- h = 60 * ((gNorm - bNorm) / delta % 6);
1686
- } else if (max === gNorm) {
1687
- h = 60 * ((bNorm - rNorm) / delta + 2);
1688
- } else {
1689
- h = 60 * ((rNorm - gNorm) / delta + 4);
1690
- }
1691
- }
1692
- if (h < 0) h += 360;
1693
- return { h, s, v };
1694
- }
1695
- function hsvToRgb(h, s, v) {
1696
- const c = v * s;
1697
- const x = c * (1 - Math.abs(h / 60 % 2 - 1));
1698
- const m = v - c;
1699
- let rPrime, gPrime, bPrime;
1700
- if (h >= 0 && h < 60) {
1701
- rPrime = c;
1702
- gPrime = x;
1703
- bPrime = 0;
1704
- } else if (h >= 60 && h < 120) {
1705
- rPrime = x;
1706
- gPrime = c;
1707
- bPrime = 0;
1708
- } else if (h >= 120 && h < 180) {
1709
- rPrime = 0;
1710
- gPrime = c;
1711
- bPrime = x;
1712
- } else if (h >= 180 && h < 240) {
1713
- rPrime = 0;
1714
- gPrime = x;
1715
- bPrime = c;
1716
- } else if (h >= 240 && h < 300) {
1717
- rPrime = x;
1718
- gPrime = 0;
1719
- bPrime = c;
1720
- } else {
1721
- rPrime = c;
1722
- gPrime = 0;
1723
- bPrime = x;
1724
- }
1725
- return {
1726
- r: Math.round((rPrime + m) * 255),
1727
- g: Math.round((gPrime + m) * 255),
1728
- b: Math.round((bPrime + m) * 255)
1729
- };
1730
- }
1731
- function rgbToHex(r, g, b) {
1732
- const toHex = (n) => {
1733
- const clamped = Math.max(0, Math.min(255, Math.round(n)));
1734
- return clamped.toString(16).padStart(2, "0");
1735
- };
1736
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
1737
- }
1738
- function lighten(hex, amount = 0.1) {
1739
- const rgb = hexToRgb(hex);
1740
- if (!rgb) return hex;
1741
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1742
- const newV = Math.min(1, hsv.v + amount);
1743
- const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
1744
- return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
1745
- }
1746
- var elevationSystem = {
1747
- // Deep inset (recessed input fields, deeply pressed buttons)
1748
- [-2]: {
1749
- name: "deep-inset",
1750
- colorAdjustment: 0,
1751
- shadowIntensity: "strong",
1752
- shadowStyle: "pressed",
1753
- description: "Deeply recessed elements (e.g., input fields, deeply pressed buttons)"
1754
- },
1755
- // Shallow inset (pressed buttons, sunken panels)
1756
- [-1]: {
1757
- name: "inset",
1758
- colorAdjustment: 0,
1759
- shadowIntensity: "medium",
1760
- shadowStyle: "pressed",
1761
- description: "Shallow inset elements (e.g., pressed buttons, sunken panels within cards)"
1762
- },
1763
- // Base level (page background, default surface)
1764
- [0]: {
1765
- name: "base",
1766
- colorAdjustment: 0,
1767
- shadowIntensity: "subtle",
1768
- shadowStyle: "raised",
1769
- description: "Base surface level (page background, default containers)"
1770
- },
1771
- // Level 1: Subtle elevation (outline cards, subtle containers)
1772
- [1]: {
1773
- name: "subtle",
1774
- // The whole ladder was re-spaced in TD-07.16. It used to run
1775
- // 0.01/0.02/0.04/0.06/0.08, where the first step was ~2 RGB values — under
1776
- // the perceptual floor, so level 1 existed in the type system and nowhere on
1777
- // screen. With drop-shadow now gated off below FLOATING_ELEVATION_MIN, TONE
1778
- // is the only thing separating 0-3, so every step has to actually land.
1779
- // Even 0.025 spacing, verified in elevation.test.ts as ΔL* > 1 per step.
1780
- colorAdjustment: 0.025,
1781
- shadowIntensity: "subtle",
1782
- shadowStyle: "raised",
1783
- description: "Subtle elevation (outline cards, subtle containers)"
1784
- },
1785
- // Level 2: Standard elevation (default cards, buttons)
1786
- [2]: {
1787
- name: "standard",
1788
- colorAdjustment: 0.05,
1789
- shadowIntensity: "medium",
1790
- shadowStyle: "raised",
1791
- description: "Standard elevation (default cards, raised buttons)"
1792
- },
1793
- // Level 3: Prominent elevation (important cards, modals)
1794
- [3]: {
1795
- name: "prominent",
1796
- colorAdjustment: 0.075,
1797
- shadowIntensity: "strong",
1798
- shadowStyle: "raised",
1799
- description: "Prominent elevation (important cards, modals, dropdowns)"
1800
- },
1801
- // Level 4: High elevation (overlays, popovers)
1802
- [4]: {
1803
- name: "high",
1804
- colorAdjustment: 0.1,
1805
- shadowIntensity: "strong",
1806
- shadowStyle: "raised",
1807
- description: "High elevation (overlays, popovers, tooltips)"
1808
- },
1809
- // Level 5: Floating (toasts, floating action buttons)
1810
- [5]: {
1811
- name: "floating",
1812
- colorAdjustment: 0.13,
1813
- shadowIntensity: "strong",
1814
- shadowStyle: "raised",
1815
- description: "Floating elevation (toasts, floating action buttons, highest z-index)"
1816
- }
1817
- };
1818
- function calculateRimLightColor(baseColor, level) {
1819
- const rgb = hexToRgb(baseColor);
1820
- if (!rgb) {
1821
- return "rgba(255, 255, 255, 0.5)";
1822
- }
1823
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1824
- const isLight = hsv.v > 0.6;
1825
- const isSaturated = hsv.s > 0.3;
1826
- const absLevel = Math.abs(level);
1827
- const opacityBoost = Math.max(0, (absLevel - 1) * 0.05);
1828
- if (isSaturated) {
1829
- const rimLightValue = 0.95;
1830
- const rimLightRgb = hsvToRgb(hsv.h, hsv.s * 0.3, rimLightValue);
1831
- const baseOpacity = isLight ? 0.9 : 0.5;
1832
- const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
1833
- return `rgba(${rimLightRgb.r}, ${rimLightRgb.g}, ${rimLightRgb.b}, ${finalOpacity.toFixed(2)})`;
1834
- } else {
1835
- const baseOpacity = isLight ? 0.9 : 0.12;
1836
- const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
1837
- return `rgba(255, 255, 255, ${finalOpacity.toFixed(2)})`;
1838
- }
1839
- }
1840
- function calculateDarkShadowColors(surfaceColor) {
1841
- const rgb = hexToRgb(surfaceColor);
1842
- if (!rgb) {
1843
- return {
1844
- dark: "rgba(0, 0, 0, 0.3)",
1845
- darker: "rgba(0, 0, 0, 0.4)"
1846
- };
1847
- }
1848
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1849
- const isLight = hsv.v > 0.6;
1850
- const isSaturated = hsv.s > 0.3;
1851
- if (isSaturated) {
1852
- const darkShadowValue = 0.15;
1853
- const darkShadowRgb = hsvToRgb(hsv.h, hsv.s, darkShadowValue);
1854
- if (isLight) {
1855
- return {
1856
- dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.3)`,
1857
- darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.4)`
1858
- };
1859
- } else {
1860
- return {
1861
- dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.5)`,
1862
- darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.6)`
1863
- };
1864
- }
1865
- } else {
1866
- if (isLight) {
1867
- return {
1868
- dark: "rgba(0, 0, 0, 0.2)",
1869
- darker: "rgba(0, 0, 0, 0.3)"
1870
- };
1871
- } else {
1872
- return {
1873
- dark: "rgba(0, 0, 0, 0.5)",
1874
- darker: "rgba(0, 0, 0, 0.6)"
1875
- };
1876
- }
1877
- }
1878
- }
1879
- function getRimLightConfig() {
1880
- return {
1881
- offset: 1,
1882
- // Fixed 1px for crisp rim
1883
- blur: 1
1884
- // Tight blur for crisp edge
1885
- };
1886
- }
1887
- var elevationSurfaceCache = /* @__PURE__ */ new Map();
1888
- var MAX_CACHE_SIZE = 100;
1889
- function getCacheKey(baseColor, level, theme) {
1890
- return `${baseColor}-${level}-${theme}`;
2167
+ var DEFAULT_CONTEXT = { mode: "dark", level: "base" };
2168
+ var SurfaceContext = createContext(DEFAULT_CONTEXT);
2169
+ function useSurface() {
2170
+ return useContext(SurfaceContext);
1891
2171
  }
1892
- function calculateElevationSurface(baseColor, level, theme) {
1893
- const config = elevationSystem[level];
1894
- if (config.colorAdjustment === 0) {
1895
- return baseColor;
1896
- }
1897
- if (level < 0) {
1898
- return baseColor;
1899
- }
1900
- return lighten(baseColor, config.colorAdjustment);
1901
- }
1902
- function getElevationSurface(baseColor, level, theme) {
1903
- const cacheKey = getCacheKey(baseColor, level, theme);
1904
- if (elevationSurfaceCache.has(cacheKey)) {
1905
- return elevationSurfaceCache.get(cacheKey);
1906
- }
1907
- const result = calculateElevationSurface(baseColor, level);
1908
- if (elevationSurfaceCache.size >= MAX_CACHE_SIZE) {
1909
- const firstKey = elevationSurfaceCache.keys().next().value;
1910
- elevationSurfaceCache.delete(firstKey);
1911
- }
1912
- elevationSurfaceCache.set(cacheKey, result);
1913
- return result;
1914
- }
1915
- var elevationShadowCache = /* @__PURE__ */ new Map();
1916
- var MAX_SHADOW_CACHE_SIZE = 50;
1917
- function getShadowCacheKey(baseColor, level, theme, isHovered) {
1918
- return `${baseColor}-${level}-${theme}-${isHovered}`;
1919
- }
1920
- function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
1921
- const config = elevationSystem[level];
1922
- if (level === 0) {
1923
- return {};
1924
- }
1925
- const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
1926
- const rimLightColor = calculateRimLightColor(baseColor, level);
1927
- const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
1928
- const intensityConfig = {
1929
- subtle: { offset: 1, blur: 2 },
1930
- medium: { offset: 2, blur: 4 },
1931
- strong: { offset: 2, blur: 5 }
1932
- };
1933
- const { offset, blur } = intensityConfig[config.shadowIntensity];
1934
- const rimConfig = getRimLightConfig();
1935
- if (config.shadowStyle === "pressed") {
1936
- if (isHovered) {
1937
- const hoverOffset = Math.max(1, Math.round(offset / 2));
1938
- const hoverBlur = Math.max(1, Math.round(blur / 2));
1939
- return Platform.select({
1940
- web: {
1941
- boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
1942
- },
1943
- default: {
1944
- shadowOpacity: 0,
1945
- elevation: 0
1946
- }
1947
- });
1948
- }
1949
- return Platform.select({
1950
- web: {
1951
- boxShadow: `inset ${offset}px ${offset}px ${blur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
1952
- },
1953
- default: {
1954
- shadowOpacity: 0,
1955
- elevation: 0
1956
- }
1957
- });
1958
- } else {
1959
- if (isHovered) {
1960
- const hoverOffset = Math.max(1, Math.round(offset / 2));
1961
- const hoverBlur = Math.max(1, Math.round(blur / 2));
1962
- return Platform.select({
1963
- web: {
1964
- boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
1965
- },
1966
- default: {
1967
- shadowColor: "#000",
1968
- shadowOffset: { width: hoverOffset, height: hoverOffset },
1969
- shadowOpacity: 0.2,
1970
- shadowRadius: hoverBlur / 2,
1971
- elevation: hoverOffset
1972
- }
1973
- });
1974
- }
1975
- return Platform.select({
1976
- web: {
1977
- boxShadow: `${offset}px ${offset}px ${blur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
1978
- },
1979
- default: {
1980
- shadowColor: "#000",
1981
- shadowOffset: { width: offset, height: offset },
1982
- shadowOpacity: 0.3,
1983
- shadowRadius: blur / 2,
1984
- elevation: offset
1985
- }
1986
- });
1987
- }
2172
+ function recessDepth(inherited, planesDown, mode) {
2173
+ let plane = inherited.level;
2174
+ for (let i = 0; i < planesDown; i++) plane = pressedLevel(plane);
2175
+ const backgroundColor = surfaceBackground(plane, mode);
2176
+ return { plane, backgroundColor, depthStyle: getPressedRecessShadow(backgroundColor, mode) };
1988
2177
  }
1989
- var FLOATING_ELEVATION_MIN = 4;
1990
- function getElevationShadow(baseColor, level, theme, isHovered = false) {
1991
- const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
1992
- if (elevationShadowCache.has(cacheKey)) {
1993
- return elevationShadowCache.get(cacheKey);
2178
+ function resolveSurfaceDepth(inherited, props) {
2179
+ const mode = props.theme ?? inherited.mode;
2180
+ const elevation = props.elevation ?? 0;
2181
+ if (props.pressed || elevation < 0) {
2182
+ const down = props.pressed ? 1 : -elevation;
2183
+ return { mode, step: 0, lifted: false, ...recessDepth(inherited, down, mode) };
1994
2184
  }
1995
- const result = level > 0 && level < FLOATING_ELEVATION_MIN ? {} : calculateElevationShadow(baseColor, level, theme, isHovered);
1996
- if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
1997
- const firstKey = elevationShadowCache.keys().next().value;
1998
- elevationShadowCache.delete(firstKey);
1999
- }
2000
- elevationShadowCache.set(cacheKey, result);
2001
- return result;
2002
- }
2003
- function getBaseSurfaceColor(theme) {
2004
- return theme === "light" ? semanticColorsLight["surface-raised"] : semanticColorsDark["surface-elevated"];
2185
+ const step = props.level != null ? 0 : props.raise ?? elevation;
2186
+ const floating = step >= FLOATING_ELEVATION_MIN;
2187
+ const plane = props.level ?? (floating ? "overlay" : raisedLevel(inherited.level, step));
2188
+ const lifted = props.lift ?? step > 0;
2189
+ const liftStep = Math.max(1, Math.min(5, step));
2190
+ const depthStyle = lifted ? liftStyle(liftStep, mode, props.liftOptions) : {};
2191
+ return { mode, plane, backgroundColor: surfaceBackground(plane, mode), depthStyle, step, lifted };
2005
2192
  }
2006
- var componentElevationRanges = {
2007
- button: {
2008
- allowed: [2],
2009
- default: 2,
2010
- hover: 3
2011
- },
2012
- card: {
2013
- allowed: [1, 2, 3],
2014
- default: 2,
2015
- hover: 3
2016
- },
2017
- input: {
2018
- allowed: [-2, -1, 0],
2019
- default: -1
2020
- },
2021
- overlay: {
2022
- allowed: [4, 5],
2023
- default: 4
2024
- }
2025
- };
2026
- function getValidatedElevation(component, requested) {
2027
- const range = componentElevationRanges[component];
2028
- if (range.allowed.includes(requested)) {
2029
- return requested;
2030
- }
2031
- const sorted = [...range.allowed].sort((a, b) => a - b);
2032
- if (requested < sorted[0]) return sorted[0];
2033
- if (requested > sorted[sorted.length - 1]) return sorted[sorted.length - 1];
2034
- return sorted.reduce(
2035
- (prev, curr) => Math.abs(curr - requested) < Math.abs(prev - requested) ? curr : prev
2193
+ function useResolvedSurface(props) {
2194
+ const inherited = useSurface();
2195
+ const { level, raise, elevation, pressed, lift, liftOptions, theme } = props;
2196
+ return useMemo(
2197
+ () => resolveSurfaceDepth(inherited, {
2198
+ level,
2199
+ raise,
2200
+ elevation,
2201
+ pressed,
2202
+ lift,
2203
+ liftOptions,
2204
+ theme
2205
+ }),
2206
+ [inherited, level, raise, elevation, pressed, lift, liftOptions, theme]
2036
2207
  );
2037
2208
  }
2038
- function getTheme() {
2039
- if (typeof document === "undefined") return "dark";
2040
- return document.documentElement.classList.contains("light") ? "light" : "dark";
2041
- }
2042
- var listeners = [];
2043
- function subscribe(listener) {
2044
- listeners = [...listeners, listener];
2045
- if (typeof document !== "undefined" && listeners.length === 1) {
2046
- const observer = new MutationObserver((mutations) => {
2047
- for (const mutation of mutations) {
2048
- if (mutation.type === "attributes" && mutation.attributeName === "class") {
2049
- listeners.forEach((l) => l());
2050
- }
2051
- }
2052
- });
2053
- observer.observe(document.documentElement, {
2054
- attributes: true,
2055
- attributeFilter: ["class"]
2056
- });
2057
- subscribe._observer = observer;
2058
- }
2059
- return () => {
2060
- listeners = listeners.filter((l) => l !== listener);
2061
- if (listeners.length === 0 && subscribe._observer) {
2062
- subscribe._observer.disconnect();
2063
- subscribe._observer = null;
2064
- }
2065
- };
2066
- }
2067
- function getSnapshot() {
2068
- return getTheme();
2069
- }
2070
- function getServerSnapshot() {
2071
- return "dark";
2072
- }
2073
- function useTheme() {
2074
- return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2075
- }
2076
2209
 
2077
2210
  // src/components/ui/card/Card.tsx
2078
- var variantStyles = {
2211
+ var EDGE_CLASS = {
2079
2212
  elevated: "",
2080
- // Will be set dynamically via elevation system
2081
- outline: "border-2 border-hairline-strong",
2082
- // Thicker border with stronger contrast
2213
+ accent: "",
2083
2214
  filled: "",
2084
- // Will be set dynamically via elevation system
2085
- accent: "border border-hairline",
2215
+ outline: "border border-hairline-strong",
2086
2216
  subtle: "border border-hairline-subtle"
2087
2217
  };
2218
+ var LIFTED = {
2219
+ elevated: true,
2220
+ accent: true,
2221
+ filled: false,
2222
+ outline: false,
2223
+ subtle: false
2224
+ };
2225
+ var STAYS_ON_HOST = {
2226
+ elevated: false,
2227
+ accent: false,
2228
+ filled: false,
2229
+ outline: true,
2230
+ subtle: true
2231
+ };
2232
+ function useCardDepth(variant, elevation, hovered) {
2233
+ const raise = STAYS_ON_HOST[variant] ? void 0 : elevation;
2234
+ const resolved = useResolvedSurface({ raise, lift: LIFTED[variant] });
2235
+ const depthStyle = useMemo(() => {
2236
+ if (!hovered || !LIFTED[variant]) return resolved.depthStyle;
2237
+ const hoverStep = Math.min(3, resolved.step + 1);
2238
+ return liftStyle(hoverStep, resolved.mode);
2239
+ }, [hovered, variant, resolved]);
2240
+ return { ...resolved, depthStyle };
2241
+ }
2088
2242
  function Card({
2089
2243
  variant = "elevated",
2090
2244
  elevation = 2,
@@ -2105,89 +2259,54 @@ function Card({
2105
2259
  }) {
2106
2260
  const isClickable = isInteractive || !!onPress;
2107
2261
  const [isHovered, setIsHovered] = useState(false);
2108
- const theme = useTheme();
2109
- const elevationLevel = useMemo(() => {
2110
- const validated = getValidatedElevation("card", elevation);
2111
- if (variant === "outline" || variant === "accent" || variant === "subtle") {
2112
- return 1;
2113
- }
2114
- return validated;
2115
- }, [variant, elevation]);
2116
- const baseColor = useMemo(() => getBaseSurfaceColor(theme), [theme]);
2117
- const surfaceColor = useMemo(() => {
2118
- if ((variant === "outline" || variant === "accent") && theme === "light") {
2119
- return "#FAFAFA";
2120
- }
2121
- if (variant === "subtle") {
2122
- return getElevationSurface(baseColor, 0, theme);
2123
- }
2124
- return getElevationSurface(baseColor, elevationLevel, theme);
2125
- }, [baseColor, elevationLevel, theme, variant]);
2126
- const shadowStyle = useMemo(() => {
2127
- const shouldHover = isHovered && isClickable;
2128
- return getElevationShadow(baseColor, elevationLevel, theme, shouldHover);
2129
- }, [baseColor, elevationLevel, theme, isHovered, isClickable]);
2130
- const cardContent = isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
2131
- skeletonHasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
2132
- /* @__PURE__ */ jsx(View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
2133
- /* @__PURE__ */ jsx(View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
2134
- ] }),
2135
- /* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: skeletonContentLines }).map((_, i) => /* @__PURE__ */ jsx(
2136
- View,
2137
- {
2138
- className: cn(
2139
- "h-4 bg-interactive-disabled rounded",
2140
- i < skeletonContentLines - 1 ? "mb-2 w-full" : "w-4/5"
2141
- )
2142
- },
2143
- i
2144
- )) }),
2145
- skeletonHasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
2146
- ] }) : children;
2262
+ const depth = useCardDepth(variant, elevation, isHovered && isClickable);
2147
2263
  const baseClassName = cn(
2148
2264
  "rounded-lg overflow-hidden relative",
2149
- // Apply variant styles, but only use default border color if no custom borderColor
2150
- variant === "outline" ? borderColor ? "border-2" : variantStyles[variant] : variantStyles[variant],
2151
- // Remove Tailwind shadow classes - we're using elevation shadows via style prop
2265
+ borderColor ? "border" : EDGE_CLASS[variant],
2152
2266
  isClickable && "web:cursor-pointer web:transition-all web:duration-150",
2153
2267
  isClickable && "web:hover:-translate-y-0.5 active:scale-[0.99]",
2154
2268
  isLoading && "pointer-events-none animate-pulse",
2155
2269
  className
2156
2270
  );
2157
- const accentStyle = useMemo(() => variant === "accent" ? {
2158
- borderLeftWidth: accentWidth ?? 3,
2159
- borderLeftColor: accentColor ?? "var(--color-brand-primary)"
2160
- } : {}, [variant, accentWidth, accentColor]);
2161
2271
  const mergedStyle = useMemo(() => {
2162
- const elevationStyle = {
2163
- backgroundColor: bgColor || surfaceColor,
2272
+ const own = {
2273
+ backgroundColor: bgColor || depth.backgroundColor,
2164
2274
  borderRadius: 8,
2165
2275
  overflow: "hidden",
2166
- ...shadowStyle,
2167
- ...accentStyle
2276
+ ...depth.depthStyle
2168
2277
  };
2169
- if (borderColor) {
2170
- elevationStyle.borderColor = borderColor;
2278
+ if (variant === "accent") {
2279
+ own.borderLeftWidth = accentWidth ?? 3;
2280
+ own.borderLeftColor = accentColor ?? "var(--color-brand-primary)";
2171
2281
  }
2172
- if (!style) return elevationStyle;
2173
- return [elevationStyle, style];
2174
- }, [style, surfaceColor, shadowStyle, borderColor, bgColor, accentStyle]);
2175
- if (isClickable) {
2176
- return /* @__PURE__ */ jsx(
2177
- Pressable,
2178
- {
2179
- onPress,
2180
- onHoverIn: () => setIsHovered(true),
2181
- onHoverOut: () => setIsHovered(false),
2182
- accessibilityRole: "button",
2183
- className: baseClassName,
2184
- style: mergedStyle,
2185
- ...props,
2186
- children: cardContent
2187
- }
2188
- );
2189
- }
2190
- return /* @__PURE__ */ jsx(View, { className: baseClassName, style: mergedStyle, ...props, children: cardContent });
2282
+ if (borderColor) own.borderColor = borderColor;
2283
+ return style ? [own, style] : own;
2284
+ }, [style, depth, bgColor, borderColor, variant, accentWidth, accentColor]);
2285
+ const context = useMemo(
2286
+ () => ({ mode: depth.mode, level: depth.plane }),
2287
+ [depth.mode, depth.plane]
2288
+ );
2289
+ const content = isLoading ? /* @__PURE__ */ jsx(
2290
+ SkeletonBody,
2291
+ {
2292
+ hasHeader: skeletonHasHeader,
2293
+ hasFooter: skeletonHasFooter,
2294
+ contentLines: skeletonContentLines
2295
+ }
2296
+ ) : children;
2297
+ return /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: context, children: isClickable ? /* @__PURE__ */ jsx(
2298
+ Pressable,
2299
+ {
2300
+ onPress,
2301
+ onHoverIn: () => setIsHovered(true),
2302
+ onHoverOut: () => setIsHovered(false),
2303
+ accessibilityRole: "button",
2304
+ className: baseClassName,
2305
+ style: mergedStyle,
2306
+ ...props,
2307
+ children: content
2308
+ }
2309
+ ) : /* @__PURE__ */ jsx(View, { className: baseClassName, style: mergedStyle, ...props, children: content }) });
2191
2310
  }
2192
2311
  function CardHeader({ children, className }) {
2193
2312
  return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-6", className), children });
@@ -2198,60 +2317,88 @@ function CardContent({ children, className }) {
2198
2317
  function CardFooter({ children, className }) {
2199
2318
  return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
2200
2319
  }
2201
- var t2 = getSemanticColors("dark");
2202
- var solidVariantColors = {
2203
- success: t2["status-success"],
2204
- warning: t2["status-warning"],
2205
- error: t2["status-error"],
2206
- neutral: greyRamp[500]
2320
+ function SkeletonBody({ hasHeader, hasFooter, contentLines }) {
2321
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
2322
+ hasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
2323
+ /* @__PURE__ */ jsx(View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
2324
+ /* @__PURE__ */ jsx(View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
2325
+ ] }),
2326
+ /* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: contentLines }).map((_, i) => /* @__PURE__ */ jsx(
2327
+ View,
2328
+ {
2329
+ className: cn(
2330
+ "h-4 bg-interactive-disabled rounded",
2331
+ i < contentLines - 1 ? "mb-2 w-full" : "w-4/5"
2332
+ )
2333
+ },
2334
+ i
2335
+ )) }),
2336
+ hasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
2337
+ ] });
2338
+ }
2339
+ var solidFillToken = {
2340
+ success: "status-success",
2341
+ warning: "status-warning",
2342
+ error: "status-error",
2343
+ neutral: "text-tertiary"
2207
2344
  };
2208
- var ringVariantStyles = {
2209
- "on-track": {
2210
- backgroundColor: "rgba(46,213,115,0.15)",
2211
- borderWidth: 1,
2212
- borderColor: "rgba(46,213,115,0.3)"
2213
- },
2214
- deviation: {
2215
- backgroundColor: "rgba(245,158,11,0.15)",
2216
- borderWidth: 1,
2217
- borderColor: "rgba(245,158,11,0.25)"
2218
- },
2219
- future: {
2220
- backgroundColor: "rgba(107,114,128,0.1)",
2221
- borderWidth: 1,
2222
- borderStyle: "dashed",
2223
- borderColor: "rgba(107,114,128,0.2)"
2224
- }
2345
+ var ringWashToken = {
2346
+ "on-track": { fill: "status-success-subtle", border: "status-success-muted" },
2347
+ deviation: { fill: "status-warning-subtle", border: "status-warning-muted" }
2348
+ };
2349
+ var FUTURE_FILL = alpha(greyRamp[500], 0.1);
2350
+ var FUTURE_BORDER = alpha(greyRamp[500], 0.2);
2351
+ var glyphToken = {
2352
+ success: "text-inverse",
2353
+ warning: "text-inverse",
2354
+ error: "text-inverse",
2355
+ neutral: "text-inverse",
2356
+ "on-track": "status-success",
2357
+ deviation: "status-warning",
2358
+ future: "text-tertiary"
2225
2359
  };
2226
- var glowStyles = {
2227
- success: { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
2228
- warning: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
2229
- error: { boxShadow: "0 0 4px rgba(239,68,68,0.4)" },
2230
- neutral: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" },
2231
- "on-track": { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
2232
- deviation: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
2233
- future: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" }
2360
+ var glowColors2 = {
2361
+ success: semanticColorsDark["status-success"],
2362
+ warning: semanticColorsDark["status-warning"],
2363
+ error: semanticColorsDark["status-error"],
2364
+ neutral: greyRamp[500],
2365
+ "on-track": semanticColorsDark["status-success"],
2366
+ deviation: semanticColorsDark["status-warning"],
2367
+ future: greyRamp[500]
2234
2368
  };
2369
+ var glowStyles = Object.fromEntries(
2370
+ Object.entries(glowColors2).map(([variant, color]) => [variant, getGlowShadow(color, "subtle")])
2371
+ );
2235
2372
  var iconChars = {
2236
2373
  check: "\u2713",
2237
2374
  exclamation: "!",
2238
2375
  dash: "\u2014"
2239
2376
  };
2240
- var iconColors = {
2241
- success: "#0A5C52",
2242
- warning: "#6B4000",
2243
- error: "#5C1A1A",
2244
- neutral: greyRamp[200],
2245
- "on-track": t2["status-success"],
2246
- deviation: t2["status-warning"],
2247
- future: greyRamp[500]
2248
- };
2249
2377
  var sizeDimensions = {
2250
2378
  sm: { size: 8, showIcon: false },
2251
2379
  md: { size: 18, showIcon: true }
2252
2380
  };
2253
2381
  function isSolidVariant(variant) {
2254
- return variant in solidVariantColors;
2382
+ return variant in solidFillToken;
2383
+ }
2384
+ function ringStyle(variant) {
2385
+ if (variant === "future") {
2386
+ return {
2387
+ backgroundColor: FUTURE_FILL,
2388
+ borderWidth: 1,
2389
+ borderStyle: "dashed",
2390
+ borderColor: FUTURE_BORDER
2391
+ };
2392
+ }
2393
+ if (variant === "on-track" || variant === "deviation") {
2394
+ const tokens = ringWashToken[variant];
2395
+ return {
2396
+ backgroundColor: resolveColor(tokens.fill),
2397
+ borderWidth: 1,
2398
+ borderColor: resolveColor(tokens.border)
2399
+ };
2400
+ }
2401
+ return void 0;
2255
2402
  }
2256
2403
  function StatusDot({
2257
2404
  variant,
@@ -2264,7 +2411,7 @@ function StatusDot({
2264
2411
  }) {
2265
2412
  const config = sizeDimensions[size];
2266
2413
  const solid = isSolidVariant(variant);
2267
- const ring = ringVariantStyles[variant];
2414
+ const ring = ringStyle(variant);
2268
2415
  const glowStyle = glow ? glowStyles[variant] : null;
2269
2416
  const dot = /* @__PURE__ */ jsx(
2270
2417
  View,
@@ -2278,22 +2425,22 @@ function StatusDot({
2278
2425
  justifyContent: "center",
2279
2426
  flexShrink: 0
2280
2427
  },
2281
- solid ? { backgroundColor: solidVariantColors[variant] } : void 0,
2282
- ring ? ring : void 0,
2428
+ solid ? { backgroundColor: resolveColor(solidFillToken[variant]) } : void 0,
2429
+ ring,
2283
2430
  glowStyle ? glowStyle : void 0
2284
2431
  ],
2285
2432
  accessibilityRole: "image",
2286
2433
  accessibilityLabel: `${variant} status`,
2287
2434
  testID: "status-dot",
2288
- children: config.showIcon && icon && /* @__PURE__ */ jsx(
2289
- Text,
2435
+ children: config.showIcon && icon && // The glyph was 11px/900, off the type scale (TOKENS.md §4); `boldLabel` is
2436
+ // the 12px sans label step and `font-black` keeps the original weight.
2437
+ /* @__PURE__ */ jsx(
2438
+ Typography,
2290
2439
  {
2291
- style: {
2292
- fontSize: 11,
2293
- lineHeight: 11,
2294
- fontWeight: "900",
2295
- color: iconColors[variant]
2296
- },
2440
+ variant: "boldLabel",
2441
+ color: "inherit",
2442
+ className: "font-black leading-none",
2443
+ style: { color: resolveColor(glyphToken[variant]) },
2297
2444
  accessibilityElementsHidden: true,
2298
2445
  children: iconChars[icon]
2299
2446
  }
@@ -2311,9 +2458,11 @@ function StatusDot({
2311
2458
  children: [
2312
2459
  /* @__PURE__ */ jsx(View, { accessibilityElementsHidden: true, children: dot }),
2313
2460
  /* @__PURE__ */ jsx(
2314
- Text,
2461
+ Typography,
2315
2462
  {
2316
- style: { fontSize: 12, lineHeight: 16, color: greyRamp[400] },
2463
+ variant: "caption",
2464
+ color: "secondary",
2465
+ className: "leading-4",
2317
2466
  accessibilityElementsHidden: true,
2318
2467
  children: label
2319
2468
  }
@@ -2329,19 +2478,19 @@ var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
2329
2478
 
2330
2479
  // src/components/custom/Workout/MesoStatusCard.tsx
2331
2480
  var t3 = getSemanticColors("dark");
2332
- var BRAND_PRIMARY4 = t3["brand-primary"];
2481
+ var BRAND_PRIMARY3 = t3["brand-primary"];
2333
2482
  var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
2334
2483
  var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
2335
2484
  var SUCCESS = t3["status-success"];
2336
2485
  var WARNING = t3["status-warning"];
2337
2486
  var ERROR = t3["status-error"];
2338
- var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY4, BRAND_PRIMARY_LIGHT];
2487
+ var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY3, BRAND_PRIMARY_LIGHT];
2339
2488
  var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
2340
- 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%)";
2489
+ var GAUGE_GRADIENT = `linear-gradient(90deg, ${alpha(SUCCESS, 0.25)} 0%, ${alpha(WARNING, 0.25)} 50%, ${alpha(ERROR, 0.25)} 100%)`;
2341
2490
  var STATUS_VARIANTS = {
2342
- success: { bg: "rgba(46,213,115,0.15)", border: "rgba(46,213,115,0.3)", text: SUCCESS },
2343
- warning: { bg: "rgba(249,180,21,0.15)", border: "rgba(249,180,21,0.3)", text: WARNING },
2344
- error: { bg: "rgba(209,67,67,0.15)", border: "rgba(209,67,67,0.25)", text: ERROR }
2491
+ success: { bg: alpha(SUCCESS, 0.15), border: alpha(SUCCESS, 0.3), text: SUCCESS },
2492
+ warning: { bg: alpha(WARNING, 0.15), border: alpha(WARNING, 0.3), text: WARNING },
2493
+ error: { bg: alpha(ERROR, 0.15), border: alpha(ERROR, 0.25), text: ERROR }
2345
2494
  };
2346
2495
  function clamp012(value) {
2347
2496
  if (!Number.isFinite(value)) return 0;
@@ -2360,15 +2509,7 @@ function renderCoachingText(text, highlights) {
2360
2509
  if (escaped.length === 0) return text;
2361
2510
  const regex = new RegExp(`(${escaped.join("|")})`, "g");
2362
2511
  return text.split(regex).map(
2363
- (part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(
2364
- Text,
2365
- {
2366
- className: "text-text-primary",
2367
- style: { fontWeight: "700" },
2368
- children: part
2369
- },
2370
- `${part}-${index}`
2371
- ) : /* @__PURE__ */ jsx(Fragment$1, { children: part }, `t-${index}`)
2512
+ (part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(Text, { className: "text-text-primary", style: { fontWeight: "700" }, children: part }, `${part}-${index}`) : /* @__PURE__ */ jsx(Fragment, { children: part }, `t-${index}`)
2372
2513
  );
2373
2514
  }
2374
2515
  function StatusPill({ badge }) {
@@ -2453,41 +2594,34 @@ function Gauge({ gauge }) {
2453
2594
  "aria-valuemax": 100,
2454
2595
  testID: "meso-status-card-gauge",
2455
2596
  children: [
2456
- /* @__PURE__ */ jsxs(
2457
- View,
2458
- {
2459
- className: "flex-row items-center justify-between",
2460
- accessibilityElementsHidden: true,
2461
- children: [
2462
- /* @__PURE__ */ jsx(
2463
- Text,
2464
- {
2465
- className: "text-text-secondary",
2466
- style: {
2467
- fontSize: 10,
2468
- fontFamily: "Inter, sans-serif",
2469
- fontWeight: "500",
2470
- letterSpacing: 0.5,
2471
- textTransform: "uppercase"
2472
- },
2473
- children: gauge.label
2474
- }
2475
- ),
2476
- gauge.sublabel != null && /* @__PURE__ */ jsx(
2477
- Text,
2478
- {
2479
- className: "text-text-tertiary",
2480
- style: {
2481
- fontSize: 10,
2482
- fontFamily: "Inter, sans-serif",
2483
- fontWeight: "500"
2484
- },
2485
- children: gauge.sublabel
2486
- }
2487
- )
2488
- ]
2489
- }
2490
- ),
2597
+ /* @__PURE__ */ jsxs(View, { className: "flex-row items-center justify-between", accessibilityElementsHidden: true, children: [
2598
+ /* @__PURE__ */ jsx(
2599
+ Text,
2600
+ {
2601
+ className: "text-text-secondary",
2602
+ style: {
2603
+ fontSize: 10,
2604
+ fontFamily: "Inter, sans-serif",
2605
+ fontWeight: "500",
2606
+ letterSpacing: 0.5,
2607
+ textTransform: "uppercase"
2608
+ },
2609
+ children: gauge.label
2610
+ }
2611
+ ),
2612
+ gauge.sublabel != null && /* @__PURE__ */ jsx(
2613
+ Text,
2614
+ {
2615
+ className: "text-text-tertiary",
2616
+ style: {
2617
+ fontSize: 10,
2618
+ fontFamily: "Inter, sans-serif",
2619
+ fontWeight: "500"
2620
+ },
2621
+ children: gauge.sublabel
2622
+ }
2623
+ )
2624
+ ] }),
2491
2625
  /* @__PURE__ */ jsxs(
2492
2626
  View,
2493
2627
  {
@@ -2509,7 +2643,7 @@ function Gauge({ gauge }) {
2509
2643
  bottom: 0,
2510
2644
  width: 1,
2511
2645
  marginLeft: -0.5,
2512
- backgroundColor: "rgba(255,255,255,0.3)"
2646
+ backgroundColor: alpha(primitiveColors.white, 0.3)
2513
2647
  },
2514
2648
  testID: "meso-status-card-gauge-center"
2515
2649
  }
@@ -2528,7 +2662,8 @@ function Gauge({ gauge }) {
2528
2662
  borderRadius: 9999,
2529
2663
  borderWidth: 2,
2530
2664
  backgroundColor: markerColor,
2531
- boxShadow: "0 0 4px rgba(0,0,0,0.5)"
2665
+ // A knob resting on the gauge: lift, with the ring as its edge.
2666
+ ...liftStyle(1, "dark", { rim: 0 })
2532
2667
  },
2533
2668
  testID: "meso-status-card-gauge-marker"
2534
2669
  }
@@ -2580,30 +2715,23 @@ function MesoStatusCard({
2580
2715
  ),
2581
2716
  /* @__PURE__ */ jsxs(View, { style: { padding: 14, gap: 14 }, testID: "meso-status-card-body", children: [
2582
2717
  /* @__PURE__ */ jsxs(View, { testID: "meso-status-card-header", children: [
2583
- /* @__PURE__ */ jsxs(
2584
- View,
2585
- {
2586
- className: "flex-row items-center justify-between",
2587
- style: { gap: 8 },
2588
- children: [
2589
- /* @__PURE__ */ jsx(
2590
- Text,
2591
- {
2592
- className: "text-text-primary",
2593
- style: {
2594
- flexShrink: 1,
2595
- fontSize: 15,
2596
- fontFamily: '"Space Grotesk", sans-serif',
2597
- fontWeight: "700"
2598
- },
2599
- testID: "meso-status-card-name",
2600
- children: mesoName
2601
- }
2602
- ),
2603
- /* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
2604
- ]
2605
- }
2606
- ),
2718
+ /* @__PURE__ */ jsxs(View, { className: "flex-row items-center justify-between", style: { gap: 8 }, children: [
2719
+ /* @__PURE__ */ jsx(
2720
+ Text,
2721
+ {
2722
+ className: "text-text-primary",
2723
+ style: {
2724
+ flexShrink: 1,
2725
+ fontSize: 15,
2726
+ fontFamily: '"Space Grotesk", sans-serif',
2727
+ fontWeight: "700"
2728
+ },
2729
+ testID: "meso-status-card-name",
2730
+ children: mesoName
2731
+ }
2732
+ ),
2733
+ /* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
2734
+ ] }),
2607
2735
  /* @__PURE__ */ jsx(
2608
2736
  Text,
2609
2737
  {
@@ -2618,23 +2746,15 @@ function MesoStatusCard({
2618
2746
  }
2619
2747
  )
2620
2748
  ] }),
2621
- metrics.length > 0 && /* @__PURE__ */ jsx(
2622
- View,
2623
- {
2624
- className: "flex-row flex-wrap",
2625
- style: { gap: 8 },
2626
- testID: "meso-status-card-metrics",
2627
- children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell, { metric }, `${metric.label}-${index}`))
2628
- }
2629
- ),
2749
+ metrics.length > 0 && /* @__PURE__ */ jsx(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}`)) }),
2630
2750
  gauges.length > 0 && /* @__PURE__ */ jsx(View, { style: { gap: 12 }, testID: "meso-status-card-gauges", children: gauges.map((gauge, index) => /* @__PURE__ */ jsx(Gauge, { gauge }, `${gauge.label}-${index}`)) }),
2631
2751
  coaching != null && /* @__PURE__ */ jsx(
2632
2752
  View,
2633
2753
  {
2634
2754
  style: {
2635
- backgroundColor: "rgba(249,180,21,0.06)",
2755
+ backgroundColor: alpha(WARNING, 0.06),
2636
2756
  borderWidth: 1,
2637
- borderColor: "rgba(249,180,21,0.15)",
2757
+ borderColor: alpha(WARNING, 0.15),
2638
2758
  borderRadius: 8,
2639
2759
  paddingVertical: 10,
2640
2760
  paddingHorizontal: 12
@@ -2660,9 +2780,9 @@ function MesoStatusCard({
2660
2780
  className: "flex-row items-center",
2661
2781
  style: {
2662
2782
  gap: 8,
2663
- backgroundColor: "rgba(46,213,115,0.06)",
2783
+ backgroundColor: alpha(SUCCESS, 0.06),
2664
2784
  borderWidth: 1,
2665
- borderColor: "rgba(46,213,115,0.2)",
2785
+ borderColor: alpha(SUCCESS, 0.2),
2666
2786
  borderRadius: 8,
2667
2787
  paddingVertical: 10,
2668
2788
  paddingHorizontal: 12