@titan-design/react-ui 0.4.0 → 0.6.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 (150) hide show
  1. package/dist/MesoStatusCard-CQk71hSi.d.mts +77 -0
  2. package/dist/MesoStatusCard-CQk71hSi.d.ts +77 -0
  3. package/dist/bodymap.d.mts +246 -3
  4. package/dist/bodymap.d.ts +246 -3
  5. package/dist/bodymap.js +232 -185
  6. package/dist/bodymap.js.map +1 -1
  7. package/dist/bodymap.mjs +1963 -11
  8. package/dist/bodymap.mjs.map +1 -1
  9. package/dist/index.d.mts +193 -744
  10. package/dist/index.d.ts +193 -744
  11. package/dist/index.js +1551 -1856
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +10770 -8213
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/pages-D7Jlssvp.d.ts +791 -0
  16. package/dist/pages-MO0JCySL.d.mts +791 -0
  17. package/dist/pages.d.mts +4 -0
  18. package/dist/pages.d.ts +4 -0
  19. package/dist/pages.js +6694 -0
  20. package/dist/pages.js.map +1 -0
  21. package/dist/pages.mjs +6674 -0
  22. package/dist/pages.mjs.map +1 -0
  23. package/dist/theme/index.d.mts +473 -211
  24. package/dist/theme/index.d.ts +473 -211
  25. package/dist/theme/index.js +341 -127
  26. package/dist/theme/index.js.map +1 -1
  27. package/dist/theme/index.mjs +2085 -2
  28. package/dist/theme/index.mjs.map +1 -1
  29. package/dist/theme/tokens-css.js +148 -139
  30. package/dist/theme/tokens-css.js.map +1 -1
  31. package/dist/theme/tokens-css.mjs +582 -1
  32. package/dist/theme/tokens-css.mjs.map +1 -1
  33. package/package.json +11 -7
  34. package/src/components/custom/DateTime/DateTime.stories.tsx +82 -6
  35. package/src/components/custom/DateTime/DateTime.test.tsx +29 -3
  36. package/src/components/custom/DateTime/DateTime.tsx +55 -15
  37. package/src/components/custom/Gauge/Gauge.test.tsx +2 -2
  38. package/src/components/custom/Gauge/Gauge.tsx +6 -3
  39. package/src/components/custom/Scatter/Scatter.tsx +3 -5
  40. package/src/components/custom/Treemap/Treemap.tsx +3 -5
  41. package/src/components/custom/Typography/Typography.stories.tsx +45 -27
  42. package/src/components/custom/Typography/Typography.test.tsx +13 -3
  43. package/src/components/custom/Typography/Typography.tsx +5 -0
  44. package/src/components/custom/Workout/ActiveWorkoutPage.tsx +2 -1
  45. package/src/components/custom/Workout/BaseBadge.stories.tsx +3 -3
  46. package/src/components/custom/Workout/BaseBadge.test.tsx +1 -1
  47. package/src/components/custom/Workout/BaseBadge.tsx +1 -1
  48. package/src/components/custom/Workout/BodyMap.tsx +6 -3
  49. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +6 -3
  50. package/src/components/custom/Workout/CapacityBandChart.test.tsx +2 -2
  51. package/src/components/custom/Workout/CapacityBandChart.tsx +9 -6
  52. package/src/components/custom/Workout/DeviationBar.test.tsx +1 -1
  53. package/src/components/custom/Workout/DeviationBar.tsx +7 -4
  54. package/src/components/custom/Workout/ExerciseCard.tsx +5 -1
  55. package/src/components/custom/Workout/ExerciseDetailPage.tsx +19 -5
  56. package/src/components/custom/Workout/InputBar.tsx +2 -1
  57. package/src/components/custom/Workout/IntensityBar.test.tsx +112 -60
  58. package/src/components/custom/Workout/IntensityBar.tsx +113 -58
  59. package/src/components/custom/Workout/MesoCard.tsx +8 -3
  60. package/src/components/custom/Workout/MesoProgressBar.test.tsx +1 -1
  61. package/src/components/custom/Workout/MesoProgressBar.tsx +3 -2
  62. package/src/components/custom/Workout/MesoStatusCard.tsx +20 -13
  63. package/src/components/custom/Workout/MuscleGroupChip.tsx +7 -4
  64. package/src/components/custom/Workout/PlaceholderStrip.tsx +5 -9
  65. package/src/components/custom/Workout/PrBadge.tsx +7 -4
  66. package/src/components/custom/Workout/PrHistoryModal.tsx +6 -5
  67. package/src/components/custom/Workout/ProgramPlanningPage.tsx +2 -1
  68. package/src/components/custom/Workout/README.md +50 -0
  69. package/src/components/custom/Workout/ReadinessCheck.tsx +7 -4
  70. package/src/components/custom/Workout/RestTimer.test.tsx +41 -10
  71. package/src/components/custom/Workout/RestTimer.tsx +50 -44
  72. package/src/components/custom/Workout/SetRow.tsx +12 -2
  73. package/src/components/custom/Workout/Sparkline.tsx +2 -1
  74. package/src/components/custom/Workout/StatusDot.test.tsx +2 -2
  75. package/src/components/custom/Workout/StatusDot.tsx +12 -9
  76. package/src/components/custom/Workout/StrengthTrendChart.tsx +9 -6
  77. package/src/components/custom/Workout/SupersetWrapper.tsx +2 -1
  78. package/src/components/custom/Workout/TempoDisplay.stories.tsx +69 -2
  79. package/src/components/custom/Workout/TempoDisplay.test.tsx +35 -0
  80. package/src/components/custom/Workout/TempoDisplay.tsx +109 -3
  81. package/src/components/custom/Workout/VelocityStrip.test.tsx +89 -2
  82. package/src/components/custom/Workout/VelocityStrip.tsx +203 -38
  83. package/src/components/custom/Workout/WeekRow.test.tsx +2 -2
  84. package/src/components/custom/Workout/WeekRow.tsx +3 -2
  85. package/src/components/custom/Workout/WeightBadge.test.tsx +2 -2
  86. package/src/components/custom/Workout/WeightBadge.tsx +8 -4
  87. package/src/components/custom/Workout/WorkoutCard.tsx +5 -2
  88. package/src/components/custom/Workout/WorkoutPill.tsx +12 -8
  89. package/src/components/custom/Workout/icons.tsx +7 -0
  90. package/src/components/custom/Workout/index.ts +38 -47
  91. package/src/components/icons/SvgIcon.tsx +50 -0
  92. package/src/components/icons/icons.stories.tsx +57 -0
  93. package/src/components/icons/icons.test.tsx +43 -0
  94. package/src/components/icons/icons.tsx +45 -0
  95. package/src/components/icons/index.ts +4 -0
  96. package/src/components/index.ts +6 -0
  97. package/src/components/shell/BrandLockup.stories.tsx +27 -0
  98. package/src/components/shell/BrandLockup.test.tsx +23 -0
  99. package/src/components/shell/BrandLockup.tsx +47 -0
  100. package/src/components/shell/DeviceIndicator.stories.tsx +28 -0
  101. package/src/components/shell/DeviceIndicator.test.tsx +26 -0
  102. package/src/components/shell/DeviceIndicator.tsx +52 -0
  103. package/src/components/shell/DeviceMenu.stories.tsx +47 -0
  104. package/src/components/shell/DeviceMenu.test.tsx +40 -0
  105. package/src/components/shell/DeviceMenu.tsx +65 -0
  106. package/src/components/shell/DeviceRow.stories.tsx +38 -0
  107. package/src/components/shell/DeviceRow.test.tsx +37 -0
  108. package/src/components/shell/DeviceRow.tsx +58 -0
  109. package/src/components/shell/README.md +86 -0
  110. package/src/components/shell/SessionStatePill.stories.tsx +27 -0
  111. package/src/components/shell/SessionStatePill.test.tsx +25 -0
  112. package/src/components/shell/SessionStatePill.tsx +46 -0
  113. package/src/components/shell/TopBar.stories.tsx +49 -0
  114. package/src/components/shell/TopBar.test.tsx +36 -0
  115. package/src/components/shell/TopBar.tsx +89 -0
  116. package/src/components/shell/index.ts +8 -0
  117. package/src/components/ui/indicator/Indicator.stories.tsx +37 -1
  118. package/src/components/ui/indicator/Indicator.test.tsx +19 -1
  119. package/src/components/ui/indicator/Indicator.tsx +45 -6
  120. package/src/components/ui/indicator/index.ts +1 -1
  121. package/src/components/ui/spinner/Spinner.tsx +3 -2
  122. package/src/components/ui/toolbar-button/ToolbarButton.tsx +2 -1
  123. package/src/index.ts +3 -2
  124. package/src/pages.ts +61 -0
  125. package/src/test/stories-smoke.test.tsx +50 -0
  126. package/src/theme/ColorSystem.stories.tsx +323 -0
  127. package/src/theme/Colors.stories.tsx +69 -1
  128. package/src/theme/barrel.ts +54 -0
  129. package/src/theme/config.ts +16 -3
  130. package/src/theme/extracted-colors-dataviz.ts +21 -0
  131. package/src/theme/extracted-colors-ui.ts +20 -0
  132. package/src/theme/global.css +64 -52
  133. package/src/theme/gradients.test.ts +25 -0
  134. package/src/theme/gradients.ts +36 -0
  135. package/src/theme/index.ts +8 -43
  136. package/src/theme/native-theming-guard.test.ts +117 -0
  137. package/src/theme/tokens/primitives.test.ts +232 -0
  138. package/src/theme/tokens/primitives.ts +247 -0
  139. package/src/theme/tokens/semantic.ts +93 -81
  140. package/src/theme/workout-tokens.ts +22 -21
  141. package/src/utils/avatar-color.ts +3 -3
  142. package/tailwind.config.js +10 -3
  143. package/dist/bodymap-BhG55xHM.d.mts +0 -318
  144. package/dist/bodymap-BhG55xHM.d.ts +0 -318
  145. package/dist/chunk-2SISKTWM.mjs +0 -1027
  146. package/dist/chunk-2SISKTWM.mjs.map +0 -1
  147. package/dist/chunk-7XPB4NAO.mjs +0 -1013
  148. package/dist/chunk-7XPB4NAO.mjs.map +0 -1
  149. package/dist/chunk-SNVKL5WZ.mjs +0 -883
  150. package/dist/chunk-SNVKL5WZ.mjs.map +0 -1
package/dist/bodymap.mjs CHANGED
@@ -1,9 +1,421 @@
1
- import { WORKOUT_TOKENS, cn, Badge, Sparkline, MesoStatusCard } from './chunk-2SISKTWM.mjs';
2
- import { jsxs, jsx, resolveColor } from './chunk-SNVKL5WZ.mjs';
3
- import './chunk-7XPB4NAO.mjs';
4
- import { useMemo, useState, useEffect } from 'react';
5
- import { Animated, Easing, View, Text, Pressable, ScrollView } from 'react-native';
1
+ import { useMemo, useState, useEffect, Fragment as Fragment$1, useSyncExternalStore } from 'react';
2
+ import { Platform, Animated, Easing, View, Text, Pressable, ScrollView } from 'react-native';
6
3
  import BodyHighlighter from 'react-native-body-highlighter';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { Fragment, jsx as jsx$1, jsxs as jsxs$1 } from 'react/jsx-runtime';
