@titan-design/react-ui 0.2.7 → 0.4.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 (92) hide show
  1. package/dist/bodymap-BhG55xHM.d.mts +318 -0
  2. package/dist/bodymap-BhG55xHM.d.ts +318 -0
  3. package/dist/bodymap.d.mts +3 -0
  4. package/dist/bodymap.d.ts +3 -0
  5. package/dist/bodymap.js +3014 -0
  6. package/dist/bodymap.js.map +1 -0
  7. package/dist/bodymap.mjs +1088 -0
  8. package/dist/bodymap.mjs.map +1 -0
  9. package/dist/chunk-2SISKTWM.mjs +1027 -0
  10. package/dist/chunk-2SISKTWM.mjs.map +1 -0
  11. package/dist/{chunk-5SSKGS6E.mjs → chunk-7XPB4NAO.mjs} +124 -4
  12. package/dist/chunk-7XPB4NAO.mjs.map +1 -0
  13. package/dist/{chunk-3VLOBS6O.mjs → chunk-SNVKL5WZ.mjs} +42 -5
  14. package/dist/chunk-SNVKL5WZ.mjs.map +1 -0
  15. package/dist/index.d.mts +416 -250
  16. package/dist/index.d.ts +416 -250
  17. package/dist/index.js +1567 -1123
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +1491 -2201
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/theme/index.d.mts +288 -2
  22. package/dist/theme/index.d.ts +288 -2
  23. package/dist/theme/index.js +159 -2
  24. package/dist/theme/index.js.map +1 -1
  25. package/dist/theme/index.mjs +2 -2
  26. package/dist/theme/tokens-css.d.mts +5 -3
  27. package/dist/theme/tokens-css.d.ts +5 -3
  28. package/dist/theme/tokens-css.js +318 -9
  29. package/dist/theme/tokens-css.js.map +1 -1
  30. package/dist/theme/tokens-css.mjs +1 -1
  31. package/dist/theme/tokens-css.mjs.map +1 -1
  32. package/package.json +10 -1
  33. package/src/bodymap.ts +37 -0
  34. package/src/components/custom/Table/Table.test.tsx +27 -0
  35. package/src/components/custom/Table/Table.tsx +33 -17
  36. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +118 -0
  37. package/src/components/custom/Workout/ActiveWorkoutPage.test.tsx +171 -0
  38. package/src/components/custom/Workout/ActiveWorkoutPage.tsx +442 -0
  39. package/src/components/custom/Workout/BodyMap.tsx +7 -9
  40. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +25 -29
  41. package/src/components/custom/Workout/CapacityBandChart.tsx +2 -3
  42. package/src/components/custom/Workout/ExerciseCard.test.tsx +24 -0
  43. package/src/components/custom/Workout/ExerciseCard.tsx +24 -26
  44. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +225 -0
  45. package/src/components/custom/Workout/ExerciseDetailPage.test.tsx +128 -0
  46. package/src/components/custom/Workout/ExerciseDetailPage.tsx +624 -0
  47. package/src/components/custom/Workout/InputBar.tsx +10 -12
  48. package/src/components/custom/Workout/MesoCard.tsx +2 -4
  49. package/src/components/custom/Workout/MesoProgressBar.test.tsx +12 -0
  50. package/src/components/custom/Workout/MesoProgressBar.tsx +5 -1
  51. package/src/components/custom/Workout/MesoStatusCard.tsx +17 -15
  52. package/src/components/custom/Workout/MuscleGroupChip.tsx +2 -4
  53. package/src/components/custom/Workout/PlaceholderStrip.tsx +2 -4
  54. package/src/components/custom/Workout/PrHistoryModal.tsx +12 -14
  55. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +257 -0
  56. package/src/components/custom/Workout/ProgramPlanningPage.test.tsx +142 -0
  57. package/src/components/custom/Workout/ProgramPlanningPage.tsx +418 -0
  58. package/src/components/custom/Workout/ReadinessCheck.tsx +13 -12
  59. package/src/components/custom/Workout/RestTimer.test.tsx +10 -0
  60. package/src/components/custom/Workout/RestTimer.tsx +12 -9
  61. package/src/components/custom/Workout/SetRow.tsx +16 -19
  62. package/src/components/custom/Workout/StatusDot.tsx +1 -0
  63. package/src/components/custom/Workout/StrengthTrendChart.tsx +15 -17
  64. package/src/components/custom/Workout/TempoBar.stories.tsx +95 -0
  65. package/src/components/custom/Workout/TempoBar.test.tsx +103 -0
  66. package/src/components/custom/Workout/TempoBar.tsx +215 -0
  67. package/src/components/custom/Workout/TempoDisplay.tsx +3 -1
  68. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +212 -0
  69. package/src/components/custom/Workout/TrainingStatusPage.test.tsx +131 -0
  70. package/src/components/custom/Workout/TrainingStatusPage.tsx +312 -0
  71. package/src/components/custom/Workout/VelocityStrip.test.tsx +10 -0
  72. package/src/components/custom/Workout/VelocityStrip.tsx +19 -16
  73. package/src/components/custom/Workout/WeekRow.tsx +2 -1
  74. package/src/components/custom/Workout/WorkoutCard.tsx +3 -6
  75. package/src/components/custom/Workout/index.ts +80 -32
  76. package/src/test/nativewind-stub.ts +13 -0
  77. package/src/theme/ThemeProvider.test.tsx +24 -0
  78. package/src/theme/ThemeProvider.tsx +50 -0
  79. package/src/theme/config.completeness.test.ts +77 -0
  80. package/src/theme/config.ts +151 -0
  81. package/src/theme/index.ts +2 -0
  82. package/src/theme/manifest/design-freeze.test.ts +155 -0
  83. package/src/theme/manifest/extract-css-properties.fixture.html +29 -0
  84. package/src/theme/manifest/extract-css-properties.test.ts +112 -0
  85. package/src/theme/resolve-color.ts +19 -0
  86. package/src/theme/tokens-css.ts +5 -3
  87. package/src/theme/workout-tokens.ts +12 -14
  88. package/src/utils/index.ts +10 -0
  89. package/src/utils/workout-format.test.ts +81 -0
  90. package/src/utils/workout-format.ts +83 -0
  91. package/dist/chunk-3VLOBS6O.mjs.map +0 -1
  92. package/dist/chunk-5SSKGS6E.mjs.map +0 -1
package/dist/index.js CHANGED
@@ -5,13 +5,12 @@ var clsx = require('clsx');
5
5
  var tailwindMerge = require('tailwind-merge');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var React24 = require('react');
8
+ var nativewind = require('nativewind');
8
9
  var lucideReact = require('lucide-react');
9
- var BodyHighlighter = require('react-native-body-highlighter');
10
10
 
11
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
12
 
13
13
  var React24__default = /*#__PURE__*/_interopDefault(React24);
14
- var BodyHighlighter__default = /*#__PURE__*/_interopDefault(BodyHighlighter);
15
14
 
