@titan-design/react-ui 0.8.0 → 0.9.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 (34) hide show
  1. package/dist/index.d.mts +19 -59
  2. package/dist/index.d.ts +19 -59
  3. package/dist/index.js +248 -371
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +249 -368
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/{pages-DCFBqp79.d.mts → pages-D7hOD4Vj.d.mts} +1 -1
  8. package/dist/{pages-_fI3-x7Z.d.ts → pages-DyEx-lBf.d.ts} +1 -1
  9. package/dist/pages.d.mts +1 -1
  10. package/dist/pages.d.ts +1 -1
  11. package/dist/pages.js +199 -161
  12. package/dist/pages.js.map +1 -1
  13. package/dist/pages.mjs +199 -161
  14. package/dist/pages.mjs.map +1 -1
  15. package/package.json +1 -1
  16. package/src/components/custom/Workout/ExerciseIndicator.tsx +1 -1
  17. package/src/components/custom/Workout/README.md +33 -13
  18. package/src/components/custom/Workout/SetsRepsLoad.test.tsx +6 -0
  19. package/src/components/custom/Workout/SetsRepsLoad.tsx +15 -6
  20. package/src/components/custom/Workout/TempoDisplay.stories.tsx +240 -65
  21. package/src/components/custom/Workout/TempoDisplay.test.tsx +61 -16
  22. package/src/components/custom/Workout/TempoDisplay.tsx +173 -60
  23. package/src/components/custom/Workout/VelocityStrip.test.tsx +3 -3
  24. package/src/components/custom/Workout/VelocityStrip.tsx +45 -11
  25. package/src/components/custom/Workout/ZoneTrack.tsx +15 -1
  26. package/src/components/custom/Workout/index.ts +1 -9
  27. package/src/lab/north-star/LivePage.tsx +101 -0
  28. package/src/lab/north-star/LiveView.tsx +409 -0
  29. package/src/lab/north-star/LiveWallDashboard.stories.tsx +129 -0
  30. package/src/lab/north-star/RestView.tsx +140 -0
  31. package/src/lab/north-star/fixtures.ts +224 -0
  32. package/src/components/custom/Workout/TempoBar.stories.tsx +0 -164
  33. package/src/components/custom/Workout/TempoBar.test.tsx +0 -218
  34. package/src/components/custom/Workout/TempoBar.tsx +0 -300
package/dist/pages.mjs CHANGED
@@ -76,6 +76,7 @@ var primitiveRamps = {
76
76
  500: "#22A444",
77
77
  600: "#298732"},
78
78
  cyan: {
79
+ 300: "#22D3EE",
79
80
  // pin
80
81
  400: "#01B5D1",
81
82
  500: "#2697B7",
@@ -90,6 +91,7 @@ var primitiveRamps = {
90
91
  // pin
91
92
  600: "#1072CB"},
92
93
  magenta: {
94
+ 400: "#ED69C3",
93
95
  600: "#BA2996"}
94
96
  };