7
+
8
+ // src/components/custom/Workout/BodyMap.tsx
9
+ function cn(...inputs) {
10
+ return twMerge(clsx(inputs));
11
+ }
12
+
13
+ // src/theme/tokens/primitives.ts
14
+ var primitiveColors = {
15
+ // Blue scale (primary brand)
16
+ blue: {
17
+ 400: "#60A5FA",
18
+ 600: "#5048E5",
19
+ // Primary main
20
+ 700: "#3832A0"},
21
+ // Red scale (error)
22
+ red: {
23
+ // Error light
24
+ 500: "#EF4444",
25
+ 600: "#D14343"},
26
+ // Vivid red scale (alert)
27
+ redVivid: {
28
+ 400: "#FF6070",
29
+ // Error vivid light
30
+ 500: "#FF4757",
31
+ 700: "#C42539"},
32
+ // Neutral/Gray scale
33
+ neutral: {
34
+ 50: "#FAFAFA",
35
+ 100: "#F3F4F6",
36
+ 300: "#D1D5DB",
37
+ 400: "#9CA3AF",
38
+ 500: "#6B7280",
39
+ 600: "#4B5563",
40
+ 900: "#111827"},
41
+ // Charcoal scale (dark backgrounds)
42
+ charcoal: {
43
+ 200: "#3C3C3C",
44
+ 300: "#2C2C2C",
45
+ 400: "#1F1F1F",
46
+ 500: "#1C1C1C",
47
+ 600: "#191919",
48
+ 700: "#161616",
49
+ 900: "#101010"
50
+ },
51
+ // Pure colors
52
+ white: "#FFFFFF"};
53
+ var primitiveRamps = {
54
+ red: {
55
+ 50: "#FFF4F4",
56
+ 500: "#E05254",
57
+ 600: "#D14343",
58
+ // pin
59
+ 700: "#A4221C"},
60
+ orange: {
61
+ 200: "#FFC7A2",
62
+ 300: "#FFA063",
63
+ 400: "#FF7900",
64
+ // pin
65
+ 500: "#DA5F00",
66
+ 600: "#B94A00"},
67
+ amber: {
68
+ 50: "#FFF7DD",
69
+ 200: "#FFD352",
70
+ 300: "#F9B415",
71
+ 500: "#C27400"},
72
+ green: {
73
+ 50: "#E3FFEE",
74
+ 200: "#58F69E",
75
+ 300: "#2ED573",
76
+ 600: "#298732"},
77
+ cyan: {
78
+ 300: "#22D3EE",
79
+ // pin
80
+ 400: "#01B5D1",
81
+ 500: "#2697B7",
82
+ 600: "#307B9B",
83
+ 700: "#2A617F",
84
+ 800: "#22465F"},
85
+ blue: {
86
+ 50: "#EFF8FF",
87
+ 300: "#78C2FF",
88
+ 500: "#2196F3",
89
+ // pin
90
+ 600: "#1072CB"}};
91
+ var divergingScale = [
92
+ primitiveRamps.blue[500],
93
+ // under
94
+ primitiveRamps.cyan[300],
95
+ // maintenance
96
+ primitiveRamps.green[200],
97
+ // optimal (light center)
98
+ primitiveRamps.amber[300],
99
+ // approaching
100
+ primitiveRamps.red[600]
101
+ // over
102
+ ];
103
+ var discreteRainbow = [
104
+ "#E8ECFB",
105
+ "#D9CCE3",
106
+ "#D1BBD7",
107
+ "#CAACCB",
108
+ "#BA8DB4",
109
+ "#AE76A3",
110
+ "#AA6F9E",
111
+ "#994F88",
112
+ "#882E72",
113
+ "#1965B0",
114
+ "#437DBF",
115
+ "#5289C7",
116
+ "#6195CF",
117
+ "#7BAFDE",
118
+ "#4EB265",
119
+ "#90C987",
120
+ "#CAE0AB",
121
+ "#F7F056",
122
+ "#F7CB45",
123
+ "#F6C141",
124
+ "#F4A736",
125
+ "#F1932D",
126
+ "#EE8026",
127
+ "#E8601C",
128
+ "#E65518",
129
+ "#DC050C",
130
+ "#A5170E",
131
+ "#72190E",
132
+ "#42150A"
133
+ ];
134
+
135
+ // src/theme/tokens/semantic.ts
136
+ var semanticColorsLight = {
137
+ // Brand colors (brand-*)
138
+ "brand-primary": primitiveRamps.orange[400],
139
+ "brand-primary-light": primitiveRamps.orange[300],
140
+ "brand-primary-dark": primitiveRamps.orange[500],
141
+ "brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
142
+ "brand-primary-hover": primitiveRamps.orange[500],
143
+ "brand-primary-active": primitiveRamps.orange[600],
144
+ "brand-secondary": primitiveRamps.cyan[600],
145
+ "brand-secondary-light": primitiveRamps.cyan[500],
146
+ "brand-secondary-dark": primitiveRamps.cyan[700],
147
+ "brand-secondary-subtle": "rgba(48, 123, 155, 0.08)",
148
+ "brand-secondary-hover": primitiveRamps.cyan[700],
149
+ "brand-secondary-active": primitiveRamps.cyan[800],
150
+ // Text on brand backgrounds (on-*)
151
+ "on-brand-primary": primitiveColors.white,
152
+ "on-brand-secondary": primitiveColors.white,
153
+ // Status colors (status-*)
154
+ "status-success": primitiveRamps.green[300],
155
+ "status-success-light": primitiveRamps.green[200],
156
+ "status-success-dark": primitiveRamps.green[600],
157
+ "status-success-subtle": primitiveRamps.green[50],
158
+ "status-error": primitiveRamps.red[600],
159
+ "status-error-light": primitiveRamps.red[500],
160
+ "status-error-dark": primitiveRamps.red[700],
161
+ "status-error-subtle": primitiveRamps.red[50],
162
+ "status-error-vivid": primitiveColors.redVivid[500],
163
+ // vivid alert red
164
+ "status-error-vivid-light": primitiveColors.redVivid[400],
165
+ "status-error-vivid-dark": primitiveColors.redVivid[700],
166
+ "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
167
+ "status-warning": primitiveRamps.amber[300],
168
+ "status-warning-light": primitiveRamps.amber[200],
169
+ "status-warning-dark": primitiveRamps.amber[500],
170
+ "status-warning-subtle": primitiveRamps.amber[50],
171
+ "status-info": primitiveRamps.blue[500],
172
+ "status-info-light": primitiveRamps.blue[300],
173
+ "status-info-dark": primitiveRamps.blue[600],
174
+ "status-info-subtle": primitiveRamps.blue[50],
175
+ // Text on status backgrounds (on-status-*)
176
+ "on-status-success": primitiveColors.white,
177
+ "on-status-error": primitiveColors.white,
178
+ "on-status-warning": primitiveColors.white,
179
+ "on-status-info": primitiveColors.white,
180
+ // Result/outcome indicators (result-*)
181
+ "result-improve": "#4caf50",
182
+ // Green - positive outcome
183
+ "result-improve-light": "rgba(76, 175, 80, 0.12)",
184
+ "result-improve-dark": "#248a24",
185
+ "result-degrade": "#ef5350",
186
+ // Red - negative outcome
187
+ "result-degrade-light": "rgba(239, 83, 80, 0.12)",
188
+ "result-degrade-dark": "#b30000",
189
+ "result-inconclusive": "#9E9A97",
190
+ // Gray - no clear result
191
+ "result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
192
+ "result-neutral": primitiveColors.neutral[500],
193
+ // Neutral baseline
194
+ // Text on result backgrounds (on-result-*)
195
+ "on-result-improve": primitiveColors.white,
196
+ "on-result-degrade": primitiveColors.white,
197
+ "on-result-inconclusive": primitiveColors.white,
198
+ // Data visualization colors (data-*)
199
+ // First 10 colors from discrete rainbow optimized for charts
200
+ "data-1": discreteRainbow[9],
201
+ // Blue
202
+ "data-2": discreteRainbow[14],
203
+ // Green
204
+ "data-3": discreteRainbow[17],
205
+ // Yellow
206
+ "data-4": discreteRainbow[25],
207
+ // Red
208
+ "data-5": discreteRainbow[8],
209
+ // Purple
210
+ "data-6": discreteRainbow[20],
211
+ // Orange
212
+ "data-7": discreteRainbow[13],
213
+ // Light Blue
214
+ "data-8": discreteRainbow[15],
215
+ // Light Green
216
+ "data-9": discreteRainbow[3],
217
+ // Lavender
218
+ "data-10": discreteRainbow[22],
219
+ // Dark Orange
220
+ // Text colors (text-*)
221
+ "text-primary": "#121828",
222
+ "text-secondary": "#65748B",
223
+ "text-tertiary": primitiveColors.neutral[400],
224
+ "text-disabled": "rgba(55, 65, 81, 0.48)",
225
+ "text-inverse": primitiveColors.white,
226
+ "text-link": primitiveColors.blue[600],
227
+ "text-link-hover": primitiveColors.blue[700],
228
+ // Surface colors (surface-*) - for elevated containers
229
+ "surface-base": primitiveColors.white,
230
+ "surface-elevated": primitiveColors.neutral[50],
231
+ // slightly off-white for elevated cards
232
+ "surface-raised": primitiveColors.neutral[100],
233
+ // light gray for raised cards
234
+ "surface-overlay": primitiveColors.white,
235
+ "surface-input": primitiveColors.neutral[50],
236
+ // Input field background (filled variant)
237
+ // Background colors (background-*)
238
+ "background-base": "#EBEBEB",
239
+ "background-default": primitiveColors.white,
240
+ "background-subtle": primitiveColors.neutral[50],
241
+ // Border colors (border-*)
242
+ "border-default": "#E8E9EB",
243
+ "border-subtle": primitiveColors.neutral[100],
244
+ "border-strong": primitiveColors.neutral[300],
245
+ "border-prominent": primitiveColors.neutral[400],
246
+ // high-visibility divider
247
+ "border-focus": primitiveColors.blue[600],
248
+ "border-input": primitiveColors.neutral[300],
249
+ // Input field border
250
+ "border-input-hover": primitiveColors.neutral[400],
251
+ // Input field border on hover
252
+ "border-input-focus": primitiveColors.blue[600],
253
+ // Input field border on focus
254
+ "border-input-error": primitiveColors.red[600],
255
+ // Input field border on error
256
+ // Interactive states (interactive-*)
257
+ "interactive-hover": "rgba(55, 65, 81, 0.04)",
258
+ "interactive-focus": "rgba(55, 65, 81, 0.12)",
259
+ "interactive-active": "rgba(55, 65, 81, 0.16)",
260
+ "interactive-selected": "rgba(55, 65, 81, 0.08)",
261
+ "interactive-disabled": "rgba(55, 65, 81, 0.12)",
262
+ "interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
263
+ // Divider
264
+ "divider": "#E8E9EB",
265
+ // Avatar default
266
+ "avatar-background": primitiveColors.neutral[500],
267
+ "avatar-text": primitiveColors.white
268
+ };
269
+ var semanticColorsDark = {
270
+ // Brand colors stay the same in dark mode
271
+ "brand-primary": primitiveRamps.orange[400],
272
+ "brand-primary-light": primitiveRamps.orange[300],
273
+ "brand-primary-dark": primitiveRamps.orange[500],
274
+ "brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
275
+ "brand-primary-hover": primitiveRamps.orange[300],
276
+ "brand-primary-active": primitiveRamps.orange[200],
277
+ "brand-secondary": primitiveRamps.cyan[600],
278
+ "brand-secondary-light": primitiveRamps.cyan[500],
279
+ "brand-secondary-dark": primitiveRamps.cyan[700],
280
+ "brand-secondary-subtle": "rgba(48, 123, 155, 0.12)",
281
+ "brand-secondary-hover": primitiveRamps.cyan[500],
282
+ "brand-secondary-active": primitiveRamps.cyan[400],
283
+ // Text on brand backgrounds
284
+ "on-brand-primary": primitiveColors.white,
285
+ "on-brand-secondary": primitiveColors.white,
286
+ // Status colors
287
+ "status-success": primitiveRamps.green[300],
288
+ "status-success-light": primitiveRamps.green[200],
289
+ "status-success-dark": primitiveRamps.green[600],
290
+ "status-success-subtle": "rgba(46, 213, 115, 0.12)",
291
+ "status-error": primitiveRamps.red[600],
292
+ "status-error-light": primitiveRamps.red[500],
293
+ "status-error-dark": primitiveRamps.red[700],
294
+ "status-error-subtle": "rgba(209, 67, 67, 0.12)",
295
+ "status-error-vivid": primitiveColors.redVivid[500],
296
+ "status-error-vivid-light": primitiveColors.redVivid[400],
297
+ "status-error-vivid-dark": primitiveColors.redVivid[700],
298
+ "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
299
+ "status-warning": primitiveRamps.amber[300],
300
+ "status-warning-light": primitiveRamps.amber[200],
301
+ "status-warning-dark": primitiveRamps.amber[500],
302
+ "status-warning-subtle": "rgba(249, 180, 21, 0.12)",
303
+ "status-info": primitiveRamps.blue[500],
304
+ "status-info-light": primitiveRamps.blue[300],
305
+ "status-info-dark": primitiveRamps.blue[600],
306
+ "status-info-subtle": "rgba(33, 150, 243, 0.12)",
307
+ // Text on status backgrounds
308
+ "on-status-success": primitiveColors.white,
309
+ "on-status-error": primitiveColors.white,
310
+ "on-status-warning": primitiveColors.white,
311
+ "on-status-info": primitiveColors.white,
312
+ // Result/outcome indicators (result-*)
313
+ "result-improve": "#4caf50",
314
+ "result-improve-light": "rgba(76, 175, 80, 0.16)",
315
+ "result-improve-dark": "#248a24",
316
+ "result-degrade": "#ef5350",
317
+ "result-degrade-light": "rgba(239, 83, 80, 0.16)",
318
+ "result-degrade-dark": "#b30000",
319
+ "result-inconclusive": "#9E9A97",
320
+ "result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
321
+ "result-neutral": primitiveColors.neutral[400],
322
+ // Text on result backgrounds
323
+ "on-result-improve": primitiveColors.white,
324
+ "on-result-degrade": primitiveColors.white,
325
+ "on-result-inconclusive": primitiveColors.white,
326
+ // Data visualization colors (same in dark mode for consistency)
327
+ "data-1": discreteRainbow[9],
328
+ "data-2": discreteRainbow[14],
329
+ "data-3": discreteRainbow[17],
330
+ "data-4": discreteRainbow[25],
331
+ "data-5": discreteRainbow[8],
332
+ "data-6": discreteRainbow[20],
333
+ "data-7": discreteRainbow[13],
334
+ "data-8": discreteRainbow[15],
335
+ "data-9": discreteRainbow[3],
336
+ "data-10": discreteRainbow[22],
337
+ // Text colors - inverted for dark mode
338
+ "text-primary": primitiveColors.neutral[100],
339
+ "text-secondary": primitiveColors.neutral[400],
340
+ "text-tertiary": primitiveColors.neutral[500],
341
+ "text-disabled": "rgba(255, 255, 255, 0.38)",
342
+ "text-inverse": primitiveColors.neutral[900],
343
+ "text-link": "#828DF8",
344
+ "text-link-hover": primitiveColors.blue[400],
345
+ // Surface colors - dark backgrounds
346
+ "surface-base": primitiveColors.charcoal[700],
347
+ // main surface
348
+ "surface-elevated": primitiveColors.charcoal[600],
349
+ // elevated surface
350
+ "surface-raised": primitiveColors.charcoal[500],
351
+ // raised surface
352
+ "surface-overlay": primitiveColors.charcoal[600],
353
+ // overlay surface
354
+ "surface-input": primitiveColors.charcoal[600],
355
+ // input surface
356
+ // Background colors
357
+ "background-base": primitiveColors.charcoal[900],
358
+ // darkest charcoal
359
+ "background-default": primitiveColors.charcoal[700],
360
+ // main background
361
+ "background-subtle": primitiveColors.charcoal[500],
362
+ // subtle background
363
+ // Border colors
364
+ "border-default": primitiveColors.charcoal[400],
365
+ // default border
366
+ "border-subtle": primitiveColors.charcoal[500],
367
+ // subtle border
368
+ "border-strong": primitiveColors.charcoal[300],
369
+ // strong border
370
+ "border-prominent": primitiveColors.charcoal[200],
371
+ // high-visibility divider
372
+ "border-focus": "#828DF8",
373
+ "border-input": primitiveColors.neutral[600],
374
+ "border-input-hover": primitiveColors.neutral[500],
375
+ "border-input-focus": "#828DF8",
376
+ "border-input-error": primitiveColors.red[500],
377
+ // Interactive states
378
+ "interactive-hover": "rgba(255, 255, 255, 0.04)",
379
+ "interactive-focus": "rgba(255, 255, 255, 0.12)",
380
+ "interactive-active": "rgba(255, 255, 255, 0.16)",
381
+ "interactive-selected": "rgba(255, 255, 255, 0.08)",
382
+ "interactive-disabled": "rgba(255, 255, 255, 0.12)",
383
+ "interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
384
+ // Divider
385
+ "divider": primitiveColors.charcoal[400],
386
+ // divider color
387
+ // Avatar default
388
+ "avatar-background": primitiveColors.neutral[600],
389
+ "avatar-text": primitiveColors.white
390
+ };
391
+ function getSemanticColors(mode) {
392
+ return mode === "dark" ? semanticColorsDark : semanticColorsLight;
393
+ }
394
+
395
+ // src/theme/resolve-color.ts
396
+ function resolveColor(token, mode = "dark") {
397
+ return Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
398
+ }
399
+
400
+ // src/theme/workout-tokens.ts
401
+ var WORKOUT_TOKENS = {
402
+ // BodyMap volume heatmap — the canonical `divergingScale` (under → optimal →
403
+ // over): a true diverging shape with a light green center, cool-blue under-
404
+ // trained end and warm-red over-reaching end (colorblind-robust in lightness).
405
+ heatmap: {
406
+ none: "#E0E0E0",
407
+ // no training data
408
+ under: divergingScale[0],
409
+ // below MEV
410
+ maintenance: divergingScale[1],
411
+ // MEV to MAV
412
+ productive: divergingScale[2],
413
+ // optimal center — MAV to MRV
414
+ approaching: divergingScale[3],
415
+ // near MRV
416
+ over: divergingScale[4]
417
+ // over MRV
418
+ }};
7
419
 