16
15
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
17
16
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -1211,6 +1210,28 @@ var PasswordInput = React24.forwardRef(function PasswordInput2({ showIcon, hideI
1211
1210
  });
1212
1211
 
1213
1212
  // src/theme/config.ts
1213
+ var themeIndependentCSSVars = {
1214
+ // RGB decomposed values for glow shadows
1215
+ "--color-brand-primary-rgb": "255, 121, 0",
1216
+ "--color-brand-secondary-rgb": "64, 109, 135",
1217
+ "--color-status-success-rgb": "20, 184, 166",
1218
+ "--color-status-error-rgb": "209, 67, 67",
1219
+ "--color-status-warning-rgb": "255, 176, 32",
1220
+ "--color-status-info-rgb": "33, 150, 243",
1221
+ "--color-background-base-rgb": "16, 16, 16",
1222
+ // Font families
1223
+ "--font-family-sans": "'Inter'",
1224
+ "--font-family-body": "'Nunito Sans'",
1225
+ "--font-family-heading": "'Space Grotesk'",
1226
+ "--font-family-mono": "'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace",
1227
+ // Animation tokens
1228
+ "--ease-out": "cubic-bezier(0.22, 1, 0.36, 1)",
1229
+ "--ease-in-out": "cubic-bezier(0.65, 0, 0.35, 1)",
1230
+ "--ease-spring": "cubic-bezier(0.34, 1.56, 0.64, 1)",
1231
+ "--duration-fast": "150ms",
1232
+ "--duration-normal": "250ms",
1233
+ "--duration-slow": "400ms"
1234
+ };
1214
1235
  var lightThemeCSSVars = {
1215
1236
  "--color-brand-primary": semanticColorsLight["brand-primary"],
1216
1237
  "--color-brand-primary-light": semanticColorsLight["brand-primary-light"],
@@ -1251,7 +1272,56 @@ var lightThemeCSSVars = {
1251
1272
  "--color-interactive-active": semanticColorsLight["interactive-active"],
1252
1273
  "--color-interactive-selected": semanticColorsLight["interactive-selected"],
1253
1274
  "--color-interactive-disabled": semanticColorsLight["interactive-disabled"],
1254
- "--color-divider": semanticColorsLight["divider"]
1275
+ "--color-divider": semanticColorsLight["divider"],
1276
+ "--color-brand-primary-hover": semanticColorsLight["brand-primary-hover"],
1277
+ "--color-brand-primary-active": semanticColorsLight["brand-primary-active"],
1278
+ "--color-brand-secondary-hover": semanticColorsLight["brand-secondary-hover"],
1279
+ "--color-brand-secondary-active": semanticColorsLight["brand-secondary-active"],
1280
+ "--color-status-success-light": semanticColorsLight["status-success-light"],
1281
+ "--color-status-success-dark": semanticColorsLight["status-success-dark"],
1282
+ "--color-status-error-light": semanticColorsLight["status-error-light"],
1283
+ "--color-status-error-dark": semanticColorsLight["status-error-dark"],
1284
+ "--color-status-warning-light": semanticColorsLight["status-warning-light"],
1285
+ "--color-status-warning-dark": semanticColorsLight["status-warning-dark"],
1286
+ "--color-status-info-light": semanticColorsLight["status-info-light"],
1287
+ "--color-status-info-dark": semanticColorsLight["status-info-dark"],
1288
+ "--color-on-status-success": semanticColorsLight["on-status-success"],
1289
+ "--color-on-status-error": semanticColorsLight["on-status-error"],
1290
+ "--color-on-status-warning": semanticColorsLight["on-status-warning"],
1291
+ "--color-on-status-info": semanticColorsLight["on-status-info"],
1292
+ "--color-result-improve": semanticColorsLight["result-improve"],
1293
+ "--color-result-improve-light": semanticColorsLight["result-improve-light"],
1294
+ "--color-result-improve-dark": semanticColorsLight["result-improve-dark"],
1295
+ "--color-result-degrade": semanticColorsLight["result-degrade"],
1296
+ "--color-result-degrade-light": semanticColorsLight["result-degrade-light"],
1297
+ "--color-result-degrade-dark": semanticColorsLight["result-degrade-dark"],
1298
+ "--color-result-inconclusive": semanticColorsLight["result-inconclusive"],
1299
+ "--color-result-inconclusive-light": semanticColorsLight["result-inconclusive-light"],
1300
+ "--color-result-neutral": semanticColorsLight["result-neutral"],
1301
+ "--color-on-result-improve": semanticColorsLight["on-result-improve"],
1302
+ "--color-on-result-degrade": semanticColorsLight["on-result-degrade"],
1303
+ "--color-on-result-inconclusive": semanticColorsLight["on-result-inconclusive"],
1304
+ "--color-data-1": semanticColorsLight["data-1"],
1305
+ "--color-data-2": semanticColorsLight["data-2"],
1306
+ "--color-data-3": semanticColorsLight["data-3"],
1307
+ "--color-data-4": semanticColorsLight["data-4"],
1308
+ "--color-data-5": semanticColorsLight["data-5"],
1309
+ "--color-data-6": semanticColorsLight["data-6"],
1310
+ "--color-data-7": semanticColorsLight["data-7"],
1311
+ "--color-data-8": semanticColorsLight["data-8"],
1312
+ "--color-data-9": semanticColorsLight["data-9"],
1313
+ "--color-data-10": semanticColorsLight["data-10"],
1314
+ "--color-text-link-hover": semanticColorsLight["text-link-hover"],
1315
+ "--color-surface-overlay": semanticColorsLight["surface-overlay"],
1316
+ "--color-surface-input": semanticColorsLight["surface-input"],
1317
+ "--color-border-input": semanticColorsLight["border-input"],
1318
+ "--color-border-input-hover": semanticColorsLight["border-input-hover"],
1319
+ "--color-border-input-focus": semanticColorsLight["border-input-focus"],
1320
+ "--color-border-input-error": semanticColorsLight["border-input-error"],
1321
+ "--color-interactive-disabled-text": semanticColorsLight["interactive-disabled-text"],
1322
+ "--color-avatar-background": semanticColorsLight["avatar-background"],
1323
+ "--color-avatar-text": semanticColorsLight["avatar-text"],
1324
+ ...themeIndependentCSSVars
1255
1325
  };
1256
1326
  var darkThemeCSSVars = {
1257
1327
  "--color-brand-primary": semanticColorsDark["brand-primary"],
@@ -1293,7 +1363,56 @@ var darkThemeCSSVars = {
1293
1363
  "--color-interactive-active": semanticColorsDark["interactive-active"],
1294
1364
  "--color-interactive-selected": semanticColorsDark["interactive-selected"],
1295
1365
  "--color-interactive-disabled": semanticColorsDark["interactive-disabled"],
1296
- "--color-divider": semanticColorsDark["divider"]
1366
+ "--color-divider": semanticColorsDark["divider"],
1367
+ "--color-brand-primary-hover": semanticColorsDark["brand-primary-hover"],
1368
+ "--color-brand-primary-active": semanticColorsDark["brand-primary-active"],
1369
+ "--color-brand-secondary-hover": semanticColorsDark["brand-secondary-hover"],
1370
+ "--color-brand-secondary-active": semanticColorsDark["brand-secondary-active"],
1371
+ "--color-status-success-light": semanticColorsDark["status-success-light"],
1372
+ "--color-status-success-dark": semanticColorsDark["status-success-dark"],
1373
+ "--color-status-error-light": semanticColorsDark["status-error-light"],
1374
+ "--color-status-error-dark": semanticColorsDark["status-error-dark"],
1375
+ "--color-status-warning-light": semanticColorsDark["status-warning-light"],
1376
+ "--color-status-warning-dark": semanticColorsDark["status-warning-dark"],
1377
+ "--color-status-info-light": semanticColorsDark["status-info-light"],
1378
+ "--color-status-info-dark": semanticColorsDark["status-info-dark"],
1379
+ "--color-on-status-success": semanticColorsDark["on-status-success"],
1380
+ "--color-on-status-error": semanticColorsDark["on-status-error"],
1381
+ "--color-on-status-warning": semanticColorsDark["on-status-warning"],
1382
+ "--color-on-status-info": semanticColorsDark["on-status-info"],
1383
+ "--color-result-improve": semanticColorsDark["result-improve"],
1384
+ "--color-result-improve-light": semanticColorsDark["result-improve-light"],
1385
+ "--color-result-improve-dark": semanticColorsDark["result-improve-dark"],
1386
+ "--color-result-degrade": semanticColorsDark["result-degrade"],
1387
+ "--color-result-degrade-light": semanticColorsDark["result-degrade-light"],
1388
+ "--color-result-degrade-dark": semanticColorsDark["result-degrade-dark"],
1389
+ "--color-result-inconclusive": semanticColorsDark["result-inconclusive"],
1390
+ "--color-result-inconclusive-light": semanticColorsDark["result-inconclusive-light"],
1391
+ "--color-result-neutral": semanticColorsDark["result-neutral"],
1392
+ "--color-on-result-improve": semanticColorsDark["on-result-improve"],
1393
+ "--color-on-result-degrade": semanticColorsDark["on-result-degrade"],
1394
+ "--color-on-result-inconclusive": semanticColorsDark["on-result-inconclusive"],
1395
+ "--color-data-1": semanticColorsDark["data-1"],
1396
+ "--color-data-2": semanticColorsDark["data-2"],
1397
+ "--color-data-3": semanticColorsDark["data-3"],
1398
+ "--color-data-4": semanticColorsDark["data-4"],
1399
+ "--color-data-5": semanticColorsDark["data-5"],
1400
+ "--color-data-6": semanticColorsDark["data-6"],
1401
+ "--color-data-7": semanticColorsDark["data-7"],
1402
+ "--color-data-8": semanticColorsDark["data-8"],
1403
+ "--color-data-9": semanticColorsDark["data-9"],
1404
+ "--color-data-10": semanticColorsDark["data-10"],
1405
+ "--color-text-link-hover": semanticColorsDark["text-link-hover"],
1406
+ "--color-surface-overlay": semanticColorsDark["surface-overlay"],
1407
+ "--color-surface-input": semanticColorsDark["surface-input"],
1408
+ "--color-border-input": semanticColorsDark["border-input"],
1409
+ "--color-border-input-hover": semanticColorsDark["border-input-hover"],
1410
+ "--color-border-input-focus": semanticColorsDark["border-input-focus"],
1411
+ "--color-border-input-error": semanticColorsDark["border-input-error"],
1412
+ "--color-interactive-disabled-text": semanticColorsDark["interactive-disabled-text"],
1413
+ "--color-avatar-background": semanticColorsDark["avatar-background"],
1414
+ "--color-avatar-text": semanticColorsDark["avatar-text"],
1415
+ ...themeIndependentCSSVars
1297
1416
  };
1298
1417
  function getThemeCSSVars(mode) {
1299
1418
  return mode === "dark" ? darkThemeCSSVars : lightThemeCSSVars;
@@ -2042,6 +2161,21 @@ function validateCssPropertyManifest(candidate) {
2042
2161
  function isCssPropertyManifest(candidate) {
2043
2162
  return validateCssPropertyManifest(candidate).valid;
2044
2163
  }
2164
+ var MODE_VARS = {
2165
+ dark: nativewind.vars(darkThemeCSSVars),
2166
+ light: nativewind.vars(lightThemeCSSVars)
2167
+ };
2168
+ function ThemeProvider({
2169
+ mode = "dark",
2170
+ style,
2171
+ children,
2172
+ ...props
2173
+ }) {
2174
+ return /* @__PURE__ */ jsx(reactNative.View, { style: [MODE_VARS[mode], { flex: 1 }, style], ...props, children });
2175
+ }
2176
+ function resolveColor(token, mode = "dark") {
2177
+ return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
2178
+ }
2045
2179
 
2046
2180
  // src/theme/presets/apply.ts
2047
2181
  function colorKeyToVar(key) {
@@ -4867,7 +5001,7 @@ function ToastProvider({
4867
5001
  return id;
4868
5002
  }, [defaultDuration, maxToasts]);
4869
5003
  const removeToast = React24.useCallback((id) => {
4870
- setToasts((prev) => prev.filter((t) => t.id !== id));
5004
+ setToasts((prev) => prev.filter((t2) => t2.id !== id));
4871
5005
  }, []);
4872
5006
  const removeAllToasts = React24.useCallback(() => {
4873
5007
  setToasts([]);
@@ -5982,7 +6116,7 @@ function Table({
5982
6116
  selectable,
5983
6117
  allRowIds: rowIds
5984
6118
  },
5985
- children: /* @__PURE__ */ jsx(reactNative.View, { className: cn("w-full", className), ...props, children: /* @__PURE__ */ jsx(reactNative.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: /* @__PURE__ */ jsx(reactNative.View, { className: "w-full min-w-full", children: isLoading ? /* @__PURE__ */ jsx(TableLoadingSkeleton, { rowCount: loadingRowCount }) : children }) }) })
6119
+ children: /* @__PURE__ */ jsx(reactNative.View, { className: cn("w-full", className), ...props, children: /* @__PURE__ */ jsx(reactNative.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: /* @__PURE__ */ jsx(reactNative.View, { role: "table", className: "w-full min-w-full", children: isLoading ? /* @__PURE__ */ jsx(TableLoadingSkeleton, { rowCount: loadingRowCount }) : children }) }) })
5986
6120
  }
5987
6121
  );
5988
6122
  }
@@ -5990,14 +6124,14 @@ function TableHeader({ children, className }) {
5990
6124
  return /* @__PURE__ */ jsx(
5991
6125
  reactNative.View,
5992
6126
  {
5993
- accessibilityRole: "none",
6127
+ role: "rowgroup",
5994
6128
  className: cn("bg-background-subtle rounded-t-lg", className),
5995
6129
  children
5996
6130
  }
5997
6131
  );
5998
6132
  }
5999
6133
  function TableBody({ children, className }) {
6000
- return /* @__PURE__ */ jsx(reactNative.View, { accessibilityRole: "none", className, children });
6134
+ return /* @__PURE__ */ jsx(reactNative.View, { role: "rowgroup", className, children });
6001
6135
  }
6002
6136
  function TableRow({
6003
6137
  isSelected = false,
@@ -6009,7 +6143,7 @@ function TableRow({
6009
6143
  return /* @__PURE__ */ jsx(
6010
6144
  reactNative.View,
6011
6145
  {
6012
- accessibilityRole: "none",
6146
+ role: "row",
6013
6147
  className: cn(
6014
6148
  "flex-row border-b border-divider",
6015
6149
  isHoverable && "web:hover:bg-interactive-hover",
@@ -6033,6 +6167,7 @@ function TableHeaderCell({
6033
6167
  const { sortColumn, sortDirection, onSort } = React24.useContext(TableContext);
6034
6168
  const isSorted = sortKey && sortColumn === sortKey;
6035
6169
  const isSortable = !!sortKey && !!onSort;
6170
+ const ariaSort = isSorted ? sortDirection === "asc" ? "ascending" : sortDirection === "desc" ? "descending" : "none" : "none";
6036
6171
  const handlePress = (e) => {
6037
6172
  if (isSortable && sortKey) {
6038
6173
  onSort(sortKey);
@@ -6059,26 +6194,34 @@ function TableHeaderCell({
6059
6194
  ] });
6060
6195
  if (isSortable) {
6061
6196
  return /* @__PURE__ */ jsx(
6062
- reactNative.Pressable,
6197
+ reactNative.View,
6063
6198
  {
6064
- accessibilityRole: "button",
6065
- accessibilityLabel: `Sort by ${children}`,
6066
- onPress: handlePress,
6199
+ role: "columnheader",
6200
+ "aria-sort": ariaSort,
6067
6201
  style: width ? { width } : { flex: 1 },
6068
- className: cn(
6069
- "flex-row items-center px-4 py-3",
6070
- alignStyles3[align],
6071
- "web:hover:bg-interactive-hover active:bg-interactive-active",
6072
- className
6073
- ),
6074
- ...props,
6075
- children: content
6202
+ children: /* @__PURE__ */ jsx(
6203
+ reactNative.Pressable,
6204
+ {
6205
+ accessibilityRole: "button",
6206
+ accessibilityLabel: `Sort by ${children}`,
6207
+ onPress: handlePress,
6208
+ className: cn(
6209
+ "flex-row items-center px-4 py-3",
6210
+ alignStyles3[align],
6211
+ "web:hover:bg-interactive-hover active:bg-interactive-active",
6212
+ className
6213
+ ),
6214
+ ...props,
6215
+ children: content
6216
+ }
6217
+ )
6076
6218
  }
6077
6219
  );
6078
6220
  }
6079
6221
  return /* @__PURE__ */ jsx(
6080
6222
  reactNative.View,
6081
6223
  {
6224
+ role: "columnheader",
6082
6225
  style: width ? { width } : { flex: 1 },
6083
6226
  className: cn(
6084
6227
  "flex-row items-center px-4 py-3",
@@ -6104,6 +6247,7 @@ function TableCell({
6104
6247
  return /* @__PURE__ */ jsx(
6105
6248
  reactNative.View,
6106
6249
  {
6250
+ role: "cell",
6107
6251
  style: width ? { width } : { flex: 1 },
6108
6252
  className: cn(
6109
6253
  "justify-center px-4 py-3.5",
@@ -6985,36 +7129,6 @@ function StatusDot({
6985
7129
  }
6986
7130
  return /* @__PURE__ */ jsx(reactNative.View, { className, ...props, children: dot });
6987
7131
  }
6988
-
6989
- // src/theme/workout-tokens.ts
6990
- var WORKOUT_TOKENS = {
6991
- // BodyMap volume heatmap scale (drive dynamic SVG fills, so inline values).
6992
- // Maps weekly-volume status against MEV/MAV/MRV landmarks to a fill color.
6993
- heatmap: {
6994
- none: "#E0E0E0",
6995
- // gray — no training data
6996
- under: "#4A90D9",
6997
- // cool blue — below MEV
6998
- maintenance: "#F5C842",
6999
- // warm yellow — MEV to MAV
7000
- productive: "#4CAF50",
7001
- // green — MAV to MRV
7002
- approaching: "#FFA502",
7003
- // orange — near MRV
7004
- over: "#FF6B35"
7005
- // red-orange — over MRV
7006
- },
7007
- // Border colors (use inline to avoid 'border' class pitfall)
7008
- border: {
7009
- default: "#1F1F1F",
7010
- strong: "#2C2C2C"},
7011
- // Surface colors for inline use
7012
- surface: {
7013
- raised: "#1C1C1C",
7014
- elevated: "#191919"
7015
- }};
7016
-
7017
- // src/components/custom/Workout/PlaceholderStrip.tsx
7018
7132
  function SingleStrip({
7019
7133
  width,
7020
7134
  className,
@@ -7023,14 +7137,13 @@ function SingleStrip({
7023
7137
  return /* @__PURE__ */ jsx(
7024
7138
  reactNative.View,
7025
7139
  {
7026
- className: cn(className),
7140
+ className: cn("border-border-strong", className),
7027
7141
  style: [
7028
7142
  {
7029
7143
  height: 3,
7030
7144
  backgroundColor: "transparent",
7031
7145
  borderWidth: 1,
7032
7146
  borderStyle: "dashed",
7033
- borderColor: WORKOUT_TOKENS.border.strong,
7034
7147
  borderRadius: 1,
7035
7148
  opacity: 0.5
7036
7149
  },
@@ -7064,13 +7177,13 @@ function SegmentedStrip({
7064
7177
  children: Array.from({ length: segments }, (_, i) => /* @__PURE__ */ jsx(
7065
7178
  reactNative.View,
7066
7179
  {
7180
+ className: "border-border-strong",
7067
7181
  style: {
7068
7182
  flex: 1,
7069
7183
  height: 3,
7070
7184
  backgroundColor: "transparent",
7071
7185
  borderWidth: 1,
7072
7186
  borderStyle: "dashed",
7073
- borderColor: WORKOUT_TOKENS.border.strong,
7074
7187
  borderRadius: 1,
7075
7188
  minWidth: 4
7076
7189
  },
@@ -7092,6 +7205,63 @@ function PlaceholderStrip({
7092
7205
  }
7093
7206
  return /* @__PURE__ */ jsx(SingleStrip, { ...props });
7094
7207
  }
7208
+
7209
+ // src/theme/workout-tokens.ts
7210
+ var WORKOUT_TOKENS = {
7211
+ // Canonical 4-band performance scale — the single source for BOTH the
7212
+ // VelocityStrip zone bars and the SetRow RPE color (TD-03.43). The direction
7213
+ // is intentionally inverted between the two consumers: for velocity, green =
7214
+ // fastest/best; for RPE, green = easiest. Each component maps its own
7215
+ // thresholds onto these four colors. Kept as vivid data-viz values (distinct
7216
+ // from the muted status tokens) and theme-independent, so — like the heatmap
7217
+ // scale below — they are consumed inline as a JS import rather than CSS vars.
7218
+ // A JS import also resolves on native RN, unlike var(--…) strings.
7219
+ scale: {
7220
+ green: "#2ed573",
7221
+ yellow: "#ffd43b",
7222
+ orange: "#ffa502",
7223
+ red: "#ff4757"
7224
+ }};
7225
+
7226
+ // src/utils/workout-format.ts
7227
+ function roundRpe(rpe) {
7228
+ return Math.round(rpe * 2) / 2;
7229
+ }
7230
+ function rpeColor(rpe) {
7231
+ if (rpe >= 9.5) return WORKOUT_TOKENS.scale.red;
7232
+ if (rpe >= 8.5) return WORKOUT_TOKENS.scale.orange;
7233
+ if (rpe >= 7) return WORKOUT_TOKENS.scale.yellow;
7234
+ return WORKOUT_TOKENS.scale.green;
7235
+ }
7236
+ function roundWeight(weight) {
7237
+ return Math.round(weight);
7238
+ }
7239
+ function formatVelocity(velocity) {
7240
+ return velocity.toFixed(2);
7241
+ }
7242
+ function roundTempo(tempo) {
7243
+ return tempo.map((v) => Math.round(v * 10) / 10);
7244
+ }
7245
+ function formatSignedPct(ratio) {
7246
+ const pct = Math.round(ratio * 100);
7247
+ return `${pct > 0 ? "+" : ""}${pct}%`;
7248
+ }
7249
+ function formatPrescription(p) {
7250
+ if (p == null) return null;
7251
+ let reps = null;
7252
+ if (p.repsLow != null && p.repsHigh != null) {
7253
+ reps = p.repsLow === p.repsHigh ? `${p.repsLow}` : `${p.repsLow}\u2013${p.repsHigh}`;
7254
+ } else if (p.repsLow != null) {
7255
+ reps = `${p.repsLow}`;
7256
+ }
7257
+ const weight = p.weightLbs != null ? `${p.weightLbs} lb` : null;
7258
+ const head = [reps, weight].filter((s) => s != null).join(" @ ");
7259
+ const rpe = p.rpe != null ? `RPE ${p.rpe}` : null;
7260
+ const full = [head.length > 0 ? head : null, rpe].filter((s) => s != null).join(" \xB7 ");
7261
+ return full.length > 0 ? full : null;
7262
+ }
7263
+
7264
+ // src/components/custom/Workout/TempoDisplay.tsx
7095
7265
  var INTER = "Inter, sans-serif";
7096
7266
  var TEXT_TERTIARY = "#6B7280";
7097
7267
  var phaseColors = {
@@ -7147,7 +7317,7 @@ function TempoDisplay({
7147
7317
  ...props
7148
7318
  }) {
7149
7319
  const [showTooltip, setShowTooltip] = React24.useState(false);
7150
- const [eccentric, pauseBottom, concentric, pauseTop] = tempo;
7320
+ const [eccentric, pauseBottom, concentric, pauseTop] = roundTempo(tempo);
7151
7321
  const isSm = size === "sm";
7152
7322
  const fontSize = isSm ? 9 : 11;
7153
7323
  const monoColor = TEXT_TERTIARY;
@@ -7300,6 +7470,198 @@ function TempoDisplay({
7300
7470
  }
7301
7471
  );
7302
7472
  }
7473
+
7474
+ // src/utils/colors.ts
7475
+ function getStatusColor(status) {
7476
+ return `var(--color-status-${status})`;
7477
+ }
7478
+ function getResultColor(result) {
7479
+ return `var(--color-result-${result})`;
7480
+ }
7481
+ function alpha(color, opacity) {
7482
+ const clampedOpacity = Math.max(0, Math.min(1, opacity));
7483
+ if (color.startsWith("#")) {
7484
+ const hex = color.slice(1);
7485
+ let r, g, b;
7486
+ if (hex.length === 3) {
7487
+ r = parseInt(hex[0] + hex[0], 16);
7488
+ g = parseInt(hex[1] + hex[1], 16);
7489
+ b = parseInt(hex[2] + hex[2], 16);
7490
+ } else if (hex.length === 6) {
7491
+ r = parseInt(hex.slice(0, 2), 16);
7492
+ g = parseInt(hex.slice(2, 4), 16);
7493
+ b = parseInt(hex.slice(4, 6), 16);
7494
+ } else {
7495
+ return color;
7496
+ }
7497
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
7498
+ }
7499
+ const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
7500
+ if (rgbMatch) {
7501
+ const [, r, g, b] = rgbMatch;
7502
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
7503
+ }
7504
+ const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
7505
+ if (rgbaMatch) {
7506
+ const [, r, g, b] = rgbaMatch;
7507
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
7508
+ }
7509
+ return color;
7510
+ }
7511
+ function getLuminance(color) {
7512
+ if (!color.startsWith("#")) return "dark";
7513
+ const hex = color.slice(1);
7514
+ let r, g, b;
7515
+ if (hex.length === 3) {
7516
+ r = parseInt(hex[0] + hex[0], 16);
7517
+ g = parseInt(hex[1] + hex[1], 16);
7518
+ b = parseInt(hex[2] + hex[2], 16);
7519
+ } else if (hex.length === 6) {
7520
+ r = parseInt(hex.slice(0, 2), 16);
7521
+ g = parseInt(hex.slice(2, 4), 16);
7522
+ b = parseInt(hex.slice(4, 6), 16);
7523
+ } else {
7524
+ return "dark";
7525
+ }
7526
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
7527
+ return luminance > 0.5 ? "light" : "dark";
7528
+ }
7529
+ function getContrastText(backgroundColor) {
7530
+ return getLuminance(backgroundColor) === "light" ? "#000000" : "#FFFFFF";
7531
+ }
7532
+
7533
+ // src/components/custom/Workout/TempoBar.tsx
7534
+ var t = getSemanticColors("dark");
7535
+ var TEMPO_PACING = {
7536
+ behindThresholdPct: 0.15,
7537
+ minPhaseDurationMs: 500
7538
+ };
7539
+ function getTempoPacingState(elapsedMs, targetMs) {
7540
+ if (!targetMs || targetMs < TEMPO_PACING.minPhaseDurationMs) return "none";
7541
+ const ratio = elapsedMs / targetMs;
7542
+ if (ratio > 1 + TEMPO_PACING.behindThresholdPct) return "behind";
7543
+ return "on-pace";
7544
+ }
7545
+ function getTempoFillPct(elapsedMs, targetMs) {
7546
+ if (!targetMs) return 100;
7547
+ return Math.min(100, elapsedMs / targetMs * 100);
7548
+ }
7549
+ var PHASE_ORDER = ["concentric", "hold", "eccentric"];
7550
+ var PHASE_CONFIG = {
7551
+ concentric: { label: "Con", color: t["status-success"], flex: 2 },
7552
+ hold: { label: "Hold", color: t["brand-primary"], flex: 1 },
7553
+ eccentric: { label: "Ecc", color: t["status-warning"], flex: 3 }
7554
+ };
7555
+ function TempoBar({
7556
+ activePhase,
7557
+ phaseElapsedMs,
7558
+ completed,
7559
+ target,
7560
+ className,
7561
+ ...props
7562
+ }) {
7563
+ return /* @__PURE__ */ jsxs(reactNative.View, { className, testID: "tempo-bar", ...props, children: [
7564
+ /* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", marginBottom: 4 }, children: PHASE_ORDER.map((phase) => {
7565
+ const config = PHASE_CONFIG[phase];
7566
+ return /* @__PURE__ */ jsx(reactNative.View, { style: { flex: config.flex, alignItems: "center" }, children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, color: t["text-disabled"] }, children: config.label }) }, phase);
7567
+ }) }),
7568
+ /* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", gap: 2, height: 20 }, children: PHASE_ORDER.map((phase) => {
7569
+ const config = PHASE_CONFIG[phase];
7570
+ const isActive = activePhase === phase;
7571
+ const completedMs = completed?.[phase];
7572
+ const targetSec = target?.[phase];
7573
+ const targetMs = targetSec != null ? targetSec * 1e3 : null;
7574
+ return /* @__PURE__ */ jsx(
7575
+ reactNative.View,
7576
+ {
7577
+ style: {
7578
+ flex: config.flex,
7579
+ backgroundColor: alpha("#ffffff", 0.06),
7580
+ borderRadius: 4,
7581
+ overflow: "hidden"
7582
+ },
7583
+ children: isActive ? /* @__PURE__ */ jsx(
7584
+ ActiveSegment,
7585
+ {
7586
+ config,
7587
+ phaseElapsedMs,
7588
+ targetMs
7589
+ }
7590
+ ) : completedMs != null ? /* @__PURE__ */ jsx(CompletedSegment, { config, completedMs, targetMs }) : null
7591
+ },
7592
+ phase
7593
+ );
7594
+ }) })
7595
+ ] });
7596
+ }
7597
+ function ActiveSegment({
7598
+ config,
7599
+ phaseElapsedMs,
7600
+ targetMs
7601
+ }) {
7602
+ const pacing = getTempoPacingState(phaseElapsedMs, targetMs);
7603
+ const barColor = pacing === "behind" ? t["status-error"] : config.color;
7604
+ const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
7605
+ const label = targetMs ? `${formatDuration(phaseElapsedMs)} / ${formatDuration(targetMs)}` : formatDuration(phaseElapsedMs);
7606
+ return /* @__PURE__ */ jsxs(reactNative.View, { style: { height: "100%", position: "relative" }, testID: `tempo-segment-active-${config.label}`, children: [
7607
+ /* @__PURE__ */ jsx(
7608
+ reactNative.View,
7609
+ {
7610
+ style: {
7611
+ position: "absolute",
7612
+ left: 0,
7613
+ top: 0,
7614
+ bottom: 0,
7615
+ width: `${fillPct}%`,
7616
+ backgroundColor: alpha(barColor, 0.3),
7617
+ borderRadius: 4
7618
+ }
7619
+ }
7620
+ ),
7621
+ /* @__PURE__ */ jsx(
7622
+ reactNative.View,
7623
+ {
7624
+ style: {
7625
+ height: "100%",
7626
+ flexDirection: "row",
7627
+ alignItems: "center",
7628
+ justifyContent: "center"
7629
+ },
7630
+ children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, fontWeight: "700", color: barColor }, children: label })
7631
+ }
7632
+ )
7633
+ ] });
7634
+ }
7635
+ function CompletedSegment({
7636
+ config,
7637
+ completedMs,
7638
+ targetMs
7639
+ }) {
7640
+ const pacing = getTempoPacingState(completedMs, targetMs);
7641
+ const hitTarget = pacing !== "behind";
7642
+ const indicator = targetMs && targetMs >= TEMPO_PACING.minPhaseDurationMs ? hitTarget ? " \u2713" : " \u2717" : "";
7643
+ return /* @__PURE__ */ jsx(
7644
+ reactNative.View,
7645
+ {
7646
+ style: {
7647
+ height: "100%",
7648
+ flexDirection: "row",
7649
+ alignItems: "center",
7650
+ justifyContent: "center",
7651
+ backgroundColor: alpha(config.color, 0.15)
7652
+ },
7653
+ testID: `tempo-segment-completed-${config.label}`,
7654
+ children: /* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 12, fontWeight: "500", color: alpha(config.color, 0.7) }, children: [
7655
+ formatDuration(completedMs),
7656
+ indicator
7657
+ ] })
7658
+ }
7659
+ );
7660
+ }
7661
+ function formatDuration(ms) {
7662
+ const s = ms / 1e3;
7663
+ return s < 10 ? s.toFixed(1) : Math.round(s).toString();
7664
+ }
7303
7665
  function getDotColor(deviation) {
7304
7666
  const abs = Math.abs(deviation);
7305
7667
  if (deviation < -0.3) return "#14B8A6";
@@ -7655,12 +8017,7 @@ function WorkoutPill({
7655
8017
  }
7656
8018
  return pill;
7657
8019
  }
7658
- var VEL_COLORS = {
7659
- green: "#2ed573",
7660
- yellow: "#ffd43b",
7661
- orange: "#ffa502",
7662
- red: "#ff4757"
7663
- };
8020
+ var VEL_COLORS = WORKOUT_TOKENS.scale;
7664
8021
  function getVelocityZoneColor(velocity) {
7665
8022
  if (velocity >= 1) return "vel-green";
7666
8023
  if (velocity >= 0.75) return "vel-yellow";
@@ -7787,7 +8144,7 @@ function VelocityStrip({
7787
8144
  const stripContent = /* @__PURE__ */ jsxs(
7788
8145
  reactNative.Animated.View,
7789
8146
  {
7790
- className,
8147
+ className: [className, expanded ? "bg-surface-raised" : "bg-transparent"].filter(Boolean).join(" "),
7791
8148
  style: [
7792
8149
  {
7793
8150
  height: heightAnim,
@@ -7798,7 +8155,6 @@ function VelocityStrip({
7798
8155
  paddingBottom: expanded ? 24 : 0,
7799
8156
  paddingHorizontal: expanded ? 6 : 0,
7800
8157
  paddingVertical: expanded ? void 0 : 8,
7801
- backgroundColor: expanded ? "#1C1C1C" : "transparent",
7802
8158
  overflow: expanded ? "visible" : "hidden"
7803
8159
  }
7804
8160
  ],
@@ -7813,7 +8169,7 @@ function VelocityStrip({
7813
8169
  style: { flexDirection: "row", flex: 1, gap: 2, alignItems: "flex-end" },
7814
8170
  children: velocities.map((v, i) => {
7815
8171
  const zone = getVelocityZoneColor(v);
7816
- const barHeightPct = Math.round(v / (maxVelocity * 1.15) * 100);
8172
+ const barHeightPct = maxVelocity > 0 ? Math.round(v / (maxVelocity * 1.15) * 100) : 0;
7817
8173
  const bar = /* @__PURE__ */ jsxs(
7818
8174
  reactNative.View,
7819
8175
  {
@@ -7822,9 +8178,10 @@ function VelocityStrip({
7822
8178
  expanded && /* @__PURE__ */ jsx(reactNative.Animated.View, { style: { opacity: labelOpacity, alignItems: "center", position: "absolute", top: -13, left: 0, right: 0 }, accessibilityElementsHidden: true, children: /* @__PURE__ */ jsx(
7823
8179
  reactNative.Text,
7824
8180
  {
7825
- style: { fontSize: 8, fontWeight: "600", color: "#9CA3AF" },
8181
+ className: "text-text-secondary",
8182
+ style: { fontSize: 8, fontWeight: "600" },
7826
8183
  testID: `velocity-label-${i}`,
7827
- children: v.toFixed(2)
8184
+ children: formatVelocity(v)
7828
8185
  }
7829
8186
  ) }),
7830
8187
  /* @__PURE__ */ jsx(
@@ -7840,7 +8197,7 @@ function VelocityStrip({
7840
8197
  },
7841
8198
  testID: `velocity-bar-${i}`,
7842
8199
  accessibilityRole: "image",
7843
- accessibilityLabel: `Rep ${i + 1}: ${v.toFixed(2)} meters per second`
8200
+ accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second`
7844
8201
  }
7845
8202
  )
7846
8203
  ]
@@ -7854,7 +8211,7 @@ function VelocityStrip({
7854
8211
  style: { flex: 1, height: "100%" },
7855
8212
  onPress: () => onRepPress(i, v),
7856
8213
  accessibilityRole: "button",
7857
- accessibilityLabel: `Rep ${i + 1}: ${v.toFixed(2)} meters per second, tap for details`,
8214
+ accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second, tap for details`,
7858
8215
  testID: `velocity-bar-pressable-${i}`,
7859
8216
  children: bar
7860
8217
  },
@@ -7882,9 +8239,9 @@ function VelocityStrip({
7882
8239
  /* @__PURE__ */ jsxs(
7883
8240
  reactNative.Text,
7884
8241
  {
8242
+ className: "text-text-secondary",
7885
8243
  style: {
7886
8244
  fontSize: 10,
7887
- color: "#9CA3AF",
7888
8245
  fontFamily: "Inter, sans-serif"
7889
8246
  },
7890
8247
  children: [
@@ -7892,7 +8249,7 @@ function VelocityStrip({
7892
8249
  " ",
7893
8250
  "\xB7",
7894
8251
  " ",
7895
- meanVelocity.toFixed(2),
8252
+ formatVelocity(meanVelocity),
7896
8253
  " m/s"
7897
8254
  ]
7898
8255
  }
@@ -7900,9 +8257,9 @@ function VelocityStrip({
7900
8257
  /* @__PURE__ */ jsxs(
7901
8258
  reactNative.Text,
7902
8259
  {
8260
+ className: "text-text-secondary",
7903
8261
  style: {
7904
8262
  fontSize: 10,
7905
- color: "#9CA3AF",
7906
8263
  fontFamily: "Inter, sans-serif",
7907
8264
  ...getLossStyle(loss)
7908
8265
  },
@@ -7952,16 +8309,14 @@ function MuscleGroupChip({
7952
8309
  const content = /* @__PURE__ */ jsxs(
7953
8310
  reactNative.View,
7954
8311
  {
7955
- className,
8312
+ className: ["bg-surface-raised border-border", className].filter(Boolean).join(" "),
7956
8313
  style: {
7957
8314
  flexDirection: "row",
7958
8315
  alignItems: "center",
7959
8316
  borderRadius: 9999,
7960
8317
  paddingHorizontal: 9,
7961
8318
  paddingVertical: 3,
7962
- backgroundColor: "var(--color-surface-raised)",
7963
- borderWidth: 1,
7964
- borderColor: "var(--color-border-default)"
8319
+ borderWidth: 1
7965
8320
  },
7966
8321
  accessibilityLabel: onPress ? void 0 : `${name}, volume status: ${statusLabel}`,
7967
8322
  testID: "muscle-group-chip",
@@ -7985,11 +8340,11 @@ function MuscleGroupChip({
7985
8340
  /* @__PURE__ */ jsx(
7986
8341
  reactNative.Text,
7987
8342
  {
8343
+ className: "text-text-secondary",
7988
8344
  style: {
7989
8345
  fontFamily: "Inter, sans-serif",
7990
8346
  fontWeight: "500",
7991
- fontSize: 11,
7992
- color: "var(--color-text-secondary)"
8347
+ fontSize: 11
7993
8348
  },
7994
8349
  accessibilityElementsHidden: true,
7995
8350
  children: name
@@ -8163,15 +8518,9 @@ function Sparkline({
8163
8518
  }
8164
8519
  );
8165
8520
  }
8166
- function getRPEColor(rpe) {
8167
- if (rpe >= 9.5) return "#ff4757";
8168
- if (rpe >= 8.5) return "#ffa502";
8169
- if (rpe >= 7) return "#ffd43b";
8170
- return "#2ed573";
8171
- }
8172
8521
  function formatAccessibilityLabel(setNumber, reps, weight, unit) {
8173
8522
  const repsText = reps != null ? `${reps} reps` : "no reps";
8174
- const weightText = weight != null ? `at ${weight} ${unit}` : "";
8523
+ const weightText = weight != null ? `at ${roundWeight(weight)} ${unit}` : "";
8175
8524
  return `Set ${setNumber}: ${repsText}${weightText ? ` ${weightText}` : ""}`;
8176
8525
  }
8177
8526
  function SetRow({
@@ -8245,11 +8594,11 @@ function SetRow({
8245
8594
  ) : /* @__PURE__ */ jsx(
8246
8595
  reactNative.Text,
8247
8596
  {
8597
+ className: "text-text-secondary",
8248
8598
  style: {
8249
8599
  fontSize: 13,
8250
8600
  fontWeight: "600",
8251
- fontFamily: "Inter, sans-serif",
8252
- color: "#9CA3AF"
8601
+ fontFamily: "Inter, sans-serif"
8253
8602
  },
8254
8603
  children: setNumber
8255
8604
  }
@@ -8264,12 +8613,12 @@ function SetRow({
8264
8613
  children: /* @__PURE__ */ jsx(
8265
8614
  reactNative.Text,
8266
8615
  {
8616
+ className: "text-text-secondary",
8267
8617
  style: {
8268
8618
  fontSize: 12,
8269
- fontFamily: "Inter, sans-serif",
8270
- color: "#9CA3AF"
8619
+ fontFamily: "Inter, sans-serif"
8271
8620
  },
8272
- children: previous ? `${previous.reps} x ${previous.weight}` : "\u2014"
8621
+ children: previous ? `${previous.reps} x ${roundWeight(previous.weight)}` : "\u2014"
8273
8622
  }
8274
8623
  )
8275
8624
  }
@@ -8282,11 +8631,11 @@ function SetRow({
8282
8631
  children: isActive && reps == null && targets ? /* @__PURE__ */ jsx(
8283
8632
  reactNative.Text,
8284
8633
  {
8634
+ className: "text-text-tertiary",
8285
8635
  style: {
8286
8636
  fontSize: 13,
8287
8637
  fontStyle: "italic",
8288
- fontFamily: "Inter, sans-serif",
8289
- color: "#6B7280"
8638
+ fontFamily: "Inter, sans-serif"
8290
8639
  },
8291
8640
  testID: "set-row-target-reps",
8292
8641
  children: targets.reps
@@ -8294,11 +8643,11 @@ function SetRow({
8294
8643
  ) : /* @__PURE__ */ jsx(
8295
8644
  reactNative.Text,
8296
8645
  {
8646
+ className: reps != null ? "text-text-primary" : "text-text-tertiary",
8297
8647
  style: {
8298
8648
  fontSize: 14,
8299
8649
  fontWeight: "600",
8300
- fontFamily: "Inter, sans-serif",
8301
- color: reps != null ? "#F3F4F6" : "#6B7280"
8650
+ fontFamily: "Inter, sans-serif"
8302
8651
  },
8303
8652
  children: reps != null ? reps : "\u2014"
8304
8653
  }
@@ -8313,25 +8662,25 @@ function SetRow({
8313
8662
  children: isActive && weight == null && targets ? /* @__PURE__ */ jsx(
8314
8663
  reactNative.Text,
8315
8664
  {
8665
+ className: "text-text-tertiary",
8316
8666
  style: {
8317
8667
  fontSize: 13,
8318
8668
  fontStyle: "italic",
8319
- fontFamily: "Inter, sans-serif",
8320
- color: "#6B7280"
8669
+ fontFamily: "Inter, sans-serif"
8321
8670
  },
8322
8671
  testID: "set-row-target-weight",
8323
- children: targets.weight
8672
+ children: roundWeight(targets.weight)
8324
8673
  }
8325
8674
  ) : /* @__PURE__ */ jsx(
8326
8675
  reactNative.Text,
8327
8676
  {
8677
+ className: weight != null ? "text-text-primary" : "text-text-tertiary",
8328
8678
  style: {
8329
8679
  fontSize: 14,
8330
8680
  fontWeight: "600",
8331
- fontFamily: "Inter, sans-serif",
8332
- color: weight != null ? "#F3F4F6" : "#6B7280"
8681
+ fontFamily: "Inter, sans-serif"
8333
8682
  },
8334
- children: weight != null ? weight : "\u2014"
8683
+ children: weight != null ? roundWeight(weight) : "\u2014"
8335
8684
  }
8336
8685
  )
8337
8686
  }
@@ -8344,13 +8693,16 @@ function SetRow({
8344
8693
  children: /* @__PURE__ */ jsx(
8345
8694
  reactNative.Text,
8346
8695
  {
8696
+ className: rpe != null ? void 0 : "text-text-tertiary",
8347
8697
  style: {
8348
8698
  fontSize: 13,
8349
8699
  fontWeight: "600",
8350
8700
  fontFamily: "Inter, sans-serif",
8351
- color: rpe != null ? getRPEColor(rpe) : "#6B7280"
8701
+ // rpeColor returns a concrete hex (native-safe); only the tertiary
8702
+ // fallback needs the className token.
8703
+ color: rpe != null ? rpeColor(rpe) : void 0
8352
8704
  },
8353
- children: rpe != null ? rpe : "\u2014"
8705
+ children: rpe != null ? roundRpe(rpe) : "\u2014"
8354
8706
  }
8355
8707
  )
8356
8708
  }
@@ -8394,18 +8746,14 @@ function SetRow({
8394
8746
  );
8395
8747
  }
8396
8748
  var BRAND_PRIMARY2 = "#FF7900";
8397
- var TEXT_PRIMARY = "#F3F4F6";
8398
- var TEXT_TERTIARY2 = "#6B7280";
8749
+ var INPUT_CLASSNAME = "bg-surface-raised border-border-strong text-text-primary";
8399
8750
  var inputStyle = {
8400
8751
  fontSize: 14,
8401
8752
  fontWeight: "600",
8402
8753
  fontFamily: "Inter, sans-serif",
8403
- backgroundColor: WORKOUT_TOKENS.surface.raised,
8404
8754
  borderWidth: 1,
8405
- borderColor: WORKOUT_TOKENS.border.strong,
8406
8755
  borderRadius: 6,
8407
8756
  textAlign: "center",
8408
- color: TEXT_PRIMARY,
8409
8757
  paddingVertical: 5,
8410
8758
  paddingHorizontal: 2
8411
8759
  };
@@ -8427,11 +8775,11 @@ function InputBar({
8427
8775
  return /* @__PURE__ */ jsxs(
8428
8776
  reactNative.View,
8429
8777
  {
8778
+ className: "bg-surface-elevated",
8430
8779
  style: {
8431
8780
  width: "100%",
8432
- backgroundColor: WORKOUT_TOKENS.surface.elevated,
8433
8781
  borderTopWidth: 1,
8434
- borderTopColor: WORKOUT_TOKENS.border.default,
8782
+ borderTopColor: resolveColor("border-default"),
8435
8783
  paddingTop: 10,
8436
8784
  paddingHorizontal: 16,
8437
8785
  paddingBottom: 12,
@@ -8446,11 +8794,11 @@ function InputBar({
8446
8794
  /* @__PURE__ */ jsx(
8447
8795
  reactNative.Text,
8448
8796
  {
8797
+ className: "text-text-primary",
8449
8798
  style: {
8450
8799
  fontSize: 12,
8451
8800
  fontWeight: "700",
8452
- fontFamily: '"Space Grotesk", sans-serif',
8453
- color: TEXT_PRIMARY
8801
+ fontFamily: '"Space Grotesk", sans-serif'
8454
8802
  },
8455
8803
  testID: "input-bar-exercise-name",
8456
8804
  numberOfLines: 1,
@@ -8460,10 +8808,10 @@ function InputBar({
8460
8808
  /* @__PURE__ */ jsx(
8461
8809
  reactNative.Text,
8462
8810
  {
8811
+ className: "text-text-tertiary",
8463
8812
  style: {
8464
8813
  fontSize: 10,
8465
- fontFamily: "Inter, sans-serif",
8466
- color: TEXT_TERTIARY2
8814
+ fontFamily: "Inter, sans-serif"
8467
8815
  },
8468
8816
  testID: "input-bar-set-info",
8469
8817
  children: setLabel
@@ -8476,6 +8824,7 @@ function InputBar({
8476
8824
  {
8477
8825
  value: reps,
8478
8826
  onChangeText: onRepsChange,
8827
+ className: INPUT_CLASSNAME,
8479
8828
  style: { ...inputStyle, width: 36 },
8480
8829
  accessibilityLabel: "Reps",
8481
8830
  testID: "input-bar-reps",
@@ -8485,10 +8834,10 @@ function InputBar({
8485
8834
  /* @__PURE__ */ jsx(
8486
8835
  reactNative.Text,
8487
8836
  {
8837
+ className: "text-text-tertiary",
8488
8838
  style: {
8489
8839
  fontSize: 12,
8490
- fontFamily: "Inter, sans-serif",
8491
- color: TEXT_TERTIARY2
8840
+ fontFamily: "Inter, sans-serif"
8492
8841
  },
8493
8842
  children: "\xD7"
8494
8843
  }
@@ -8498,6 +8847,7 @@ function InputBar({
8498
8847
  {
8499
8848
  value: weight,
8500
8849
  onChangeText: onWeightChange,
8850
+ className: INPUT_CLASSNAME,
8501
8851
  style: { ...inputStyle, width: 52 },
8502
8852
  accessibilityLabel: `Weight in ${unit}`,
8503
8853
  testID: "input-bar-weight",
@@ -8507,11 +8857,11 @@ function InputBar({
8507
8857
  /* @__PURE__ */ jsx(
8508
8858
  reactNative.Text,
8509
8859
  {
8860
+ className: "text-text-tertiary",
8510
8861
  style: {
8511
8862
  fontSize: 12,
8512
8863
  fontWeight: "500",
8513
- fontFamily: "Inter, sans-serif",
8514
- color: TEXT_TERTIARY2
8864
+ fontFamily: "Inter, sans-serif"
8515
8865
  },
8516
8866
  testID: "input-bar-unit",
8517
8867
  children: unit
@@ -8566,15 +8916,16 @@ function RestTimer({
8566
8916
  const minutes = Math.floor(remainingSec / 60);
8567
8917
  const seconds = remainingSec % 60;
8568
8918
  const timeDisplay = `${minutes}:${String(seconds).padStart(2, "0")}`;
8569
- const progressPct = Math.min(100, elapsedMs / (totalSeconds * 1e3) * 100);
8919
+ const totalMs = totalSeconds * 1e3;
8920
+ const progressPct = totalMs > 0 ? Math.min(100, elapsedMs / totalMs * 100) : 100;
8570
8921
  return /* @__PURE__ */ jsxs(
8571
8922
  reactNative.View,
8572
8923
  {
8924
+ className: "bg-surface-raised",
8573
8925
  style: {
8574
8926
  width: "100%",
8575
- backgroundColor: WORKOUT_TOKENS.surface.raised,
8576
8927
  borderTopWidth: 1,
8577
- borderTopColor: WORKOUT_TOKENS.border.default,
8928
+ borderTopColor: resolveColor("border-default"),
8578
8929
  paddingVertical: 12,
8579
8930
  paddingHorizontal: 16
8580
8931
  },
@@ -8596,13 +8947,13 @@ function RestTimer({
8596
8947
  /* @__PURE__ */ jsx(
8597
8948
  reactNative.Text,
8598
8949
  {
8950
+ className: "text-text-secondary",
8599
8951
  style: {
8600
8952
  fontSize: 11,
8601
8953
  fontFamily: "Inter, sans-serif",
8602
8954
  fontWeight: "600",
8603
8955
  textTransform: "uppercase",
8604
- letterSpacing: 1,
8605
- color: "#9CA3AF"
8956
+ letterSpacing: 1
8606
8957
  },
8607
8958
  testID: "rest-timer-label",
8608
8959
  children: "REST"
@@ -8611,10 +8962,10 @@ function RestTimer({
8611
8962
  nextSetInfo != null && /* @__PURE__ */ jsx(
8612
8963
  reactNative.Text,
8613
8964
  {
8965
+ className: "text-text-tertiary",
8614
8966
  style: {
8615
8967
  fontSize: 11,
8616
8968
  fontFamily: "Inter, sans-serif",
8617
- color: "#6B7280",
8618
8969
  marginTop: 2
8619
8970
  },
8620
8971
  testID: "rest-timer-next-set",
@@ -8625,11 +8976,11 @@ function RestTimer({
8625
8976
  /* @__PURE__ */ jsx(
8626
8977
  reactNative.Text,
8627
8978
  {
8979
+ className: "text-text-primary",
8628
8980
  style: {
8629
8981
  fontSize: 28,
8630
8982
  fontFamily: '"Space Grotesk", sans-serif',
8631
8983
  fontWeight: "700",
8632
- color: "#F3F4F6",
8633
8984
  fontVariant: ["tabular-nums"],
8634
8985
  letterSpacing: -0.5
8635
8986
  },
@@ -8643,9 +8994,9 @@ function RestTimer({
8643
8994
  /* @__PURE__ */ jsx(
8644
8995
  reactNative.View,
8645
8996
  {
8997
+ className: "bg-border",
8646
8998
  style: {
8647
8999
  height: 3,
8648
- backgroundColor: WORKOUT_TOKENS.border.default,
8649
9000
  borderRadius: 2,
8650
9001
  marginBottom: 12
8651
9002
  },
@@ -8681,11 +9032,11 @@ function RestTimer({
8681
9032
  children: /* @__PURE__ */ jsx(
8682
9033
  reactNative.Text,
8683
9034
  {
9035
+ className: "text-text-secondary",
8684
9036
  style: {
8685
9037
  fontSize: 11,
8686
9038
  fontFamily: "Inter, sans-serif",
8687
- fontWeight: "600",
8688
- color: "#9CA3AF"
9039
+ fontWeight: "600"
8689
9040
  },
8690
9041
  children: "+30s"
8691
9042
  }
@@ -8724,11 +9075,9 @@ function RestTimer({
8724
9075
  }
8725
9076
  );
8726
9077
  }
8727
- var COLORS = {
8728
- textPrimary: "#F3F4F6",
8729
- textSecondary: "#9CA3AF",
8730
- textTertiary: "#6B7280"};
8731
- var COLUMN_HEADERS = ["SET", "PREV", "REPS", "LBS", "RPE"];
9078
+ function buildColumnHeaders(unit) {
9079
+ return ["SET", "PREV", "REPS", unit.toUpperCase(), "RPE"];
9080
+ }
8732
9081
  function getSupersetBorderRadius(position) {
8733
9082
  switch (position) {
8734
9083
  case "first":
@@ -8769,7 +9118,7 @@ function getSupersetMargin(position) {
8769
9118
  }
8770
9119
  function formatSummary(summary) {
8771
9120
  if (!summary) return "";
8772
- return `${summary.sets}\xD7${summary.reps} @ ${summary.weight} ${summary.unit}`;
9121
+ return `${summary.sets}\xD7${summary.reps} @ ${roundWeight(summary.weight)} ${summary.unit}`;
8773
9122
  }
8774
9123
  function formatAccessibilityLabel2(name, summary, prescription) {
8775
9124
  if (summary) return `${name}, ${formatSummary(summary)}`;
@@ -8803,11 +9152,11 @@ function CollapsedCard({
8803
9152
  children: /* @__PURE__ */ jsxs(
8804
9153
  reactNative.View,
8805
9154
  {
9155
+ className: pressed ? "bg-surface-raised" : void 0,
8806
9156
  style: {
8807
9157
  padding: 12,
8808
9158
  paddingHorizontal: 14,
8809
9159
  cursor: "pointer",
8810
- backgroundColor: pressed ? WORKOUT_TOKENS.surface.raised : "transparent",
8811
9160
  ...borderRadius,
8812
9161
  ...supersetMargin
8813
9162
  },
@@ -8821,11 +9170,11 @@ function CollapsedCard({
8821
9170
  /* @__PURE__ */ jsx(
8822
9171
  reactNative.Text,
8823
9172
  {
9173
+ className: "text-text-primary",
8824
9174
  style: {
8825
9175
  fontSize: 14,
8826
9176
  fontFamily: '"Space Grotesk", sans-serif',
8827
- fontWeight: "700",
8828
- color: COLORS.textPrimary
9177
+ fontWeight: "700"
8829
9178
  },
8830
9179
  testID: "exercise-card-name",
8831
9180
  children: name
@@ -8835,10 +9184,10 @@ function CollapsedCard({
8835
9184
  summary && /* @__PURE__ */ jsx(
8836
9185
  reactNative.Text,
8837
9186
  {
9187
+ className: "text-text-secondary",
8838
9188
  style: {
8839
9189
  fontSize: 12,
8840
9190
  fontFamily: "Inter, sans-serif",
8841
- color: COLORS.textSecondary,
8842
9191
  marginRight: 8
8843
9192
  },
8844
9193
  testID: "exercise-card-summary",
@@ -8848,7 +9197,7 @@ function CollapsedCard({
8848
9197
  e1rm && /* @__PURE__ */ jsx(
8849
9198
  WeightBadge,
8850
9199
  {
8851
- value: e1rm.value,
9200
+ value: roundWeight(e1rm.value),
8852
9201
  unit: e1rm.unit,
8853
9202
  size: "sm",
8854
9203
  showIcon: false,
@@ -8903,13 +9252,14 @@ function ExpandedCard({
8903
9252
  }) {
8904
9253
  const borderRadius = getSupersetBorderRadius(supersetPosition);
8905
9254
  const supersetMargin = getSupersetMargin(supersetPosition);
9255
+ const unit = summary?.unit ?? sets?.[0]?.unit ?? "lbs";
9256
+ const columnHeaders = buildColumnHeaders(unit);
8906
9257
  return /* @__PURE__ */ jsxs(
8907
9258
  reactNative.View,
8908
9259
  {
9260
+ className: "bg-surface-elevated border-border",
8909
9261
  style: {
8910
- backgroundColor: WORKOUT_TOKENS.surface.elevated,
8911
9262
  borderWidth: 1,
8912
- borderColor: WORKOUT_TOKENS.border.default,
8913
9263
  ...borderRadius,
8914
9264
  ...supersetMargin
8915
9265
  },
@@ -8932,17 +9282,17 @@ function ExpandedCard({
8932
9282
  paddingHorizontal: 14,
8933
9283
  paddingBottom: 10,
8934
9284
  borderBottomWidth: 1,
8935
- borderBottomColor: WORKOUT_TOKENS.border.default
9285
+ borderBottomColor: resolveColor("border-default")
8936
9286
  },
8937
9287
  children: [
8938
9288
  /* @__PURE__ */ jsx(
8939
9289
  reactNative.Text,
8940
9290
  {
9291
+ className: "text-text-primary",
8941
9292
  style: {
8942
9293
  fontSize: 14,
8943
9294
  fontFamily: '"Space Grotesk", sans-serif',
8944
- fontWeight: "700",
8945
- color: COLORS.textPrimary
9295
+ fontWeight: "700"
8946
9296
  },
8947
9297
  testID: "exercise-card-name",
8948
9298
  children: name
@@ -8952,10 +9302,10 @@ function ExpandedCard({
8952
9302
  summary && /* @__PURE__ */ jsx(
8953
9303
  reactNative.Text,
8954
9304
  {
9305
+ className: "text-text-secondary",
8955
9306
  style: {
8956
9307
  fontSize: 12,
8957
9308
  fontFamily: "Inter, sans-serif",
8958
- color: COLORS.textSecondary,
8959
9309
  marginRight: 8
8960
9310
  },
8961
9311
  testID: "exercise-card-summary",
@@ -8965,7 +9315,7 @@ function ExpandedCard({
8965
9315
  e1rm && /* @__PURE__ */ jsx(
8966
9316
  WeightBadge,
8967
9317
  {
8968
- value: e1rm.value,
9318
+ value: roundWeight(e1rm.value),
8969
9319
  unit: e1rm.unit,
8970
9320
  size: "sm",
8971
9321
  showIcon: false,
@@ -8989,7 +9339,7 @@ function ExpandedCard({
8989
9339
  paddingBottom: 4
8990
9340
  },
8991
9341
  testID: "exercise-card-column-headers",
8992
- children: COLUMN_HEADERS.map((header, i) => {
9342
+ children: columnHeaders.map((header, i) => {
8993
9343
  const widths = [36, void 0, 44, 56, 36];
8994
9344
  const width = widths[i];
8995
9345
  const isFlex = width === void 0;
@@ -9006,13 +9356,13 @@ function ExpandedCard({
9006
9356
  children: /* @__PURE__ */ jsx(
9007
9357
  reactNative.Text,
9008
9358
  {
9359
+ className: "text-text-tertiary",
9009
9360
  style: {
9010
9361
  fontSize: 10,
9011
9362
  fontWeight: "600",
9012
9363
  fontFamily: "Inter, sans-serif",
9013
9364
  textTransform: "uppercase",
9014
- letterSpacing: 0.8,
9015
- color: COLORS.textTertiary
9365
+ letterSpacing: 0.8
9016
9366
  },
9017
9367
  children: header
9018
9368
  }
@@ -9052,11 +9402,11 @@ function UpcomingCard({
9052
9402
  /* @__PURE__ */ jsx(
9053
9403
  reactNative.Text,
9054
9404
  {
9405
+ className: "text-text-primary",
9055
9406
  style: {
9056
9407
  fontSize: 14,
9057
9408
  fontFamily: '"Space Grotesk", sans-serif',
9058
- fontWeight: "700",
9059
- color: COLORS.textPrimary
9409
+ fontWeight: "700"
9060
9410
  },
9061
9411
  testID: "exercise-card-name",
9062
9412
  children: name
@@ -9065,10 +9415,10 @@ function UpcomingCard({
9065
9415
  prescription && /* @__PURE__ */ jsx(
9066
9416
  reactNative.Text,
9067
9417
  {
9418
+ className: "text-text-secondary",
9068
9419
  style: {
9069
9420
  fontSize: 12,
9070
9421
  fontFamily: "Inter, sans-serif",
9071
- color: COLORS.textSecondary,
9072
9422
  marginLeft: 8
9073
9423
  },
9074
9424
  testID: "exercise-card-prescription",
@@ -9079,10 +9429,10 @@ function UpcomingCard({
9079
9429
  previousBest && /* @__PURE__ */ jsx(
9080
9430
  reactNative.Text,
9081
9431
  {
9432
+ className: "text-text-tertiary",
9082
9433
  style: {
9083
9434
  fontSize: 11,
9084
- fontFamily: "Inter, sans-serif",
9085
- color: COLORS.textTertiary
9435
+ fontFamily: "Inter, sans-serif"
9086
9436
  },
9087
9437
  testID: "exercise-card-previous-best",
9088
9438
  children: previousBest
@@ -9183,10 +9533,11 @@ function MesoSegment({ meso, isActive, onPress }) {
9183
9533
  }).start();
9184
9534
  };
9185
9535
  const progress = meso.status === "current" ? clampProgress(meso.currentWeek, meso.weekCount) : 0;
9536
+ const segmentFlex = Math.max(1, meso.weekCount);
9186
9537
  return /* @__PURE__ */ jsx(
9187
9538
  reactNative.Pressable,
9188
9539
  {
9189
- style: { flex: meso.weekCount },
9540
+ style: { flex: segmentFlex },
9190
9541
  onPress: () => onPress(meso.id),
9191
9542
  onPressIn: handlePressIn,
9192
9543
  onPressOut: handlePressOut,
@@ -9319,11 +9670,12 @@ function WeekRow({
9319
9670
  /* @__PURE__ */ jsx(
9320
9671
  reactNative.Text,
9321
9672
  {
9673
+ className: isCurrent ? void 0 : "text-text-primary",
9322
9674
  style: {
9323
9675
  fontSize: 13,
9324
9676
  fontWeight: "700",
9325
9677
  fontFamily: "Inter, sans-serif",
9326
- color: isCurrent ? BRAND_PRIMARY5 : "#F3F4F6"
9678
+ color: isCurrent ? BRAND_PRIMARY5 : void 0
9327
9679
  },
9328
9680
  accessibilityElementsHidden: true,
9329
9681
  children: `W${weekNumber}`
@@ -9362,19 +9714,16 @@ function WeekRow({
9362
9714
  }
9363
9715
  );
9364
9716
  }
9365
- var COLORS2 = {
9366
- textPrimary: "#F3F4F6",
9367
- textSecondary: "#9CA3AF",
9368
- textTertiary: "#6B7280",
9717
+ var COLORS = {
9369
9718
  statusSuccess: "#14B8A6",
9370
9719
  brandPrimary: "#FF7900",
9371
9720
  borderDefault: "#1F1F1F",
9372
9721
  brandPrimarySubtle: "rgba(255,121,0,0.06)"
9373
9722
  };
9374
9723
  var statusBorderColors = {
9375
- completed: COLORS2.statusSuccess,
9376
- today: COLORS2.brandPrimary,
9377
- upcoming: COLORS2.borderDefault
9724
+ completed: COLORS.statusSuccess,
9725
+ today: COLORS.brandPrimary,
9726
+ upcoming: COLORS.borderDefault
9378
9727
  };
9379
9728
  var volumeStatusMap = {
9380
9729
  under: "behind",
@@ -9411,11 +9760,11 @@ function WorkoutCard({
9411
9760
  /* @__PURE__ */ jsx(
9412
9761
  reactNative.Text,
9413
9762
  {
9763
+ className: "text-text-primary",
9414
9764
  style: {
9415
9765
  fontSize: 15,
9416
9766
  fontFamily: '"Space Grotesk", sans-serif',
9417
- fontWeight: "700",
9418
- color: COLORS2.textPrimary
9767
+ fontWeight: "700"
9419
9768
  },
9420
9769
  testID: "workout-card-name",
9421
9770
  children: name
@@ -9425,10 +9774,10 @@ function WorkoutCard({
9425
9774
  /* @__PURE__ */ jsx(
9426
9775
  reactNative.Text,
9427
9776
  {
9777
+ className: "text-text-tertiary",
9428
9778
  style: {
9429
9779
  fontSize: 11,
9430
- fontFamily: "Inter, sans-serif",
9431
- color: COLORS2.textTertiary
9780
+ fontFamily: "Inter, sans-serif"
9432
9781
  },
9433
9782
  testID: "workout-card-date",
9434
9783
  children: date
@@ -9438,11 +9787,11 @@ function WorkoutCard({
9438
9787
  /* @__PURE__ */ jsx(
9439
9788
  reactNative.Text,
9440
9789
  {
9790
+ className: "text-text-secondary",
9441
9791
  style: {
9442
9792
  marginTop: 4,
9443
9793
  fontSize: 12,
9444
- fontFamily: "Inter, sans-serif",
9445
- color: COLORS2.textSecondary
9794
+ fontFamily: "Inter, sans-serif"
9446
9795
  },
9447
9796
  testID: "workout-card-stats",
9448
9797
  children: formatStats(totalSets, totalVolume, unit, duration)
@@ -9473,7 +9822,7 @@ function WorkoutCard({
9473
9822
  variant: "accent",
9474
9823
  elevation: 1,
9475
9824
  accentColor: statusBorderColors[status],
9476
- bgColor: isToday ? COLORS2.brandPrimarySubtle : void 0,
9825
+ bgColor: isToday ? COLORS.brandPrimarySubtle : void 0,
9477
9826
  className,
9478
9827
  style: isUpcoming ? { opacity: 0.6 } : void 0,
9479
9828
  testID: "workout-card",
@@ -9513,8 +9862,6 @@ var BRAND_PRIMARY6 = "#FF7900";
9513
9862
  var BRAND_PRIMARY_DARK = "#C45E00";
9514
9863
  var BRAND_PRIMARY_LIGHT = "#FFB066";
9515
9864
  var BORDER_DEFAULT = "#1F1F1F";
9516
- var TEXT_PRIMARY2 = "#F3F4F6";
9517
- var TEXT_SECONDARY = "#9CA3AF";
9518
9865
  var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY6, BRAND_PRIMARY_LIGHT];
9519
9866
  function heatmapColor(percentage) {
9520
9867
  const clamped = Math.max(0, Math.min(100, percentage));
@@ -9557,11 +9904,11 @@ function MesoCard({
9557
9904
  /* @__PURE__ */ jsx(
9558
9905
  reactNative.Text,
9559
9906
  {
9907
+ className: "text-text-primary",
9560
9908
  style: {
9561
9909
  fontSize: 15,
9562
9910
  fontFamily: '"Space Grotesk", sans-serif',
9563
- fontWeight: "700",
9564
- color: TEXT_PRIMARY2
9911
+ fontWeight: "700"
9565
9912
  },
9566
9913
  testID: "meso-card-name",
9567
9914
  children: name
@@ -9572,11 +9919,11 @@ function MesoCard({
9572
9919
  /* @__PURE__ */ jsx(
9573
9920
  reactNative.Text,
9574
9921
  {
9922
+ className: "text-text-secondary",
9575
9923
  style: {
9576
9924
  marginTop: 4,
9577
9925
  fontSize: 12,
9578
- fontFamily: "Inter, sans-serif",
9579
- color: TEXT_SECONDARY
9926
+ fontFamily: "Inter, sans-serif"
9580
9927
  },
9581
9928
  testID: "meso-card-subheader",
9582
9929
  children: `${split} \xB7 ${weekRange}`
@@ -9670,11 +10017,7 @@ function MesoCard({
9670
10017
  var BRAND_PRIMARY7 = "#FF7900";
9671
10018
  var RECENT_BORDER = "rgba(255,176,32,0.3)";
9672
10019
  var RECENT_GLOW = "0 0 12px rgba(255,176,32,0.06)";
9673
- var SURFACE_RAISED = "#1C1C1C";
9674
- var BORDER_DEFAULT2 = "#1F1F1F";
9675
- var TEXT_PRIMARY3 = "#F3F4F6";
9676
- var TEXT_SECONDARY2 = "#9CA3AF";
9677
- var TEXT_TERTIARY3 = "#6B7280";
10020
+ var BORDER_DEFAULT2 = resolveColor("border-default");
9678
10021
  var TYPE_LABELS = {
9679
10022
  e1rm: "e1RM",
9680
10023
  weight: "Weight",
@@ -9700,14 +10043,13 @@ function PrRecordRow({ record, index }) {
9700
10043
  {
9701
10044
  accessibilityRole: "text",
9702
10045
  accessibilityLabel: a11yLabel,
9703
- className: "flex-row items-center",
10046
+ className: "flex-row items-center bg-surface-raised",
9704
10047
  style: {
9705
10048
  gap: 10,
9706
10049
  paddingVertical: 10,
9707
10050
  paddingHorizontal: 12,
9708
10051
  marginBottom: 8,
9709
10052
  borderRadius: 8,
9710
- backgroundColor: SURFACE_RAISED,
9711
10053
  borderWidth: 1,
9712
10054
  borderColor: record.isRecent ? RECENT_BORDER : BORDER_DEFAULT2,
9713
10055
  ...record.isRecent ? { boxShadow: RECENT_GLOW } : {}
@@ -9718,12 +10060,12 @@ function PrRecordRow({ record, index }) {
9718
10060
  /* @__PURE__ */ jsx(
9719
10061
  reactNative.Text,
9720
10062
  {
10063
+ className: "text-text-secondary",
9721
10064
  style: {
9722
10065
  flex: 1,
9723
10066
  fontSize: 13,
9724
10067
  fontFamily: "Inter, sans-serif",
9725
- fontWeight: "600",
9726
- color: TEXT_SECONDARY2
10068
+ fontWeight: "600"
9727
10069
  },
9728
10070
  testID: `pr-history-modal-record-${index}-type`,
9729
10071
  children: label
@@ -9732,11 +10074,11 @@ function PrRecordRow({ record, index }) {
9732
10074
  /* @__PURE__ */ jsx(
9733
10075
  reactNative.Text,
9734
10076
  {
10077
+ className: "text-text-primary",
9735
10078
  style: {
9736
10079
  fontSize: 14,
9737
10080
  fontFamily: '"Space Grotesk", sans-serif',
9738
- fontWeight: "700",
9739
- color: TEXT_PRIMARY3
10081
+ fontWeight: "700"
9740
10082
  },
9741
10083
  testID: `pr-history-modal-record-${index}-value`,
9742
10084
  children: valueText
@@ -9745,12 +10087,12 @@ function PrRecordRow({ record, index }) {
9745
10087
  /* @__PURE__ */ jsx(
9746
10088
  reactNative.Text,
9747
10089
  {
10090
+ className: "text-text-tertiary",
9748
10091
  style: {
9749
10092
  minWidth: 64,
9750
10093
  textAlign: "right",
9751
10094
  fontSize: 11,
9752
- fontFamily: "Inter, sans-serif",
9753
- color: TEXT_TERTIARY3
10095
+ fontFamily: "Inter, sans-serif"
9754
10096
  },
9755
10097
  testID: `pr-history-modal-record-${index}-date`,
9756
10098
  children: record.date
@@ -9788,13 +10130,13 @@ function PrHistoryModal({
9788
10130
  reactNative.View,
9789
10131
  {
9790
10132
  accessibilityElementsHidden: true,
10133
+ className: "bg-border",
9791
10134
  style: {
9792
10135
  alignSelf: "center",
9793
10136
  width: 40,
9794
10137
  height: 4,
9795
10138
  borderRadius: 2,
9796
- marginTop: 8,
9797
- backgroundColor: BORDER_DEFAULT2
10139
+ marginTop: 8
9798
10140
  },
9799
10141
  testID: "pr-history-modal-handle"
9800
10142
  }
@@ -9810,11 +10152,11 @@ function PrHistoryModal({
9810
10152
  reactNative.Text,
9811
10153
  {
9812
10154
  accessibilityRole: "header",
10155
+ className: "text-text-primary",
9813
10156
  style: {
9814
10157
  fontSize: 16,
9815
10158
  fontFamily: '"Space Grotesk", sans-serif',
9816
- fontWeight: "700",
9817
- color: TEXT_PRIMARY3
10159
+ fontWeight: "700"
9818
10160
  },
9819
10161
  testID: "pr-history-modal-title",
9820
10162
  children: dialogLabel
@@ -9829,7 +10171,7 @@ function PrHistoryModal({
9829
10171
  hitSlop: 8,
9830
10172
  style: { padding: 4, margin: -4 },
9831
10173
  testID: "pr-history-modal-close",
9832
- children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 22, lineHeight: 22, color: TEXT_SECONDARY2 }, children: "\xD7" })
10174
+ children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 22, lineHeight: 22 }, children: "\xD7" })
9833
10175
  }
9834
10176
  )
9835
10177
  ]
@@ -9838,11 +10180,11 @@ function PrHistoryModal({
9838
10180
  /* @__PURE__ */ jsx(DrawerBody, { className: "px-4 pt-0 pb-4", children: records.length === 0 ? /* @__PURE__ */ jsx(reactNative.View, { style: { paddingVertical: 24 }, testID: "pr-history-modal-empty", children: /* @__PURE__ */ jsx(
9839
10181
  reactNative.Text,
9840
10182
  {
10183
+ className: "text-text-tertiary",
9841
10184
  style: {
9842
10185
  textAlign: "center",
9843
10186
  fontSize: 13,
9844
- fontFamily: "Inter, sans-serif",
9845
- color: TEXT_TERTIARY3
10187
+ fontFamily: "Inter, sans-serif"
9846
10188
  },
9847
10189
  children: "No personal records yet"
9848
10190
  }
@@ -9863,8 +10205,6 @@ var BRAND_PRIMARY_SUBTLE = "rgba(255,121,0,0.12)";
9863
10205
  var STATUS_SUCCESS = "#14B8A6";
9864
10206
  var STATUS_WARNING = "#FFB020";
9865
10207
  var STATUS_ERROR = "#D14343";
9866
- var TEXT_PRIMARY4 = "#F3F4F6";
9867
- var TEXT_SECONDARY3 = "#9CA3AF";
9868
10208
  var EMOJI_SETS = {
9869
10209
  sleep: ["\u{1F634}", "\u{1F610}", "\u{1F642}", "\u{1F60A}", "\u{1F929}"],
9870
10210
  soreness: ["\u{1F635}", "\u{1F623}", "\u{1F610}", "\u{1F642}", "\u{1F4AA}"],
@@ -9896,7 +10236,8 @@ function EmojiSlider({ factor }) {
9896
10236
  /* @__PURE__ */ jsx(
9897
10237
  reactNative.Text,
9898
10238
  {
9899
- style: { fontSize: 12, fontWeight: "500", fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY3 },
10239
+ className: "text-text-secondary",
10240
+ style: { fontSize: 12, fontWeight: "500", fontFamily: "Inter, sans-serif" },
9900
10241
  testID: "readiness-check-factor-label",
9901
10242
  children: factor.label
9902
10243
  }
@@ -9920,14 +10261,15 @@ function EmojiSlider({ factor }) {
9920
10261
  accessibilityLabel: `${factor.label} level ${level} of 5`,
9921
10262
  "aria-checked": selected,
9922
10263
  testID: "readiness-check-emoji",
10264
+ className: selected ? void 0 : "border-border bg-surface-raised",
9923
10265
  style: ({ pressed }) => ({
9924
10266
  flex: 1,
9925
10267
  alignItems: "center",
9926
10268
  paddingVertical: 8,
9927
10269
  borderRadius: 8,
9928
10270
  borderWidth: 1,
9929
- borderColor: selected ? BRAND_PRIMARY8 : WORKOUT_TOKENS.border.default,
9930
- backgroundColor: selected ? BRAND_PRIMARY_SUBTLE : WORKOUT_TOKENS.surface.raised,
10271
+ borderColor: selected ? BRAND_PRIMARY8 : void 0,
10272
+ backgroundColor: selected ? BRAND_PRIMARY_SUBTLE : void 0,
9931
10273
  opacity: selected ? 1 : pressed ? 0.8 : 0.55,
9932
10274
  transform: [{ scale: selected ? 1.06 : 1 }]
9933
10275
  }),
@@ -9948,13 +10290,13 @@ function ScoreGauge({ score }) {
9948
10290
  accessibilityRole: "image",
9949
10291
  accessibilityLabel: `Readiness score: ${score} out of 100`,
9950
10292
  testID: "readiness-check-score",
10293
+ className: "bg-surface-raised",
9951
10294
  style: {
9952
10295
  width: 60,
9953
10296
  height: 60,
9954
10297
  borderRadius: 30,
9955
10298
  borderWidth: 4,
9956
10299
  borderColor: color,
9957
- backgroundColor: WORKOUT_TOKENS.surface.raised,
9958
10300
  alignItems: "center",
9959
10301
  justifyContent: "center"
9960
10302
  },
@@ -9974,13 +10316,12 @@ function WarmUpCard({ validation }) {
9974
10316
  return /* @__PURE__ */ jsxs(
9975
10317
  reactNative.View,
9976
10318
  {
10319
+ className: "border-border bg-surface-raised",
9977
10320
  style: {
9978
10321
  marginTop: 16,
9979
10322
  padding: 12,
9980
10323
  borderRadius: 8,
9981
- borderWidth: 1,
9982
- borderColor: WORKOUT_TOKENS.border.default,
9983
- backgroundColor: WORKOUT_TOKENS.surface.raised
10324
+ borderWidth: 1
9984
10325
  },
9985
10326
  testID: "readiness-check-warmup",
9986
10327
  children: [
@@ -9988,7 +10329,8 @@ function WarmUpCard({ validation }) {
9988
10329
  /* @__PURE__ */ jsx(
9989
10330
  reactNative.Text,
9990
10331
  {
9991
- style: { fontSize: 12, fontWeight: "600", fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY3 },
10332
+ className: "text-text-secondary",
10333
+ style: { fontSize: 12, fontWeight: "600", fontFamily: "Inter, sans-serif" },
9992
10334
  testID: "readiness-check-warmup-deficit",
9993
10335
  children: velocityDeficitText(validation.velocityDeficit)
9994
10336
  }
@@ -9998,7 +10340,8 @@ function WarmUpCard({ validation }) {
9998
10340
  /* @__PURE__ */ jsx(
9999
10341
  reactNative.Text,
10000
10342
  {
10001
- style: { marginTop: 6, fontSize: 13, fontFamily: "Inter, sans-serif", color: TEXT_PRIMARY4 },
10343
+ className: "text-text-primary",
10344
+ style: { marginTop: 6, fontSize: 13, fontFamily: "Inter, sans-serif" },
10002
10345
  testID: "readiness-check-warmup-recommendation",
10003
10346
  children: validation.recommendation
10004
10347
  }
@@ -10020,7 +10363,8 @@ function ReadinessCheck({
10020
10363
  /* @__PURE__ */ jsx(
10021
10364
  reactNative.Text,
10022
10365
  {
10023
- style: { fontSize: 18, fontWeight: "700", fontFamily: '"Space Grotesk", sans-serif', color: TEXT_PRIMARY4 },
10366
+ className: "text-text-primary",
10367
+ style: { fontSize: 18, fontWeight: "700", fontFamily: '"Space Grotesk", sans-serif' },
10024
10368
  testID: "readiness-check-title",
10025
10369
  children: "How are you feeling?"
10026
10370
  }
@@ -10053,14 +10397,11 @@ function ReadinessCheck({
10053
10397
  var BRAND_PRIMARY9 = "#FF7900";
10054
10398
  var BRAND_PRIMARY_DARK2 = "#C45E00";
10055
10399
  var BRAND_PRIMARY_LIGHT2 = "#FFB066";
10056
- var TEXT_PRIMARY5 = "#F3F4F6";
10057
- var TEXT_SECONDARY4 = "#9CA3AF";
10058
- var TEXT_TERTIARY4 = "#6B7280";
10059
10400
  var SUCCESS = "#14B8A6";
10060
10401
  var WARNING = "#FFB020";
10061
10402
  var ERROR = "#D14343";
10062
10403
  var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2, BRAND_PRIMARY9, BRAND_PRIMARY_LIGHT2];
10063
- var CARD_GRADIENT = "linear-gradient(135deg, #191919 0%, rgba(25,25,25,0.95) 100%)";
10404
+ var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
10064
10405
  var GAUGE_GRADIENT = "linear-gradient(90deg, rgba(20,184,166,0.25) 0%, rgba(255,176,32,0.25) 50%, rgba(209,67,67,0.25) 100%)";
10065
10406
  var STATUS_VARIANTS = {
10066
10407
  success: { bg: "rgba(20,184,166,0.15)", border: "rgba(20,184,166,0.3)", text: SUCCESS },
@@ -10087,7 +10428,8 @@ function renderCoachingText(text, highlights) {
10087
10428
  (part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(
10088
10429
  reactNative.Text,
10089
10430
  {
10090
- style: { fontWeight: "700", color: TEXT_PRIMARY5 },
10431
+ className: "text-text-primary",
10432
+ style: { fontWeight: "700" },
10091
10433
  children: part
10092
10434
  },
10093
10435
  `${part}-${index}`
@@ -10134,13 +10476,13 @@ function MetricCell({ metric }) {
10134
10476
  /* @__PURE__ */ jsx(
10135
10477
  reactNative.Text,
10136
10478
  {
10479
+ className: "text-text-tertiary",
10137
10480
  style: {
10138
10481
  fontSize: 10,
10139
10482
  fontFamily: "Inter, sans-serif",
10140
10483
  fontWeight: "600",
10141
10484
  letterSpacing: 0.5,
10142
- textTransform: "uppercase",
10143
- color: TEXT_TERTIARY4
10485
+ textTransform: "uppercase"
10144
10486
  },
10145
10487
  children: metric.label
10146
10488
  }
@@ -10148,12 +10490,12 @@ function MetricCell({ metric }) {
10148
10490
  /* @__PURE__ */ jsx(
10149
10491
  reactNative.Text,
10150
10492
  {
10493
+ className: "text-text-primary",
10151
10494
  style: {
10152
10495
  marginTop: 2,
10153
10496
  fontSize: 13,
10154
10497
  fontFamily: "Inter, sans-serif",
10155
- fontWeight: "600",
10156
- color: TEXT_PRIMARY5
10498
+ fontWeight: "600"
10157
10499
  },
10158
10500
  children: metric.value
10159
10501
  }
@@ -10185,13 +10527,13 @@ function Gauge({ gauge }) {
10185
10527
  /* @__PURE__ */ jsx(
10186
10528
  reactNative.Text,
10187
10529
  {
10530
+ className: "text-text-secondary",
10188
10531
  style: {
10189
10532
  fontSize: 10,
10190
10533
  fontFamily: "Inter, sans-serif",
10191
10534
  fontWeight: "500",
10192
10535
  letterSpacing: 0.5,
10193
- textTransform: "uppercase",
10194
- color: TEXT_SECONDARY4
10536
+ textTransform: "uppercase"
10195
10537
  },
10196
10538
  children: gauge.label
10197
10539
  }
@@ -10199,11 +10541,11 @@ function Gauge({ gauge }) {
10199
10541
  gauge.sublabel != null && /* @__PURE__ */ jsx(
10200
10542
  reactNative.Text,
10201
10543
  {
10544
+ className: "text-text-tertiary",
10202
10545
  style: {
10203
10546
  fontSize: 10,
10204
10547
  fontFamily: "Inter, sans-serif",
10205
- fontWeight: "500",
10206
- color: TEXT_TERTIARY4
10548
+ fontWeight: "500"
10207
10549
  },
10208
10550
  children: gauge.sublabel
10209
10551
  }
@@ -10240,6 +10582,7 @@ function Gauge({ gauge }) {
10240
10582
  /* @__PURE__ */ jsx(
10241
10583
  reactNative.View,
10242
10584
  {
10585
+ className: "border-text-primary",
10243
10586
  style: {
10244
10587
  position: "absolute",
10245
10588
  left: `${percentage}%`,
@@ -10249,7 +10592,6 @@ function Gauge({ gauge }) {
10249
10592
  height: 14,
10250
10593
  borderRadius: 9999,
10251
10594
  borderWidth: 2,
10252
- borderColor: TEXT_PRIMARY5,
10253
10595
  backgroundColor: markerColor,
10254
10596
  boxShadow: "0 0 4px rgba(0,0,0,0.5)"
10255
10597
  },
@@ -10312,12 +10654,12 @@ function MesoStatusCard({
10312
10654
  /* @__PURE__ */ jsx(
10313
10655
  reactNative.Text,
10314
10656
  {
10657
+ className: "text-text-primary",
10315
10658
  style: {
10316
10659
  flexShrink: 1,
10317
10660
  fontSize: 15,
10318
10661
  fontFamily: '"Space Grotesk", sans-serif',
10319
- fontWeight: "700",
10320
- color: TEXT_PRIMARY5
10662
+ fontWeight: "700"
10321
10663
  },
10322
10664
  testID: "meso-status-card-name",
10323
10665
  children: mesoName
@@ -10330,11 +10672,11 @@ function MesoStatusCard({
10330
10672
  /* @__PURE__ */ jsx(
10331
10673
  reactNative.Text,
10332
10674
  {
10675
+ className: "text-text-secondary",
10333
10676
  style: {
10334
10677
  marginTop: 4,
10335
10678
  fontSize: 12,
10336
- fontFamily: "Inter, sans-serif",
10337
- color: TEXT_SECONDARY4
10679
+ fontFamily: "Inter, sans-serif"
10338
10680
  },
10339
10681
  testID: "meso-status-card-subtitle",
10340
10682
  children: mesoSubtitle
@@ -10366,11 +10708,11 @@ function MesoStatusCard({
10366
10708
  children: /* @__PURE__ */ jsx(
10367
10709
  reactNative.Text,
10368
10710
  {
10711
+ className: "text-text-secondary",
10369
10712
  style: {
10370
10713
  fontSize: 12,
10371
10714
  lineHeight: 17,
10372
- fontFamily: "Inter, sans-serif",
10373
- color: TEXT_SECONDARY4
10715
+ fontFamily: "Inter, sans-serif"
10374
10716
  },
10375
10717
  children: renderCoachingText(coaching.text, coaching.highlights)
10376
10718
  }
@@ -10415,15 +10757,11 @@ function MesoStatusCard({
10415
10757
  );
10416
10758
  }
10417
10759
  var BRAND_PRIMARY10 = "#FF7900";
10418
- var TEXT_PRIMARY6 = "#F3F4F6";
10419
- var TEXT_SECONDARY5 = "#9CA3AF";
10420
- var TEXT_TERTIARY5 = "#6B7280";
10421
- var BORDER_STRONG = "#2C2C2C";
10760
+ var PROJECTION_LINE_COLOR = resolveColor("text-tertiary");
10422
10761
  var STATUS_SUCCESS2 = "#14B8A6";
10423
10762
  var STATUS_ERROR2 = "#D14343";
10424
10763
  var STATUS_WARNING2 = "#FFB020";
10425
10764
  var GRID_LINE = "rgba(255,255,255,0.06)";
10426
- var TOOLTIP_BG = "rgba(28,28,28,0.95)";
10427
10765
  var SUCCESS_PILL_BG = "rgba(20,184,166,0.10)";
10428
10766
  var SUCCESS_PILL_BORDER = "rgba(20,184,166,0.20)";
10429
10767
  var ERROR_PILL_BG = "rgba(209,67,67,0.10)";
@@ -10431,8 +10769,8 @@ var ERROR_PILL_BORDER = "rgba(209,67,67,0.20)";
10431
10769
  var PLOT_LEFT = 26;
10432
10770
  var TOOLTIP_WIDTH = 124;
10433
10771
  function timeOf(dateStr) {
10434
- const t = Date.parse(dateStr);
10435
- return Number.isNaN(t) ? 0 : t;
10772
+ const t2 = Date.parse(dateStr);
10773
+ return Number.isNaN(t2) ? 0 : t2;
10436
10774
  }
10437
10775
  function formatValue(value) {
10438
10776
  return `${Math.round(value)}`;
@@ -10604,7 +10942,7 @@ function StrengthTrendChart({
10604
10942
  alignItems: "center",
10605
10943
  justifyContent: "center"
10606
10944
  },
10607
- children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_TERTIARY5 }, children: "No strength data yet" })
10945
+ children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-tertiary", style: { fontSize: 12, fontFamily: "Inter, sans-serif" }, children: "No strength data yet" })
10608
10946
  }
10609
10947
  )
10610
10948
  }
@@ -10648,6 +10986,7 @@ function StrengthTrendChart({
10648
10986
  children: /* @__PURE__ */ jsx(
10649
10987
  reactNative.Text,
10650
10988
  {
10989
+ className: "text-text-tertiary",
10651
10990
  style: {
10652
10991
  position: "absolute",
10653
10992
  left: -PLOT_LEFT,
@@ -10655,8 +10994,7 @@ function StrengthTrendChart({
10655
10994
  width: PLOT_LEFT - 4,
10656
10995
  textAlign: "right",
10657
10996
  fontSize: 9,
10658
- fontFamily: "Inter, sans-serif",
10659
- color: TEXT_TERTIARY5
10997
+ fontFamily: "Inter, sans-serif"
10660
10998
  },
10661
10999
  children: line.label
10662
11000
  }
@@ -10699,7 +11037,7 @@ function StrengthTrendChart({
10699
11037
  ChartLine,
10700
11038
  {
10701
11039
  coords: geometry.projection,
10702
- color: TEXT_TERTIARY5,
11040
+ color: PROJECTION_LINE_COLOR,
10703
11041
  strokeWidth: 2,
10704
11042
  dashed: true,
10705
11043
  testID: "strength-trend-chart-projection-segment"
@@ -10775,6 +11113,7 @@ function StrengthTrendChart({
10775
11113
  {
10776
11114
  testID: "strength-trend-chart-tooltip",
10777
11115
  accessibilityElementsHidden: true,
11116
+ className: "bg-surface-elevated border-border-strong",
10778
11117
  style: {
10779
11118
  position: "absolute",
10780
11119
  left: Math.max(
@@ -10783,9 +11122,7 @@ function StrengthTrendChart({
10783
11122
  ),
10784
11123
  top: Math.max(0, selectedCoord.y - 52),
10785
11124
  maxWidth: TOOLTIP_WIDTH,
10786
- backgroundColor: TOOLTIP_BG,
10787
11125
  borderWidth: 1,
10788
- borderColor: BORDER_STRONG,
10789
11126
  borderRadius: 8,
10790
11127
  paddingVertical: 8,
10791
11128
  paddingHorizontal: 10
@@ -10794,10 +11131,10 @@ function StrengthTrendChart({
10794
11131
  /* @__PURE__ */ jsx(
10795
11132
  reactNative.Text,
10796
11133
  {
11134
+ className: "text-text-tertiary",
10797
11135
  style: {
10798
11136
  fontSize: 10,
10799
- fontFamily: "Inter, sans-serif",
10800
- color: TEXT_TERTIARY5
11137
+ fontFamily: "Inter, sans-serif"
10801
11138
  },
10802
11139
  children: selectedCoord.point.sessionLabel ?? selectedCoord.point.date
10803
11140
  }
@@ -10805,12 +11142,12 @@ function StrengthTrendChart({
10805
11142
  /* @__PURE__ */ jsx(
10806
11143
  reactNative.Text,
10807
11144
  {
11145
+ className: "text-text-primary",
10808
11146
  style: {
10809
11147
  marginTop: 2,
10810
11148
  fontSize: 13,
10811
11149
  fontFamily: "Inter, sans-serif",
10812
- fontWeight: "700",
10813
- color: TEXT_PRIMARY6
11150
+ fontWeight: "700"
10814
11151
  },
10815
11152
  children: `${formatValue(selectedCoord.point.e1rm)} ${unit}`
10816
11153
  }
@@ -10843,14 +11180,14 @@ function StrengthTrendChart({
10843
11180
  reactNative.Text,
10844
11181
  {
10845
11182
  testID: "strength-trend-chart-axis-label",
11183
+ className: "text-text-tertiary",
10846
11184
  style: {
10847
11185
  position: "absolute",
10848
11186
  left: boundary.x - 24,
10849
11187
  width: 48,
10850
11188
  textAlign: "center",
10851
11189
  fontSize: 10,
10852
- fontFamily: "Inter, sans-serif",
10853
- color: TEXT_TERTIARY5
11190
+ fontFamily: "Inter, sans-serif"
10854
11191
  },
10855
11192
  children: boundary.label
10856
11193
  },
@@ -10894,7 +11231,7 @@ function StrengthTrendChart({
10894
11231
  children: [
10895
11232
  /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
10896
11233
  /* @__PURE__ */ jsx(reactNative.View, { style: { width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY10 } }),
10897
- /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY5 }, children: "Actual" })
11234
+ /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Actual" })
10898
11235
  ] }),
10899
11236
  /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
10900
11237
  /* @__PURE__ */ jsx(
@@ -10905,15 +11242,15 @@ function StrengthTrendChart({
10905
11242
  height: 0,
10906
11243
  borderTopWidth: 2,
10907
11244
  borderStyle: "dashed",
10908
- borderTopColor: TEXT_TERTIARY5
11245
+ borderTopColor: PROJECTION_LINE_COLOR
10909
11246
  }
10910
11247
  }
10911
11248
  ),
10912
- /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY5 }, children: "Projected" })
11249
+ /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Projected" })
10913
11250
  ] }),
10914
11251
  /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
10915
11252
  /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, color: STATUS_WARNING2 }, children: "\u2605" }),
10916
- /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY5 }, children: "PR" })
11253
+ /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "PR" })
10917
11254
  ] })
10918
11255
  ]
10919
11256
  }
@@ -10926,7 +11263,6 @@ var STATUS_SUCCESS3 = "#14B8A6";
10926
11263
  var STATUS_WARNING3 = "#FFB020";
10927
11264
  var STATUS_INFO = "#2196F3";
10928
11265
  var DOT_BORDER = "#F3F4F6";
10929
- var TEXT_TERTIARY6 = "#6B7280";
10930
11266
  var BAND_FILL = "rgba(20,184,166,0.1)";
10931
11267
  var BAND_EDGE = "rgba(20,184,166,0.45)";
10932
11268
  var PROJECTION_FILL = "rgba(20,184,166,0.05)";
@@ -10968,8 +11304,8 @@ function interpEdge(pixels, x, key) {
10968
11304
  const a = pixels[i];
10969
11305
  const b = pixels[i + 1];
10970
11306
  if (x >= a.x && x <= b.x) {
10971
- const t = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
10972
- return a[key] + t * (b[key] - a[key]);
11307
+ const t2 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
11308
+ return a[key] + t2 * (b[key] - a[key]);
10973
11309
  }
10974
11310
  }
10975
11311
  return pixels[pixels.length - 1][key];
@@ -11207,6 +11543,7 @@ function CapacityBandChart({
11207
11543
  /* @__PURE__ */ jsx(
11208
11544
  reactNative.Text,
11209
11545
  {
11546
+ className: "text-text-tertiary",
11210
11547
  style: {
11211
11548
  position: "absolute",
11212
11549
  left: PADDING_LEFT / 2 - 14,
@@ -11215,7 +11552,6 @@ function CapacityBandChart({
11215
11552
  textAlign: "center",
11216
11553
  fontSize: 9,
11217
11554
  fontFamily: "Inter, sans-serif",
11218
- color: TEXT_TERTIARY6,
11219
11555
  transform: [{ rotate: "-90deg" }]
11220
11556
  },
11221
11557
  accessibilityElementsHidden: true,
@@ -11229,6 +11565,7 @@ function CapacityBandChart({
11229
11565
  return /* @__PURE__ */ jsx(
11230
11566
  reactNative.Text,
11231
11567
  {
11568
+ className: "text-text-tertiary",
11232
11569
  style: {
11233
11570
  position: "absolute",
11234
11571
  left: toX(point.date) - 14,
@@ -11236,8 +11573,7 @@ function CapacityBandChart({
11236
11573
  width: 28,
11237
11574
  textAlign: "center",
11238
11575
  fontSize: 10,
11239
- fontFamily: "Inter, sans-serif",
11240
- color: TEXT_TERTIARY6
11576
+ fontFamily: "Inter, sans-serif"
11241
11577
  },
11242
11578
  accessibilityElementsHidden: true,
11243
11579
  importantForAccessibility: "no-hide-descendants",
@@ -11299,854 +11635,1002 @@ function CapacityBandChart({
11299
11635
  }
11300
11636
  );
11301
11637
  }
11302
-
11303
- // src/components/custom/Workout/muscleTaxonomy.ts
11304
- var MuscleGroup = /* @__PURE__ */ ((MuscleGroup4) => {
11305
- MuscleGroup4["CHEST"] = "chest";
11306
- MuscleGroup4["FRONT_DELTS"] = "front_delts";
11307
- MuscleGroup4["SIDE_DELTS"] = "side_delts";
11308
- MuscleGroup4["TRICEPS"] = "triceps";
11309
- MuscleGroup4["LATS"] = "lats";
11310
- MuscleGroup4["UPPER_BACK"] = "upper_back";
11311
- MuscleGroup4["REAR_DELTS"] = "rear_delts";
11312
- MuscleGroup4["BICEPS"] = "biceps";
11313
- MuscleGroup4["FOREARMS"] = "forearms";
11314
- MuscleGroup4["QUADS"] = "quads";
11315
- MuscleGroup4["HAMSTRINGS"] = "hamstrings";
11316
- MuscleGroup4["GLUTES"] = "glutes";
11317
- MuscleGroup4["CALVES"] = "calves";
11318
- MuscleGroup4["ABS"] = "abs";
11319
- MuscleGroup4["OBLIQUES"] = "obliques";
11320
- return MuscleGroup4;
11321
- })(MuscleGroup || {});
11322
- var SimpleMuscleGroup = /* @__PURE__ */ ((SimpleMuscleGroup3) => {
11323
- SimpleMuscleGroup3["CHEST"] = "chest";
11324
- SimpleMuscleGroup3["BACK"] = "back";
11325
- SimpleMuscleGroup3["SHOULDERS"] = "shoulders";
11326
- SimpleMuscleGroup3["BICEPS"] = "biceps";
11327
- SimpleMuscleGroup3["TRICEPS"] = "triceps";
11328
- SimpleMuscleGroup3["LEGS"] = "legs";
11329
- SimpleMuscleGroup3["CORE"] = "core";
11330
- SimpleMuscleGroup3["FOREARMS"] = "forearms";
11331
- return SimpleMuscleGroup3;
11332
- })(SimpleMuscleGroup || {});
11333
- var SIMPLE_TO_DETAILED = {
11334
- ["chest" /* CHEST */]: ["chest" /* CHEST */],
11335
- ["back" /* BACK */]: ["lats" /* LATS */, "upper_back" /* UPPER_BACK */],
11336
- ["shoulders" /* SHOULDERS */]: [
11337
- "front_delts" /* FRONT_DELTS */,
11338
- "side_delts" /* SIDE_DELTS */,
11339
- "rear_delts" /* REAR_DELTS */
11340
- ],
11341
- ["biceps" /* BICEPS */]: ["biceps" /* BICEPS */],
11342
- ["triceps" /* TRICEPS */]: ["triceps" /* TRICEPS */],
11343
- ["legs" /* LEGS */]: [
11344
- "quads" /* QUADS */,
11345
- "hamstrings" /* HAMSTRINGS */,
11346
- "glutes" /* GLUTES */,
11347
- "calves" /* CALVES */
11348
- ],
11349
- ["core" /* CORE */]: ["abs" /* ABS */, "obliques" /* OBLIQUES */],
11350
- ["forearms" /* FOREARMS */]: ["forearms" /* FOREARMS */]
11351
- };
11352
- var DETAILED_TO_SIMPLE = Object.entries(
11353
- SIMPLE_TO_DETAILED
11354
- ).reduce(
11355
- (acc, [simple, groups]) => {
11356
- for (const group of groups) {
11357
- acc[group] = simple;
11358
- }
11359
- return acc;
11360
- },
11361
- {}
11362
- );
11363
- var MUSCLE_TO_CATEGORY = {
11364
- ["chest" /* CHEST */]: "push",
11365
- ["front_delts" /* FRONT_DELTS */]: "push",
11366
- ["side_delts" /* SIDE_DELTS */]: "push",
11367
- ["triceps" /* TRICEPS */]: "push",
11368
- ["lats" /* LATS */]: "pull",
11369
- ["upper_back" /* UPPER_BACK */]: "pull",
11370
- ["rear_delts" /* REAR_DELTS */]: "pull",
11371
- ["biceps" /* BICEPS */]: "pull",
11372
- ["forearms" /* FOREARMS */]: "pull",
11373
- ["quads" /* QUADS */]: "legs",
11374
- ["hamstrings" /* HAMSTRINGS */]: "legs",
11375
- ["glutes" /* GLUTES */]: "legs",
11376
- ["calves" /* CALVES */]: "legs",
11377
- ["abs" /* ABS */]: "core",
11378
- ["obliques" /* OBLIQUES */]: "core"
11379
- };
11380
- var MUSCLE_TO_SVG_SLUGS = {
11381
- ["chest" /* CHEST */]: ["chest"],
11382
- ["front_delts" /* FRONT_DELTS */]: ["deltoids"],
11383
- ["side_delts" /* SIDE_DELTS */]: ["deltoids"],
11384
- ["rear_delts" /* REAR_DELTS */]: ["deltoids"],
11385
- ["triceps" /* TRICEPS */]: ["triceps"],
11386
- ["lats" /* LATS */]: ["upper-back"],
11387
- ["upper_back" /* UPPER_BACK */]: ["upper-back", "trapezius"],
11388
- ["biceps" /* BICEPS */]: ["biceps"],
11389
- ["forearms" /* FOREARMS */]: ["forearm"],
11390
- ["quads" /* QUADS */]: ["quadriceps"],
11391
- ["hamstrings" /* HAMSTRINGS */]: ["hamstring"],
11392
- ["glutes" /* GLUTES */]: ["gluteal"],
11393
- ["calves" /* CALVES */]: ["calves"],
11394
- ["abs" /* ABS */]: ["abs"],
11395
- ["obliques" /* OBLIQUES */]: ["obliques"]
11396
- };
11397
- var MUSCLE_DISPLAY_NAMES = {
11398
- ["chest" /* CHEST */]: "Chest",
11399
- ["front_delts" /* FRONT_DELTS */]: "Front Delts",
11400
- ["side_delts" /* SIDE_DELTS */]: "Side Delts",
11401
- ["rear_delts" /* REAR_DELTS */]: "Rear Delts",
11402
- ["triceps" /* TRICEPS */]: "Triceps",
11403
- ["lats" /* LATS */]: "Lats",
11404
- ["upper_back" /* UPPER_BACK */]: "Upper Back",
11405
- ["biceps" /* BICEPS */]: "Biceps",
11406
- ["forearms" /* FOREARMS */]: "Forearms",
11407
- ["quads" /* QUADS */]: "Quads",
11408
- ["hamstrings" /* HAMSTRINGS */]: "Hamstrings",
11409
- ["glutes" /* GLUTES */]: "Glutes",
11410
- ["calves" /* CALVES */]: "Calves",
11411
- ["abs" /* ABS */]: "Abs",
11412
- ["obliques" /* OBLIQUES */]: "Obliques"
11413
- };
11414
- var SIMPLE_DISPLAY_NAMES = {
11415
- ["chest" /* CHEST */]: "Chest",
11416
- ["back" /* BACK */]: "Back",
11417
- ["shoulders" /* SHOULDERS */]: "Shoulders",
11418
- ["biceps" /* BICEPS */]: "Biceps",
11419
- ["triceps" /* TRICEPS */]: "Triceps",
11420
- ["legs" /* LEGS */]: "Legs",
11421
- ["core" /* CORE */]: "Core",
11422
- ["forearms" /* FOREARMS */]: "Forearms"
11423
- };
11424
- var DEFAULT_VOLUME_LANDMARKS = {
11425
- ["chest" /* CHEST */]: { mev: 8, mav: 14, mrv: 20 },
11426
- ["lats" /* LATS */]: { mev: 8, mav: 14, mrv: 20 },
11427
- ["upper_back" /* UPPER_BACK */]: { mev: 6, mav: 12, mrv: 18 },
11428
- ["front_delts" /* FRONT_DELTS */]: { mev: 2, mav: 6, mrv: 10 },
11429
- ["side_delts" /* SIDE_DELTS */]: { mev: 6, mav: 14, mrv: 22 },
11430
- ["rear_delts" /* REAR_DELTS */]: { mev: 6, mav: 12, mrv: 18 },
11431
- ["biceps" /* BICEPS */]: { mev: 4, mav: 10, mrv: 18 },
11432
- ["triceps" /* TRICEPS */]: { mev: 4, mav: 8, mrv: 14 },
11433
- ["forearms" /* FOREARMS */]: { mev: 2, mav: 6, mrv: 12 },
11434
- ["quads" /* QUADS */]: { mev: 6, mav: 12, mrv: 18 },
11435
- ["hamstrings" /* HAMSTRINGS */]: { mev: 4, mav: 10, mrv: 16 },
11436
- ["glutes" /* GLUTES */]: { mev: 4, mav: 10, mrv: 16 },
11437
- ["calves" /* CALVES */]: { mev: 6, mav: 10, mrv: 16 },
11438
- ["abs" /* ABS */]: { mev: 0, mav: 8, mrv: 16 },
11439
- ["obliques" /* OBLIQUES */]: { mev: 0, mav: 6, mrv: 12 }
11440
- };
11441
- var VOLUME_STATUS_LABELS = {
11442
- under: "under-trained",
11443
- maintenance: "maintenance",
11444
- productive: "productive",
11445
- over: "over-reaching"
11446
- };
11447
- var STATUS_SEVERITY = {
11448
- under: 1,
11449
- maintenance: 2,
11450
- productive: 3,
11451
- over: 4
11452
- };
11453
- function getHeatmapColor(status, intensity = 0) {
11454
- const heatmap = WORKOUT_TOKENS.heatmap;
11455
- switch (status) {
11456
- case "under":
11457
- return heatmap.under;
11458
- case "maintenance":
11459
- return heatmap.maintenance;
11460
- case "productive":
11461
- return intensity >= 0.85 ? heatmap.approaching : heatmap.productive;
11462
- case "over":
11463
- return heatmap.over;
11464
- default:
11465
- return heatmap.none;
11466
- }
11467
- }
11468
- function isMoreSevere(a, b) {
11469
- return STATUS_SEVERITY[a] >= STATUS_SEVERITY[b];
11470
- }
11471
- var SLUG_TO_PRIMARY_MUSCLE = {
11472
- chest: "chest" /* CHEST */,
11473
- deltoids: "side_delts" /* SIDE_DELTS */,
11474
- triceps: "triceps" /* TRICEPS */,
11475
- "upper-back": "lats" /* LATS */,
11476
- trapezius: "upper_back" /* UPPER_BACK */,
11477
- biceps: "biceps" /* BICEPS */,
11478
- forearm: "forearms" /* FOREARMS */,
11479
- quadriceps: "quads" /* QUADS */,
11480
- hamstring: "hamstrings" /* HAMSTRINGS */,
11481
- gluteal: "glutes" /* GLUTES */,
11482
- calves: "calves" /* CALVES */,
11483
- abs: "abs" /* ABS */,
11484
- obliques: "obliques" /* OBLIQUES */
11485
- };
11486
-
11487
- // src/components/custom/Workout/BodyMap.tsx
11488
- var Body = BodyHighlighter__default.default.default ?? BodyHighlighter__default.default;
11489
- var OUTLINE_FILL = "rgba(255,255,255,0.08)";
11490
- var OUTLINE_BORDER = "rgba(255,255,255,0.12)";
11491
- var BODY_SCALE = 0.8;
11492
- var TEXT_PRIMARY7 = "#F3F4F6";
11493
- var TEXT_SECONDARY6 = "#9CA3AF";
11494
- function buildSlugParts(data) {
11495
- const bySlug = /* @__PURE__ */ new Map();
11496
- for (const d of data) {
11497
- for (const slug of MUSCLE_TO_SVG_SLUGS[d.muscleGroup] ?? []) {
11498
- const existing = bySlug.get(slug);
11499
- if (!existing || isMoreSevere(d.volumeStatus, existing.status)) {
11500
- bySlug.set(slug, { status: d.volumeStatus, intensity: d.intensity });
11501
- }
11502
- }
11503
- }
11504
- return Array.from(bySlug.entries()).map(([slug, v]) => ({
11505
- slug,
11506
- color: getHeatmapColor(v.status, v.intensity)
11638
+ var BRAND_PRIMARY11 = "#FF7900";
11639
+ var WORKOUT_PILL_STATUS = {
11640
+ completed: "completed",
11641
+ today: "current",
11642
+ upcoming: "upcoming"
11643
+ };
11644
+ function deriveNavLevel(selection) {
11645
+ if (selection.workoutId != null) return "workout";
11646
+ if (selection.weekNumber != null) return "week";
11647
+ return "meso";
11648
+ }
11649
+ function toProgressBarMesos(mesos) {
11650
+ return mesos.map(({ id, name, weekCount, status, currentWeek }) => ({
11651
+ id,
11652
+ name,
11653
+ weekCount,
11654
+ status,
11655
+ currentWeek
11507
11656
  }));
11508
11657
  }
11509
- function buildSimpleLegend(data) {
11510
- const bySimple = /* @__PURE__ */ new Map();
11511
- for (const d of data) {
11512
- const simple = DETAILED_TO_SIMPLE[d.muscleGroup];
11513
- const existing = bySimple.get(simple);
11514
- if (!existing) {
11515
- bySimple.set(simple, {
11516
- key: simple,
11517
- name: SIMPLE_DISPLAY_NAMES[simple],
11518
- status: d.volumeStatus,
11519
- intensity: d.intensity,
11520
- sets: d.weeklySets,
11521
- muscle: d.muscleGroup
11522
- });
11523
- continue;
11524
- }
11525
- existing.sets += d.weeklySets;
11526
- existing.intensity = Math.max(existing.intensity, d.intensity);
11527
- if (isMoreSevere(d.volumeStatus, existing.status)) {
11528
- existing.status = d.volumeStatus;
11529
- existing.muscle = d.muscleGroup;
11530
- }
11658
+ function findMeso(mesos, id) {
11659
+ if (id == null) return null;
11660
+ return mesos.find((meso) => meso.id === id) ?? null;
11661
+ }
11662
+ function findWeek(meso, weekNumber) {
11663
+ if (meso == null || weekNumber == null) return null;
11664
+ return meso.weeks.find((week) => week.weekNumber === weekNumber) ?? null;
11665
+ }
11666
+ function findWorkout(week, workoutId) {
11667
+ if (week == null || workoutId == null) return null;
11668
+ return week.workouts.find((workout) => workout.id === workoutId) ?? null;
11669
+ }
11670
+ function buildBreadcrumbs(meso, weekNumber, workout) {
11671
+ const crumbs = [{ key: "meso", label: meso.name, level: "meso" }];
11672
+ if (weekNumber != null) {
11673
+ crumbs.push({ key: "week", label: `Week ${weekNumber}`, level: "week" });
11531
11674
  }
11532
- return Array.from(bySimple.values());
11675
+ if (workout != null) {
11676
+ crumbs.push({ key: "workout", label: workout.name, level: "workout" });
11677
+ }
11678
+ return crumbs;
11679
+ }
11680
+ function Breadcrumbs2({ crumbs, onNavigate }) {
11681
+ return /* @__PURE__ */ jsx(
11682
+ reactNative.View,
11683
+ {
11684
+ className: "flex-row items-center flex-wrap",
11685
+ style: { gap: 4 },
11686
+ testID: "program-planning-page-breadcrumbs",
11687
+ children: crumbs.map((crumb, index) => {
11688
+ const isLast = index === crumbs.length - 1;
11689
+ return /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 4 }, children: [
11690
+ index > 0 && /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-tertiary", style: { fontSize: 12 }, children: "\u203A" }),
11691
+ /* @__PURE__ */ jsx(
11692
+ reactNative.Pressable,
11693
+ {
11694
+ onPress: () => onNavigate(crumb.level),
11695
+ disabled: isLast,
11696
+ accessibilityRole: "button",
11697
+ testID: `program-planning-page-crumb-${crumb.key}`,
11698
+ children: /* @__PURE__ */ jsx(
11699
+ reactNative.Text,
11700
+ {
11701
+ className: isLast ? "text-text-primary" : void 0,
11702
+ style: {
11703
+ fontSize: 12,
11704
+ fontFamily: "Inter, sans-serif",
11705
+ fontWeight: isLast ? "700" : "500",
11706
+ color: isLast ? void 0 : BRAND_PRIMARY11
11707
+ },
11708
+ children: crumb.label
11709
+ }
11710
+ )
11711
+ }
11712
+ )
11713
+ ] }, crumb.key);
11714
+ })
11715
+ }
11716
+ );
11533
11717
  }
11534
- function buildDetailedLegend(data) {
11535
- return data.map((d) => ({
11536
- key: d.muscleGroup,
11537
- name: MUSCLE_DISPLAY_NAMES[d.muscleGroup],
11538
- status: d.volumeStatus,
11539
- intensity: d.intensity,
11540
- sets: d.weeklySets,
11541
- muscle: d.muscleGroup
11718
+ function toWeekRow(week, meso, onSelectWeek) {
11719
+ const workouts = week.workouts.map((workout) => ({
11720
+ name: workout.name,
11721
+ status: WORKOUT_PILL_STATUS[workout.status],
11722
+ onPress: () => onSelectWeek(week.weekNumber)
11542
11723
  }));
11724
+ return {
11725
+ weekNumber: week.weekNumber,
11726
+ totalWeeks: meso.weekCount,
11727
+ workouts,
11728
+ intensityLevel: week.intensityLevel,
11729
+ intensityThreshold: week.intensityThreshold,
11730
+ isCurrent: week.isCurrent ?? week.weekNumber === meso.currentWeek,
11731
+ isDeload: week.isDeload
11732
+ };
11543
11733
  }
11544
- function BodyMap({
11545
- data,
11546
- view,
11547
- onViewChange,
11548
- onMusclePress,
11549
- highlightedMuscle,
11550
- mode = "detailed",
11551
- className,
11552
- ...props
11553
- }) {
11554
- const slugParts = React24.useMemo(() => buildSlugParts(data), [data]);
11555
- const legend = React24.useMemo(
11556
- () => mode === "simple" ? buildSimpleLegend(data) : buildDetailedLegend(data),
11557
- [data, mode]
11558
- );
11559
- const [highlight] = React24.useState(() => new reactNative.Animated.Value(highlightedMuscle ? 1 : 0));
11560
- React24.useEffect(() => {
11561
- const animation = reactNative.Animated.timing(highlight, {
11562
- toValue: highlightedMuscle ? 1 : 0,
11563
- duration: 250,
11564
- easing: reactNative.Easing.out(reactNative.Easing.ease),
11565
- useNativeDriver: false
11566
- });
11567
- animation.start();
11568
- return () => animation.stop();
11569
- }, [highlightedMuscle, highlight]);
11570
- const scale = highlight.interpolate({ inputRange: [0, 1], outputRange: [1, 1.02] });
11571
- const glowColor = highlightedMuscle ? getHeatmapColor(
11572
- data.find((d) => d.muscleGroup === highlightedMuscle)?.volumeStatus,
11573
- data.find((d) => d.muscleGroup === highlightedMuscle)?.intensity ?? 0
11574
- ) : null;
11575
- const handleBodyPress = (part) => {
11576
- if (!onMusclePress || !part.slug) return;
11577
- const fromData = data.find(
11578
- (d) => (MUSCLE_TO_SVG_SLUGS[d.muscleGroup] ?? []).includes(part.slug)
11734
+ function MesoLevel({ mesos, activeMesoId, onSelectMeso, onSelectWeek }) {
11735
+ return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 12 }, testID: "program-planning-page-meso-level", children: mesos.map((meso) => {
11736
+ const expanded = meso.id === activeMesoId;
11737
+ return /* @__PURE__ */ jsx(
11738
+ MesoCard,
11739
+ {
11740
+ name: meso.name,
11741
+ goal: meso.goal,
11742
+ split: meso.split,
11743
+ weekRange: meso.weekRange,
11744
+ currentWeek: meso.currentWeek,
11745
+ totalWeeks: meso.weekCount,
11746
+ weeks: expanded ? meso.weeks.map((week) => toWeekRow(week, meso, onSelectWeek)) : [],
11747
+ volumeHeatmap: meso.volumeHeatmap,
11748
+ expanded,
11749
+ onToggle: () => onSelectMeso(meso.id),
11750
+ highlighted: expanded
11751
+ },
11752
+ meso.id
11579
11753
  );
11580
- const muscle = fromData?.muscleGroup ?? SLUG_TO_PRIMARY_MUSCLE[part.slug];
11581
- if (muscle) onMusclePress(muscle);
11754
+ }) });
11755
+ }
11756
+ function WeekLevel({ week, onSelectWorkout }) {
11757
+ return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 10 }, testID: "program-planning-page-week-level", children: week.workouts.map((workout) => /* @__PURE__ */ jsx(
11758
+ WorkoutCard,
11759
+ {
11760
+ name: workout.name,
11761
+ date: workout.date,
11762
+ duration: workout.duration,
11763
+ status: workout.status,
11764
+ muscleGroups: workout.muscleGroups,
11765
+ totalSets: workout.totalSets,
11766
+ totalVolume: workout.totalVolume,
11767
+ unit: workout.unit,
11768
+ exercises: workout.exercises,
11769
+ expanded: false,
11770
+ onToggle: () => onSelectWorkout(workout.id)
11771
+ },
11772
+ workout.id
11773
+ )) });
11774
+ }
11775
+ function WorkoutLevel({ workout, expandedExercise, onToggleExercise }) {
11776
+ const exercises = workout.exercises.map((exercise, index) => ({
11777
+ ...exercise,
11778
+ state: exercise.state === "upcoming" ? exercise.state : index === expandedExercise ? "expanded" : "collapsed",
11779
+ onToggle: () => onToggleExercise(index)
11780
+ }));
11781
+ return /* @__PURE__ */ jsx(reactNative.View, { testID: "program-planning-page-workout-level", children: /* @__PURE__ */ jsx(
11782
+ WorkoutCard,
11783
+ {
11784
+ name: workout.name,
11785
+ date: workout.date,
11786
+ duration: workout.duration,
11787
+ status: workout.status,
11788
+ muscleGroups: workout.muscleGroups,
11789
+ totalSets: workout.totalSets,
11790
+ totalVolume: workout.totalVolume,
11791
+ unit: workout.unit,
11792
+ exercises,
11793
+ expanded: true,
11794
+ onToggle: () => void 0
11795
+ }
11796
+ ) });
11797
+ }
11798
+ function ProgramPlanningPage({
11799
+ title = "Program Plan",
11800
+ mesos,
11801
+ className,
11802
+ ...props
11803
+ }) {
11804
+ const [activeMesoId, setActiveMesoId] = React24.useState(mesos[0]?.id ?? null);
11805
+ const [selectedWeek, setSelectedWeek] = React24.useState(null);
11806
+ const [selectedWorkoutId, setSelectedWorkoutId] = React24.useState(null);
11807
+ const [expandedExercise, setExpandedExercise] = React24.useState(null);
11808
+ const progressMesos = React24.useMemo(() => toProgressBarMesos(mesos), [mesos]);
11809
+ const activeMeso = findMeso(mesos, activeMesoId);
11810
+ const level = deriveNavLevel({ weekNumber: selectedWeek, workoutId: selectedWorkoutId });
11811
+ const activeWeek = findWeek(activeMeso, selectedWeek);
11812
+ const activeWorkout = findWorkout(activeWeek, selectedWorkoutId);
11813
+ const selectMeso = (id) => {
11814
+ setActiveMesoId(id);
11815
+ setSelectedWeek(null);
11816
+ setSelectedWorkoutId(null);
11582
11817
  };
11583
- return /* @__PURE__ */ jsxs(reactNative.View, { className: cn(className), testID: "body-map", ...props, children: [
11584
- /* @__PURE__ */ jsx(ViewToggle, { view, onViewChange }),
11585
- /* @__PURE__ */ jsx(
11586
- reactNative.Animated.View,
11587
- {
11588
- style: [
11818
+ const selectWeek = (weekNumber) => {
11819
+ setSelectedWeek(weekNumber);
11820
+ setSelectedWorkoutId(null);
11821
+ setExpandedExercise(null);
11822
+ };
11823
+ const selectWorkout = (id) => {
11824
+ setSelectedWorkoutId(id);
11825
+ setExpandedExercise(null);
11826
+ };
11827
+ const toggleExercise = (index) => setExpandedExercise((current) => current === index ? null : index);
11828
+ const navigateTo = (target) => {
11829
+ if (target === "meso") selectMeso(activeMesoId ?? mesos[0]?.id);
11830
+ else if (target === "week" && selectedWeek != null) selectWeek(selectedWeek);
11831
+ };
11832
+ return /* @__PURE__ */ jsx(
11833
+ reactNative.View,
11834
+ {
11835
+ className: cn(className, "bg-background-base"),
11836
+ style: { width: 390 },
11837
+ accessibilityRole: "main",
11838
+ "aria-label": title,
11839
+ testID: "program-planning-page",
11840
+ ...props,
11841
+ children: /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 16, gap: 14 }, testID: "program-planning-page-content", children: [
11842
+ /* @__PURE__ */ jsx(
11843
+ reactNative.Text,
11589
11844
  {
11590
- width: 200 * BODY_SCALE,
11591
- alignSelf: "center",
11592
- transform: [{ scale }]
11593
- },
11594
- glowColor ? { boxShadow: `0 0 14px 2px ${glowColor}` } : void 0
11595
- ],
11596
- "aria-hidden": true,
11597
- accessibilityElementsHidden: true,
11598
- importantForAccessibility: "no-hide-descendants",
11599
- testID: "body-map-svg",
11600
- children: /* @__PURE__ */ jsx(
11601
- Body,
11845
+ accessibilityRole: "header",
11846
+ className: "text-text-primary",
11847
+ style: {
11848
+ fontSize: 20,
11849
+ fontFamily: '"Space Grotesk", sans-serif',
11850
+ fontWeight: "700"
11851
+ },
11852
+ testID: "program-planning-page-title",
11853
+ children: title
11854
+ }
11855
+ ),
11856
+ /* @__PURE__ */ jsx(reactNative.View, { style: { marginHorizontal: -16 }, children: /* @__PURE__ */ jsx(
11857
+ MesoProgressBar,
11602
11858
  {
11603
- side: view,
11604
- data: slugParts,
11605
- scale: BODY_SCALE,
11606
- gender: "male",
11607
- defaultFill: OUTLINE_FILL,
11608
- border: OUTLINE_BORDER,
11609
- onBodyPartPress: handleBodyPress
11859
+ mesos: progressMesos,
11860
+ activeMesoId,
11861
+ onMesoPress: selectMeso
11610
11862
  }
11611
- )
11612
- }
11613
- ),
11614
- legend.length === 0 ? /* @__PURE__ */ jsx(
11615
- reactNative.Text,
11616
- {
11617
- style: {
11618
- marginTop: 8,
11619
- fontSize: 12,
11620
- color: TEXT_SECONDARY6,
11621
- textAlign: "center",
11622
- fontFamily: "Inter, sans-serif"
11623
- },
11624
- testID: "body-map-empty",
11625
- children: "No training data"
11626
- }
11627
- ) : /* @__PURE__ */ jsx(
11628
- reactNative.View,
11629
- {
11630
- className: "flex-row flex-wrap",
11631
- style: { marginTop: 10, gap: 6, justifyContent: "center" },
11632
- testID: "body-map-legend",
11633
- children: legend.map((entry) => /* @__PURE__ */ jsx(
11634
- MuscleButton,
11863
+ ) }),
11864
+ activeMeso != null && /* @__PURE__ */ jsx(
11865
+ Breadcrumbs2,
11635
11866
  {
11636
- entry,
11637
- highlighted: highlightedMuscle === entry.muscle,
11638
- onMusclePress
11639
- },
11640
- entry.key
11641
- ))
11642
- }
11643
- )
11644
- ] });
11867
+ crumbs: buildBreadcrumbs(activeMeso, selectedWeek, activeWorkout),
11868
+ onNavigate: navigateTo
11869
+ }
11870
+ ),
11871
+ /* @__PURE__ */ jsxs(
11872
+ reactNative.View,
11873
+ {
11874
+ className: "bg-surface-elevated border-border",
11875
+ style: {
11876
+ borderWidth: 1,
11877
+ borderRadius: 12,
11878
+ padding: 12
11879
+ },
11880
+ testID: "program-planning-page-body",
11881
+ children: [
11882
+ level === "meso" && /* @__PURE__ */ jsx(
11883
+ MesoLevel,
11884
+ {
11885
+ mesos,
11886
+ activeMesoId,
11887
+ onSelectMeso: selectMeso,
11888
+ onSelectWeek: selectWeek
11889
+ }
11890
+ ),
11891
+ level === "week" && activeWeek != null && /* @__PURE__ */ jsx(WeekLevel, { week: activeWeek, onSelectWorkout: selectWorkout }),
11892
+ level === "workout" && activeWorkout != null && /* @__PURE__ */ jsx(
11893
+ WorkoutLevel,
11894
+ {
11895
+ workout: activeWorkout,
11896
+ expandedExercise,
11897
+ onToggleExercise: toggleExercise
11898
+ }
11899
+ )
11900
+ ]
11901
+ }
11902
+ )
11903
+ ] })
11904
+ }
11905
+ );
11645
11906
  }
11646
- function ViewToggle({ view, onViewChange }) {
11907
+ var BRAND_PRIMARY12 = "#FF7900";
11908
+ var CHART_WIDTH = 326;
11909
+ var CHART_HEIGHT = 150;
11910
+ var EXERCISE_DETAIL_TABS = [
11911
+ { key: "progress", label: "Progress" },
11912
+ { key: "history", label: "History" },
11913
+ { key: "advanced", label: "Advanced" }
11914
+ ];
11915
+ function deriveExerciseStats(entries) {
11916
+ let bestE1rm = null;
11917
+ let prCount = 0;
11918
+ for (const entry of entries) {
11919
+ if (entry.e1rm != null && (bestE1rm == null || entry.e1rm.value > bestE1rm)) {
11920
+ bestE1rm = entry.e1rm.value;
11921
+ }
11922
+ if (entry.isPR) prCount += 1;
11923
+ }
11924
+ return { sessions: entries.length, bestE1rm, prCount };
11925
+ }
11926
+ function toExerciseCardProps(entry, expanded, onToggle) {
11927
+ return {
11928
+ name: entry.title,
11929
+ state: expanded ? "expanded" : "collapsed",
11930
+ onToggle,
11931
+ summary: entry.summary,
11932
+ e1rm: entry.e1rm,
11933
+ isPR: entry.isPR,
11934
+ tempo: entry.tempo,
11935
+ sets: expanded ? entry.sets : void 0
11936
+ };
11937
+ }
11938
+ function summarizeVbt(sets) {
11939
+ const allReps = sets.flatMap((set) => set.velocities);
11940
+ const meanVelocity = calculateMeanVelocity(allReps);
11941
+ let velocityLoss = 0;
11942
+ for (const set of sets) {
11943
+ velocityLoss = Math.max(velocityLoss, calculateVelocityLoss(set.velocities));
11944
+ }
11945
+ return { meanVelocity, velocityLoss };
11946
+ }
11947
+ function TabBar({ active, onSelect }) {
11647
11948
  return /* @__PURE__ */ jsx(
11648
11949
  reactNative.View,
11649
11950
  {
11650
- className: "flex-row self-center",
11651
- style: { gap: 4, marginBottom: 8 },
11652
- testID: "body-map-view-toggle",
11653
- children: ["front", "back"].map((side) => {
11654
- const active = view === side;
11951
+ className: "flex-row",
11952
+ style: {
11953
+ borderBottomWidth: 1,
11954
+ borderBottomColor: resolveColor("border-default")
11955
+ },
11956
+ accessibilityRole: "tablist",
11957
+ testID: "exercise-detail-page-tabs",
11958
+ children: EXERCISE_DETAIL_TABS.map(({ key, label }) => {
11959
+ const isActive = key === active;
11655
11960
  return /* @__PURE__ */ jsx(
11656
11961
  reactNative.Pressable,
11657
11962
  {
11658
- onPress: () => onViewChange?.(side),
11659
- accessibilityRole: "button",
11660
- accessibilityLabel: `Show ${side} view`,
11661
- "aria-pressed": active,
11662
- disabled: !onViewChange,
11963
+ onPress: () => onSelect(key),
11964
+ accessibilityRole: "tab",
11965
+ accessibilityState: { selected: isActive },
11663
11966
  style: {
11664
- paddingHorizontal: 12,
11665
- paddingVertical: 4,
11666
- borderRadius: 9999,
11667
- backgroundColor: active ? "rgba(255,121,0,0.16)" : "transparent",
11668
- borderWidth: 1,
11669
- borderColor: active ? "#FF7900" : WORKOUT_TOKENS.border.strong
11967
+ flex: 1,
11968
+ alignItems: "center",
11969
+ paddingVertical: 10,
11970
+ borderBottomWidth: 2,
11971
+ borderBottomColor: isActive ? BRAND_PRIMARY12 : "transparent"
11670
11972
  },
11671
- testID: `body-map-toggle-${side}`,
11973
+ testID: `exercise-detail-page-tab-${key}`,
11672
11974
  children: /* @__PURE__ */ jsx(
11673
11975
  reactNative.Text,
11674
11976
  {
11977
+ className: isActive ? "text-text-primary" : "text-text-tertiary",
11675
11978
  style: {
11676
- fontSize: 12,
11979
+ fontSize: 13,
11677
11980
  fontFamily: "Inter, sans-serif",
11678
- fontWeight: active ? "700" : "500",
11679
- color: active ? "#FF7900" : TEXT_SECONDARY6,
11680
- textTransform: "capitalize"
11981
+ fontWeight: isActive ? "700" : "500"
11681
11982
  },
11682
- children: side
11983
+ children: label
11683
11984
  }
11684
11985
  )
11685
11986
  },
11686
- side
11987
+ key
11687
11988
  );
11688
11989
  })
11689
11990
  }
11690
11991
  );
11691
11992
  }
11692
- function MuscleButton({ entry, highlighted, onMusclePress }) {
11693
- const dotColor = getHeatmapColor(entry.status, entry.intensity);
11694
- const label = `${entry.name}, ${VOLUME_STATUS_LABELS[entry.status]}, ${entry.sets} sets this week`;
11993
+ var STAT_CARDS = [
11994
+ { key: "sessions", label: "Sessions" },
11995
+ { key: "bestE1rm", label: "Best e1RM" },
11996
+ { key: "prCount", label: "PRs" }
11997
+ ];
11998
+ function StatStrip({ stats, unit }) {
11999
+ return /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row", style: { gap: 8 }, testID: "exercise-detail-page-stats", children: STAT_CARDS.map(({ key, label }) => {
12000
+ const raw = stats[key];
12001
+ const value = key === "bestE1rm" ? raw == null ? "\u2014" : `${raw} ${unit}` : `${raw}`;
12002
+ return /* @__PURE__ */ jsxs(
12003
+ reactNative.View,
12004
+ {
12005
+ className: "bg-surface-elevated border-border",
12006
+ style: {
12007
+ flex: 1,
12008
+ padding: 12,
12009
+ borderRadius: 10,
12010
+ borderWidth: 1
12011
+ },
12012
+ testID: `exercise-detail-page-stat-${key}`,
12013
+ children: [
12014
+ /* @__PURE__ */ jsx(
12015
+ reactNative.Text,
12016
+ {
12017
+ className: "text-text-primary",
12018
+ style: {
12019
+ fontSize: 18,
12020
+ fontFamily: '"Space Grotesk", sans-serif',
12021
+ fontWeight: "700"
12022
+ },
12023
+ children: value
12024
+ }
12025
+ ),
12026
+ /* @__PURE__ */ jsx(
12027
+ reactNative.Text,
12028
+ {
12029
+ className: "text-text-tertiary",
12030
+ style: {
12031
+ marginTop: 2,
12032
+ fontSize: 10,
12033
+ fontFamily: "Inter, sans-serif",
12034
+ fontWeight: "600",
12035
+ letterSpacing: 0.4,
12036
+ textTransform: "uppercase"
12037
+ },
12038
+ children: label
12039
+ }
12040
+ )
12041
+ ]
12042
+ },
12043
+ key
12044
+ );
12045
+ }) });
12046
+ }
12047
+ function SectionCard({
12048
+ title,
12049
+ children,
12050
+ testID
12051
+ }) {
11695
12052
  return /* @__PURE__ */ jsxs(
11696
- reactNative.Pressable,
12053
+ reactNative.View,
11697
12054
  {
11698
- onPress: () => onMusclePress?.(entry.muscle),
11699
- accessibilityRole: "button",
11700
- accessibilityLabel: label,
11701
- "aria-pressed": highlighted,
12055
+ className: "bg-surface-elevated border-border",
11702
12056
  style: {
11703
- flexDirection: "row",
11704
- alignItems: "center",
11705
- gap: 5,
11706
- paddingHorizontal: 8,
11707
- paddingVertical: 3,
11708
- borderRadius: 9999,
11709
12057
  borderWidth: 1,
11710
- borderColor: highlighted ? "#FF7900" : WORKOUT_TOKENS.border.default,
11711
- backgroundColor: WORKOUT_TOKENS.surface.raised
12058
+ borderRadius: 12,
12059
+ padding: 12,
12060
+ gap: 10
11712
12061
  },
11713
- testID: `body-map-muscle-${entry.key}`,
12062
+ testID,
11714
12063
  children: [
11715
12064
  /* @__PURE__ */ jsx(
11716
- reactNative.View,
12065
+ reactNative.Text,
12066
+ {
12067
+ className: "text-text-tertiary",
12068
+ style: {
12069
+ fontSize: 11,
12070
+ fontFamily: "Inter, sans-serif",
12071
+ fontWeight: "600",
12072
+ letterSpacing: 0.6,
12073
+ textTransform: "uppercase"
12074
+ },
12075
+ children: title
12076
+ }
12077
+ ),
12078
+ children
12079
+ ]
12080
+ }
12081
+ );
12082
+ }
12083
+ function EntryList({ entries, expandedId, onToggle, emptyLabel, testID }) {
12084
+ if (entries.length === 0) {
12085
+ return /* @__PURE__ */ jsx(
12086
+ reactNative.Text,
12087
+ {
12088
+ className: "text-text-tertiary",
12089
+ style: { fontSize: 12, fontFamily: "Inter, sans-serif" },
12090
+ testID: `${testID}-empty`,
12091
+ children: emptyLabel
12092
+ }
12093
+ );
12094
+ }
12095
+ return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 8 }, testID, children: entries.map((entry) => /* @__PURE__ */ jsx(
12096
+ ExerciseCard,
12097
+ {
12098
+ ...toExerciseCardProps(entry, entry.id === expandedId, () => onToggle(entry.id))
12099
+ },
12100
+ entry.id
12101
+ )) });
12102
+ }
12103
+ function VbtBreakdown({ sets }) {
12104
+ return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 10 }, testID: "exercise-detail-page-vbt-breakdown", children: sets.map((set) => {
12105
+ const mean = calculateMeanVelocity(set.velocities);
12106
+ const loss = calculateVelocityLoss(set.velocities);
12107
+ return /* @__PURE__ */ jsxs(
12108
+ reactNative.View,
12109
+ {
12110
+ className: "flex-row items-center",
12111
+ style: { gap: 10 },
12112
+ testID: "exercise-detail-page-vbt-set",
12113
+ children: [
12114
+ /* @__PURE__ */ jsx(
12115
+ reactNative.Text,
12116
+ {
12117
+ className: "text-text-secondary",
12118
+ style: {
12119
+ width: 44,
12120
+ fontSize: 11,
12121
+ fontFamily: "Inter, sans-serif",
12122
+ fontWeight: "600"
12123
+ },
12124
+ children: set.label
12125
+ }
12126
+ ),
12127
+ /* @__PURE__ */ jsx(reactNative.View, { className: "flex-1", style: { height: 8, justifyContent: "center" }, children: /* @__PURE__ */ jsx(VelocityStrip, { velocities: set.velocities, variant: "mini" }) }),
12128
+ /* @__PURE__ */ jsx(
12129
+ reactNative.Text,
12130
+ {
12131
+ className: "text-text-tertiary",
12132
+ style: {
12133
+ fontSize: 11,
12134
+ fontFamily: "Inter, sans-serif",
12135
+ fontVariant: ["tabular-nums"]
12136
+ },
12137
+ children: `${mean.toFixed(2)} \xB7 -${loss}%`
12138
+ }
12139
+ )
12140
+ ]
12141
+ },
12142
+ set.label
12143
+ );
12144
+ }) });
12145
+ }
12146
+ function VbtSummaryRow({ summary }) {
12147
+ const cells = [
12148
+ { label: "Mean Velocity", value: `${summary.meanVelocity.toFixed(2)} m/s` },
12149
+ { label: "Peak Vel. Loss", value: `-${summary.velocityLoss}%` }
12150
+ ];
12151
+ return /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row", style: { gap: 8 }, testID: "exercise-detail-page-vbt-summary", children: cells.map((cell) => /* @__PURE__ */ jsxs(
12152
+ reactNative.View,
12153
+ {
12154
+ className: "bg-surface-elevated border-border",
12155
+ style: {
12156
+ flex: 1,
12157
+ padding: 12,
12158
+ borderRadius: 10,
12159
+ borderWidth: 1
12160
+ },
12161
+ children: [
12162
+ /* @__PURE__ */ jsx(
12163
+ reactNative.Text,
12164
+ {
12165
+ className: "text-text-primary",
12166
+ style: {
12167
+ fontSize: 16,
12168
+ fontFamily: '"Space Grotesk", sans-serif',
12169
+ fontWeight: "700"
12170
+ },
12171
+ children: cell.value
12172
+ }
12173
+ ),
12174
+ /* @__PURE__ */ jsx(
12175
+ reactNative.Text,
12176
+ {
12177
+ className: "text-text-tertiary",
12178
+ style: {
12179
+ marginTop: 2,
12180
+ fontSize: 10,
12181
+ fontFamily: "Inter, sans-serif",
12182
+ fontWeight: "600",
12183
+ letterSpacing: 0.4,
12184
+ textTransform: "uppercase"
12185
+ },
12186
+ children: cell.label
12187
+ }
12188
+ )
12189
+ ]
12190
+ },
12191
+ cell.label
12192
+ )) });
12193
+ }
12194
+ function ExerciseDetailPage({
12195
+ exercise,
12196
+ meso,
12197
+ trend,
12198
+ progression,
12199
+ history,
12200
+ vbt,
12201
+ className,
12202
+ ...props
12203
+ }) {
12204
+ const [tab, setTab] = React24.useState("progress");
12205
+ const [expandedProgressId, setExpandedProgressId] = React24.useState(null);
12206
+ const [expandedHistoryId, setExpandedHistoryId] = React24.useState(null);
12207
+ const stats = React24.useMemo(() => deriveExerciseStats(history), [history]);
12208
+ const vbtSummary = React24.useMemo(() => summarizeVbt(vbt.sets), [vbt.sets]);
12209
+ const toggle = (setId) => (id) => setId((current) => current === id ? null : id);
12210
+ return /* @__PURE__ */ jsx(
12211
+ reactNative.View,
12212
+ {
12213
+ className: cn("bg-background-base", className),
12214
+ style: { width: 390 },
12215
+ accessibilityRole: "main",
12216
+ "aria-label": exercise.name,
12217
+ testID: "exercise-detail-page",
12218
+ ...props,
12219
+ children: /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 16, gap: 14 }, testID: "exercise-detail-page-content", children: [
12220
+ /* @__PURE__ */ jsxs(
12221
+ reactNative.View,
12222
+ {
12223
+ className: "flex-row items-start justify-between",
12224
+ style: { gap: 8 },
12225
+ testID: "exercise-detail-page-header",
12226
+ children: [
12227
+ /* @__PURE__ */ jsxs(reactNative.View, { style: { flexShrink: 1 }, children: [
12228
+ /* @__PURE__ */ jsx(
12229
+ reactNative.Text,
12230
+ {
12231
+ accessibilityRole: "header",
12232
+ className: "text-text-primary",
12233
+ style: {
12234
+ fontSize: 20,
12235
+ fontFamily: '"Space Grotesk", sans-serif',
12236
+ fontWeight: "700"
12237
+ },
12238
+ testID: "exercise-detail-page-title",
12239
+ children: exercise.name
12240
+ }
12241
+ ),
12242
+ /* @__PURE__ */ jsx(
12243
+ reactNative.Text,
12244
+ {
12245
+ className: "text-text-secondary",
12246
+ style: {
12247
+ marginTop: 2,
12248
+ fontSize: 12,
12249
+ fontFamily: "Inter, sans-serif"
12250
+ },
12251
+ testID: "exercise-detail-page-subtitle",
12252
+ children: exercise.subtitle
12253
+ }
12254
+ )
12255
+ ] }),
12256
+ exercise.currentE1rm != null && /* @__PURE__ */ jsxs(
12257
+ reactNative.View,
12258
+ {
12259
+ style: {
12260
+ paddingVertical: 4,
12261
+ paddingHorizontal: 10,
12262
+ borderRadius: 6,
12263
+ backgroundColor: "rgba(255,121,0,0.10)",
12264
+ borderWidth: 1,
12265
+ borderColor: "rgba(255,121,0,0.25)"
12266
+ },
12267
+ testID: "exercise-detail-page-e1rm",
12268
+ children: [
12269
+ /* @__PURE__ */ jsx(
12270
+ reactNative.Text,
12271
+ {
12272
+ className: "text-text-tertiary",
12273
+ style: {
12274
+ fontSize: 9,
12275
+ fontFamily: "Inter, sans-serif",
12276
+ fontWeight: "600",
12277
+ letterSpacing: 0.4,
12278
+ textTransform: "uppercase"
12279
+ },
12280
+ children: "e1RM"
12281
+ }
12282
+ ),
12283
+ /* @__PURE__ */ jsx(
12284
+ reactNative.Text,
12285
+ {
12286
+ style: {
12287
+ fontSize: 15,
12288
+ fontFamily: '"Space Grotesk", sans-serif',
12289
+ fontWeight: "700",
12290
+ color: BRAND_PRIMARY12
12291
+ },
12292
+ children: `${exercise.currentE1rm} ${exercise.unit}`
12293
+ }
12294
+ )
12295
+ ]
12296
+ }
12297
+ )
12298
+ ]
12299
+ }
12300
+ ),
12301
+ /* @__PURE__ */ jsx(TabBar, { active: tab, onSelect: setTab }),
12302
+ tab === "progress" && /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 14 }, testID: "exercise-detail-page-panel-progress", children: [
12303
+ /* @__PURE__ */ jsx(MesoStatusCard, { ...meso }),
12304
+ /* @__PURE__ */ jsx(StatStrip, { stats, unit: exercise.unit }),
12305
+ /* @__PURE__ */ jsx(SectionCard, { title: "Strength Trend", testID: "exercise-detail-page-trend", children: /* @__PURE__ */ jsx(
12306
+ StrengthTrendChart,
12307
+ {
12308
+ data: trend.data,
12309
+ projection: trend.projection,
12310
+ mesoBoundaries: trend.mesoBoundaries,
12311
+ width: CHART_WIDTH,
12312
+ height: CHART_HEIGHT,
12313
+ unit: exercise.unit,
12314
+ animateOnMount: false
12315
+ }
12316
+ ) }),
12317
+ /* @__PURE__ */ jsx(SectionCard, { title: "Week-by-Week", testID: "exercise-detail-page-progression", children: /* @__PURE__ */ jsx(
12318
+ EntryList,
12319
+ {
12320
+ entries: progression,
12321
+ expandedId: expandedProgressId,
12322
+ onToggle: toggle(setExpandedProgressId),
12323
+ emptyLabel: "No progression logged yet",
12324
+ testID: "exercise-detail-page-progression-list"
12325
+ }
12326
+ ) })
12327
+ ] }),
12328
+ tab === "history" && /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 14 }, testID: "exercise-detail-page-panel-history", children: /* @__PURE__ */ jsx(SectionCard, { title: "All Sessions", testID: "exercise-detail-page-history", children: /* @__PURE__ */ jsx(
12329
+ EntryList,
12330
+ {
12331
+ entries: history,
12332
+ expandedId: expandedHistoryId,
12333
+ onToggle: toggle(setExpandedHistoryId),
12334
+ emptyLabel: "No sessions logged yet",
12335
+ testID: "exercise-detail-page-history-list"
12336
+ }
12337
+ ) }) }),
12338
+ tab === "advanced" && /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 14 }, testID: "exercise-detail-page-panel-advanced", children: [
12339
+ /* @__PURE__ */ jsx(SectionCard, { title: "Capacity Band", testID: "exercise-detail-page-capacity", children: /* @__PURE__ */ jsx(
12340
+ CapacityBandChart,
12341
+ {
12342
+ band: vbt.band,
12343
+ workouts: vbt.workouts,
12344
+ projection: vbt.projection,
12345
+ width: CHART_WIDTH,
12346
+ height: CHART_HEIGHT
12347
+ }
12348
+ ) }),
12349
+ /* @__PURE__ */ jsx(VbtSummaryRow, { summary: vbtSummary }),
12350
+ /* @__PURE__ */ jsx(SectionCard, { title: "Velocity Breakdown", testID: "exercise-detail-page-velocity", children: /* @__PURE__ */ jsx(VbtBreakdown, { sets: vbt.sets }) })
12351
+ ] })
12352
+ ] })
12353
+ }
12354
+ );
12355
+ }
12356
+ var BRAND_PRIMARY13 = "#FF7900";
12357
+ function countCompletedSets(exercise) {
12358
+ if (exercise.setVelocities != null) return exercise.setVelocities.length;
12359
+ if (exercise.status === "completed") return exercise.totalPlannedSets;
12360
+ return 0;
12361
+ }
12362
+ function deriveWorkoutProgress(exercises) {
12363
+ let completedExercises = 0;
12364
+ let completedSets = 0;
12365
+ let totalSets = 0;
12366
+ for (const exercise of exercises) {
12367
+ if (exercise.status === "completed") completedExercises += 1;
12368
+ completedSets += countCompletedSets(exercise);
12369
+ totalSets += exercise.totalPlannedSets;
12370
+ }
12371
+ return {
12372
+ completedExercises,
12373
+ totalExercises: exercises.length,
12374
+ completedSets,
12375
+ totalSets,
12376
+ fraction: totalSets === 0 ? 0 : completedSets / totalSets
12377
+ };
12378
+ }
12379
+ function findActiveExercise(exercises) {
12380
+ return exercises.find((exercise) => exercise.status === "active") ?? null;
12381
+ }
12382
+ function statusToCardState(status, focused) {
12383
+ if (status === "upcoming") return "upcoming";
12384
+ return focused ? "expanded" : "collapsed";
12385
+ }
12386
+ function toActiveCardProps(exercise, focused, onToggle, supersetPosition = null, supersetColor) {
12387
+ const state = statusToCardState(exercise.status, focused);
12388
+ return {
12389
+ name: exercise.name,
12390
+ state,
12391
+ onToggle,
12392
+ summary: exercise.summary,
12393
+ e1rm: exercise.e1rm,
12394
+ isPR: exercise.isPR,
12395
+ tempo: exercise.tempo,
12396
+ setVelocities: exercise.setVelocities,
12397
+ totalPlannedSets: exercise.totalPlannedSets,
12398
+ sets: state === "expanded" ? exercise.sets : void 0,
12399
+ prescription: exercise.prescription,
12400
+ previousBest: exercise.previousBest,
12401
+ supersetPosition,
12402
+ supersetColor
12403
+ };
12404
+ }
12405
+ function groupExercises(exercises, supersets) {
12406
+ const byId = new Map(supersets.map((superset) => [superset.id, superset]));
12407
+ const groups = [];
12408
+ for (const exercise of exercises) {
12409
+ const superset = exercise.supersetId != null ? byId.get(exercise.supersetId) : void 0;
12410
+ const last = groups[groups.length - 1];
12411
+ if (superset != null && last?.type === "superset" && last.superset.id === superset.id) {
12412
+ last.exercises.push(exercise);
12413
+ } else if (superset != null) {
12414
+ groups.push({ type: "superset", superset, exercises: [exercise] });
12415
+ } else {
12416
+ groups.push({ type: "single", exercise });
12417
+ }
12418
+ }
12419
+ return groups;
12420
+ }
12421
+ function supersetPositionAt(index, length) {
12422
+ if (length === 1) return null;
12423
+ if (index === 0) return "first";
12424
+ if (index === length - 1) return "last";
12425
+ return "middle";
12426
+ }
12427
+ function WorkoutHeader({
12428
+ title,
12429
+ subtitle,
12430
+ progress
12431
+ }) {
12432
+ return /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 10 }, testID: "active-workout-page-header", children: [
12433
+ /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-start justify-between", style: { gap: 8 }, children: [
12434
+ /* @__PURE__ */ jsxs(reactNative.View, { style: { flexShrink: 1 }, children: [
12435
+ /* @__PURE__ */ jsx(
12436
+ reactNative.Text,
12437
+ {
12438
+ accessibilityRole: "header",
12439
+ className: "text-text-primary",
12440
+ style: {
12441
+ fontSize: 20,
12442
+ fontFamily: '"Space Grotesk", sans-serif',
12443
+ fontWeight: "700"
12444
+ },
12445
+ testID: "active-workout-page-title",
12446
+ children: title
12447
+ }
12448
+ ),
12449
+ subtitle != null && /* @__PURE__ */ jsx(
12450
+ reactNative.Text,
12451
+ {
12452
+ className: "text-text-secondary",
12453
+ style: {
12454
+ marginTop: 2,
12455
+ fontSize: 12,
12456
+ fontFamily: "Inter, sans-serif"
12457
+ },
12458
+ testID: "active-workout-page-subtitle",
12459
+ children: subtitle
12460
+ }
12461
+ )
12462
+ ] }),
12463
+ /* @__PURE__ */ jsxs(reactNative.View, { style: { alignItems: "flex-end" }, testID: "active-workout-page-progress-count", children: [
12464
+ /* @__PURE__ */ jsx(
12465
+ reactNative.Text,
11717
12466
  {
11718
- style: { width: 7, height: 7, borderRadius: 9999, backgroundColor: dotColor },
11719
- accessibilityElementsHidden: true,
11720
- testID: `body-map-muscle-dot-${entry.key}`
12467
+ style: {
12468
+ fontSize: 15,
12469
+ fontFamily: '"Space Grotesk", sans-serif',
12470
+ fontWeight: "700",
12471
+ color: BRAND_PRIMARY13,
12472
+ fontVariant: ["tabular-nums"]
12473
+ },
12474
+ children: `${progress.completedExercises}/${progress.totalExercises}`
11721
12475
  }
11722
12476
  ),
11723
12477
  /* @__PURE__ */ jsx(
11724
12478
  reactNative.Text,
11725
12479
  {
12480
+ className: "text-text-tertiary",
11726
12481
  style: {
11727
- fontSize: 11,
12482
+ fontSize: 10,
11728
12483
  fontFamily: "Inter, sans-serif",
11729
- fontWeight: "500",
11730
- color: TEXT_PRIMARY7
12484
+ fontWeight: "600",
12485
+ letterSpacing: 0.4,
12486
+ textTransform: "uppercase"
11731
12487
  },
11732
- accessibilityElementsHidden: true,
11733
- children: entry.name
12488
+ children: `${progress.completedSets}/${progress.totalSets} sets`
11734
12489
  }
11735
12490
  )
11736
- ]
11737
- }
11738
- );
11739
- }
11740
- var SURFACE_ELEVATED = WORKOUT_TOKENS.surface.elevated;
11741
- var SURFACE_RAISED2 = WORKOUT_TOKENS.surface.raised;
11742
- var BORDER_STRONG2 = WORKOUT_TOKENS.border.strong;
11743
- var BORDER_DEFAULT3 = WORKOUT_TOKENS.border.default;
11744
- var BRAND_PRIMARY11 = "#FF7900";
11745
- var TEXT_PRIMARY8 = "#F3F4F6";
11746
- var TEXT_SECONDARY7 = "#9CA3AF";
11747
- var TEXT_TERTIARY7 = "#6B7280";
11748
- var VOLUME_GRADIENT = "linear-gradient(90deg, #2196F3 0%, #14B8A6 50%, #D14343 100%)";
11749
- var SLIDE_OFFSET = 400;
11750
- var BACKDROP_OPACITY = 0.4;
11751
- var STATUS_BADGE_COLOR = {
11752
- under: "info",
11753
- maintenance: "warning",
11754
- productive: "success",
11755
- over: "error"
11756
- };
11757
- function clamp013(value) {
11758
- if (value < 0) return 0;
11759
- if (value > 1) return 1;
11760
- return value;
12491
+ ] })
12492
+ ] }),
12493
+ /* @__PURE__ */ jsx(
12494
+ reactNative.View,
12495
+ {
12496
+ className: "bg-border",
12497
+ style: { height: 4, borderRadius: 2 },
12498
+ testID: "active-workout-page-progress-track",
12499
+ children: /* @__PURE__ */ jsx(
12500
+ reactNative.View,
12501
+ {
12502
+ style: {
12503
+ height: "100%",
12504
+ width: `${Math.round(progress.fraction * 100)}%`,
12505
+ backgroundColor: BRAND_PRIMARY13,
12506
+ borderRadius: 2
12507
+ },
12508
+ testID: "active-workout-page-progress-fill"
12509
+ }
12510
+ )
12511
+ }
12512
+ )
12513
+ ] });
11761
12514
  }
11762
- function markerFraction(weeklySets, { mev, mrv }) {
11763
- const span = mrv - mev;
11764
- if (span <= 0) return weeklySets >= mrv ? 1 : 0;
11765
- return clamp013((weeklySets - mev) / span);
12515
+ function ExerciseList({ groups, focusedId, onToggle }) {
12516
+ return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 10 }, testID: "active-workout-page-exercises", children: groups.map((group) => {
12517
+ if (group.type === "single") {
12518
+ return /* @__PURE__ */ jsx(
12519
+ reactNative.View,
12520
+ {
12521
+ className: "bg-surface-elevated border-border",
12522
+ style: {
12523
+ borderWidth: 1,
12524
+ borderRadius: 12
12525
+ },
12526
+ children: /* @__PURE__ */ jsx(
12527
+ ExerciseCard,
12528
+ {
12529
+ ...toActiveCardProps(
12530
+ group.exercise,
12531
+ group.exercise.id === focusedId,
12532
+ () => onToggle(group.exercise.id)
12533
+ )
12534
+ }
12535
+ )
12536
+ },
12537
+ group.exercise.id
12538
+ );
12539
+ }
12540
+ return /* @__PURE__ */ jsx(
12541
+ SupersetWrapper,
12542
+ {
12543
+ label: group.superset.label,
12544
+ color: group.superset.color,
12545
+ children: group.exercises.map((exercise, index) => /* @__PURE__ */ jsx(
12546
+ ExerciseCard,
12547
+ {
12548
+ ...toActiveCardProps(
12549
+ exercise,
12550
+ exercise.id === focusedId,
12551
+ () => onToggle(exercise.id),
12552
+ supersetPositionAt(index, group.exercises.length),
12553
+ group.superset.color
12554
+ )
12555
+ },
12556
+ exercise.id
12557
+ ))
12558
+ },
12559
+ group.superset.id
12560
+ );
12561
+ }) });
11766
12562
  }
11767
- function BodyMapDetailPanel({
11768
- muscleGroup,
11769
- displayName,
11770
- weeklySets,
11771
- landmarks,
11772
- volumeStatus,
11773
- lastTrained,
11774
- weeklyHistory,
11775
- contributingExercises,
11776
- upcomingExercises,
11777
- isOpen,
11778
- visible,
11779
- onClose,
11780
- onViewExercises,
12563
+ function ActiveWorkoutPage({
12564
+ title = "Active Workout",
12565
+ subtitle,
12566
+ exercises,
12567
+ supersets = [],
12568
+ input,
12569
+ rest,
12570
+ initialResting = false,
12571
+ className,
11781
12572
  ...props
11782
12573
  }) {
11783
- const open = isOpen ?? visible ?? false;
11784
- const [translateY] = React24.useState(() => new reactNative.Animated.Value(SLIDE_OFFSET));
11785
- const [backdrop] = React24.useState(() => new reactNative.Animated.Value(0));
11786
- React24.useEffect(() => {
11787
- if (!open) return;
11788
- const animation = reactNative.Animated.parallel([
11789
- reactNative.Animated.timing(translateY, {
11790
- toValue: 0,
11791
- duration: 400,
11792
- easing: reactNative.Easing.out(reactNative.Easing.ease),
11793
- useNativeDriver: false
11794
- }),
11795
- reactNative.Animated.timing(backdrop, {
11796
- toValue: BACKDROP_OPACITY,
11797
- duration: 300,
11798
- easing: reactNative.Easing.out(reactNative.Easing.ease),
11799
- useNativeDriver: false
11800
- })
11801
- ]);
11802
- animation.start();
11803
- return () => animation.stop();
11804
- }, [open, translateY, backdrop]);
11805
- if (!open) return null;
11806
- const dialogLabel = `${displayName} volume details`;
11807
- const markerLeft = markerFraction(weeklySets, landmarks) * 100;
11808
- const hasContributing = (contributingExercises?.length ?? 0) > 0;
11809
- const hasUpcoming = (upcomingExercises?.length ?? 0) > 0;
12574
+ const active = findActiveExercise(exercises);
12575
+ const [focusedId, setFocusedId] = React24.useState(active?.id ?? null);
12576
+ const [resting, setResting] = React24.useState(initialResting);
12577
+ const [reps, setReps] = React24.useState(input?.reps ?? "");
12578
+ const [weight, setWeight] = React24.useState(input?.weight ?? "");
12579
+ const progress = React24.useMemo(() => deriveWorkoutProgress(exercises), [exercises]);
12580
+ const groups = React24.useMemo(() => groupExercises(exercises, supersets), [exercises, supersets]);
12581
+ const toggleFocus = (id) => setFocusedId((current) => current === id ? null : id);
12582
+ const nextSetNumber = active != null ? countCompletedSets(active) + 1 : 1;
12583
+ const canRecord = reps.trim() !== "" && weight.trim() !== "";
12584
+ const showRest = resting && rest != null;
12585
+ const showInput = !showRest && active != null;
11810
12586
  return /* @__PURE__ */ jsxs(
11811
12587
  reactNative.View,
11812
12588
  {
11813
- style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, justifyContent: "flex-end" },
11814
- testID: "body-map-detail-panel-root",
12589
+ className: ["bg-background-base", className].filter(Boolean).join(" "),
12590
+ style: { position: "relative", width: 390 },
12591
+ accessibilityRole: "main",
12592
+ "aria-label": title,
12593
+ testID: "active-workout-page",
12594
+ ...props,
11815
12595
  children: [
11816
- /* @__PURE__ */ jsx(
11817
- reactNative.Animated.View,
12596
+ /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 16, gap: 14 }, testID: "active-workout-page-content", children: [
12597
+ /* @__PURE__ */ jsx(WorkoutHeader, { title, subtitle, progress }),
12598
+ /* @__PURE__ */ jsx(ExerciseList, { groups, focusedId, onToggle: toggleFocus })
12599
+ ] }),
12600
+ (showRest || showInput) && /* @__PURE__ */ jsx(
12601
+ reactNative.View,
11818
12602
  {
11819
- style: {
11820
- position: "absolute",
11821
- top: 0,
11822
- left: 0,
11823
- right: 0,
11824
- bottom: 0,
11825
- backgroundColor: "#000000",
11826
- opacity: backdrop
11827
- },
11828
- testID: "body-map-detail-panel-backdrop-anim",
11829
- children: /* @__PURE__ */ jsx(
11830
- reactNative.Pressable,
12603
+ style: { borderTopWidth: 1, borderTopColor: resolveColor("border-default") },
12604
+ testID: "active-workout-page-bottom-bar",
12605
+ children: showRest && rest != null ? /* @__PURE__ */ jsx(
12606
+ RestTimer,
11831
12607
  {
11832
- onPress: onClose,
11833
- accessibilityRole: "button",
11834
- accessibilityLabel: `Close ${displayName} details`,
11835
- style: { flex: 1 },
11836
- testID: "body-map-detail-panel-backdrop"
12608
+ totalSeconds: rest.totalSeconds,
12609
+ elapsedMs: rest.elapsedMs,
12610
+ nextSetInfo: rest.nextSetInfo,
12611
+ onSkip: () => setResting(false),
12612
+ onAddTime: () => void 0,
12613
+ visible: true
12614
+ }
12615
+ ) : active != null && /* @__PURE__ */ jsx(
12616
+ InputBar,
12617
+ {
12618
+ exerciseName: active.name,
12619
+ setNumber: nextSetNumber,
12620
+ totalSets: active.totalPlannedSets,
12621
+ reps,
12622
+ weight,
12623
+ unit: active.unit,
12624
+ onRepsChange: setReps,
12625
+ onWeightChange: setWeight,
12626
+ onRecord: () => {
12627
+ if (rest != null) setResting(true);
12628
+ },
12629
+ canRecord,
12630
+ visible: true
11837
12631
  }
11838
12632
  )
11839
12633
  }
11840
- ),
11841
- /* @__PURE__ */ jsxs(
11842
- reactNative.Animated.View,
11843
- {
11844
- accessibilityRole: "dialog",
11845
- accessibilityLabel: dialogLabel,
11846
- "aria-label": dialogLabel,
11847
- style: {
11848
- backgroundColor: SURFACE_ELEVATED,
11849
- borderTopLeftRadius: 16,
11850
- borderTopRightRadius: 16,
11851
- maxHeight: "88%",
11852
- transform: [{ translateY }]
11853
- },
11854
- testID: "body-map-detail-panel",
11855
- ...props,
11856
- children: [
11857
- /* @__PURE__ */ jsx(
11858
- reactNative.Pressable,
11859
- {
11860
- onPress: onClose,
11861
- accessibilityRole: "button",
11862
- accessibilityLabel: `Close ${displayName} details`,
11863
- hitSlop: 12,
11864
- style: { alignSelf: "center", paddingVertical: 8 },
11865
- testID: "body-map-detail-panel-handle",
11866
- children: /* @__PURE__ */ jsx(
11867
- reactNative.View,
11868
- {
11869
- style: { width: 40, height: 4, borderRadius: 2, backgroundColor: BORDER_STRONG2 },
11870
- accessibilityElementsHidden: true
11871
- }
11872
- )
11873
- }
11874
- ),
11875
- /* @__PURE__ */ jsxs(
11876
- reactNative.ScrollView,
11877
- {
11878
- style: { paddingHorizontal: 16 },
11879
- contentContainerStyle: { paddingBottom: 20 },
11880
- testID: "body-map-detail-panel-scroll",
11881
- children: [
11882
- /* @__PURE__ */ jsxs(
11883
- reactNative.View,
11884
- {
11885
- className: "flex-row items-center justify-between",
11886
- style: { gap: 8, paddingTop: 4, paddingBottom: 4 },
11887
- testID: "body-map-detail-panel-header",
11888
- children: [
11889
- /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 8, flexShrink: 1 }, children: [
11890
- /* @__PURE__ */ jsx(
11891
- reactNative.Text,
11892
- {
11893
- accessibilityRole: "header",
11894
- style: {
11895
- fontSize: 16,
11896
- fontFamily: '"Space Grotesk", sans-serif',
11897
- fontWeight: "700",
11898
- color: TEXT_PRIMARY8
11899
- },
11900
- testID: "body-map-detail-panel-title",
11901
- children: displayName
11902
- }
11903
- ),
11904
- /* @__PURE__ */ jsx(
11905
- Badge,
11906
- {
11907
- variant: "subtle",
11908
- color: STATUS_BADGE_COLOR[volumeStatus],
11909
- size: "sm",
11910
- testID: "body-map-detail-panel-status-badge",
11911
- children: VOLUME_STATUS_LABELS[volumeStatus]
11912
- }
11913
- )
11914
- ] }),
11915
- /* @__PURE__ */ jsx(
11916
- reactNative.Pressable,
11917
- {
11918
- onPress: onClose,
11919
- accessibilityRole: "button",
11920
- accessibilityLabel: `Close ${displayName} details`,
11921
- hitSlop: 8,
11922
- style: { padding: 4, margin: -4 },
11923
- testID: "body-map-detail-panel-close",
11924
- children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 22, lineHeight: 22, color: TEXT_SECONDARY7 }, children: "\xD7" })
11925
- }
11926
- )
11927
- ]
11928
- }
11929
- ),
11930
- lastTrained != null && /* @__PURE__ */ jsx(
11931
- reactNative.Text,
11932
- {
11933
- style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY7 },
11934
- testID: "body-map-detail-panel-last-trained",
11935
- children: `Last trained ${lastTrained}`
11936
- }
11937
- ),
11938
- /* @__PURE__ */ jsxs(reactNative.View, { style: { marginTop: 16 }, testID: "body-map-detail-panel-volume", children: [
11939
- /* @__PURE__ */ jsxs(
11940
- reactNative.View,
11941
- {
11942
- className: "flex-row items-center justify-between",
11943
- style: { marginBottom: 6 },
11944
- accessibilityElementsHidden: true,
11945
- children: [
11946
- /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600", color: TEXT_TERTIARY7 }, children: `MEV ${landmarks.mev}` }),
11947
- /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif", fontWeight: "600", color: TEXT_TERTIARY7 }, children: `MRV ${landmarks.mrv}` })
11948
- ]
11949
- }
11950
- ),
11951
- /* @__PURE__ */ jsxs(
11952
- reactNative.View,
11953
- {
11954
- style: { height: 14, justifyContent: "center" },
11955
- accessibilityRole: "progressbar",
11956
- accessibilityValue: { min: landmarks.mev, max: landmarks.mrv, now: weeklySets },
11957
- accessibilityLabel: `${weeklySets} weekly sets, between MEV ${landmarks.mev} and MRV ${landmarks.mrv}`,
11958
- "aria-valuenow": weeklySets,
11959
- "aria-valuemin": landmarks.mev,
11960
- "aria-valuemax": landmarks.mrv,
11961
- testID: "body-map-detail-panel-volume-bar",
11962
- children: [
11963
- /* @__PURE__ */ jsx(
11964
- reactNative.View,
11965
- {
11966
- style: { height: 8, borderRadius: 4, backgroundImage: VOLUME_GRADIENT },
11967
- accessibilityElementsHidden: true
11968
- }
11969
- ),
11970
- /* @__PURE__ */ jsx(
11971
- reactNative.View,
11972
- {
11973
- style: {
11974
- position: "absolute",
11975
- left: `${markerLeft}%`,
11976
- marginLeft: -7,
11977
- width: 14,
11978
- height: 14,
11979
- borderRadius: 7,
11980
- borderWidth: 2,
11981
- borderColor: TEXT_PRIMARY8,
11982
- backgroundColor: SURFACE_ELEVATED,
11983
- boxShadow: "0 0 4px rgba(0,0,0,0.5)"
11984
- },
11985
- accessibilityElementsHidden: true,
11986
- testID: "body-map-detail-panel-volume-marker"
11987
- }
11988
- )
11989
- ]
11990
- }
11991
- )
11992
- ] }),
11993
- /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-baseline", style: { marginTop: 14, gap: 4 }, children: [
11994
- /* @__PURE__ */ jsx(
11995
- reactNative.Text,
11996
- {
11997
- style: {
11998
- fontSize: 24,
11999
- fontFamily: '"Space Grotesk", sans-serif',
12000
- fontWeight: "700",
12001
- color: TEXT_PRIMARY8
12002
- },
12003
- testID: "body-map-detail-panel-set-count",
12004
- children: weeklySets
12005
- }
12006
- ),
12007
- /* @__PURE__ */ jsx(
12008
- reactNative.Text,
12009
- {
12010
- style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY7 },
12011
- testID: "body-map-detail-panel-mrv-suffix",
12012
- children: `/ ${landmarks.mrv} MRV`
12013
- }
12014
- )
12015
- ] }),
12016
- weeklyHistory != null && weeklyHistory.length > 0 && /* @__PURE__ */ jsxs(reactNative.View, { style: { marginTop: 14 }, testID: "body-map-detail-panel-sparkline", children: [
12017
- /* @__PURE__ */ jsx(
12018
- reactNative.Text,
12019
- {
12020
- style: {
12021
- fontSize: 10,
12022
- fontFamily: "Inter, sans-serif",
12023
- fontWeight: "600",
12024
- color: TEXT_TERTIARY7,
12025
- marginBottom: 6
12026
- },
12027
- accessibilityElementsHidden: true,
12028
- children: "VOLUME TREND"
12029
- }
12030
- ),
12031
- /* @__PURE__ */ jsx(Sparkline, { data: weeklyHistory, width: 80, height: 30, highlightLast: true })
12032
- ] }),
12033
- hasContributing && /* @__PURE__ */ jsxs(reactNative.View, { style: { marginTop: 16 }, testID: "body-map-detail-panel-contributing", children: [
12034
- /* @__PURE__ */ jsx(
12035
- reactNative.Text,
12036
- {
12037
- style: {
12038
- fontSize: 10,
12039
- fontFamily: "Inter, sans-serif",
12040
- fontWeight: "600",
12041
- color: TEXT_TERTIARY7,
12042
- marginBottom: 8
12043
- },
12044
- children: "CONTRIBUTING EXERCISES"
12045
- }
12046
- ),
12047
- contributingExercises.map((exercise, index) => /* @__PURE__ */ jsxs(
12048
- reactNative.View,
12049
- {
12050
- className: "flex-row items-center justify-between",
12051
- style: {
12052
- gap: 10,
12053
- paddingVertical: 8,
12054
- paddingHorizontal: 12,
12055
- marginBottom: 6,
12056
- borderRadius: 8,
12057
- backgroundColor: SURFACE_RAISED2,
12058
- borderWidth: 1,
12059
- borderColor: BORDER_DEFAULT3
12060
- },
12061
- testID: `body-map-detail-panel-contributing-${index}`,
12062
- children: [
12063
- /* @__PURE__ */ jsx(
12064
- reactNative.Text,
12065
- {
12066
- style: { flex: 1, fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "600", color: TEXT_PRIMARY8 },
12067
- testID: `body-map-detail-panel-contributing-${index}-name`,
12068
- children: exercise.name
12069
- }
12070
- ),
12071
- /* @__PURE__ */ jsx(
12072
- reactNative.Text,
12073
- {
12074
- style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_SECONDARY7 },
12075
- testID: `body-map-detail-panel-contributing-${index}-detail`,
12076
- children: `${exercise.sets} sets \xB7 ${Math.round(exercise.contributionWeight * 100)}%`
12077
- }
12078
- )
12079
- ]
12080
- },
12081
- `${exercise.name}-${index}`
12082
- ))
12083
- ] }),
12084
- hasUpcoming && /* @__PURE__ */ jsxs(reactNative.View, { style: { marginTop: 16 }, testID: "body-map-detail-panel-upcoming", children: [
12085
- /* @__PURE__ */ jsx(
12086
- reactNative.Text,
12087
- {
12088
- style: {
12089
- fontSize: 10,
12090
- fontFamily: "Inter, sans-serif",
12091
- fontWeight: "600",
12092
- color: TEXT_TERTIARY7,
12093
- marginBottom: 8
12094
- },
12095
- children: "UPCOMING"
12096
- }
12097
- ),
12098
- upcomingExercises.map((exercise, index) => /* @__PURE__ */ jsxs(
12099
- reactNative.View,
12100
- {
12101
- className: "flex-row items-center justify-between",
12102
- style: { gap: 10, paddingVertical: 6 },
12103
- testID: `body-map-detail-panel-upcoming-${index}`,
12104
- children: [
12105
- /* @__PURE__ */ jsx(
12106
- reactNative.Text,
12107
- {
12108
- style: { flex: 1, fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "600", color: TEXT_PRIMARY8 },
12109
- testID: `body-map-detail-panel-upcoming-${index}-name`,
12110
- children: exercise.name
12111
- }
12112
- ),
12113
- /* @__PURE__ */ jsx(
12114
- reactNative.Text,
12115
- {
12116
- style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_TERTIARY7 },
12117
- testID: `body-map-detail-panel-upcoming-${index}-detail`,
12118
- children: `${exercise.workoutName} \xB7 ${exercise.sets} sets`
12119
- }
12120
- )
12121
- ]
12122
- },
12123
- `${exercise.name}-${index}`
12124
- ))
12125
- ] }),
12126
- onViewExercises != null && /* @__PURE__ */ jsx(
12127
- reactNative.Pressable,
12128
- {
12129
- onPress: onViewExercises,
12130
- accessibilityRole: "button",
12131
- accessibilityLabel: `View ${displayName} exercises`,
12132
- style: {
12133
- marginTop: 16,
12134
- paddingVertical: 10,
12135
- borderRadius: 8,
12136
- alignItems: "center",
12137
- backgroundColor: "rgba(255,121,0,0.12)",
12138
- borderWidth: 1,
12139
- borderColor: "rgba(255,121,0,0.3)"
12140
- },
12141
- testID: "body-map-detail-panel-view-exercises",
12142
- children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "700", color: BRAND_PRIMARY11 }, children: "View exercises" })
12143
- }
12144
- )
12145
- ]
12146
- }
12147
- )
12148
- ]
12149
- }
12150
12634
  )
12151
12635
  ]
12152
12636
  }
@@ -12376,28 +12860,28 @@ function Scatter({
12376
12860
  testID: "scatter-canvas",
12377
12861
  style: { position: "absolute", top: 0, left: 0, width, height, overflow: "hidden" },
12378
12862
  children: [
12379
- ticksOf(yd, TICK_COUNT).map((t, i) => {
12380
- const y = toY(t);
12863
+ ticksOf(yd, TICK_COUNT).map((t2, i) => {
12864
+ const y = toY(t2);
12381
12865
  return /* @__PURE__ */ jsx(
12382
12866
  reactNative.View,
12383
12867
  {
12384
12868
  accessibilityElementsHidden: true,
12385
12869
  testID: "scatter-gridline-y",
12386
12870
  style: { position: "absolute", left: PLOT_LEFT2, width: innerW, top: y, height: 1, backgroundColor: GRID_LINE2 },
12387
- children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", left: -PLOT_LEFT2, top: -6, width: PLOT_LEFT2 - 6, textAlign: "right" }, children: formatTick(t) })
12871
+ children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", left: -PLOT_LEFT2, top: -6, width: PLOT_LEFT2 - 6, textAlign: "right" }, children: formatTick(t2) })
12388
12872
  },
12389
12873
  `y-${i}`
12390
12874
  );
12391
12875
  }),
12392
- ticksOf(xd, TICK_COUNT).map((t, i) => {
12393
- const x = toX(t);
12876
+ ticksOf(xd, TICK_COUNT).map((t2, i) => {
12877
+ const x = toX(t2);
12394
12878
  return /* @__PURE__ */ jsx(
12395
12879
  reactNative.View,
12396
12880
  {
12397
12881
  accessibilityElementsHidden: true,
12398
12882
  testID: "scatter-gridline-x",
12399
12883
  style: { position: "absolute", top: PLOT_TOP, height: innerH, left: x, width: 1, backgroundColor: GRID_LINE2 },
12400
- children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", top: innerH + 4, left: -16, width: 32, textAlign: "center" }, children: formatTick(t) })
12884
+ children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", top: innerH + 4, left: -16, width: 32, textAlign: "center" }, children: formatTick(t2) })
12401
12885
  },
12402
12886
  `x-${i}`
12403
12887
  );
@@ -12469,7 +12953,7 @@ var DEFAULT_THRESHOLDS = [
12469
12953
  var ARC_START = 135;
12470
12954
  var ARC_SWEEP = 270;
12471
12955
  var SEGMENTS = 40;
12472
- function clamp014(n) {
12956
+ function clamp013(n) {
12473
12957
  if (Number.isNaN(n)) return 0;
12474
12958
  return Math.max(0, Math.min(1, n));
12475
12959
  }
@@ -12514,7 +12998,7 @@ function Gauge2({
12514
12998
  ...props
12515
12999
  }) {
12516
13000
  const span = max - min || 1;
12517
- const fill = clamp014((value - min) / span);
13001
+ const fill = clamp013((value - min) / span);
12518
13002
  const activeColor = (f) => color ?? bandColor(f, thresholds, min, max);
12519
13003
  const ticks = buildTicks(fill, size, activeColor);
12520
13004
  const displayColor = color ?? bandColor(fill, thresholds, min, max);
@@ -12531,23 +13015,23 @@ function Gauge2({
12531
13015
  testID: "gauge",
12532
13016
  ...props,
12533
13017
  children: [
12534
- ticks.map((t) => /* @__PURE__ */ jsx(
13018
+ ticks.map((t2) => /* @__PURE__ */ jsx(
12535
13019
  reactNative.View,
12536
13020
  {
12537
13021
  accessibilityElementsHidden: true,
12538
13022
  testID: "gauge-segment",
12539
13023
  style: {
12540
13024
  position: "absolute",
12541
- left: t.left - tickThickness / 2,
12542
- top: t.top - tickLength / 2,
13025
+ left: t2.left - tickThickness / 2,
13026
+ top: t2.top - tickLength / 2,
12543
13027
  width: tickThickness,
12544
13028
  height: tickLength,
12545
13029
  borderRadius: tickThickness / 2,
12546
- backgroundColor: t.color,
12547
- transform: [{ rotate: t.rotate }]
13030
+ backgroundColor: t2.color,
13031
+ transform: [{ rotate: t2.rotate }]
12548
13032
  }
12549
13033
  },
12550
- t.key
13034
+ t2.key
12551
13035
  )),
12552
13036
  /* @__PURE__ */ jsxs(reactNative.View, { style: { position: "absolute", top: 0, left: 0, width: size, height: size }, className: "items-center justify-center", children: [
12553
13037
  /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-baseline gap-0.5", children: [
@@ -12561,65 +13045,6 @@ function Gauge2({
12561
13045
  );
12562
13046
  }
12563
13047
 
12564
- // src/utils/colors.ts
12565
- function getStatusColor(status) {
12566
- return `var(--color-status-${status})`;
12567
- }
12568
- function getResultColor(result) {
12569
- return `var(--color-result-${result})`;
12570
- }
12571
- function alpha(color, opacity) {
12572
- const clampedOpacity = Math.max(0, Math.min(1, opacity));
12573
- if (color.startsWith("#")) {
12574
- const hex = color.slice(1);
12575
- let r, g, b;
12576
- if (hex.length === 3) {
12577
- r = parseInt(hex[0] + hex[0], 16);
12578
- g = parseInt(hex[1] + hex[1], 16);
12579
- b = parseInt(hex[2] + hex[2], 16);
12580
- } else if (hex.length === 6) {
12581
- r = parseInt(hex.slice(0, 2), 16);
12582
- g = parseInt(hex.slice(2, 4), 16);
12583
- b = parseInt(hex.slice(4, 6), 16);
12584
- } else {
12585
- return color;
12586
- }
12587
- return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
12588
- }
12589
- const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
12590
- if (rgbMatch) {
12591
- const [, r, g, b] = rgbMatch;
12592
- return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
12593
- }
12594
- const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
12595
- if (rgbaMatch) {
12596
- const [, r, g, b] = rgbaMatch;
12597
- return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
12598
- }
12599
- return color;
12600
- }
12601
- function getLuminance(color) {
12602
- if (!color.startsWith("#")) return "dark";
12603
- const hex = color.slice(1);
12604
- let r, g, b;
12605
- if (hex.length === 3) {
12606
- r = parseInt(hex[0] + hex[0], 16);
12607
- g = parseInt(hex[1] + hex[1], 16);
12608
- b = parseInt(hex[2] + hex[2], 16);
12609
- } else if (hex.length === 6) {
12610
- r = parseInt(hex.slice(0, 2), 16);
12611
- g = parseInt(hex.slice(2, 4), 16);
12612
- b = parseInt(hex.slice(4, 6), 16);
12613
- } else {
12614
- return "dark";
12615
- }
12616
- const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
12617
- return luminance > 0.5 ? "light" : "dark";
12618
- }
12619
- function getContrastText(backgroundColor) {
12620
- return getLuminance(backgroundColor) === "light" ? "#000000" : "#FFFFFF";
12621
- }
12622
-
12623
13048
  // src/utils/form.ts
12624
13049
  function getFieldValidationProps(state) {
12625
13050
  return {
@@ -12712,6 +13137,7 @@ exports.Accordion = Accordion;
12712
13137
  exports.AccordionButton = AccordionButton;
12713
13138
  exports.AccordionItem = AccordionItem;
12714
13139
  exports.AccordionPanel = AccordionPanel;
13140
+ exports.ActiveWorkoutPage = ActiveWorkoutPage;
12715
13141
  exports.Alert = Alert;
12716
13142
  exports.AlertDescription = AlertDescription;
12717
13143
  exports.AlertTitle = AlertTitle;
@@ -12722,8 +13148,6 @@ exports.AvatarGroup = AvatarGroup;
12722
13148
  exports.Badge = Badge;
12723
13149
  exports.BadgeText = BadgeText;
12724
13150
  exports.BaseBadge = BaseBadge;
12725
- exports.BodyMap = BodyMap;
12726
- exports.BodyMapDetailPanel = BodyMapDetailPanel;
12727
13151
  exports.BreadcrumbItem = BreadcrumbItem;
12728
13152
  exports.Breadcrumbs = Breadcrumbs;
12729
13153
  exports.Button = Button;
@@ -12746,8 +13170,6 @@ exports.CircularProgress = CircularProgress;
12746
13170
  exports.Collapse = Collapse;
12747
13171
  exports.CollapseButton = CollapseButton;
12748
13172
  exports.CollapseContent = CollapseContent;
12749
- exports.DEFAULT_VOLUME_LANDMARKS = DEFAULT_VOLUME_LANDMARKS;
12750
- exports.DETAILED_TO_SIMPLE = DETAILED_TO_SIMPLE;
12751
13173
  exports.DataRow = DataRow;
12752
13174
  exports.DateTime = DateTime;
12753
13175
  exports.DeviationBar = DeviationBar;
@@ -12756,8 +13178,10 @@ exports.Drawer = Drawer;
12756
13178
  exports.DrawerBody = DrawerBody;
12757
13179
  exports.DrawerFooter = DrawerFooter;
12758
13180
  exports.DrawerHeader = DrawerHeader;
13181
+ exports.EXERCISE_DETAIL_TABS = EXERCISE_DETAIL_TABS;
12759
13182
  exports.EmptyState = EmptyState;
12760
13183
  exports.ExerciseCard = ExerciseCard;
13184
+ exports.ExerciseDetailPage = ExerciseDetailPage;
12761
13185
  exports.FormActions = FormActions;
12762
13186
  exports.FormField = FormField;
12763
13187
  exports.FormRow = FormRow;
@@ -12780,9 +13204,6 @@ exports.ListItemContent = ListItemContent;
12780
13204
  exports.ListItemDivider = ListItemDivider;
12781
13205
  exports.ListItemIcon = ListItemIcon;
12782
13206
  exports.ListItemTrailing = ListItemTrailing;
12783
- exports.MUSCLE_DISPLAY_NAMES = MUSCLE_DISPLAY_NAMES;
12784
- exports.MUSCLE_TO_CATEGORY = MUSCLE_TO_CATEGORY;
12785
- exports.MUSCLE_TO_SVG_SLUGS = MUSCLE_TO_SVG_SLUGS;
12786
13207
  exports.Menu = Menu;
12787
13208
  exports.MenuDivider = MenuDivider;
12788
13209
  exports.MenuGroup = MenuGroup;
@@ -12801,7 +13222,6 @@ exports.ModalContent = ModalContent;
12801
13222
  exports.ModalFooter = ModalFooter;
12802
13223
  exports.ModalHeader = ModalHeader;
12803
13224
  exports.ModalTitle = ModalTitle;
12804
- exports.MuscleGroup = MuscleGroup;
12805
13225
  exports.MuscleGroupChip = MuscleGroupChip;
12806
13226
  exports.Overline = Overline;
12807
13227
  exports.Paragraph = Paragraph;
@@ -12814,14 +13234,13 @@ exports.PopoverContent = PopoverContent;
12814
13234
  exports.PopoverTrigger = PopoverTrigger;
12815
13235
  exports.PrBadge = PrBadge;
12816
13236
  exports.PrHistoryModal = PrHistoryModal;
13237
+ exports.ProgramPlanningPage = ProgramPlanningPage;
12817
13238
  exports.Progress = Progress;
12818
13239
  exports.ProgressSteps = ProgressSteps;
12819
13240
  exports.Radio = Radio;
12820
13241
  exports.RadioGroup = RadioGroup;
12821
13242
  exports.ReadinessCheck = ReadinessCheck;
12822
13243
  exports.RestTimer = RestTimer;
12823
- exports.SIMPLE_DISPLAY_NAMES = SIMPLE_DISPLAY_NAMES;
12824
- exports.SIMPLE_TO_DETAILED = SIMPLE_TO_DETAILED;
12825
13244
  exports.Scatter = Scatter;
12826
13245
  exports.Section = Section;
12827
13246
  exports.SectionContent = SectionContent;
@@ -12835,7 +13254,6 @@ exports.SidebarFooter = SidebarFooter;
12835
13254
  exports.SidebarHeader = SidebarHeader;
12836
13255
  exports.SidebarItem = SidebarItem;
12837
13256
  exports.SidebarSection = SidebarSection;
12838
- exports.SimpleMuscleGroup = SimpleMuscleGroup;
12839
13257
  exports.Skeleton = Skeleton;
12840
13258
  exports.SkeletonCard = SkeletonCard;
12841
13259
  exports.SkeletonCircle = SkeletonCircle;
@@ -12854,6 +13272,7 @@ exports.StrengthTrendChart = StrengthTrendChart;
12854
13272
  exports.SupersetWrapper = SupersetWrapper;
12855
13273
  exports.Surface = Surface;
12856
13274
  exports.Switch = Switch;
13275
+ exports.TEMPO_PACING = TEMPO_PACING;
12857
13276
  exports.Tab = Tab;
12858
13277
  exports.TabList = TabList;
12859
13278
  exports.TabPanel = TabPanel;
@@ -12866,7 +13285,9 @@ exports.TableHeaderCell = TableHeaderCell;
12866
13285
  exports.TablePagination = TablePagination;
12867
13286
  exports.TableRow = TableRow;
12868
13287
  exports.Tabs = Tabs;
13288
+ exports.TempoBar = TempoBar;
12869
13289
  exports.TempoDisplay = TempoDisplay;
13290
+ exports.ThemeProvider = ThemeProvider;
12870
13291
  exports.Toast = Toast;
12871
13292
  exports.ToastProvider = ToastProvider;
12872
13293
  exports.ToolbarButton = ToolbarButton;
@@ -12874,7 +13295,6 @@ exports.ToolbarButtonGroup = ToolbarButtonGroup;
12874
13295
  exports.Tooltip = Tooltip;
12875
13296
  exports.Treemap = Treemap;
12876
13297
  exports.Typography = Typography;
12877
- exports.VOLUME_STATUS_LABELS = VOLUME_STATUS_LABELS;
12878
13298
  exports.VStack = VStack;
12879
13299
  exports.VelocityStrip = VelocityStrip;
12880
13300
  exports.WeekRow = WeekRow;
@@ -12884,12 +13304,14 @@ exports.WorkoutPill = WorkoutPill;
12884
13304
  exports.alpha = alpha;
12885
13305
  exports.applyThemePreset = applyThemePreset;
12886
13306
  exports.audiobookPreset = audiobookPreset;
13307
+ exports.buildBreadcrumbs = buildBreadcrumbs;
12887
13308
  exports.buttonSizes = buttonSizes;
12888
13309
  exports.calculateMeanVelocity = calculateMeanVelocity;
12889
13310
  exports.calculateVelocityLoss = calculateVelocityLoss;
12890
13311
  exports.cn = cn;
12891
13312
  exports.componentElevationRanges = componentElevationRanges;
12892
13313
  exports.composeValidators = composeValidators;
13314
+ exports.countCompletedSets = countCompletedSets;
12893
13315
  exports.createFieldId = createFieldId;
12894
13316
  exports.createFlatShadow = createFlatShadow;
12895
13317
  exports.createPressedHoverShadow = createPressedHoverShadow;
@@ -12899,9 +13321,19 @@ exports.createRaisedShadow = createRaisedShadow;
12899
13321
  exports.darkThemeCSSVars = darkThemeCSSVars;
12900
13322
  exports.darken = darken;
12901
13323
  exports.defaultPreset = defaultPreset;
13324
+ exports.deriveExerciseStats = deriveExerciseStats;
13325
+ exports.deriveNavLevel = deriveNavLevel;
13326
+ exports.deriveWorkoutProgress = deriveWorkoutProgress;
12902
13327
  exports.discreteRainbow = discreteRainbow;
12903
13328
  exports.elevationSystem = elevationSystem;
13329
+ exports.findActiveExercise = findActiveExercise;
13330
+ exports.findMeso = findMeso;
13331
+ exports.findWeek = findWeek;
13332
+ exports.findWorkout = findWorkout;
12904
13333
  exports.formatDateTime = formatDateTime;
13334
+ exports.formatPrescription = formatPrescription;
13335
+ exports.formatSignedPct = formatSignedPct;
13336
+ exports.formatVelocity = formatVelocity;
12905
13337
  exports.getBaseSurfaceColor = getBaseSurfaceColor;
12906
13338
  exports.getContrastText = getContrastText;
12907
13339
  exports.getDiscreteRainbowColor = getDiscreteRainbowColor;
@@ -12911,17 +13343,19 @@ exports.getElevationSurface = getElevationSurface;
12911
13343
  exports.getFieldAriaProps = getFieldAriaProps;
12912
13344
  exports.getFieldValidationProps = getFieldValidationProps;
12913
13345
  exports.getGlowShadow = getGlowShadow;
12914
- exports.getHeatmapColor = getHeatmapColor;
12915
13346
  exports.getHoverColors = getHoverColors;
12916
13347
  exports.getLuminance = getLuminance;
12917
13348
  exports.getResultColor = getResultColor;
12918
13349
  exports.getSemanticColors = getSemanticColors;
12919
13350
  exports.getStatusColor = getStatusColor;
13351
+ exports.getTempoFillPct = getTempoFillPct;
13352
+ exports.getTempoPacingState = getTempoPacingState;
12920
13353
  exports.getThemeCSSVars = getThemeCSSVars;
12921
13354
  exports.getValidatedElevation = getValidatedElevation;
12922
13355
  exports.getVelocityZoneColor = getVelocityZoneColor;
12923
13356
  exports.getVelocityZoneName = getVelocityZoneName;
12924
13357
  exports.gluestackConfig = gluestackConfig;
13358
+ exports.groupExercises = groupExercises;
12925
13359
  exports.hasMaxLength = hasMaxLength;
12926
13360
  exports.hasMinLength = hasMinLength;
12927
13361
  exports.hexToRgb = hexToRgb;
@@ -12940,12 +13374,22 @@ exports.primitiveShadows = primitiveShadows;
12940
13374
  exports.primitiveSpacing = primitiveSpacing;
12941
13375
  exports.primitiveTypography = primitiveTypography;
12942
13376
  exports.primitiveZIndex = primitiveZIndex;
13377
+ exports.resolveColor = resolveColor;
12943
13378
  exports.rgbToHex = rgbToHex;
12944
13379
  exports.rgbToHsv = rgbToHsv;
13380
+ exports.roundRpe = roundRpe;
13381
+ exports.roundTempo = roundTempo;
13382
+ exports.roundWeight = roundWeight;
13383
+ exports.rpeColor = rpeColor;
12945
13384
  exports.semanticColorsDark = semanticColorsDark;
12946
13385
  exports.semanticColorsLight = semanticColorsLight;
12947
13386
  exports.semanticTypography = semanticTypography;
12948
13387
  exports.shadowColors = shadowColors;
13388
+ exports.statusToCardState = statusToCardState;
13389
+ exports.summarizeVbt = summarizeVbt;
13390
+ exports.toActiveCardProps = toActiveCardProps;
13391
+ exports.toExerciseCardProps = toExerciseCardProps;
13392
+ exports.toProgressBarMesos = toProgressBarMesos;
12949
13393
  exports.useTable = useTable;
12950
13394
  exports.useToast = useToast;
12951
13395
  exports.useToolbarButton = useToolbarButton;