95
97
  var sequentialEffort = [
@@ -609,13 +611,15 @@ var BARE_STUB_HEIGHT = 3;
609
611
  var HERO_HEIGHT = 220;
610
612
  var HERO_LABEL_HEADROOM = 20;
611
613
  var HERO_BAR_GAP = 8;
612
- var HERO_BAR_MAX_WIDTH = 52;
614
+ var HERO_BAR_MAX_WIDTH = 120;
615
+ var HERO_LABEL_MIN_BAR_WIDTH = 30;
613
616
  var HERO_BAR_RADIUS = 5;
614
617
  var HERO_MIN_BAR_HEIGHT = 4;
615
618
  var HERO_PENDING_COLOR = primitiveColors.charcoal[100];
616
619
  var HERO_REFERENCE_COLOR = primitiveColors.charcoal[0];
620
+ var PEAK_HEADROOM = 1.06;
617
621
  function scaleDenominator(scale, maxVelocity) {
618
- return scale === "fixed" ? FIXED_MAX_VELOCITY : maxVelocity * 1.15;
622
+ return scale === "fixed" ? FIXED_MAX_VELOCITY : maxVelocity * PEAK_HEADROOM;
619
623
  }
620
624
  function bareSlotHeight(slot, height, denom) {
621
625
  if (slot.kind !== "rep" || denom <= 0) return BARE_STUB_HEIGHT;
@@ -692,10 +696,21 @@ function HeroVelocityChart({
692
696
  }) {
693
697
  const liveVelocity = liveRepIndex != null ? doneVelocities[liveRepIndex] : void 0;
694
698
  const liveScale = useLiveRepPop(true, liveRepIndex, liveVelocity, isNewPeak);
699
+ const [plotW, setPlotW] = useState(0);
700
+ const onPlotLayout = (e) => setPlotW(e.nativeEvent.layout.width);
695
701
  const plotHeight = Math.max(0, height - HERO_LABEL_HEADROOM);
696
702
  const barHeight = (velocity) => scaleDenom > 0 ? Math.max(HERO_MIN_BAR_HEIGHT, Math.min(1, velocity / scaleDenom) * plotHeight) : HERO_MIN_BAR_HEIGHT;
697
703
  const pendingCount = Math.max(0, (targetReps ?? 0) - doneVelocities.length);
698
704
  const referencePx = referenceVelocity > 0 && scaleDenom > 0 ? Math.min(plotHeight, referenceVelocity / scaleDenom * plotHeight) : 0;
705
+ const totalSlots = doneVelocities.length + pendingCount;
706
+ const barWidth = plotW > 0 && totalSlots > 0 ? Math.min(HERO_BAR_MAX_WIDTH, (plotW - HERO_BAR_GAP * (totalSlots - 1)) / totalSlots) : HERO_BAR_MAX_WIDTH;
707
+ const labelsCrowded = plotW > 0 && barWidth < HERO_LABEL_MIN_BAR_WIDTH;
708
+ const heroGap = plotW === 0 ? HERO_BAR_GAP : barWidth < 16 ? 2 : barWidth < 28 ? 4 : HERO_BAR_GAP;
709
+ const peakIndex = doneVelocities.reduce(
710
+ (best, v, i) => v > doneVelocities[best] ? i : best,
711
+ 0
712
+ );
713
+ const showBarLabel = (i) => !labelsCrowded || i === peakIndex || i === liveRepIndex;
699
714
  const repCount = doneVelocities.length;
700
715
  const total = Math.max(repCount, targetReps ?? repCount);
701
716
  const label = referenceVelocity > 0 ? `Velocity chart, ${repCount} of ${total} reps, best ${formatVelocity(referenceVelocity)} meters per second` : `Velocity chart, ${repCount} of ${total} reps`;
@@ -712,11 +727,12 @@ function HeroVelocityChart({
712
727
  children: /* @__PURE__ */ jsxs(
713
728
  View,
714
729
  {
730
+ onLayout: onPlotLayout,
715
731
  style: {
716
732
  flex: 1,
717
733
  flexDirection: "row",
718
734
  alignItems: "flex-end",
719
- gap: HERO_BAR_GAP,
735
+ gap: heroGap,
720
736
  position: "relative",
721
737
  borderBottomWidth: 2,
722
738
  borderBottomColor: HERO_PENDING_COLOR
@@ -753,7 +769,7 @@ function HeroVelocityChart({
753
769
  justifyContent: "flex-end"
754
770
  },
755
771
  children: [
756
- /* @__PURE__ */ jsx(
772
+ showBarLabel(i) && /* @__PURE__ */ jsx(
757
773
  Text,
758
774
  {
759
775
  className: "text-text-primary",
@@ -1952,6 +1968,7 @@ function SetsRepsLoad({
1952
1968
  reps,
1953
1969
  load,
1954
1970
  unit = "lb",
1971
+ fontSize,
1955
1972
  className,
1956
1973
  ...props
1957
1974
  }) {
@@ -1966,12 +1983,12 @@ function SetsRepsLoad({
1966
1983
  testID: "sets-reps-load",
1967
1984
  ...props,
1968
1985
  children: [
1969
- /* @__PURE__ */ jsx(MetricCell, { color: value, children: sets }),
1970
- /* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${TIMES} ` }),
1971
- /* @__PURE__ */ jsx(MetricCell, { color: value, children: reps }),
1972
- /* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${AT} ` }),
1973
- /* @__PURE__ */ jsx(MetricCell, { color: value, children: load }),
1974
- /* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${unit}` })
1986
+ /* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: sets }),
1987
+ /* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children: ` ${TIMES} ` }),
1988
+ /* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: reps }),
1989
+ /* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children: ` ${AT} ` }),
1990
+ /* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: load }),
1991
+ /* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children: ` ${unit}` })
1975
1992
  ]
1976
1993
  }
1977
1994
  );
@@ -2285,36 +2302,34 @@ function alpha(color, opacity) {
2285
2302
  }
2286
2303
  return color;
2287
2304
  }
2305
+
2306
+ // src/components/custom/Workout/TempoDisplay.tsx
2288
2307
  var t2 = getSemanticColors("dark");
2289
- var TEMPO_PACING = {
2290
- behindThresholdPct: 0.15,
2291
- minPhaseDurationMs: 500
2292
- };
2293
- function getTempoPacingState(elapsedMs, targetMs) {
2294
- if (!targetMs || targetMs < TEMPO_PACING.minPhaseDurationMs) return "none";
2295
- const ratio = elapsedMs / targetMs;
2296
- if (ratio > 1 + TEMPO_PACING.behindThresholdPct) return "behind";
2297
- return "on-pace";
2298
- }
2308
+ var INTER = "Inter, sans-serif";
2309
+ var TEXT_TERTIARY = "#6B7280";
2310
+ var STATUS_ERROR = t2["status-error"];
2311
+ var STATUS_SUCCESS = t2["status-success"];
2312
+ var STATUS_WARNING = t2["status-warning"];
2313
+ var ON_TARGET_MS = 100;
2299
2314
  function getTempoFillPct(elapsedMs, targetMs) {
2300
2315
  if (!targetMs) return 100;
2301
2316
  return Math.min(100, elapsedMs / targetMs * 100);
2302
2317
  }
2303
- ({
2304
- concentric: { color: t2["status-success"]},
2305
- hold: { color: t2["brand-primary"]},
2306
- eccentric: { color: t2["status-warning"]}
2307
- });
2308
-
2309
- // src/components/custom/Workout/TempoDisplay.tsx
2310
- var t3 = getSemanticColors("dark");
2311
- var INTER = "Inter, sans-serif";
2312
- var TEXT_TERTIARY = "#6B7280";
2313
- var STATUS_ERROR = t3["status-error"];
2318
+ function activeNumberTone(elapsedMs, targetMs) {
2319
+ if (targetMs == null) return t2["text-primary"];
2320
+ const remainingMs = targetMs - elapsedMs;
2321
+ if (remainingMs > ON_TARGET_MS) return STATUS_WARNING;
2322
+ if (remainingMs >= -ON_TARGET_MS) return STATUS_SUCCESS;
2323
+ return STATUS_ERROR;
2324
+ }
2325
+ function liveReadoutText(elapsedMs, targetMs, readout) {
2326
+ const seconds = readout === "countup" ? elapsedMs / 1e3 : (targetMs - elapsedMs) / 1e3;
2327
+ return seconds.toFixed(1);
2328
+ }
2314
2329
  var phaseColors = {
2315
- eccentric: t3["status-warning"],
2330
+ eccentric: primitiveRamps.magenta[400],
2316
2331
  pauseBottom: TEXT_TERTIARY,
2317
- concentric: t3["status-success"],
2332
+ concentric: primitiveRamps.cyan[300],
2318
2333
  pauseTop: TEXT_TERTIARY,
2319
2334
  dash: TEXT_TERTIARY
2320
2335
  };
@@ -2334,63 +2349,98 @@ var LIVE_PHASES = [
2334
2349
  { key: "concentric", color: phaseColors.concentric },
2335
2350
  { key: "pauseTop", color: phaseColors.pauseTop }
2336
2351
  ];
2352
+ function CellFill({ color, pct }) {
2353
+ return /* @__PURE__ */ jsx(
2354
+ View,
2355
+ {
2356
+ style: {
2357
+ position: "absolute",
2358
+ left: 2,
2359
+ right: 2,
2360
+ bottom: 0,
2361
+ height: `${pct}%`,
2362
+ backgroundColor: alpha(color, 0.28),
2363
+ borderRadius: 3
2364
+ }
2365
+ }
2366
+ );
2367
+ }
2368
+ var MONO = "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace";
2369
+ var READOUT_MAX_CHARS = 5;
2337
2370
  function LiveTempoCell({
2338
2371
  value,
2339
2372
  color,
2340
- isActive,
2373
+ status,
2341
2374
  phaseElapsedMs,
2342
- fontSize
2375
+ completedMs,
2376
+ fontSize,
2377
+ readout
2343
2378
  }) {
2344
- if (!isActive) {
2345
- return /* @__PURE__ */ jsx(TempoValue, { value, color: alpha(color, 0.35), fontSize });
2346
- }
2347
2379
  const targetMs = value > 0 ? value * 1e3 : null;
2348
- const barColor = getTempoPacingState(phaseElapsedMs, targetMs) === "behind" ? STATUS_ERROR : color;
2380
+ const cellW = Math.ceil(fontSize * 0.62 * READOUT_MAX_CHARS);
2381
+ const wrap = {
2382
+ position: "relative",
2383
+ width: cellW,
2384
+ minHeight: Math.round(fontSize * 1.25),
2385
+ alignItems: "center",
2386
+ justifyContent: "center"
2387
+ };
2388
+ const num = (c, text) => /* @__PURE__ */ jsx(Text, { style: { fontFamily: MONO, fontSize, color: c, fontWeight: "700" }, children: text });
2389
+ if (status === "upcoming") {
2390
+ const targetText = targetMs != null ? (targetMs / 1e3).toFixed(1) : String(value);
2391
+ return /* @__PURE__ */ jsx(View, { style: wrap, children: num(color, targetText) });
2392
+ }
2393
+ if (status === "done") {
2394
+ const finalMs = completedMs ?? targetMs ?? 0;
2395
+ const finalText = targetMs != null ? liveReadoutText(finalMs, targetMs, readout) : String(value);
2396
+ const finalTone = targetMs != null ? activeNumberTone(finalMs, targetMs) : color;
2397
+ return /* @__PURE__ */ jsxs(View, { style: wrap, testID: "tempo-live-done", children: [
2398
+ /* @__PURE__ */ jsx(CellFill, { color, pct: 100 }),
2399
+ num(finalTone, finalText)
2400
+ ] });
2401
+ }
2402
+ const numberTone = activeNumberTone(phaseElapsedMs, targetMs);
2349
2403
  const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
2350
- return /* @__PURE__ */ jsxs(View, { style: { position: "relative" }, testID: "tempo-live-active", children: [
2351
- /* @__PURE__ */ jsx(
2352
- View,
2353
- {
2354
- style: {
2355
- position: "absolute",
2356
- left: 0,
2357
- top: 0,
2358
- bottom: 0,
2359
- width: `${fillPct}%`,
2360
- backgroundColor: alpha(barColor, 0.3),
2361
- borderRadius: 2
2362
- }
2363
- }
2364
- ),
2365
- /* @__PURE__ */ jsx(TempoValue, { value, color: barColor, fontSize })
2404
+ const activeText = targetMs != null ? liveReadoutText(phaseElapsedMs, targetMs, readout) : String(value);
2405
+ return /* @__PURE__ */ jsxs(View, { style: wrap, testID: "tempo-live-active", children: [
2406
+ /* @__PURE__ */ jsx(CellFill, { color, pct: fillPct }),
2407
+ num(numberTone, activeText)
2366
2408
  ] });
2367
2409
  }
2368
2410
  function LiveTempoRow({
2369
2411
  values,
2370
2412
  live,
2371
- fontSize
2413
+ fontSize,
2414
+ readout
2372
2415
  }) {
2373
- return /* @__PURE__ */ jsx(Fragment, { children: LIVE_PHASES.map((phase, i) => /* @__PURE__ */ jsxs(View, { style: { flexDirection: "row" }, children: [
2374
- i > 0 && /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
2375
- /* @__PURE__ */ jsx(
2376
- LiveTempoCell,
2377
- {
2378
- value: values[i],
2379
- color: phase.color,
2380
- isActive: live.activePhase === phase.key,
2381
- phaseElapsedMs: live.phaseElapsedMs,
2382
- fontSize
2383
- }
2384
- )
2385
- ] }, phase.key)) });
2416
+ const activeIndex = live.activePhase ? LIVE_PHASES.findIndex((p) => p.key === live.activePhase) : -1;
2417
+ return /* @__PURE__ */ jsx(Fragment, { children: LIVE_PHASES.map((phase, i) => {
2418
+ const status = activeIndex < 0 || i > activeIndex ? "upcoming" : i < activeIndex ? "done" : "active";
2419
+ return /* @__PURE__ */ jsxs(View, { style: { flexDirection: "row", alignItems: "center" }, children: [
2420
+ i > 0 && /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
2421
+ /* @__PURE__ */ jsx(
2422
+ LiveTempoCell,
2423
+ {
2424
+ value: values[i],
2425
+ color: phase.color,
2426
+ status,
2427
+ phaseElapsedMs: live.phaseElapsedMs,
2428
+ completedMs: live.completed?.[phase.key],
2429
+ fontSize,
2430
+ readout
2431
+ }
2432
+ )
2433
+ ] }, phase.key);
2434
+ }) });
2386
2435
  }
2387
2436
  function TempoDisplay({
2388
2437
  tempo,
2389
2438
  size = "md",
2390
- colored = true,
2439
+ fontSize: fontSizeProp,
2391
2440
  showLabel = true,
2392
2441
  showInfo = true,
2393
2442
  live,
2443
+ liveReadout = "countdown",
2394
2444
  onPress,
2395
2445
  className,
2396
2446
  ...props
@@ -2398,8 +2448,11 @@ function TempoDisplay({
2398
2448
  const [showTooltip, setShowTooltip] = useState(false);
2399
2449
  const [eccentric, pauseBottom, concentric, pauseTop] = roundTempo(tempo);
2400
2450
  const isSm = size === "sm";
2401
- const fontSize = isSm ? 9 : 11;
2402
- const monoColor = TEXT_TERTIARY;
2451
+ const fontSize = fontSizeProp ?? (isSm ? 9 : 11);
2452
+ const chromePadX = Math.round(fontSize * 0.6);
2453
+ const chromePadY = Math.round(fontSize * 0.3);
2454
+ const chromeRadius = Math.round(fontSize * 0.4);
2455
+ const labelFont = Math.max(9, Math.round(fontSize * 0.5));
2403
2456
  const handlePress = useCallback(() => {
2404
2457
  if (onPress) {
2405
2458
  onPress();
@@ -2416,9 +2469,9 @@ function TempoDisplay({
2416
2469
  flexDirection: "row",
2417
2470
  alignItems: "center",
2418
2471
  backgroundColor: "#1C1C1C",
2419
- paddingHorizontal: isSm ? 6 : 8,
2420
- paddingVertical: 3,
2421
- borderRadius: 4
2472
+ paddingHorizontal: chromePadX,
2473
+ paddingVertical: chromePadY,
2474
+ borderRadius: chromeRadius
2422
2475
  },
2423
2476
  ...props,
2424
2477
  children: [
@@ -2427,12 +2480,13 @@ function TempoDisplay({
2427
2480
  {
2428
2481
  style: {
2429
2482
  fontFamily: INTER,
2430
- fontSize: 9,
2483
+ fontSize: labelFont,
2431
2484
  fontWeight: "500",
2432
- color: TEXT_TERTIARY,
2485
+ // Live-muted green while a rep is running, tertiary at rest.
2486
+ color: live ? t2["status-live-muted"] : TEXT_TERTIARY,
2433
2487
  letterSpacing: 0.5,
2434
2488
  textTransform: "uppercase",
2435
- marginRight: 6
2489
+ marginRight: Math.round(fontSize * 0.5)
2436
2490
  },
2437
2491
  children: "TEMPO"
2438
2492
  }
@@ -2442,36 +2496,20 @@ function TempoDisplay({
2442
2496
  {
2443
2497
  values: [eccentric, pauseBottom, concentric, pauseTop],
2444
2498
  live,
2445
- fontSize
2446
- }
2447
- ) : colored ? /* @__PURE__ */ jsxs(Fragment, { children: [
2448
- /* @__PURE__ */ jsx(TempoValue, { value: eccentric, color: phaseColors.eccentric, fontSize }),
2449
- /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
2450
- /* @__PURE__ */ jsx(TempoValue, { value: pauseBottom, color: phaseColors.pauseBottom, fontSize }),
2451
- /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
2452
- /* @__PURE__ */ jsx(TempoValue, { value: concentric, color: phaseColors.concentric, fontSize }),
2453
- /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
2454
- /* @__PURE__ */ jsx(TempoValue, { value: pauseTop, color: phaseColors.pauseTop, fontSize })
2455
- ] }) : /* @__PURE__ */ jsxs(
2456
- Text,
2457
- {
2458
- style: {
2459
- fontFamily: INTER,
2460
- fontSize,
2461
- color: monoColor,
2462
- fontWeight: "600",
2463
- letterSpacing: 1
2464
- },
2465
- children: [
2466
- eccentric,
2467
- "-",
2468
- pauseBottom,
2469
- "-",
2470
- concentric,
2471
- "-",
2472
- pauseTop
2473
- ]
2499
+ fontSize,
2500
+ readout: liveReadout
2474
2501
  }
2502
+ ) : (
2503
+ // Static prescription: the phase-coloured lockup (the same colours the live row rests at).
2504
+ /* @__PURE__ */ jsxs(Fragment, { children: [
2505
+ /* @__PURE__ */ jsx(TempoValue, { value: eccentric, color: phaseColors.eccentric, fontSize }),
2506
+ /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
2507
+ /* @__PURE__ */ jsx(TempoValue, { value: pauseBottom, color: phaseColors.pauseBottom, fontSize }),
2508
+ /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
2509
+ /* @__PURE__ */ jsx(TempoValue, { value: concentric, color: phaseColors.concentric, fontSize }),
2510
+ /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
2511
+ /* @__PURE__ */ jsx(TempoValue, { value: pauseTop, color: phaseColors.pauseTop, fontSize })
2512
+ ] })
2475
2513
  ) })
2476
2514
  ]
2477
2515
  }
@@ -2556,14 +2594,14 @@ function TempoDisplay({
2556
2594
  }
2557
2595
  );
2558
2596
  }
2559
- var t4 = getSemanticColors("dark");
2597
+ var t3 = getSemanticColors("dark");
2560
2598
  var INDICATOR_CONFIG = {
2561
- imbalance: { Icon: ScaleIcon, color: t4["status-error"], label: "Left/right imbalance" },
2562
- overshoot: { Icon: AlertTriangleIcon, color: t4["status-error"], label: "Load overshoot" },
2563
- "velocity-loss": { Icon: TrendingDownIcon, color: t4["status-warning"], label: "Velocity loss" },
2564
- "missed-reps": { Icon: CircleSlashIcon, color: t4["status-warning"], label: "Missed reps" },
2565
- pr: { Icon: AwardIcon, color: t4["status-success"], label: "Personal record" },
2566
- info: { Icon: InfoIcon, color: t4["status-info"], label: "More info" }
2599
+ imbalance: { Icon: ScaleIcon, color: t3["status-error"], label: "Left/right imbalance" },
2600
+ overshoot: { Icon: AlertTriangleIcon, color: t3["status-error"], label: "Load overshoot" },
2601
+ "velocity-loss": { Icon: TrendingDownIcon, color: t3["status-warning"], label: "Velocity loss" },
2602
+ "missed-reps": { Icon: CircleSlashIcon, color: t3["status-warning"], label: "Missed reps" },
2603
+ pr: { Icon: AwardIcon, color: t3["status-success"], label: "Personal record" },
2604
+ info: { Icon: InfoIcon, color: t3["status-info"], label: "More info" }
2567
2605
  };
2568
2606
  function ExerciseIndicator({ kind, onPress, className, ...props }) {
2569
2607
  const { Icon, color, label } = INDICATOR_CONFIG[kind];
@@ -4360,11 +4398,11 @@ function CardContent({ children, className }) {
4360
4398
  function CardFooter({ children, className }) {
4361
4399
  return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
4362
4400
  }
4363
- var t5 = getSemanticColors("dark");
4401
+ var t4 = getSemanticColors("dark");
4364
4402
  var solidVariantColors = {
4365
- success: t5["status-success"],
4366
- warning: t5["status-warning"],
4367
- error: t5["status-error"],
4403
+ success: t4["status-success"],
4404
+ warning: t4["status-warning"],
4405
+ error: t4["status-error"],
4368
4406
  neutral: "#6B7280"
4369
4407
  };
4370
4408
  var ringVariantStyles = {
@@ -4404,8 +4442,8 @@ var iconColors = {
4404
4442
  warning: "#6B4000",
4405
4443
  error: "#5C1A1A",
4406
4444
  neutral: "#D1D5DB",
4407
- "on-track": t5["status-success"],
4408
- deviation: t5["status-warning"],
4445
+ "on-track": t4["status-success"],
4446
+ deviation: t4["status-warning"],
4409
4447
  future: "#6B7280"
4410
4448
  };
4411
4449
  var sizeDimensions = {
@@ -4491,13 +4529,13 @@ var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
4491
4529
  var WORKOUT_PILL_DELOAD = primitiveRamps.magenta[600];
4492
4530
 
4493
4531
  // src/components/custom/Workout/MesoStatusCard.tsx
4494
- var t6 = getSemanticColors("dark");
4495
- var BRAND_PRIMARY5 = t6["brand-primary"];
4532
+ var t5 = getSemanticColors("dark");
4533
+ var BRAND_PRIMARY5 = t5["brand-primary"];
4496
4534
  var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
4497
4535
  var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
4498
- var SUCCESS = t6["status-success"];
4499
- var WARNING = t6["status-warning"];
4500
- var ERROR = t6["status-error"];
4536
+ var SUCCESS = t5["status-success"];
4537
+ var WARNING = t5["status-warning"];
4538
+ var ERROR = t5["status-error"];
4501
4539
  var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY5, BRAND_PRIMARY_LIGHT];
4502
4540
  var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
4503
4541
  var GAUGE_GRADIENT = "linear-gradient(90deg, rgba(46,213,115,0.25) 0%, rgba(249,180,21,0.25) 50%, rgba(209,67,67,0.25) 100%)";
@@ -4857,9 +4895,9 @@ function MesoStatusCard({
4857
4895
  var sem = getSemanticColors("dark");
4858
4896
  var BRAND_PRIMARY6 = sem["brand-primary"];
4859
4897
  var PROJECTION_LINE_COLOR = resolveColor("text-tertiary");
4860
- var STATUS_SUCCESS = sem["status-success"];
4898
+ var STATUS_SUCCESS2 = sem["status-success"];
4861
4899
  var STATUS_ERROR2 = sem["status-error"];
4862
- var STATUS_WARNING = sem["status-warning"];
4900
+ var STATUS_WARNING2 = sem["status-warning"];
4863
4901
  var GRID_LINE = "rgba(255,255,255,0.06)";
4864
4902
  var SUCCESS_PILL_BG = "rgba(46,213,115,0.10)";
4865
4903
  var SUCCESS_PILL_BORDER = "rgba(46,213,115,0.20)";
@@ -4868,8 +4906,8 @@ var ERROR_PILL_BORDER = "rgba(209,67,67,0.20)";
4868
4906
  var PLOT_LEFT = 26;
4869
4907
  var TOOLTIP_WIDTH = 124;
4870
4908
  function timeOf(dateStr) {
4871
- const t12 = Date.parse(dateStr);
4872
- return Number.isNaN(t12) ? 0 : t12;
4909
+ const t11 = Date.parse(dateStr);
4910
+ return Number.isNaN(t11) ? 0 : t11;
4873
4911
  }
4874
4912
  function formatValue(value) {
4875
4913
  return `${Math.round(value)}`;
@@ -5165,7 +5203,7 @@ function StrengthTrendChart({
5165
5203
  left: c.x - 7,
5166
5204
  top: c.y - 20,
5167
5205
  fontSize: 12,
5168
- color: STATUS_WARNING
5206
+ color: STATUS_WARNING2
5169
5207
  },
5170
5208
  children: "\u2605"
5171
5209
  },
@@ -5258,7 +5296,7 @@ function StrengthTrendChart({
5258
5296
  marginTop: 1,
5259
5297
  fontSize: 10,
5260
5298
  fontFamily: "Inter, sans-serif",
5261
- color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS : STATUS_ERROR2
5299
+ color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS2 : STATUS_ERROR2
5262
5300
  },
5263
5301
  children: `${selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? "+" : "-"}${Math.abs(
5264
5302
  selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm
@@ -5314,7 +5352,7 @@ function StrengthTrendChart({
5314
5352
  fontSize: 11,
5315
5353
  fontFamily: "Inter, sans-serif",
5316
5354
  fontWeight: "600",
5317
- color: trend.positive ? STATUS_SUCCESS : STATUS_ERROR2
5355
+ color: trend.positive ? STATUS_SUCCESS2 : STATUS_ERROR2
5318
5356
  },
5319
5357
  children: trendText
5320
5358
  }
@@ -5348,7 +5386,7 @@ function StrengthTrendChart({
5348
5386
  /* @__PURE__ */ jsx(Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Projected" })
5349
5387
  ] }),
5350
5388
  /* @__PURE__ */ jsxs(View, { className: "flex-row items-center", style: { gap: 5 }, children: [
5351
- /* @__PURE__ */ jsx(Text, { style: { fontSize: 12, color: STATUS_WARNING }, children: "\u2605" }),
5389
+ /* @__PURE__ */ jsx(Text, { style: { fontSize: 12, color: STATUS_WARNING2 }, children: "\u2605" }),
5352
5390
  /* @__PURE__ */ jsx(Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "PR" })
5353
5391
  ] })
5354
5392
  ]
@@ -5358,10 +5396,10 @@ function StrengthTrendChart({
5358
5396
  }
5359
5397
  );
5360
5398
  }
5361
- var t7 = getSemanticColors("dark");
5362
- var STATUS_SUCCESS2 = t7["status-success"];
5363
- var STATUS_WARNING2 = t7["status-warning"];
5364
- var STATUS_INFO = t7["status-info"];
5399
+ var t6 = getSemanticColors("dark");
5400
+ var STATUS_SUCCESS3 = t6["status-success"];
5401
+ var STATUS_WARNING3 = t6["status-warning"];
5402
+ var STATUS_INFO = t6["status-info"];
5365
5403
  var DOT_BORDER = "#F3F4F6";
5366
5404
  var BAND_FILL = "rgba(46,213,115,0.1)";
5367
5405
  var BAND_EDGE = "rgba(46,213,115,0.45)";
@@ -5373,8 +5411,8 @@ var PADDING_BOTTOM = 16;
5373
5411
  var COLUMN_STEP = 4;
5374
5412
  var DOT_SIZE = 8;
5375
5413
  var DOT_COLORS = {
5376
- within: STATUS_SUCCESS2,
5377
- above: STATUS_WARNING2,
5414
+ within: STATUS_SUCCESS3,
5415
+ above: STATUS_WARNING3,
5378
5416
  below: STATUS_INFO
5379
5417
  };
5380
5418
  var STATUS_PHRASES = {
@@ -5404,8 +5442,8 @@ function interpEdge(pixels, x, key) {
5404
5442
  const a = pixels[i];
5405
5443
  const b = pixels[i + 1];
5406
5444
  if (x >= a.x && x <= b.x) {
5407
- const t12 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
5408
- return a[key] + t12 * (b[key] - a[key]);
5445
+ const t11 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
5446
+ return a[key] + t11 * (b[key] - a[key]);
5409
5447
  }
5410
5448
  }
5411
5449
  return pixels[pixels.length - 1][key];
@@ -5599,8 +5637,8 @@ function CapacityBandChart({
5599
5637
  projection && /* @__PURE__ */ jsxs(View, { testID: "capacity-band-chart-projection", children: [
5600
5638
  renderColumns(buildColumns2(trainingPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
5601
5639
  renderColumns(buildColumns2(restPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
5602
- renderEdges(buildEdges(trainingPixels, "yHigh"), STATUS_SUCCESS2, true, "capacity-band-chart-projection-training"),
5603
- renderEdges(buildEdges(trainingPixels, "yLow"), STATUS_SUCCESS2, true, "capacity-band-chart-projection-training"),
5640
+ renderEdges(buildEdges(trainingPixels, "yHigh"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
5641
+ renderEdges(buildEdges(trainingPixels, "yLow"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
5604
5642
  renderEdges(buildEdges(restPixels, "yHigh"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
5605
5643
  renderEdges(buildEdges(restPixels, "yLow"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
5606
5644
  /* @__PURE__ */ jsx(
@@ -5612,7 +5650,7 @@ function CapacityBandChart({
5612
5650
  top: trainingPixels[trainingPixels.length - 1]?.yHigh - 12,
5613
5651
  fontSize: 9,
5614
5652
  fontFamily: "Inter, sans-serif",
5615
- color: STATUS_SUCCESS2
5653
+ color: STATUS_SUCCESS3
5616
5654
  },
5617
5655
  testID: "capacity-band-chart-projection-training-label",
5618
5656
  children: "Training"
@@ -6444,7 +6482,7 @@ function Badge({
6444
6482
  }
6445
6483
  );
6446
6484
  }
6447
- var t8 = getSemanticColors("dark");
6485
+ var t7 = getSemanticColors("dark");
6448
6486
  var statusBgColors = {
6449
6487
  completed: "rgba(46,213,115,0.15)",
6450
6488
  current: "rgba(255,121,0,0.15)",
@@ -6462,9 +6500,9 @@ var statusBorderStyles = {
6462
6500
  deload: { borderWidth: 1, borderColor: "rgba(186,41,150,0.3)" }
6463
6501
  };
6464
6502
  var textColors = {
6465
- completed: t8["status-success"],
6466
- current: t8["brand-primary"],
6467
- next: t8["brand-primary"],
6503
+ completed: t7["status-success"],
6504
+ current: t7["brand-primary"],
6505
+ next: t7["brand-primary"],
6468
6506
  upcoming: "#6B7280",
6469
6507
  missed: "rgba(209,67,67,0.7)",
6470
6508
  deload: WORKOUT_PILL_DELOAD
@@ -6597,19 +6635,19 @@ function WorkoutPill({
6597
6635
  }
6598
6636
  return pill;
6599
6637
  }
6600
- var t9 = getSemanticColors("dark");
6638
+ var t8 = getSemanticColors("dark");
6601
6639
  var TRACK_BG = "#333333";
6602
6640
  var LABEL_COLOR = "#6B7280";
6603
6641
  var TARGET_LINE_COLOR = "rgba(33, 150, 243, 0.5)";
6604
6642
  var AT_TARGET_GLOW = "0 0 5px 1px rgba(33, 150, 243, 0.35), 0 0 10px 3px rgba(33, 150, 243, 0.15)";
6605
6643
  var ZONE = {
6606
- building: t9["status-success"],
6644
+ building: t8["status-success"],
6607
6645
  // below target ramp-up
6608
- approaching: t9["status-warning"],
6646
+ approaching: t8["status-warning"],
6609
6647
  // nearing target
6610
- target: t9["brand-primary"],
6648
+ target: t8["brand-primary"],
6611
6649
  // exactly at target
6612
- over1: t9["status-error"],
6650
+ over1: t8["status-error"],
6613
6651
  // mild over-target
6614
6652
  over2: WORKOUT_TOKENS.intensity.over2,
6615
6653
  // moderate over-target
@@ -7032,13 +7070,13 @@ function MesoCard({
7032
7070
  }
7033
7071
  ) });
7034
7072
  }
7035
- var t10 = getSemanticColors("dark");
7073
+ var t9 = getSemanticColors("dark");
7036
7074
  var dotColorMap = {
7037
7075
  untrained: "#2C2C2C",
7038
- behind: t10["brand-secondary"],
7039
- ontrack: t10["status-success"],
7040
- target: t10["brand-primary"],
7041
- over: t10["status-error"]
7076
+ behind: t9["brand-secondary"],
7077
+ ontrack: t9["status-success"],
7078
+ target: t9["brand-primary"],
7079
+ over: t9["status-error"]
7042
7080
  };
7043
7081
  function MuscleGroupChip({
7044
7082
  name,
@@ -7112,10 +7150,10 @@ function MuscleGroupChip({
7112
7150
  }
7113
7151
 
7114
7152
  // src/components/custom/Workout/WorkoutCard.tsx
7115
- var t11 = getSemanticColors("dark");
7153
+ var t10 = getSemanticColors("dark");
7116
7154
  var COLORS = {
7117
- statusSuccess: t11["status-success"],
7118
- brandPrimary: t11["brand-primary"],
7155
+ statusSuccess: t10["status-success"],
7156
+ brandPrimary: t10["brand-primary"],
7119
7157
  borderDefault: "#1F1F1F",
7120
7158
  brandPrimarySubtle: "rgba(255,121,0,0.06)"
7121
7159
  };