8
420
  // src/components/custom/Workout/muscleTaxonomy.ts
9
421
  var MuscleGroup = /* @__PURE__ */ ((MuscleGroup5) => {
@@ -188,9 +600,27 @@ var SLUG_TO_PRIMARY_MUSCLE = {
188
600
  abs: "abs" /* ABS */,
189
601
  obliques: "obliques" /* OBLIQUES */
190
602
  };
603
+ function wrapJsx(fn) {
604
+ return function(type, props, ...rest) {
605
+ if (props && typeof props.className === "string" && props.className) {
606
+ const cn2 = props.className;
607
+ const cssStyle = { $$css: true, [cn2]: cn2 };
608
+ const existing = props.style;
609
+ props = {
610
+ ...props,
611
+ style: existing ? [cssStyle, existing] : cssStyle
612
+ };
613
+ delete props.className;
614
+ }
615
+ return fn(type, props, ...rest);
616
+ };
617
+ }
618
+ var jsx = wrapJsx(jsx$1);
619
+ var jsxs = wrapJsx(jsxs$1);
191
620
 
192
621
  // src/components/custom/Workout/BodyMap.tsx
193
622
  var Body = BodyHighlighter.default ?? BodyHighlighter;
623
+ var BRAND_PRIMARY = getSemanticColors("dark")["brand-primary"];
194
624
  var OUTLINE_FILL = "rgba(255,255,255,0.08)";
195
625
  var OUTLINE_BORDER = "rgba(255,255,255,0.12)";
196
626
  var BODY_SCALE = 0.8;
@@ -369,7 +799,7 @@ function ViewToggle({ view, onViewChange }) {
369
799
  borderRadius: 9999,
370
800
  backgroundColor: active ? "rgba(255,121,0,0.16)" : "transparent",
371
801
  borderWidth: 1,
372
- borderColor: active ? "#FF7900" : resolveColor("border-strong")
802
+ borderColor: active ? BRAND_PRIMARY : resolveColor("border-strong")
373
803
  },
374
804
  testID: `body-map-toggle-${side}`,
375
805
  children: /* @__PURE__ */ jsx(
@@ -379,7 +809,7 @@ function ViewToggle({ view, onViewChange }) {
379
809
  fontSize: 12,
380
810
  fontFamily: "Inter, sans-serif",
381
811
  fontWeight: active ? "700" : "500",
382
- color: active ? "#FF7900" : resolveColor("text-secondary"),
812
+ color: active ? BRAND_PRIMARY : resolveColor("text-secondary"),
383
813
  textTransform: "capitalize"
384
814
  },
385
815
  children: side
@@ -411,7 +841,7 @@ function MuscleButton({ entry, highlighted, onMusclePress }) {
411
841
  paddingVertical: 3,
412
842
  borderRadius: 9999,
413
843
  borderWidth: 1,
414
- borderColor: highlighted ? "#FF7900" : resolveColor("border-default")
844
+ borderColor: highlighted ? BRAND_PRIMARY : resolveColor("border-default")
415
845
  },
416
846
  testID: `body-map-muscle-${entry.key}`,
417
847
  children: [
@@ -440,8 +870,310 @@ function MuscleButton({ entry, highlighted, onMusclePress }) {
440
870
  }
441
871
  );
442
872
  }
443
- var BRAND_PRIMARY = "#FF7900";
444
- var VOLUME_GRADIENT = "linear-gradient(90deg, #2196F3 0%, #14B8A6 50%, #D14343 100%)";
873
+ var sizeStyles = {
874
+ xs: "w-1 h-1",
875
+ sm: "w-1.5 h-1.5",
876
+ md: "w-2 h-2",
877
+ lg: "w-2.5 h-2.5"
878
+ };
879
+ var colorStyles = {
880
+ default: "bg-text-tertiary",
881
+ primary: "bg-brand-primary",
882
+ success: "bg-status-success",
883
+ error: "bg-status-error",
884
+ warning: "bg-status-warning",
885
+ info: "bg-status-info",
886
+ "error-vivid": "bg-status-error-vivid"
887
+ };
888
+ function Indicator({
889
+ size = "sm",
890
+ color = "default",
891
+ customColor,
892
+ glow = false,
893
+ ring = false,
894
+ pulse = false,
895
+ className,
896
+ style,
897
+ ...props
898
+ }) {
899
+ const pulseMode = pulse === true ? "opacity" : pulse || false;
900
+ const colorClass = !customColor ? colorStyles[color] : void 0;
901
+ const colorStyle = customColor ? { backgroundColor: customColor } : void 0;
902
+ if (pulseMode === "ping") {
903
+ return /* @__PURE__ */ jsxs(View, { className: cn("relative", sizeStyles[size], className), style, ...props, children: [
904
+ /* @__PURE__ */ jsx(
905
+ View,
906
+ {
907
+ className: cn("absolute inset-0 rounded-full animate-ping", colorClass),
908
+ style: colorStyle
909
+ }
910
+ ),
911
+ /* @__PURE__ */ jsx(
912
+ View,
913
+ {
914
+ className: cn(
915
+ "relative rounded-full",
916
+ sizeStyles[size],
917
+ colorClass,
918
+ ring && "border-2 border-background-base"
919
+ ),
920
+ style: colorStyle
921
+ }
922
+ )
923
+ ] });
924
+ }
925
+ const dynamicStyle = {
926
+ ...typeof style === "object" ? style : {},
927
+ ...colorStyle ?? {},
928
+ ...glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}
929
+ };
930
+ return /* @__PURE__ */ jsx(
931
+ View,
932
+ {
933
+ className: cn(
934
+ "rounded-full shrink-0",
935
+ sizeStyles[size],
936
+ colorClass,
937
+ pulseMode === "opacity" && "animate-pulse",
938
+ ring && "border-2 border-background-base",
939
+ glow && !customColor && color === "success" && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
940
+ glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
941
+ glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
942
+ glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
943
+ glow && !customColor && color === "error-vivid" && "shadow-[0_0_6px_rgba(255,71,87,0.6)]",
944
+ className
945
+ ),
946
+ style: Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style,
947
+ ...props
948
+ }
949
+ );
950
+ }
951
+
952
+ // src/components/ui/badge/Badge.tsx
953
+ var variantColorStyles = {
954
+ solid: {
955
+ default: "bg-border-strong text-text-inverse",
956
+ primary: "bg-brand-primary text-text-inverse",
957
+ secondary: "bg-brand-secondary text-text-inverse",
958
+ success: "bg-status-success text-text-inverse",
959
+ error: "bg-status-error text-text-inverse",
960
+ warning: "bg-status-warning text-text-inverse",
961
+ info: "bg-status-info text-text-inverse"
962
+ },
963
+ subtle: {
964
+ default: "bg-surface-raised text-text-secondary",
965
+ primary: "bg-brand-primary-subtle text-brand-primary",
966
+ secondary: "bg-brand-secondary-subtle text-brand-secondary",
967
+ success: "bg-status-success-subtle text-status-success",
968
+ error: "bg-status-error-subtle text-status-error",
969
+ warning: "bg-status-warning-subtle text-status-warning",
970
+ info: "bg-status-info-subtle text-status-info"
971
+ },
972
+ outline: {
973
+ default: "border border-border-strong text-text-secondary",
974
+ primary: "border border-brand-primary text-brand-primary",
975
+ secondary: "border border-brand-secondary text-brand-secondary",
976
+ success: "border border-status-success text-status-success",
977
+ error: "border border-status-error text-status-error",
978
+ warning: "border border-status-warning text-status-warning",
979
+ info: "border border-status-info text-status-info"
980
+ }
981
+ };
982
+ var sizeStyles2 = {
983
+ sm: "px-1.5 py-0.5 text-xs",
984
+ md: "px-2 py-0.5 text-xs",
985
+ lg: "px-2.5 py-1 text-sm"
986
+ };
987
+ function Badge({
988
+ variant = "subtle",
989
+ color = "default",
990
+ size = "md",
991
+ dot,
992
+ dotColor,
993
+ className,
994
+ children,
995
+ ...props
996
+ }) {
997
+ return /* @__PURE__ */ jsxs(
998
+ View,
999
+ {
1000
+ className: cn(
1001
+ "inline-flex items-center justify-center rounded-full font-medium",
1002
+ variantColorStyles[variant][color],
1003
+ sizeStyles2[size],
1004
+ className
1005
+ ),
1006
+ ...props,
1007
+ children: [
1008
+ dot && /* @__PURE__ */ jsx(
1009
+ Indicator,
1010
+ {
1011
+ size: "xs",
1012
+ color: dotColor ?? (color === "default" || color === "secondary" ? "default" : color),
1013
+ className: "mr-0.5"
1014
+ }
1015
+ ),
1016
+ typeof children === "string" ? /* @__PURE__ */ jsx(Text, { className: "text-inherit font-medium", children }) : children
1017
+ ]
1018
+ }
1019
+ );
1020
+ }
1021
+ var BRAND_PRIMARY2 = getSemanticColors("dark")["brand-primary"];
1022
+ function normalizeData(data, height) {
1023
+ if (data.length === 0) return [];
1024
+ const min = Math.min(...data);
1025
+ const max = Math.max(...data);
1026
+ const range = max - min || 1;
1027
+ return data.map((v) => height - (v - min) / range * height);
1028
+ }
1029
+ function normalizeValue(value, data, height) {
1030
+ const min = Math.min(...data);
1031
+ const max = Math.max(...data);
1032
+ const range = max - min || 1;
1033
+ return height - (value - min) / range * height;
1034
+ }
1035
+ function Sparkline({
1036
+ data,
1037
+ width = 80,
1038
+ height = 30,
1039
+ color,
1040
+ showDots = false,
1041
+ referenceLines,
1042
+ highlightLast = false,
1043
+ className,
1044
+ ...props
1045
+ }) {
1046
+ if (data.length === 0) {
1047
+ return /* @__PURE__ */ jsx(
1048
+ View,
1049
+ {
1050
+ style: { width, height },
1051
+ className,
1052
+ testID: "sparkline-empty",
1053
+ accessibilityLabel: "Sparkline chart, no data",
1054
+ ...props
1055
+ }
1056
+ );
1057
+ }
1058
+ const resolvedColor = color ?? BRAND_PRIMARY2;
1059
+ const normalized = normalizeData(data, height);
1060
+ const stepX = data.length > 1 ? width / (data.length - 1) : 0;
1061
+ const dotSize = 3;
1062
+ const highlightSize = 6;
1063
+ return /* @__PURE__ */ jsxs(
1064
+ View,
1065
+ {
1066
+ style: { width, height, position: "relative" },
1067
+ className: cn(className),
1068
+ accessibilityRole: "image",
1069
+ accessibilityLabel: `Sparkline chart with ${data.length} data points`,
1070
+ testID: "sparkline",
1071
+ ...props,
1072
+ children: [
1073
+ referenceLines?.map((line, i) => {
1074
+ const y = normalizeValue(line.value, data, height);
1075
+ return /* @__PURE__ */ jsx(
1076
+ View,
1077
+ {
1078
+ style: [
1079
+ {
1080
+ position: "absolute",
1081
+ top: y,
1082
+ left: 0,
1083
+ right: 0,
1084
+ opacity: 0.6
1085
+ },
1086
+ line.dashed ? {
1087
+ height: 0,
1088
+ borderStyle: "dashed",
1089
+ borderTopWidth: 1,
1090
+ borderTopColor: line.color
1091
+ } : {
1092
+ height: 1,
1093
+ backgroundColor: line.color
1094
+ }
1095
+ ],
1096
+ accessibilityElementsHidden: true,
1097
+ testID: `sparkline-reference-${i}`,
1098
+ children: line.label && /* @__PURE__ */ jsx(
1099
+ Text,
1100
+ {
1101
+ style: {
1102
+ position: "absolute",
1103
+ right: 0,
1104
+ top: -10,
1105
+ fontSize: 7,
1106
+ color: line.color,
1107
+ opacity: 1
1108
+ },
1109
+ testID: `sparkline-reference-label-${i}`,
1110
+ children: line.label
1111
+ }
1112
+ )
1113
+ },
1114
+ `ref-${i}`
1115
+ );
1116
+ }),
1117
+ normalized.map((y, i) => {
1118
+ if (i === 0) return null;
1119
+ const prevY = normalized[i - 1];
1120
+ const x1 = (i - 1) * stepX;
1121
+ const x2 = i * stepX;
1122
+ const dx = x2 - x1;
1123
+ const dy = y - prevY;
1124
+ const length = Math.sqrt(dx * dx + dy * dy);
1125
+ const angle = Math.atan2(dy, dx) * (180 / Math.PI);
1126
+ return /* @__PURE__ */ jsx(
1127
+ View,
1128
+ {
1129
+ style: {
1130
+ position: "absolute",
1131
+ left: x1,
1132
+ top: prevY,
1133
+ width: length,
1134
+ height: 1.5,
1135
+ backgroundColor: resolvedColor,
1136
+ transformOrigin: "0 0",
1137
+ transform: [{ rotate: `${angle}deg` }]
1138
+ },
1139
+ accessibilityElementsHidden: true,
1140
+ testID: `sparkline-segment-${i}`
1141
+ },
1142
+ `line-${i}`
1143
+ );
1144
+ }),
1145
+ (showDots || highlightLast) && normalized.map((y, i) => {
1146
+ const isLast = i === data.length - 1;
1147
+ const shouldShow = showDots || highlightLast && isLast;
1148
+ if (!shouldShow) return null;
1149
+ const size = highlightLast && isLast ? highlightSize : dotSize;
1150
+ return /* @__PURE__ */ jsx(
1151
+ View,
1152
+ {
1153
+ style: {
1154
+ position: "absolute",
1155
+ left: i * stepX - size / 2,
1156
+ top: y - size / 2,
1157
+ width: size,
1158
+ height: size,
1159
+ borderRadius: size / 2,
1160
+ backgroundColor: resolvedColor
1161
+ },
1162
+ accessibilityElementsHidden: true,
1163
+ testID: `sparkline-dot-${i}`
1164
+ },
1165
+ `dot-${i}`
1166
+ );
1167
+ })
1168
+ ]
1169
+ }
1170
+ );
1171
+ }
1172
+
1173
+ // src/components/custom/Workout/BodyMapDetailPanel.tsx
1174
+ var t = getSemanticColors("dark");
1175
+ var BRAND_PRIMARY3 = t["brand-primary"];
1176
+ var VOLUME_GRADIENT = `linear-gradient(90deg, ${t["status-info"]} 0%, ${t["status-success"]} 50%, ${t["status-error"]} 100%)`;
445
1177
  var SLIDE_OFFSET = 400;
446
1178
  var BACKDROP_OPACITY = 0.4;
447
1179
  var STATUS_BADGE_COLOR = {
@@ -839,7 +1571,7 @@ function BodyMapDetailPanel({
839
1571
  borderColor: "rgba(255,121,0,0.3)"
840
1572
  },
841
1573
  testID: "body-map-detail-panel-view-exercises",
842
- children: /* @__PURE__ */ jsx(Text, { style: { fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "700", color: BRAND_PRIMARY }, children: "View exercises" })
1574
+ children: /* @__PURE__ */ jsx(Text, { style: { fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "700", color: BRAND_PRIMARY3 }, children: "View exercises" })
843
1575
  }
844
1576
  )
845
1577
  ]
@@ -852,6 +1584,1226 @@ function BodyMapDetailPanel({
852
1584
  }
853
1585
  );
854
1586
  }
1587
+ function hexToRgb(hex) {
1588
+ const cleaned = hex.replace("#", "");
1589
+ let r, g, b;
1590
+ if (cleaned.length === 3) {
1591
+ r = parseInt(cleaned[0] + cleaned[0], 16);
1592
+ g = parseInt(cleaned[1] + cleaned[1], 16);
1593
+ b = parseInt(cleaned[2] + cleaned[2], 16);
1594
+ } else if (cleaned.length === 6) {
1595
+ r = parseInt(cleaned.slice(0, 2), 16);
1596
+ g = parseInt(cleaned.slice(2, 4), 16);
1597
+ b = parseInt(cleaned.slice(4, 6), 16);
1598
+ } else {
1599
+ return null;
1600
+ }
1601
+ return { r, g, b };
1602
+ }
1603
+ function rgbToHsv(r, g, b) {
1604
+ const rNorm = r / 255;
1605
+ const gNorm = g / 255;
1606
+ const bNorm = b / 255;
1607
+ const max = Math.max(rNorm, gNorm, bNorm);
1608
+ const min = Math.min(rNorm, gNorm, bNorm);
1609
+ const delta = max - min;
1610
+ const v = max;
1611
+ const s = max === 0 ? 0 : delta / max;
1612
+ let h = 0;
1613
+ if (delta !== 0) {
1614
+ if (max === rNorm) {
1615
+ h = 60 * ((gNorm - bNorm) / delta % 6);
1616
+ } else if (max === gNorm) {
1617
+ h = 60 * ((bNorm - rNorm) / delta + 2);
1618
+ } else {
1619
+ h = 60 * ((rNorm - gNorm) / delta + 4);
1620
+ }
1621
+ }
1622
+ if (h < 0) h += 360;
1623
+ return { h, s, v };
1624
+ }
1625
+ function hsvToRgb(h, s, v) {
1626
+ const c = v * s;
1627
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
1628
+ const m = v - c;
1629
+ let rPrime, gPrime, bPrime;
1630
+ if (h >= 0 && h < 60) {
1631
+ rPrime = c;
1632
+ gPrime = x;
1633
+ bPrime = 0;
1634
+ } else if (h >= 60 && h < 120) {
1635
+ rPrime = x;
1636
+ gPrime = c;
1637
+ bPrime = 0;
1638
+ } else if (h >= 120 && h < 180) {
1639
+ rPrime = 0;
1640
+ gPrime = c;
1641
+ bPrime = x;
1642
+ } else if (h >= 180 && h < 240) {
1643
+ rPrime = 0;
1644
+ gPrime = x;
1645
+ bPrime = c;
1646
+ } else if (h >= 240 && h < 300) {
1647
+ rPrime = x;
1648
+ gPrime = 0;
1649
+ bPrime = c;
1650
+ } else {
1651
+ rPrime = c;
1652
+ gPrime = 0;
1653
+ bPrime = x;
1654
+ }
1655
+ return {
1656
+ r: Math.round((rPrime + m) * 255),
1657
+ g: Math.round((gPrime + m) * 255),
1658
+ b: Math.round((bPrime + m) * 255)
1659
+ };
1660
+ }
1661
+ function rgbToHex(r, g, b) {
1662
+ const toHex = (n) => {
1663
+ const clamped = Math.max(0, Math.min(255, Math.round(n)));
1664
+ return clamped.toString(16).padStart(2, "0");
1665
+ };
1666
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
1667
+ }
1668
+ function lighten(hex, amount = 0.1) {
1669
+ const rgb = hexToRgb(hex);
1670
+ if (!rgb) return hex;
1671
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1672
+ const newV = Math.min(1, hsv.v + amount);
1673
+ const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
1674
+ return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
1675
+ }
1676
+ var shadowColors = {
1677
+ // For charcoal surfaces (~#2C2C2C to #3C3C3C)
1678
+ charcoal: {
1679
+ dark: "rgba(0, 0, 0, 0.5)",
1680
+ light: "rgba(255, 255, 255, 0.12)",
1681
+ // brighter for crisp rim light
1682
+ darker: "rgba(0, 0, 0, 0.6)"
1683
+ },
1684
+ // For neutral dark surfaces (~#1F2937)
1685
+ neutralDark: {
1686
+ dark: "rgba(0, 0, 0, 0.4)",
1687
+ light: "rgba(255, 255, 255, 0.08)",
1688
+ darker: "rgba(0, 0, 0, 0.5)"
1689
+ },
1690
+ // For light surfaces (white/light gray backgrounds)
1691
+ neutralLight: {
1692
+ dark: "rgba(0, 0, 0, 0.15)",
1693
+ // Visible dark shadow for depth on light backgrounds
1694
+ light: "rgba(255, 255, 255, 1)",
1695
+ // Bright highlight for raised effect (visible on light gray)
1696
+ darker: "rgba(0, 0, 0, 0.2)"
1697
+ // Deeper shadow for pressed states
1698
+ }
1699
+ };
1700
+ var intensityConfig = {
1701
+ subtle: { offset: 1, blur: 2 },
1702
+ // very light, barely visible
1703
+ medium: { offset: 2, blur: 4 },
1704
+ // noticeable but restrained
1705
+ strong: { offset: 2, blur: 5 }
1706
+ // slightly deeper blur, same offset as medium
1707
+ };
1708
+ function createRaisedShadow(surface = "charcoal", intensity = "medium") {
1709
+ const colors = shadowColors[surface];
1710
+ const { offset, blur } = intensityConfig[intensity];
1711
+ const rimBlur = 1;
1712
+ return Platform.select({
1713
+ web: {
1714
+ boxShadow: `${offset}px ${offset}px ${blur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
1715
+ },
1716
+ default: {
1717
+ // React Native shadow approximation (limited compared to web)
1718
+ shadowColor: "#000",
1719
+ shadowOffset: { width: offset, height: offset },
1720
+ shadowOpacity: 0.3,
1721
+ shadowRadius: blur / 2,
1722
+ elevation: offset
1723
+ }
1724
+ });
1725
+ }
1726
+ function createPressedShadow(surface = "charcoal", intensity = "medium") {
1727
+ const colors = shadowColors[surface];
1728
+ const { offset, blur } = intensityConfig[intensity];
1729
+ const rimOffset = 1;
1730
+ const rimBlur = 1;
1731
+ return Platform.select({
1732
+ web: {
1733
+ boxShadow: `inset ${offset}px ${offset}px ${blur}px ${colors.darker}, inset -${rimOffset}px -${rimOffset}px ${rimBlur}px ${colors.light}`
1734
+ },
1735
+ default: {
1736
+ // React Native doesn't support inset shadows, approximate with darker bg
1737
+ shadowOpacity: 0,
1738
+ elevation: 0
1739
+ }
1740
+ });
1741
+ }
1742
+ function createFlatShadow() {
1743
+ return Platform.select({
1744
+ web: {
1745
+ boxShadow: "none"
1746
+ },
1747
+ default: {
1748
+ shadowOpacity: 0,
1749
+ elevation: 0
1750
+ }
1751
+ });
1752
+ }
1753
+ function createRaisedHoverShadow(surface = "charcoal", intensity = "medium") {
1754
+ const colors = shadowColors[surface];
1755
+ const { offset, blur } = intensityConfig[intensity];
1756
+ const hoverOffset = Math.max(1, Math.round(offset / 2));
1757
+ const hoverBlur = Math.max(1, Math.round(blur / 2));
1758
+ const rimBlur = 1;
1759
+ return Platform.select({
1760
+ web: {
1761
+ // Keep same offsets as normal state for rim to prevent "shrinking" effect
1762
+ boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
1763
+ },
1764
+ default: {
1765
+ shadowColor: "#000",
1766
+ shadowOffset: { width: hoverOffset, height: hoverOffset },
1767
+ shadowOpacity: 0.2,
1768
+ shadowRadius: hoverBlur / 2,
1769
+ elevation: hoverOffset
1770
+ }
1771
+ });
1772
+ }
1773
+ function createPressedHoverShadow(surface = "charcoal", intensity = "medium") {
1774
+ const colors = shadowColors[surface];
1775
+ const { offset, blur } = intensityConfig[intensity];
1776
+ const hoverOffset = Math.max(1, Math.round(offset / 2));
1777
+ const hoverBlur = Math.max(1, Math.round(blur / 2));
1778
+ const rimBlur = 1;
1779
+ return Platform.select({
1780
+ web: {
1781
+ // Keep rim offset at 1px (same as pressed normal) to prevent "shrinking" effect
1782
+ boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.darker}, inset -1px -1px ${rimBlur}px ${colors.light}`
1783
+ },
1784
+ default: {
1785
+ shadowOpacity: 0,
1786
+ elevation: 0
1787
+ }
1788
+ });
1789
+ }
1790
+ ({
1791
+ // Charcoal surface shadows (for dark toolbars, cards)
1792
+ charcoal: {
1793
+ raised: {
1794
+ subtle: createRaisedShadow("charcoal", "subtle"),
1795
+ medium: createRaisedShadow("charcoal", "medium"),
1796
+ strong: createRaisedShadow("charcoal", "strong")
1797
+ },
1798
+ raisedHover: {
1799
+ subtle: createRaisedHoverShadow("charcoal", "subtle"),
1800
+ medium: createRaisedHoverShadow("charcoal", "medium"),
1801
+ strong: createRaisedHoverShadow("charcoal", "strong")
1802
+ },
1803
+ pressed: {
1804
+ subtle: createPressedShadow("charcoal", "subtle"),
1805
+ medium: createPressedShadow("charcoal", "medium"),
1806
+ strong: createPressedShadow("charcoal", "strong")
1807
+ },
1808
+ pressedHover: {
1809
+ subtle: createPressedHoverShadow("charcoal", "subtle"),
1810
+ medium: createPressedHoverShadow("charcoal", "medium"),
1811
+ strong: createPressedHoverShadow("charcoal", "strong")
1812
+ },
1813
+ flat: createFlatShadow()
1814
+ },
1815
+ // Neutral dark surface shadows
1816
+ neutralDark: {
1817
+ raised: {
1818
+ subtle: createRaisedShadow("neutralDark", "subtle"),
1819
+ medium: createRaisedShadow("neutralDark", "medium"),
1820
+ strong: createRaisedShadow("neutralDark", "strong")
1821
+ },
1822
+ raisedHover: {
1823
+ subtle: createRaisedHoverShadow("neutralDark", "subtle"),
1824
+ medium: createRaisedHoverShadow("neutralDark", "medium"),
1825
+ strong: createRaisedHoverShadow("neutralDark", "strong")
1826
+ },
1827
+ pressed: {
1828
+ subtle: createPressedShadow("neutralDark", "subtle"),
1829
+ medium: createPressedShadow("neutralDark", "medium"),
1830
+ strong: createPressedShadow("neutralDark", "strong")
1831
+ },
1832
+ pressedHover: {
1833
+ subtle: createPressedHoverShadow("neutralDark", "subtle"),
1834
+ medium: createPressedHoverShadow("neutralDark", "medium"),
1835
+ strong: createPressedHoverShadow("neutralDark", "strong")
1836
+ },
1837
+ flat: createFlatShadow()
1838
+ },
1839
+ // Neutral light surface shadows
1840
+ neutralLight: {
1841
+ raised: {
1842
+ subtle: createRaisedShadow("neutralLight", "subtle"),
1843
+ medium: createRaisedShadow("neutralLight", "medium"),
1844
+ strong: createRaisedShadow("neutralLight", "strong")
1845
+ },
1846
+ raisedHover: {
1847
+ subtle: createRaisedHoverShadow("neutralLight", "subtle"),
1848
+ medium: createRaisedHoverShadow("neutralLight", "medium"),
1849
+ strong: createRaisedHoverShadow("neutralLight", "strong")
1850
+ },
1851
+ pressed: {
1852
+ subtle: createPressedShadow("neutralLight", "subtle"),
1853
+ medium: createPressedShadow("neutralLight", "medium"),
1854
+ strong: createPressedShadow("neutralLight", "strong")
1855
+ },
1856
+ pressedHover: {
1857
+ subtle: createPressedHoverShadow("neutralLight", "subtle"),
1858
+ medium: createPressedHoverShadow("neutralLight", "medium"),
1859
+ strong: createPressedHoverShadow("neutralLight", "strong")
1860
+ },
1861
+ flat: createFlatShadow()
1862
+ }
1863
+ });
1864
+ var elevationSystem = {
1865
+ // Deep inset (recessed input fields, deeply pressed buttons)
1866
+ [-2]: {
1867
+ name: "deep-inset",
1868
+ colorAdjustment: 0,
1869
+ shadowIntensity: "strong",
1870
+ shadowStyle: "pressed",
1871
+ description: "Deeply recessed elements (e.g., input fields, deeply pressed buttons)"
1872
+ },
1873
+ // Shallow inset (pressed buttons, sunken panels)
1874
+ [-1]: {
1875
+ name: "inset",
1876
+ colorAdjustment: 0,
1877
+ shadowIntensity: "medium",
1878
+ shadowStyle: "pressed",
1879
+ description: "Shallow inset elements (e.g., pressed buttons, sunken panels within cards)"
1880
+ },
1881
+ // Base level (page background, default surface)
1882
+ [0]: {
1883
+ name: "base",
1884
+ colorAdjustment: 0,
1885
+ shadowIntensity: "subtle",
1886
+ shadowStyle: "raised",
1887
+ description: "Base surface level (page background, default containers)"
1888
+ },
1889
+ // Level 1: Subtle elevation (outline cards, subtle containers)
1890
+ [1]: {
1891
+ name: "subtle",
1892
+ colorAdjustment: 0.01,
1893
+ shadowIntensity: "subtle",
1894
+ shadowStyle: "raised",
1895
+ description: "Subtle elevation (outline cards, subtle containers)"
1896
+ },
1897
+ // Level 2: Standard elevation (default cards, buttons)
1898
+ [2]: {
1899
+ name: "standard",
1900
+ colorAdjustment: 0.02,
1901
+ shadowIntensity: "medium",
1902
+ shadowStyle: "raised",
1903
+ description: "Standard elevation (default cards, raised buttons)"
1904
+ },
1905
+ // Level 3: Prominent elevation (important cards, modals)
1906
+ [3]: {
1907
+ name: "prominent",
1908
+ colorAdjustment: 0.04,
1909
+ shadowIntensity: "strong",
1910
+ shadowStyle: "raised",
1911
+ description: "Prominent elevation (important cards, modals, dropdowns)"
1912
+ },
1913
+ // Level 4: High elevation (overlays, popovers)
1914
+ [4]: {
1915
+ name: "high",
1916
+ colorAdjustment: 0.06,
1917
+ shadowIntensity: "strong",
1918
+ shadowStyle: "raised",
1919
+ description: "High elevation (overlays, popovers, tooltips)"
1920
+ },
1921
+ // Level 5: Floating (toasts, floating action buttons)
1922
+ [5]: {
1923
+ name: "floating",
1924
+ colorAdjustment: 0.08,
1925
+ shadowIntensity: "strong",
1926
+ shadowStyle: "raised",
1927
+ description: "Floating elevation (toasts, floating action buttons, highest z-index)"
1928
+ }
1929
+ };
1930
+ function calculateRimLightColor(baseColor, level) {
1931
+ const rgb = hexToRgb(baseColor);
1932
+ if (!rgb) {
1933
+ return "rgba(255, 255, 255, 0.5)";
1934
+ }
1935
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1936
+ const isLight = hsv.v > 0.6;
1937
+ const isSaturated = hsv.s > 0.3;
1938
+ const absLevel = Math.abs(level);
1939
+ const opacityBoost = Math.max(0, (absLevel - 1) * 0.05);
1940
+ if (isSaturated) {
1941
+ const rimLightValue = 0.95;
1942
+ const rimLightRgb = hsvToRgb(hsv.h, hsv.s * 0.3, rimLightValue);
1943
+ const baseOpacity = isLight ? 0.9 : 0.5;
1944
+ const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
1945
+ return `rgba(${rimLightRgb.r}, ${rimLightRgb.g}, ${rimLightRgb.b}, ${finalOpacity.toFixed(2)})`;
1946
+ } else {
1947
+ const baseOpacity = isLight ? 0.9 : 0.12;
1948
+ const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
1949
+ return `rgba(255, 255, 255, ${finalOpacity.toFixed(2)})`;
1950
+ }
1951
+ }
1952
+ function calculateDarkShadowColors(surfaceColor) {
1953
+ const rgb = hexToRgb(surfaceColor);
1954
+ if (!rgb) {
1955
+ return {
1956
+ dark: "rgba(0, 0, 0, 0.3)",
1957
+ darker: "rgba(0, 0, 0, 0.4)"
1958
+ };
1959
+ }
1960
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1961
+ const isLight = hsv.v > 0.6;
1962
+ const isSaturated = hsv.s > 0.3;
1963
+ if (isSaturated) {
1964
+ const darkShadowValue = 0.15;
1965
+ const darkShadowRgb = hsvToRgb(hsv.h, hsv.s, darkShadowValue);
1966
+ if (isLight) {
1967
+ return {
1968
+ dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.3)`,
1969
+ darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.4)`
1970
+ };
1971
+ } else {
1972
+ return {
1973
+ dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.5)`,
1974
+ darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.6)`
1975
+ };
1976
+ }
1977
+ } else {
1978
+ if (isLight) {
1979
+ return {
1980
+ dark: "rgba(0, 0, 0, 0.2)",
1981
+ darker: "rgba(0, 0, 0, 0.3)"
1982
+ };
1983
+ } else {
1984
+ return {
1985
+ dark: "rgba(0, 0, 0, 0.5)",
1986
+ darker: "rgba(0, 0, 0, 0.6)"
1987
+ };
1988
+ }
1989
+ }
1990
+ }
1991
+ function getRimLightConfig() {
1992
+ return {
1993
+ offset: 1,
1994
+ // Fixed 1px for crisp rim
1995
+ blur: 1
1996
+ // Tight blur for crisp edge
1997
+ };
1998
+ }
1999
+ var elevationSurfaceCache = /* @__PURE__ */ new Map();
2000
+ var MAX_CACHE_SIZE = 100;
2001
+ function getCacheKey(baseColor, level, theme) {
2002
+ return `${baseColor}-${level}-${theme}`;
2003
+ }
2004
+ function calculateElevationSurface(baseColor, level, theme) {
2005
+ const config = elevationSystem[level];
2006
+ if (config.colorAdjustment === 0) {
2007
+ return baseColor;
2008
+ }
2009
+ if (level < 0) {
2010
+ return baseColor;
2011
+ }
2012
+ return lighten(baseColor, config.colorAdjustment);
2013
+ }
2014
+ function getElevationSurface(baseColor, level, theme) {
2015
+ const cacheKey = getCacheKey(baseColor, level, theme);
2016
+ if (elevationSurfaceCache.has(cacheKey)) {
2017
+ return elevationSurfaceCache.get(cacheKey);
2018
+ }
2019
+ const result = calculateElevationSurface(baseColor, level);
2020
+ if (elevationSurfaceCache.size >= MAX_CACHE_SIZE) {
2021
+ const firstKey = elevationSurfaceCache.keys().next().value;
2022
+ elevationSurfaceCache.delete(firstKey);
2023
+ }
2024
+ elevationSurfaceCache.set(cacheKey, result);
2025
+ return result;
2026
+ }
2027
+ var elevationShadowCache = /* @__PURE__ */ new Map();
2028
+ var MAX_SHADOW_CACHE_SIZE = 50;
2029
+ function getShadowCacheKey(baseColor, level, theme, isHovered) {
2030
+ return `${baseColor}-${level}-${theme}-${isHovered}`;
2031
+ }
2032
+ function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
2033
+ const config = elevationSystem[level];
2034
+ if (level === 0) {
2035
+ return {};
2036
+ }
2037
+ const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
2038
+ const rimLightColor = calculateRimLightColor(baseColor, level);
2039
+ const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
2040
+ const intensityConfig2 = {
2041
+ subtle: { offset: 1, blur: 2 },
2042
+ medium: { offset: 2, blur: 4 },
2043
+ strong: { offset: 2, blur: 5 }
2044
+ };
2045
+ const { offset, blur } = intensityConfig2[config.shadowIntensity];
2046
+ const rimConfig = getRimLightConfig();
2047
+ if (config.shadowStyle === "pressed") {
2048
+ if (isHovered) {
2049
+ const hoverOffset = Math.max(1, Math.round(offset / 2));
2050
+ const hoverBlur = Math.max(1, Math.round(blur / 2));
2051
+ return Platform.select({
2052
+ web: {
2053
+ boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
2054
+ },
2055
+ default: {
2056
+ shadowOpacity: 0,
2057
+ elevation: 0
2058
+ }
2059
+ });
2060
+ }
2061
+ return Platform.select({
2062
+ web: {
2063
+ boxShadow: `inset ${offset}px ${offset}px ${blur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
2064
+ },
2065
+ default: {
2066
+ shadowOpacity: 0,
2067
+ elevation: 0
2068
+ }
2069
+ });
2070
+ } else {
2071
+ if (isHovered) {
2072
+ const hoverOffset = Math.max(1, Math.round(offset / 2));
2073
+ const hoverBlur = Math.max(1, Math.round(blur / 2));
2074
+ return Platform.select({
2075
+ web: {
2076
+ boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
2077
+ },
2078
+ default: {
2079
+ shadowColor: "#000",
2080
+ shadowOffset: { width: hoverOffset, height: hoverOffset },
2081
+ shadowOpacity: 0.2,
2082
+ shadowRadius: hoverBlur / 2,
2083
+ elevation: hoverOffset
2084
+ }
2085
+ });
2086
+ }
2087
+ return Platform.select({
2088
+ web: {
2089
+ boxShadow: `${offset}px ${offset}px ${blur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
2090
+ },
2091
+ default: {
2092
+ shadowColor: "#000",
2093
+ shadowOffset: { width: offset, height: offset },
2094
+ shadowOpacity: 0.3,
2095
+ shadowRadius: blur / 2,
2096
+ elevation: offset
2097
+ }
2098
+ });
2099
+ }
2100
+ }
2101
+ function getElevationShadow(baseColor, level, theme, isHovered = false) {
2102
+ const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
2103
+ if (elevationShadowCache.has(cacheKey)) {
2104
+ return elevationShadowCache.get(cacheKey);
2105
+ }
2106
+ const result = calculateElevationShadow(baseColor, level, theme, isHovered);
2107
+ if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
2108
+ const firstKey = elevationShadowCache.keys().next().value;
2109
+ elevationShadowCache.delete(firstKey);
2110
+ }
2111
+ elevationShadowCache.set(cacheKey, result);
2112
+ return result;
2113
+ }
2114
+ function getBaseSurfaceColor(theme) {
2115
+ return theme === "light" ? semanticColorsLight["surface-raised"] : semanticColorsDark["surface-elevated"];
2116
+ }
2117
+ var componentElevationRanges = {
2118
+ button: {
2119
+ allowed: [2],
2120
+ default: 2,
2121
+ hover: 3
2122
+ },
2123
+ card: {
2124
+ allowed: [1, 2, 3],
2125
+ default: 2,
2126
+ hover: 3
2127
+ },
2128
+ input: {
2129
+ allowed: [-2, -1, 0],
2130
+ default: -1
2131
+ },
2132
+ overlay: {
2133
+ allowed: [4, 5],
2134
+ default: 4
2135
+ }
2136
+ };
2137
+ function getValidatedElevation(component, requested) {
2138
+ const range = componentElevationRanges[component];
2139
+ if (range.allowed.includes(requested)) {
2140
+ return requested;
2141
+ }
2142
+ const sorted = [...range.allowed].sort((a, b) => a - b);
2143
+ if (requested < sorted[0]) return sorted[0];
2144
+ if (requested > sorted[sorted.length - 1]) return sorted[sorted.length - 1];
2145
+ return sorted.reduce(
2146
+ (prev, curr) => Math.abs(curr - requested) < Math.abs(prev - requested) ? curr : prev
2147
+ );
2148
+ }
2149
+ function getTheme() {
2150
+ if (typeof document === "undefined") return "dark";
2151
+ return document.documentElement.classList.contains("light") ? "light" : "dark";
2152
+ }
2153
+ var listeners = [];
2154
+ function subscribe(listener) {
2155
+ listeners = [...listeners, listener];
2156
+ if (typeof document !== "undefined" && listeners.length === 1) {
2157
+ const observer = new MutationObserver((mutations) => {
2158
+ for (const mutation of mutations) {
2159
+ if (mutation.type === "attributes" && mutation.attributeName === "class") {
2160
+ listeners.forEach((l) => l());
2161
+ }
2162
+ }
2163
+ });
2164
+ observer.observe(document.documentElement, {
2165
+ attributes: true,
2166
+ attributeFilter: ["class"]
2167
+ });
2168
+ subscribe._observer = observer;
2169
+ }
2170
+ return () => {
2171
+ listeners = listeners.filter((l) => l !== listener);
2172
+ if (listeners.length === 0 && subscribe._observer) {
2173
+ subscribe._observer.disconnect();
2174
+ subscribe._observer = null;
2175
+ }
2176
+ };
2177
+ }
2178
+ function getSnapshot() {
2179
+ return getTheme();
2180
+ }
2181
+ function getServerSnapshot() {
2182
+ return "dark";
2183
+ }
2184
+ function useTheme() {
2185
+ return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2186
+ }
2187
+
2188
+ // src/components/ui/card/Card.tsx
2189
+ var variantStyles = {
2190
+ elevated: "",
2191
+ // Will be set dynamically via elevation system
2192
+ outline: "border-2 border-border-strong",
2193
+ // Thicker border with stronger contrast
2194
+ filled: "",
2195
+ // Will be set dynamically via elevation system
2196
+ accent: "border border-border",
2197
+ subtle: "border border-border-subtle"
2198
+ };
2199
+ function Card({
2200
+ variant = "elevated",
2201
+ elevation = 2,
2202
+ isInteractive = false,
2203
+ isLoading = false,
2204
+ onPress,
2205
+ borderColor,
2206
+ bgColor,
2207
+ accentColor,
2208
+ accentWidth,
2209
+ className,
2210
+ children,
2211
+ style,
2212
+ skeletonHasHeader = true,
2213
+ skeletonHasFooter = false,
2214
+ skeletonContentLines = 3,
2215
+ ...props
2216
+ }) {
2217
+ const isClickable = isInteractive || !!onPress;
2218
+ const [isHovered, setIsHovered] = useState(false);
2219
+ const theme = useTheme();
2220
+ const elevationLevel = useMemo(() => {
2221
+ const validated = getValidatedElevation("card", elevation);
2222
+ if (variant === "outline" || variant === "accent" || variant === "subtle") {
2223
+ return 1;
2224
+ }
2225
+ return validated;
2226
+ }, [variant, elevation]);
2227
+ const baseColor = useMemo(() => getBaseSurfaceColor(theme), [theme]);
2228
+ const surfaceColor = useMemo(() => {
2229
+ if ((variant === "outline" || variant === "accent") && theme === "light") {
2230
+ return "#FAFAFA";
2231
+ }
2232
+ if (variant === "subtle") {
2233
+ return getElevationSurface(baseColor, 0, theme);
2234
+ }
2235
+ return getElevationSurface(baseColor, elevationLevel, theme);
2236
+ }, [baseColor, elevationLevel, theme, variant]);
2237
+ const shadowStyle = useMemo(() => {
2238
+ const shouldHover = isHovered && isClickable;
2239
+ return getElevationShadow(baseColor, elevationLevel, theme, shouldHover);
2240
+ }, [baseColor, elevationLevel, theme, isHovered, isClickable]);
2241
+ const cardContent = isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
2242
+ skeletonHasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
2243
+ /* @__PURE__ */ jsx(View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
2244
+ /* @__PURE__ */ jsx(View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
2245
+ ] }),
2246
+ /* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: skeletonContentLines }).map((_, i) => /* @__PURE__ */ jsx(
2247
+ View,
2248
+ {
2249
+ className: cn(
2250
+ "h-4 bg-interactive-disabled rounded",
2251
+ i < skeletonContentLines - 1 ? "mb-2 w-full" : "w-4/5"
2252
+ )
2253
+ },
2254
+ i
2255
+ )) }),
2256
+ skeletonHasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
2257
+ ] }) : children;
2258
+ const baseClassName = cn(
2259
+ "rounded-lg overflow-hidden relative",
2260
+ // Apply variant styles, but only use default border color if no custom borderColor
2261
+ variant === "outline" ? borderColor ? "border-2" : variantStyles[variant] : variantStyles[variant],
2262
+ // Remove Tailwind shadow classes - we're using elevation shadows via style prop
2263
+ isClickable && "web:cursor-pointer web:transition-all web:duration-150",
2264
+ isClickable && "web:hover:-translate-y-0.5 active:scale-[0.99]",
2265
+ isLoading && "pointer-events-none animate-pulse",
2266
+ className
2267
+ );
2268
+ const accentStyle = useMemo(() => variant === "accent" ? {
2269
+ borderLeftWidth: accentWidth ?? 3,
2270
+ borderLeftColor: accentColor ?? "var(--color-brand-primary)"
2271
+ } : {}, [variant, accentWidth, accentColor]);
2272
+ const mergedStyle = useMemo(() => {
2273
+ const elevationStyle = {
2274
+ backgroundColor: bgColor || surfaceColor,
2275
+ borderRadius: 8,
2276
+ overflow: "hidden",
2277
+ ...shadowStyle,
2278
+ ...accentStyle
2279
+ };
2280
+ if (borderColor) {
2281
+ elevationStyle.borderColor = borderColor;
2282
+ }
2283
+ if (!style) return elevationStyle;
2284
+ return [elevationStyle, style];
2285
+ }, [style, surfaceColor, shadowStyle, borderColor, bgColor, accentStyle]);
2286
+ if (isClickable) {
2287
+ return /* @__PURE__ */ jsx(
2288
+ Pressable,
2289
+ {
2290
+ onPress,
2291
+ onHoverIn: () => setIsHovered(true),
2292
+ onHoverOut: () => setIsHovered(false),
2293
+ accessibilityRole: "button",
2294
+ className: baseClassName,
2295
+ style: mergedStyle,
2296
+ ...props,
2297
+ children: cardContent
2298
+ }
2299
+ );
2300
+ }
2301
+ return /* @__PURE__ */ jsx(View, { className: baseClassName, style: mergedStyle, ...props, children: cardContent });
2302
+ }
2303
+ function CardHeader({ children, className }) {
2304
+ return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-6", className), children });
2305
+ }
2306
+ function CardContent({ children, className }) {
2307
+ return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-4", className), children });
2308
+ }
2309
+ function CardFooter({ children, className }) {
2310
+ return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
2311
+ }
2312
+ var t2 = getSemanticColors("dark");
2313
+ var solidVariantColors = {
2314
+ success: t2["status-success"],
2315
+ warning: t2["status-warning"],
2316
+ error: t2["status-error"],
2317
+ neutral: "#6B7280"
2318
+ };
2319
+ var ringVariantStyles = {
2320
+ "on-track": {
2321
+ backgroundColor: "rgba(46,213,115,0.15)",
2322
+ borderWidth: 1,
2323
+ borderColor: "rgba(46,213,115,0.3)"
2324
+ },
2325
+ deviation: {
2326
+ backgroundColor: "rgba(245,158,11,0.15)",
2327
+ borderWidth: 1,
2328
+ borderColor: "rgba(245,158,11,0.25)"
2329
+ },
2330
+ future: {
2331
+ backgroundColor: "rgba(107,114,128,0.1)",
2332
+ borderWidth: 1,
2333
+ borderStyle: "dashed",
2334
+ borderColor: "rgba(107,114,128,0.2)"
2335
+ }
2336
+ };
2337
+ var glowStyles = {
2338
+ success: { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
2339
+ warning: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
2340
+ error: { boxShadow: "0 0 4px rgba(239,68,68,0.4)" },
2341
+ neutral: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" },
2342
+ "on-track": { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
2343
+ deviation: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
2344
+ future: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" }
2345
+ };
2346
+ var iconChars = {
2347
+ check: "\u2713",
2348
+ exclamation: "!",
2349
+ dash: "\u2014"
2350
+ };
2351
+ var iconColors = {
2352
+ success: "#0A5C52",
2353
+ warning: "#6B4000",
2354
+ error: "#5C1A1A",
2355
+ neutral: "#D1D5DB",
2356
+ "on-track": t2["status-success"],
2357
+ deviation: t2["status-warning"],
2358
+ future: "#6B7280"
2359
+ };
2360
+ var sizeDimensions = {
2361
+ sm: { size: 8, showIcon: false },
2362
+ md: { size: 18, showIcon: true }
2363
+ };
2364
+ function isSolidVariant(variant) {
2365
+ return variant in solidVariantColors;
2366
+ }
2367
+ function StatusDot({
2368
+ variant,
2369
+ icon,
2370
+ size = "sm",
2371
+ glow,
2372
+ label,
2373
+ className,
2374
+ ...props
2375
+ }) {
2376
+ const config = sizeDimensions[size];
2377
+ const solid = isSolidVariant(variant);
2378
+ const ring = ringVariantStyles[variant];
2379
+ const glowStyle = glow ? glowStyles[variant] : null;
2380
+ const dot = /* @__PURE__ */ jsx(
2381
+ View,
2382
+ {
2383
+ style: [
2384
+ {
2385
+ width: config.size,
2386
+ height: config.size,
2387
+ borderRadius: 9999,
2388
+ alignItems: "center",
2389
+ justifyContent: "center",
2390
+ flexShrink: 0
2391
+ },
2392
+ solid ? { backgroundColor: solidVariantColors[variant] } : void 0,
2393
+ ring ? ring : void 0,
2394
+ glowStyle ? glowStyle : void 0
2395
+ ],
2396
+ accessibilityRole: "image",
2397
+ accessibilityLabel: `${variant} status`,
2398
+ testID: "status-dot",
2399
+ children: config.showIcon && icon && /* @__PURE__ */ jsx(
2400
+ Text,
2401
+ {
2402
+ style: {
2403
+ fontSize: 11,
2404
+ lineHeight: 11,
2405
+ fontWeight: "900",
2406
+ color: iconColors[variant]
2407
+ },
2408
+ accessibilityElementsHidden: true,
2409
+ children: iconChars[icon]
2410
+ }
2411
+ )
2412
+ }
2413
+ );
2414
+ if (label) {
2415
+ return /* @__PURE__ */ jsxs(
2416
+ View,
2417
+ {
2418
+ className,
2419
+ style: { flexDirection: "row", alignItems: "center", gap: 6 },
2420
+ accessibilityLabel: `${variant} status: ${label}`,
2421
+ ...props,
2422
+ children: [
2423
+ /* @__PURE__ */ jsx(View, { accessibilityElementsHidden: true, children: dot }),
2424
+ /* @__PURE__ */ jsx(
2425
+ Text,
2426
+ {
2427
+ style: { fontSize: 12, lineHeight: 16, color: "#9CA3AF" },
2428
+ accessibilityElementsHidden: true,
2429
+ children: label
2430
+ }
2431
+ )
2432
+ ]
2433
+ }
2434
+ );
2435
+ }
2436
+ return /* @__PURE__ */ jsx(View, { className, ...props, children: dot });
2437
+ }
2438
+ var MESO_ACCENT_GRADIENT_DARK = primitiveRamps.orange[500];
2439
+ var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
2440
+
2441
+ // src/components/custom/Workout/MesoStatusCard.tsx
2442
+ var t3 = getSemanticColors("dark");
2443
+ var BRAND_PRIMARY4 = t3["brand-primary"];
2444
+ var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
2445
+ var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
2446
+ var SUCCESS = t3["status-success"];
2447
+ var WARNING = t3["status-warning"];
2448
+ var ERROR = t3["status-error"];
2449
+ var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY4, BRAND_PRIMARY_LIGHT];
2450
+ var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
2451
+ 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%)";
2452
+ var STATUS_VARIANTS = {
2453
+ success: { bg: "rgba(46,213,115,0.15)", border: "rgba(46,213,115,0.3)", text: SUCCESS },
2454
+ warning: { bg: "rgba(249,180,21,0.15)", border: "rgba(249,180,21,0.3)", text: WARNING },
2455
+ error: { bg: "rgba(209,67,67,0.15)", border: "rgba(209,67,67,0.25)", text: ERROR }
2456
+ };
2457
+ function clamp012(value) {
2458
+ if (!Number.isFinite(value)) return 0;
2459
+ if (value < 0) return 0;
2460
+ if (value > 1) return 1;
2461
+ return value;
2462
+ }
2463
+ function getGaugeZoneColor(level) {
2464
+ if (level >= 0.7) return ERROR;
2465
+ if (level >= 0.4) return WARNING;
2466
+ return SUCCESS;
2467
+ }
2468
+ function renderCoachingText(text, highlights) {
2469
+ if (!highlights || highlights.length === 0) return text;
2470
+ const escaped = highlights.filter(Boolean).map((h) => h.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
2471
+ if (escaped.length === 0) return text;
2472
+ const regex = new RegExp(`(${escaped.join("|")})`, "g");
2473
+ return text.split(regex).map(
2474
+ (part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(
2475
+ Text,
2476
+ {
2477
+ className: "text-text-primary",
2478
+ style: { fontWeight: "700" },
2479
+ children: part
2480
+ },
2481
+ `${part}-${index}`
2482
+ ) : /* @__PURE__ */ jsx(Fragment$1, { children: part }, `t-${index}`)
2483
+ );
2484
+ }
2485
+ function StatusPill({ badge }) {
2486
+ const colors = STATUS_VARIANTS[badge.variant];
2487
+ return /* @__PURE__ */ jsxs(
2488
+ View,
2489
+ {
2490
+ className: "flex-row items-center",
2491
+ style: {
2492
+ gap: 5,
2493
+ paddingVertical: 3,
2494
+ paddingHorizontal: 8,
2495
+ borderRadius: 4,
2496
+ borderWidth: 1,
2497
+ backgroundColor: colors.bg,
2498
+ borderColor: colors.border
2499
+ },
2500
+ testID: "meso-status-card-badge",
2501
+ children: [
2502
+ /* @__PURE__ */ jsx(View, { accessibilityElementsHidden: true, children: /* @__PURE__ */ jsx(StatusDot, { variant: badge.variant, size: "sm" }) }),
2503
+ /* @__PURE__ */ jsx(
2504
+ Text,
2505
+ {
2506
+ style: {
2507
+ fontSize: 10,
2508
+ fontFamily: "Inter, sans-serif",
2509
+ fontWeight: "700",
2510
+ letterSpacing: 0.3,
2511
+ color: colors.text
2512
+ },
2513
+ children: badge.label
2514
+ }
2515
+ )
2516
+ ]
2517
+ }
2518
+ );
2519
+ }
2520
+ function MetricCell({ metric }) {
2521
+ return /* @__PURE__ */ jsxs(View, { style: { width: "48%" }, testID: "meso-status-card-metric", children: [
2522
+ /* @__PURE__ */ jsx(
2523
+ Text,
2524
+ {
2525
+ className: "text-text-tertiary",
2526
+ style: {
2527
+ fontSize: 10,
2528
+ fontFamily: "Inter, sans-serif",
2529
+ fontWeight: "600",
2530
+ letterSpacing: 0.5,
2531
+ textTransform: "uppercase"
2532
+ },
2533
+ children: metric.label
2534
+ }
2535
+ ),
2536
+ /* @__PURE__ */ jsx(
2537
+ Text,
2538
+ {
2539
+ className: "text-text-primary",
2540
+ style: {
2541
+ marginTop: 2,
2542
+ fontSize: 13,
2543
+ fontFamily: "Inter, sans-serif",
2544
+ fontWeight: "600"
2545
+ },
2546
+ children: metric.value
2547
+ }
2548
+ )
2549
+ ] });
2550
+ }
2551
+ function Gauge({ gauge }) {
2552
+ const level = clamp012(gauge.level);
2553
+ const percentage = Math.round(level * 100);
2554
+ const markerColor = getGaugeZoneColor(level);
2555
+ return /* @__PURE__ */ jsxs(
2556
+ View,
2557
+ {
2558
+ style: { gap: 6 },
2559
+ accessibilityRole: "progressbar",
2560
+ accessibilityValue: { min: 0, max: 100, now: percentage },
2561
+ accessibilityLabel: `${gauge.label}: ${percentage}%`,
2562
+ "aria-valuenow": percentage,
2563
+ "aria-valuemin": 0,
2564
+ "aria-valuemax": 100,
2565
+ testID: "meso-status-card-gauge",
2566
+ children: [
2567
+ /* @__PURE__ */ jsxs(
2568
+ View,
2569
+ {
2570
+ className: "flex-row items-center justify-between",
2571
+ accessibilityElementsHidden: true,
2572
+ children: [
2573
+ /* @__PURE__ */ jsx(
2574
+ Text,
2575
+ {
2576
+ className: "text-text-secondary",
2577
+ style: {
2578
+ fontSize: 10,
2579
+ fontFamily: "Inter, sans-serif",
2580
+ fontWeight: "500",
2581
+ letterSpacing: 0.5,
2582
+ textTransform: "uppercase"
2583
+ },
2584
+ children: gauge.label
2585
+ }
2586
+ ),
2587
+ gauge.sublabel != null && /* @__PURE__ */ jsx(
2588
+ Text,
2589
+ {
2590
+ className: "text-text-tertiary",
2591
+ style: {
2592
+ fontSize: 10,
2593
+ fontFamily: "Inter, sans-serif",
2594
+ fontWeight: "500"
2595
+ },
2596
+ children: gauge.sublabel
2597
+ }
2598
+ )
2599
+ ]
2600
+ }
2601
+ ),
2602
+ /* @__PURE__ */ jsxs(
2603
+ View,
2604
+ {
2605
+ style: {
2606
+ height: 8,
2607
+ borderRadius: 4,
2608
+ position: "relative",
2609
+ backgroundImage: GAUGE_GRADIENT
2610
+ },
2611
+ accessibilityElementsHidden: true,
2612
+ children: [
2613
+ /* @__PURE__ */ jsx(
2614
+ View,
2615
+ {
2616
+ style: {
2617
+ position: "absolute",
2618
+ left: "50%",
2619
+ top: 0,
2620
+ bottom: 0,
2621
+ width: 1,
2622
+ marginLeft: -0.5,
2623
+ backgroundColor: "rgba(255,255,255,0.3)"
2624
+ },
2625
+ testID: "meso-status-card-gauge-center"
2626
+ }
2627
+ ),
2628
+ /* @__PURE__ */ jsx(
2629
+ View,
2630
+ {
2631
+ className: "border-text-primary",
2632
+ style: {
2633
+ position: "absolute",
2634
+ left: `${percentage}%`,
2635
+ top: -3,
2636
+ marginLeft: -7,
2637
+ width: 14,
2638
+ height: 14,
2639
+ borderRadius: 9999,
2640
+ borderWidth: 2,
2641
+ backgroundColor: markerColor,
2642
+ boxShadow: "0 0 4px rgba(0,0,0,0.5)"
2643
+ },
2644
+ testID: "meso-status-card-gauge-marker"
2645
+ }
2646
+ )
2647
+ ]
2648
+ }
2649
+ )
2650
+ ]
2651
+ }
2652
+ );
2653
+ }
2654
+ function MesoStatusCard({
2655
+ mesoName,
2656
+ mesoSubtitle,
2657
+ statusBadge,
2658
+ metrics,
2659
+ gauges,
2660
+ coaching,
2661
+ nextTarget,
2662
+ className,
2663
+ ...props
2664
+ }) {
2665
+ return /* @__PURE__ */ jsxs(
2666
+ Card,
2667
+ {
2668
+ variant: "outline",
2669
+ elevation: 1,
2670
+ borderColor: BRAND_PRIMARY_DARK,
2671
+ className,
2672
+ style: {
2673
+ borderColor: BRAND_PRIMARY_DARK,
2674
+ borderWidth: 1,
2675
+ backgroundImage: CARD_GRADIENT
2676
+ },
2677
+ role: "article",
2678
+ "aria-label": `Mesocycle status for ${mesoName}`,
2679
+ testID: "meso-status-card",
2680
+ ...props,
2681
+ children: [
2682
+ /* @__PURE__ */ jsx(
2683
+ View,
2684
+ {
2685
+ className: "flex-row",
2686
+ style: { position: "absolute", top: 0, left: 0, right: 0, height: 3, zIndex: 1 },
2687
+ accessibilityElementsHidden: true,
2688
+ testID: "meso-status-card-accent",
2689
+ children: ACCENT_STOPS.map((color) => /* @__PURE__ */ jsx(View, { style: { flex: 1, backgroundColor: color } }, color))
2690
+ }
2691
+ ),
2692
+ /* @__PURE__ */ jsxs(View, { style: { padding: 14, gap: 14 }, testID: "meso-status-card-body", children: [
2693
+ /* @__PURE__ */ jsxs(View, { testID: "meso-status-card-header", children: [
2694
+ /* @__PURE__ */ jsxs(
2695
+ View,
2696
+ {
2697
+ className: "flex-row items-center justify-between",
2698
+ style: { gap: 8 },
2699
+ children: [
2700
+ /* @__PURE__ */ jsx(
2701
+ Text,
2702
+ {
2703
+ className: "text-text-primary",
2704
+ style: {
2705
+ flexShrink: 1,
2706
+ fontSize: 15,
2707
+ fontFamily: '"Space Grotesk", sans-serif',
2708
+ fontWeight: "700"
2709
+ },
2710
+ testID: "meso-status-card-name",
2711
+ children: mesoName
2712
+ }
2713
+ ),
2714
+ /* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
2715
+ ]
2716
+ }
2717
+ ),
2718
+ /* @__PURE__ */ jsx(
2719
+ Text,
2720
+ {
2721
+ className: "text-text-secondary",
2722
+ style: {
2723
+ marginTop: 4,
2724
+ fontSize: 12,
2725
+ fontFamily: "Inter, sans-serif"
2726
+ },
2727
+ testID: "meso-status-card-subtitle",
2728
+ children: mesoSubtitle
2729
+ }
2730
+ )
2731
+ ] }),
2732
+ metrics.length > 0 && /* @__PURE__ */ jsx(
2733
+ View,
2734
+ {
2735
+ className: "flex-row flex-wrap",
2736
+ style: { gap: 8 },
2737
+ testID: "meso-status-card-metrics",
2738
+ children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell, { metric }, `${metric.label}-${index}`))
2739
+ }
2740
+ ),
2741
+ 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}`)) }),
2742
+ coaching != null && /* @__PURE__ */ jsx(
2743
+ View,
2744
+ {
2745
+ style: {
2746
+ backgroundColor: "rgba(249,180,21,0.06)",
2747
+ borderWidth: 1,
2748
+ borderColor: "rgba(249,180,21,0.15)",
2749
+ borderRadius: 8,
2750
+ paddingVertical: 10,
2751
+ paddingHorizontal: 12
2752
+ },
2753
+ testID: "meso-status-card-coaching",
2754
+ children: /* @__PURE__ */ jsx(
2755
+ Text,
2756
+ {
2757
+ className: "text-text-secondary",
2758
+ style: {
2759
+ fontSize: 12,
2760
+ lineHeight: 17,
2761
+ fontFamily: "Inter, sans-serif"
2762
+ },
2763
+ children: renderCoachingText(coaching.text, coaching.highlights)
2764
+ }
2765
+ )
2766
+ }
2767
+ ),
2768
+ nextTarget != null && /* @__PURE__ */ jsxs(
2769
+ View,
2770
+ {
2771
+ className: "flex-row items-center",
2772
+ style: {
2773
+ gap: 8,
2774
+ backgroundColor: "rgba(46,213,115,0.06)",
2775
+ borderWidth: 1,
2776
+ borderColor: "rgba(46,213,115,0.2)",
2777
+ borderRadius: 8,
2778
+ paddingVertical: 10,
2779
+ paddingHorizontal: 12
2780
+ },
2781
+ testID: "meso-status-card-next-target",
2782
+ children: [
2783
+ /* @__PURE__ */ jsx(Text, { style: { fontSize: 14, color: SUCCESS }, accessibilityElementsHidden: true, children: nextTarget.icon }),
2784
+ /* @__PURE__ */ jsx(
2785
+ Text,
2786
+ {
2787
+ style: {
2788
+ flexShrink: 1,
2789
+ fontSize: 12,
2790
+ fontFamily: "Inter, sans-serif",
2791
+ fontWeight: "600",
2792
+ color: SUCCESS
2793
+ },
2794
+ children: nextTarget.text
2795
+ }
2796
+ )
2797
+ ]
2798
+ }
2799
+ )
2800
+ ] })
2801
+ ]
2802
+ }
2803
+ );
2804
+ }
2805
+
2806
+ // src/components/custom/Workout/TrainingStatusPage.tsx
855
2807
  var STATUS_ORDER = ["under", "maintenance", "productive", "over"];
856
2808
  function deriveTrainingSummary(muscles) {
857
2809
  const statusCounts = {