@titan-design/react-ui 0.11.0 → 0.12.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 (142) hide show
  1. package/dist/bodymap.js +173 -343
  2. package/dist/bodymap.js.map +1 -1
  3. package/dist/bodymap.mjs +173 -343
  4. package/dist/bodymap.mjs.map +1 -1
  5. package/dist/index.d.mts +24 -21
  6. package/dist/index.d.ts +24 -21
  7. package/dist/index.js +366 -561
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +360 -553
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/pages.js +242 -407
  12. package/dist/pages.js.map +1 -1
  13. package/dist/pages.mjs +242 -407
  14. package/dist/pages.mjs.map +1 -1
  15. package/dist/theme/index.d.mts +409 -415
  16. package/dist/theme/index.d.ts +409 -415
  17. package/dist/theme/index.js +234 -408
  18. package/dist/theme/index.js.map +1 -1
  19. package/dist/theme/index.mjs +227 -399
  20. package/dist/theme/index.mjs.map +1 -1
  21. package/dist/theme/tokens-css.js +141 -140
  22. package/dist/theme/tokens-css.js.map +1 -1
  23. package/dist/theme/tokens-css.mjs +141 -140
  24. package/dist/theme/tokens-css.mjs.map +1 -1
  25. package/package.json +1 -1
  26. package/src/arch/Architecture.stories.tsx +9 -9
  27. package/src/components/custom/DateTime/DateTime.stories.tsx +1 -1
  28. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +3 -3
  29. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  30. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +3 -3
  31. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +1 -1
  32. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +2 -2
  33. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  34. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +4 -4
  35. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +3 -3
  36. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  37. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -12
  38. package/src/components/custom/Sidebar/Sidebar.tsx +4 -4
  39. package/src/components/custom/Table/Table.tsx +2 -2
  40. package/src/components/custom/Workout/ActiveWorkoutPage.tsx +3 -3
  41. package/src/components/custom/Workout/BaseBadge.test.tsx +6 -1
  42. package/src/components/custom/Workout/BaseBadge.tsx +1 -1
  43. package/src/components/custom/Workout/BodyMap.tsx +2 -2
  44. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +2 -2
  45. package/src/components/custom/Workout/DeviationBar.test.tsx +2 -1
  46. package/src/components/custom/Workout/DeviationBar.tsx +3 -2
  47. package/src/components/custom/Workout/ExerciseCard.test.tsx +3 -3
  48. package/src/components/custom/Workout/ExerciseCard.tsx +2 -2
  49. package/src/components/custom/Workout/ExerciseDetailPage.tsx +4 -4
  50. package/src/components/custom/Workout/InputBar.tsx +2 -2
  51. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +1 -1
  52. package/src/components/custom/Workout/LiveAuraFrame.test.tsx +1 -1
  53. package/src/components/custom/Workout/LiveAuraFrame.tsx +3 -3
  54. package/src/components/custom/Workout/MesoCard.tsx +3 -1
  55. package/src/components/custom/Workout/MuscleGroupChip.tsx +4 -3
  56. package/src/components/custom/Workout/PrHistoryModal.tsx +2 -2
  57. package/src/components/custom/Workout/ProgramPlanningPage.tsx +1 -1
  58. package/src/components/custom/Workout/ReadinessCheck.tsx +2 -2
  59. package/src/components/custom/Workout/RestTimer.tsx +2 -2
  60. package/src/components/custom/Workout/S3SetTypes.stories.tsx +3 -3
  61. package/src/components/custom/Workout/SessionHeader.stories.tsx +2 -2
  62. package/src/components/custom/Workout/SessionHeader.tsx +1 -1
  63. package/src/components/custom/Workout/SessionRail.stories.tsx +2 -2
  64. package/src/components/custom/Workout/SessionRail.tsx +13 -5
  65. package/src/components/custom/Workout/SetBar.tsx +3 -3
  66. package/src/components/custom/Workout/SetRow.test.tsx +6 -3
  67. package/src/components/custom/Workout/StatusDot.tsx +5 -4
  68. package/src/components/custom/Workout/StrengthTrendChart.tsx +1 -1
  69. package/src/components/custom/Workout/TrainingStatusPage.tsx +2 -2
  70. package/src/components/custom/Workout/VelocityStrip.test.tsx +5 -2
  71. package/src/components/custom/Workout/VelocityStrip.tsx +4 -4
  72. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +3 -3
  73. package/src/components/custom/Workout/WeightBadge.test.tsx +6 -1
  74. package/src/components/custom/Workout/WeightBadge.tsx +2 -1
  75. package/src/components/custom/Workout/WorkoutCard.tsx +3 -1
  76. package/src/components/custom/Workout/WorkoutPill.tsx +5 -2
  77. package/src/components/custom/Workout/ZoneTrack.tsx +4 -4
  78. package/src/components/custom/Workout/setHeadingKit.tsx +14 -8
  79. package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
  80. package/src/components/custom/charts/SetBarChart.tsx +3 -3
  81. package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
  82. package/src/components/custom/stepper/Stepper.tsx +3 -3
  83. package/src/components/shell/DeviceMenu.tsx +2 -2
  84. package/src/components/shell/SideNav.tsx +1 -1
  85. package/src/components/shell/TopBar.tsx +1 -1
  86. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +1 -1
  87. package/src/components/ui/autocomplete/Autocomplete.tsx +1 -1
  88. package/src/components/ui/avatar/Avatar.tsx +2 -2
  89. package/src/components/ui/badge/Badge.tsx +2 -2
  90. package/src/components/ui/card/Card.tsx +3 -3
  91. package/src/components/ui/checkbox/Checkbox.tsx +1 -1
  92. package/src/components/ui/collapse/Collapse.tsx +1 -1
  93. package/src/components/ui/data-row/DataRow.stories.tsx +1 -1
  94. package/src/components/ui/drawer/Drawer.tsx +3 -3
  95. package/src/components/ui/form-field/FormField.tsx +1 -1
  96. package/src/components/ui/help-tip/HelpTip.tsx +1 -1
  97. package/src/components/ui/menu/Menu.tsx +2 -2
  98. package/src/components/ui/pill/Pill.tsx +2 -2
  99. package/src/components/ui/popover/Popover.stories.tsx +2 -2
  100. package/src/components/ui/popover/Popover.tsx +1 -1
  101. package/src/components/ui/progress/Progress.tsx +3 -3
  102. package/src/components/ui/radio/Radio.stories.tsx +1 -1
  103. package/src/components/ui/radio/Radio.tsx +4 -4
  104. package/src/components/ui/select/Select.tsx +3 -3
  105. package/src/components/ui/surface/Surface.stories.tsx +3 -3
  106. package/src/components/ui/surface/Surface.test.tsx +32 -19
  107. package/src/components/ui/surface/Surface.tsx +3 -3
  108. package/src/components/ui/surface/SurfaceContext.ts +19 -29
  109. package/src/components/ui/surface/surface.contract.test.ts +57 -44
  110. package/src/components/ui/switch/Switch.tsx +1 -1
  111. package/src/components/ui/tabs/Tabs.tsx +2 -2
  112. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +5 -5
  113. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +1 -1
  114. package/src/components/ui/toolbar-button/ToolbarButton.tsx +36 -22
  115. package/src/stories/PresetShowcase.stories.tsx +21 -21
  116. package/src/theme/ColorPalettes.stories.tsx +41 -38
  117. package/src/theme/ColorPrimitives.stories.tsx +89 -41
  118. package/src/theme/Depth.stories.tsx +312 -0
  119. package/src/theme/DepthCalibration.stories.tsx +655 -0
  120. package/src/theme/ThemeProvider.tsx +1 -1
  121. package/src/theme/barrel.ts +7 -14
  122. package/src/theme/color-stories.coverage.test.ts +15 -20
  123. package/src/theme/color-story-kit.tsx +1 -1
  124. package/src/theme/color-utils.ts +197 -0
  125. package/src/theme/config.ts +0 -8
  126. package/src/theme/depth-calibration.test.tsx +97 -0
  127. package/src/theme/elevation.test.ts +62 -1
  128. package/src/theme/elevation.ts +34 -8
  129. package/src/theme/global.css +47 -53
  130. package/src/theme/grey-ramp.test.ts +166 -0
  131. package/src/theme/materials.test.ts +106 -0
  132. package/src/theme/materials.ts +211 -0
  133. package/src/theme/presets/audiobook.ts +4 -4
  134. package/src/theme/presets/types.ts +3 -3
  135. package/src/theme/semantic-contrast.test.ts +83 -0
  136. package/src/theme/tokens/primitives.ts +62 -115
  137. package/src/theme/tokens/semantic.ts +130 -82
  138. package/src/utils/colors.ts +1 -1
  139. package/tailwind.config.js +2 -5
  140. package/src/theme/bar-paper.ts +0 -59
  141. package/src/theme/shadows.stories.tsx +0 -523
  142. package/src/theme/shadows.ts +0 -439
package/dist/bodymap.js CHANGED
@@ -18,52 +18,37 @@ function cn(...inputs) {
18
18
 
19
19
  // src/theme/tokens/primitives.ts
20
20
  var primitiveColors = {
21
- // Blue scale
22
- blue: {
23
- 400: "#60A5FA",
24
- 600: "#5048E5",
25
- 700: "#3832A0"},
26
- // Red scale
27
- red: {
28
- 500: "#EF4444",
29
- 600: "#D14343"},
30
- // Vivid red scale
31
- redVivid: {
32
- 400: "#FF6070",
33
- 500: "#FF4757",
34
- 700: "#C42539"},
35
- // Neutral/Gray scale
36
- neutral: {
37
- 50: "#FAFAFA",
38
- 100: "#F3F4F6",
39
- 300: "#D1D5DB",
40
- 400: "#9CA3AF",
41
- 500: "#6B7280",
42
- 600: "#4B5563",
43
- 900: "#111827"},
44
- // Charcoal scale (dark backgrounds)
45
- charcoal: {
46
- 200: "#3C3C3C",
47
- 300: "#2C2C2C",
48
- 400: "#1F1F1F",
49
- 500: "#1C1C1C"},
50
- // Pure colors
51
21
  white: "#FFFFFF"};
52
- var surfaceRampDark = {
53
- inset: "#13100D",
54
- // L*4.5 — sub-shell well / pressed
55
- background: "#1C1916",
56
- // L*9 — shell / frame
57
- base: "#252321",
58
- // L*13.5 — main content plane
59
- elevated: "#2C2A28",
60
- // L*17 — nav / rail
61
- raised: "#31302F",
62
- // L*20 — cards
63
- overlay: "#373635"
64
- // L*22.5 — hero / popover
22
+ var greyRamp = {
23
+ 50: "#F9F6F3",
24
+ // L*97.0 W6
25
+ 100: "#EDEAE7",
26
+ // L*92.8 W6
27
+ 200: "#D4D1CE",
28
+ // L*75.7 W6
29
+ 400: "#A29F9D",
30
+ // L*65.7 W5
31
+ 500: "#888684",
32
+ // L*56.0 W4
33
+ 600: "#72716F",
34
+ // L*47.7 W3
35
+ 700: "#5A5958",
36
+ // L*37.9 W2
37
+ 800: "#424140",
38
+ // L*27.6 W2 — generated bridge
39
+ 850: "#373635",
40
+ // L*22.7 W2 — surface overlay
41
+ 875: "#31302F",
42
+ // L*19.9 W2 — surface raised
43
+ 900: "#2C2A28",
44
+ // L*17.2 W4 — surface elevated
45
+ 925: "#252321",
46
+ // L*13.9 W4 — surface base
47
+ 950: "#1C1916",
48
+ // L*9.0 W6 — background base / shell
49
+ 975: "#100D0A"
50
+ // L*3.8 W6 — background frame / bezel
65
51
  };
66
- var backgroundFrameDark = "#100D0A";
67
52
  var primitiveRamps = {
68
53
  red: {
69
54
  50: "#FFF4F4",
@@ -100,9 +85,11 @@ var primitiveRamps = {
100
85
  blue: {
101
86
  50: "#EFF8FF",
102
87
  300: "#78C2FF",
88
+ 400: "#3CA8FF",
103
89
  500: "#2196F3",
104
90
  // pin
105
- 600: "#1072CB"}};
91
+ 600: "#1072CB",
92
+ 700: "#135AA8"}};
106
93
  var divergingScale = [
107
94
  primitiveRamps.blue[500],
108
95
  // under
@@ -177,10 +164,10 @@ var semanticColorsLight = {
177
164
  "status-error-light": primitiveRamps.red[500],
178
165
  "status-error-dark": primitiveRamps.red[700],
179
166
  "status-error-subtle": primitiveRamps.red[50],
180
- "status-error-vivid": primitiveColors.redVivid[500],
167
+ "status-error-vivid": primitiveRamps.red[600],
181
168
  // vivid alert red
182
- "status-error-vivid-light": primitiveColors.redVivid[400],
183
- "status-error-vivid-dark": primitiveColors.redVivid[700],
169
+ "status-error-vivid-light": primitiveRamps.red[500],
170
+ "status-error-vivid-dark": primitiveRamps.red[700],
184
171
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
185
172
  "status-warning": primitiveRamps.amber[300],
186
173
  "status-warning-light": primitiveRamps.amber[200],
@@ -207,7 +194,7 @@ var semanticColorsLight = {
207
194
  "result-inconclusive": "#9E9A97",
208
195
  // Gray - no clear result
209
196
  "result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
210
- "result-neutral": primitiveColors.neutral[500],
197
+ "result-neutral": greyRamp[600],
211
198
  // Neutral baseline
212
199
  // Text on result backgrounds (on-result-*)
213
200
  "on-result-improve": primitiveColors.white,
@@ -238,47 +225,38 @@ var semanticColorsLight = {
238
225
  // Text colors (text-*)
239
226
  "text-primary": "#121828",
240
227
  "text-secondary": "#65748B",
241
- "text-tertiary": primitiveColors.neutral[400],
228
+ "text-tertiary": greyRamp[400],
242
229
  "text-disabled": "rgba(55, 65, 81, 0.48)",
243
230
  "text-inverse": primitiveColors.white,
244
- "text-link": primitiveColors.blue[600],
245
- "text-link-hover": primitiveColors.blue[700],
231
+ "text-link": primitiveRamps.blue[600],
232
+ "text-link-hover": primitiveRamps.blue[700],
246
233
  // Surface colors (surface-*) - for elevated containers
247
234
  "surface-base": primitiveColors.white,
248
- "surface-elevated": primitiveColors.neutral[50],
235
+ "surface-elevated": greyRamp[50],
249
236
  // slightly off-white for elevated cards
250
- "surface-raised": primitiveColors.neutral[100],
237
+ "surface-raised": greyRamp[100],
251
238
  // light gray for raised cards
252
239
  "surface-overlay": primitiveColors.white,
253
- "surface-input": primitiveColors.neutral[50],
240
+ "surface-input": greyRamp[50],
254
241
  // Input field background (filled variant)
255
- // Deepest pressed pit (TD-surface-tokens, S-3) — light-mode counterpart of
256
- // the dark ramp's `inset` plane; a placeholder pairing, not part of the
257
- // dark-ramp investigation (surface.contract.test.ts is dark-mode only).
258
- "surface-inset": primitiveColors.neutral[300],
259
242
  // Background colors (background-*)
260
243
  "background-base": "#EBEBEB",
261
244
  "background-default": primitiveColors.white,
262
- "background-subtle": primitiveColors.neutral[50],
263
- // Frame/bezel chrome (TD-surface-tokens, S-3) — top bar + side nav shell,
264
- // one step below `background-base` (darker still than `surface-inset`
265
- // above, mirroring the dark-mode ordering). Placeholder pairing for light
266
- // mode (see dark-mode note on `surface-inset` above).
267
- "background-frame": primitiveColors.neutral[400],
245
+ "background-subtle": greyRamp[50],
246
+ // Frame/bezel chrome — top bar + side nav shell, one step below
247
+ // `background-base`. Placeholder pairing for light mode, which is deferred.
248
+ "background-frame": greyRamp[400],
268
249
  // Border colors (border-*)
269
- "border-default": "#E8E9EB",
270
- "border-subtle": primitiveColors.neutral[100],
271
- "border-strong": primitiveColors.neutral[300],
272
- "border-prominent": primitiveColors.neutral[400],
250
+ "border-prominent": greyRamp[400],
273
251
  // high-visibility divider
274
- "border-focus": primitiveColors.blue[600],
275
- "border-input": primitiveColors.neutral[300],
252
+ "border-focus": primitiveRamps.blue[600],
253
+ "border-input": greyRamp[200],
276
254
  // Input field border
277
- "border-input-hover": primitiveColors.neutral[400],
255
+ "border-input-hover": greyRamp[400],
278
256
  // Input field border on hover
279
- "border-input-focus": primitiveColors.blue[600],
257
+ "border-input-focus": primitiveRamps.blue[600],
280
258
  // Input field border on focus
281
- "border-input-error": primitiveColors.red[600],
259
+ "border-input-error": primitiveRamps.red[600],
282
260
  // Input field border on error
283
261
  // Alpha hairline separators (surface-independent — composite toward black on
284
262
  // light surfaces, mirroring the dark-mode white-alpha family). See §4/S-2.
@@ -295,7 +273,7 @@ var semanticColorsLight = {
295
273
  // Divider
296
274
  "divider": "#E8E9EB",
297
275
  // Avatar default
298
- "avatar-background": primitiveColors.neutral[500],
276
+ "avatar-background": greyRamp[600],
299
277
  "avatar-text": primitiveColors.white
300
278
  };
301
279
  var semanticColorsDark = {
@@ -327,9 +305,9 @@ var semanticColorsDark = {
327
305
  "status-error-light": primitiveRamps.red[500],
328
306
  "status-error-dark": primitiveRamps.red[700],
329
307
  "status-error-subtle": "rgba(209, 67, 67, 0.12)",
330
- "status-error-vivid": primitiveColors.redVivid[500],
331
- "status-error-vivid-light": primitiveColors.redVivid[400],
332
- "status-error-vivid-dark": primitiveColors.redVivid[700],
308
+ "status-error-vivid": primitiveRamps.red[600],
309
+ "status-error-vivid-light": primitiveRamps.red[500],
310
+ "status-error-vivid-dark": primitiveRamps.red[700],
333
311
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
334
312
  "status-warning": primitiveRamps.amber[300],
335
313
  "status-warning-light": primitiveRamps.amber[200],
@@ -353,7 +331,7 @@ var semanticColorsDark = {
353
331
  "result-degrade-dark": "#b30000",
354
332
  "result-inconclusive": "#9E9A97",
355
333
  "result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
356
- "result-neutral": primitiveColors.neutral[400],
334
+ "result-neutral": greyRamp[400],
357
335
  // Text on result backgrounds
358
336
  "on-result-improve": primitiveColors.white,
359
337
  "on-result-degrade": primitiveColors.white,
@@ -370,74 +348,106 @@ var semanticColorsDark = {
370
348
  "data-9": discreteRainbow[3],
371
349
  "data-10": discreteRainbow[22],
372
350
  // Text colors - inverted for dark mode
373
- "text-primary": primitiveColors.neutral[100],
374
- "text-secondary": primitiveColors.neutral[400],
375
- "text-tertiary": primitiveColors.neutral[500],
351
+ "text-primary": greyRamp[50],
352
+ "text-secondary": greyRamp[400],
353
+ // Deliberately ONE step lighter than the L*-nearest match (`greyRamp[600]`).
354
+ // The colour this replaced failed WCAG large-text outright on the three
355
+ // lightest planes — 2.96 / 2.72 / 2.49 against elevated / raised / overlay —
356
+ // and `600` carried that failure forward almost exactly (2.93 / 2.70 / 2.47).
357
+ // `500` clears 3:1 everywhere (3.32–5.34). Contrast beats colour fidelity for
358
+ // text roles; borders and surfaces still use strict L*-nearest. See
359
+ // semantic-contrast.test.ts, which fails if this is moved back down.
360
+ "text-tertiary": greyRamp[500],
376
361
  "text-disabled": "rgba(255, 255, 255, 0.38)",
377
- "text-inverse": primitiveColors.neutral[900],
362
+ "text-inverse": greyRamp[950],
378
363
  "text-link": "#828DF8",
379
- "text-link-hover": primitiveColors.blue[400],
364
+ "text-link-hover": primitiveRamps.blue[400],
380
365
  // Surface colors - dark backgrounds — warm-tapered DERIVED ramp (TD-surface-tokens,
381
366
  // S-1, re-spaced S-3). Shipped verbatim from `deriveSurfaceRamp()` — see
382
367
  // `surfaceRampDark` in primitives.ts for the full derivation note. `surface-overlay`
383
368
  // and `surface-elevated` are distinct (were both #191919 pre-S-1); `surface-input`
384
369
  // tracks one plane above `surface-base`, same relative position as before the remap.
385
370
  // `background-base` backs `Surface level="background"` (SurfaceContext.SURFACE_LEVEL_TOKEN),
386
- // so it takes the ramp's `background` (shell/frame) role, NOT `inset`. The ramp's
387
- // deepest `inset` plane is now promoted to `surface-inset` below (S-3) still no
388
- // `SurfaceLevel` member for it (follow-up, alongside the elevation.ts -1/-2 pressed
389
- // levels — parallel workstream, not this branch).
390
- "surface-base": surfaceRampDark.base,
391
- // main surface (#252321, L*13.5)
392
- "surface-elevated": surfaceRampDark.elevated,
393
- // elevated surface (#2C2A28, L*17 nav/rail)
394
- "surface-raised": surfaceRampDark.raised,
395
- // raised surface (#31302F, L*20 cards)
396
- "surface-overlay": surfaceRampDark.overlay,
397
- // overlay surface (#373635, L*22.5 — hero/popover)
398
- "surface-input": surfaceRampDark.elevated,
371
+ // so it takes the ramp's shell role. The deepest plane is `background-frame`,
372
+ // which is also the `SurfaceLevel` floor a pressed surface clamps at.
373
+ "surface-base": greyRamp[925],
374
+ // main surface (#252321, L*13.9)
375
+ "surface-elevated": greyRamp[900],
376
+ // elevated surface (#2C2A28, L*17.2 — nav/rail)
377
+ "surface-raised": greyRamp[875],
378
+ // raised surface (#31302F, L*19.9 cards)
379
+ "surface-overlay": greyRamp[850],
380
+ // overlay surface (#373635, L*22.7 hero/popover)
381
+ "surface-input": greyRamp[900],
399
382
  // input surface (#2C2A28 — one plane above base)
400
- "surface-inset": surfaceRampDark.inset,
401
- // deepest pressed pit (#13100D, L*4.5 — sub-shell well)
402
383
  // Background colors — same ramp, the frame/shell end of it.
403
- "background-base": surfaceRampDark.background,
404
- // shell / frame (#1C1916, L*9 — Surface level="background")
405
- "background-default": surfaceRampDark.base,
406
- // main background (#252321, L*13.5 — matches surface-base)
407
- "background-subtle": surfaceRampDark.elevated,
408
- // subtle background (#2C2A28, L*17 — matches surface-elevated)
409
- // Frame/bezel chrome (S-3) — the top bar + side nav shell; one step BELOW
410
- // `background-base`, darker even than `surface-inset` it exits the content
411
- // ramp entirely rather than sitting in it. See `backgroundFrameDark` in
412
- // primitives.ts.
413
- "background-frame": backgroundFrameDark,
414
- // frame / bezel (#100D0A, L*3.79)
415
- // Border colors `border-subtle` (#1C1C1C) previously collided with
416
- // `surface-raised` (also #1C1C1C, an invisible border on raised cards). The
417
- // re-spaced ramp above moved `surface-raised` to #2D2C2B, so this value is now
418
- // distinct from every surface hex without needing to change it see
419
- // `surface.contract.test.ts` R2/R4.
420
- "border-default": primitiveColors.charcoal[400],
421
- // default border
422
- "border-subtle": primitiveColors.charcoal[500],
423
- // subtle border
424
- "border-strong": primitiveColors.charcoal[300],
425
- // strong border
426
- "border-prominent": primitiveColors.charcoal[200],
384
+ "background-base": greyRamp[950],
385
+ // shell (#1C1916, L*9 — Surface level="background")
386
+ "background-default": greyRamp[925],
387
+ // main background (#252321, L*13.9 — matches surface-base)
388
+ "background-subtle": greyRamp[900],
389
+ // subtle background (#2C2A28, L*17.2 — matches surface-elevated)
390
+ // Frame/bezel chrome — the top bar + side nav shell, one step BELOW
391
+ // `background-base`. It used to be described as sitting OUTSIDE the ramp; it
392
+ // is simply the ramp's last step now, and the floor `<Surface pressed>` clamps at.
393
+ "background-frame": greyRamp[975],
394
+ // frame / bezel (#100D0A, L*3.8)
395
+ // Border colors — solid dark borders are RETIRED (TD-07.14). Not a preference — a structural
396
+ // consequence of one ramp. Every step from 850 to 975 is now a surface plane,
397
+ // so a solid border dark enough to read as a border necessarily equals some
398
+ // plane's fill, which is exactly the collision `surface.contract.test.ts` R2
399
+ // forbids. The only non-plane steps left in that band are 800 and 700, and
400
+ // borders there jump from L*~10-25 to L*~28-38 — a restyle, not a migration.
401
+ //
402
+ // So separation moves to the alpha hairlines, which dark mode already called
403
+ // "the primary separation cue". Being alpha, they composite against whatever
404
+ // plane they land on and cannot collide with any of them — the problem stops
405
+ // existing rather than being re-solved per plane. The three solid tokens were
406
+ // deleted outright; consumers point at the `hairline-*` family below.
407
+ //
408
+ // `border-prominent` stays SOLID: it is the one border meant to be seen
409
+ // outright (4 call sites, high-visibility dividers), and grey-800 is not a
410
+ // plane, so it keeps its job without collision.
411
+ "border-prominent": greyRamp[800],
427
412
  // high-visibility divider
428
413
  "border-focus": "#828DF8",
429
- "border-input": primitiveColors.neutral[600],
430
- "border-input-hover": primitiveColors.neutral[500],
414
+ "border-input": greyRamp[700],
415
+ "border-input-hover": greyRamp[600],
431
416
  "border-input-focus": "#828DF8",
432
- "border-input-error": primitiveColors.red[500],
417
+ "border-input-error": primitiveRamps.red[500],
433
418
  // Alpha hairline separators — the primary separation cue (§4/S-2). Self-
434
419
  // normalizing: composites toward white by ~the same amount on ANY plane, so
435
420
  // one family works at every elevation instead of per-surface border tokens.
436
421
  // Shadows are demoted to floating-overlay use only (not shipped as a fill
437
422
  // separator here — see elevation.ts, follow-up S-4).
438
- "hairline-subtle": "rgba(255, 255, 255, 0.06)",
439
- "hairline-default": "rgba(255, 255, 255, 0.09)",
440
- "hairline-strong": "rgba(255, 255, 255, 0.14)",
423
+ //
424
+ // RETUNED on the wall (VW-99, S-6). The original .06/.09/.14 were set at a
425
+ // desk. On the panel at ~3 m `subtle` rendered but was indiscernible, and
426
+ // `default` — the load-bearing one, with no solid-border fallback since
427
+ // TD-07.14 — went weak on the lightest plane. `strong` read cleanly with room
428
+ // to spare, which is what made raising the whole family viable.
429
+ //
430
+ // Each tier steps up onto the next MEASURED-GOOD rung rather than an
431
+ // interpolated one: the new `subtle` is the old `default`, and the new
432
+ // `default` is the old `strong` — a value just confirmed legible on all four
433
+ // planes. Spacing goes 1 : 1.56 : 2.33, against the original 1 : 1.5 : 2.33.
434
+ //
435
+ // RUN 2 (VW-99): all three tiers were seen on all four planes — the retune
436
+ // worked — but `subtle` was still "a bit hard to read", so the whole family
437
+ // took a further +.01. That is a comfort margin on a passing row, not a fix
438
+ // for a failing one, which is why it is a flat offset: the 1 : 1.56 : 2.33
439
+ // spacing that the run validated is preserved rather than re-derived.
440
+ //
441
+ // Keep these to TWO decimals. react-native-web quantises alpha to 8 bits, so
442
+ // a 3-decimal value silently rounds on the way to the DOM (.135 renders as
443
+ // .13) — the token would say one thing and paint another.
444
+ //
445
+ // DARK ONLY. The light family above composites toward BLACK on light planes,
446
+ // which this run says nothing about — do not mirror these numbers into it
447
+ // without its own verification.
448
+ "hairline-subtle": "rgba(255, 255, 255, 0.10)",
449
+ "hairline-default": "rgba(255, 255, 255, 0.15)",
450
+ "hairline-strong": "rgba(255, 255, 255, 0.22)",
441
451
  // Interactive states
442
452
  "interactive-hover": "rgba(255, 255, 255, 0.04)",
443
453
  "interactive-focus": "rgba(255, 255, 255, 0.12)",
@@ -446,10 +456,9 @@ var semanticColorsDark = {
446
456
  "interactive-disabled": "rgba(255, 255, 255, 0.12)",
447
457
  "interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
448
458
  // Divider
449
- "divider": primitiveColors.charcoal[400],
450
- // divider color
459
+ "divider": "rgba(255, 255, 255, 0.09)",
451
460
  // Avatar default
452
- "avatar-background": primitiveColors.neutral[600],
461
+ "avatar-background": greyRamp[700],
453
462
  "avatar-text": primitiveColors.white
454
463
  };
455
464
  function getSemanticColors(mode) {
@@ -863,7 +872,7 @@ function ViewToggle({ view, onViewChange }) {
863
872
  borderRadius: 9999,
864
873
  backgroundColor: active ? "rgba(255,121,0,0.16)" : "transparent",
865
874
  borderWidth: 1,
866
- borderColor: active ? BRAND_PRIMARY : resolveColor("border-strong")
875
+ borderColor: active ? BRAND_PRIMARY : resolveColor("hairline-strong")
867
876
  },
868
877
  testID: `body-map-toggle-${side}`,
869
878
  children: /* @__PURE__ */ jsx(
@@ -905,7 +914,7 @@ function MuscleButton({ entry, highlighted, onMusclePress }) {
905
914
  paddingVertical: 3,
906
915
  borderRadius: 9999,
907
916
  borderWidth: 1,
908
- borderColor: highlighted ? BRAND_PRIMARY : resolveColor("border-default")
917
+ borderColor: highlighted ? BRAND_PRIMARY : resolveColor("hairline-default")
909
918
  },
910
919
  testID: `body-map-muscle-${entry.key}`,
911
920
  children: [
@@ -1017,7 +1026,7 @@ function Indicator({
1017
1026
  // src/components/ui/badge/Badge.tsx
1018
1027
  var variantColorStyles = {
1019
1028
  solid: {
1020
- default: "bg-border-strong text-text-inverse",
1029
+ default: "bg-hairline-strong text-text-inverse",
1021
1030
  primary: "bg-brand-primary text-text-inverse",
1022
1031
  secondary: "bg-brand-secondary text-text-inverse",
1023
1032
  success: "bg-status-success text-text-inverse",
@@ -1035,7 +1044,7 @@ var variantColorStyles = {
1035
1044
  info: "bg-status-info-subtle text-status-info"
1036
1045
  },
1037
1046
  outline: {
1038
- default: "border border-border-strong text-text-secondary",
1047
+ default: "border border-hairline-strong text-text-secondary",
1039
1048
  primary: "border border-brand-primary text-brand-primary",
1040
1049
  secondary: "border border-brand-secondary text-brand-secondary",
1041
1050
  success: "border border-status-success text-status-success",
@@ -1359,7 +1368,7 @@ function BodyMapDetailPanel({
1359
1368
  children: /* @__PURE__ */ jsx(
1360
1369
  reactNative.View,
1361
1370
  {
1362
- className: "bg-border-strong",
1371
+ className: "bg-hairline-strong",
1363
1372
  style: { width: 40, height: 4, borderRadius: 2 },
1364
1373
  accessibilityElementsHidden: true
1365
1374
  }
@@ -1542,7 +1551,7 @@ function BodyMapDetailPanel({
1542
1551
  contributingExercises.map((exercise, index) => /* @__PURE__ */ jsxs(
1543
1552
  reactNative.View,
1544
1553
  {
1545
- className: "flex-row items-center justify-between bg-surface-raised border-border",
1554
+ className: "flex-row items-center justify-between bg-surface-raised border-hairline",
1546
1555
  style: {
1547
1556
  gap: 10,
1548
1557
  paddingVertical: 8,
@@ -1649,6 +1658,8 @@ function BodyMapDetailPanel({
1649
1658
  }
1650
1659
  );
1651
1660
  }
1661
+
1662
+ // src/theme/color-utils.ts
1652
1663
  function hexToRgb(hex) {
1653
1664
  const cleaned = hex.replace("#", "");
1654
1665
  let r, g, b;
@@ -1738,194 +1749,6 @@ function lighten(hex, amount = 0.1) {
1738
1749
  const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
1739
1750
  return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
1740
1751
  }
1741
- var shadowColors = {
1742
- // For charcoal surfaces (~#2C2C2C to #3C3C3C)
1743
- charcoal: {
1744
- dark: "rgba(0, 0, 0, 0.5)",
1745
- light: "rgba(255, 255, 255, 0.12)",
1746
- // brighter for crisp rim light
1747
- darker: "rgba(0, 0, 0, 0.6)"
1748
- },
1749
- // For neutral dark surfaces (~#1F2937)
1750
- neutralDark: {
1751
- dark: "rgba(0, 0, 0, 0.4)",
1752
- light: "rgba(255, 255, 255, 0.08)",
1753
- darker: "rgba(0, 0, 0, 0.5)"
1754
- },
1755
- // For light surfaces (white/light gray backgrounds)
1756
- neutralLight: {
1757
- dark: "rgba(0, 0, 0, 0.15)",
1758
- // Visible dark shadow for depth on light backgrounds
1759
- light: "rgba(255, 255, 255, 1)",
1760
- // Bright highlight for raised effect (visible on light gray)
1761
- darker: "rgba(0, 0, 0, 0.2)"
1762
- // Deeper shadow for pressed states
1763
- }
1764
- };
1765
- var intensityConfig = {
1766
- subtle: { offset: 1, blur: 2 },
1767
- // very light, barely visible
1768
- medium: { offset: 2, blur: 4 },
1769
- // noticeable but restrained
1770
- strong: { offset: 2, blur: 5 }
1771
- // slightly deeper blur, same offset as medium
1772
- };
1773
- function createRaisedShadow(surface = "charcoal", intensity = "medium") {
1774
- const colors = shadowColors[surface];
1775
- const { offset, blur } = intensityConfig[intensity];
1776
- const rimBlur = 1;
1777
- return reactNative.Platform.select({
1778
- web: {
1779
- boxShadow: `${offset}px ${offset}px ${blur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
1780
- },
1781
- default: {
1782
- // React Native shadow approximation (limited compared to web)
1783
- shadowColor: "#000",
1784
- shadowOffset: { width: offset, height: offset },
1785
- shadowOpacity: 0.3,
1786
- shadowRadius: blur / 2,
1787
- elevation: offset
1788
- }
1789
- });
1790
- }
1791
- function createPressedShadow(surface = "charcoal", intensity = "medium") {
1792
- const colors = shadowColors[surface];
1793
- const { offset, blur } = intensityConfig[intensity];
1794
- const rimOffset = 1;
1795
- const rimBlur = 1;
1796
- return reactNative.Platform.select({
1797
- web: {
1798
- boxShadow: `inset ${offset}px ${offset}px ${blur}px ${colors.darker}, inset -${rimOffset}px -${rimOffset}px ${rimBlur}px ${colors.light}`
1799
- },
1800
- default: {
1801
- // React Native doesn't support inset shadows, approximate with darker bg
1802
- shadowOpacity: 0,
1803
- elevation: 0
1804
- }
1805
- });
1806
- }
1807
- function createFlatShadow() {
1808
- return reactNative.Platform.select({
1809
- web: {
1810
- boxShadow: "none"
1811
- },
1812
- default: {
1813
- shadowOpacity: 0,
1814
- elevation: 0
1815
- }
1816
- });
1817
- }
1818
- function createRaisedHoverShadow(surface = "charcoal", intensity = "medium") {
1819
- const colors = shadowColors[surface];
1820
- const { offset, blur } = intensityConfig[intensity];
1821
- const hoverOffset = Math.max(1, Math.round(offset / 2));
1822
- const hoverBlur = Math.max(1, Math.round(blur / 2));
1823
- const rimBlur = 1;
1824
- return reactNative.Platform.select({
1825
- web: {
1826
- // Keep same offsets as normal state for rim to prevent "shrinking" effect
1827
- boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
1828
- },
1829
- default: {
1830
- shadowColor: "#000",
1831
- shadowOffset: { width: hoverOffset, height: hoverOffset },
1832
- shadowOpacity: 0.2,
1833
- shadowRadius: hoverBlur / 2,
1834
- elevation: hoverOffset
1835
- }
1836
- });
1837
- }
1838
- function createPressedHoverShadow(surface = "charcoal", intensity = "medium") {
1839
- const colors = shadowColors[surface];
1840
- const { offset, blur } = intensityConfig[intensity];
1841
- const hoverOffset = Math.max(1, Math.round(offset / 2));
1842
- const hoverBlur = Math.max(1, Math.round(blur / 2));
1843
- const rimBlur = 1;
1844
- return reactNative.Platform.select({
1845
- web: {
1846
- // Keep rim offset at 1px (same as pressed normal) to prevent "shrinking" effect
1847
- boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.darker}, inset -1px -1px ${rimBlur}px ${colors.light}`
1848
- },
1849
- default: {
1850
- shadowOpacity: 0,
1851
- elevation: 0
1852
- }
1853
- });
1854
- }
1855
- ({
1856
- // Charcoal surface shadows (for dark toolbars, cards)
1857
- charcoal: {
1858
- raised: {
1859
- subtle: createRaisedShadow("charcoal", "subtle"),
1860
- medium: createRaisedShadow("charcoal", "medium"),
1861
- strong: createRaisedShadow("charcoal", "strong")
1862
- },
1863
- raisedHover: {
1864
- subtle: createRaisedHoverShadow("charcoal", "subtle"),
1865
- medium: createRaisedHoverShadow("charcoal", "medium"),
1866
- strong: createRaisedHoverShadow("charcoal", "strong")
1867
- },
1868
- pressed: {
1869
- subtle: createPressedShadow("charcoal", "subtle"),
1870
- medium: createPressedShadow("charcoal", "medium"),
1871
- strong: createPressedShadow("charcoal", "strong")
1872
- },
1873
- pressedHover: {
1874
- subtle: createPressedHoverShadow("charcoal", "subtle"),
1875
- medium: createPressedHoverShadow("charcoal", "medium"),
1876
- strong: createPressedHoverShadow("charcoal", "strong")
1877
- },
1878
- flat: createFlatShadow()
1879
- },
1880
- // Neutral dark surface shadows
1881
- neutralDark: {
1882
- raised: {
1883
- subtle: createRaisedShadow("neutralDark", "subtle"),
1884
- medium: createRaisedShadow("neutralDark", "medium"),
1885
- strong: createRaisedShadow("neutralDark", "strong")
1886
- },
1887
- raisedHover: {
1888
- subtle: createRaisedHoverShadow("neutralDark", "subtle"),
1889
- medium: createRaisedHoverShadow("neutralDark", "medium"),
1890
- strong: createRaisedHoverShadow("neutralDark", "strong")
1891
- },
1892
- pressed: {
1893
- subtle: createPressedShadow("neutralDark", "subtle"),
1894
- medium: createPressedShadow("neutralDark", "medium"),
1895
- strong: createPressedShadow("neutralDark", "strong")
1896
- },
1897
- pressedHover: {
1898
- subtle: createPressedHoverShadow("neutralDark", "subtle"),
1899
- medium: createPressedHoverShadow("neutralDark", "medium"),
1900
- strong: createPressedHoverShadow("neutralDark", "strong")
1901
- },
1902
- flat: createFlatShadow()
1903
- },
1904
- // Neutral light surface shadows
1905
- neutralLight: {
1906
- raised: {
1907
- subtle: createRaisedShadow("neutralLight", "subtle"),
1908
- medium: createRaisedShadow("neutralLight", "medium"),
1909
- strong: createRaisedShadow("neutralLight", "strong")
1910
- },
1911
- raisedHover: {
1912
- subtle: createRaisedHoverShadow("neutralLight", "subtle"),
1913
- medium: createRaisedHoverShadow("neutralLight", "medium"),
1914
- strong: createRaisedHoverShadow("neutralLight", "strong")
1915
- },
1916
- pressed: {
1917
- subtle: createPressedShadow("neutralLight", "subtle"),
1918
- medium: createPressedShadow("neutralLight", "medium"),
1919
- strong: createPressedShadow("neutralLight", "strong")
1920
- },
1921
- pressedHover: {
1922
- subtle: createPressedHoverShadow("neutralLight", "subtle"),
1923
- medium: createPressedHoverShadow("neutralLight", "medium"),
1924
- strong: createPressedHoverShadow("neutralLight", "strong")
1925
- },
1926
- flat: createFlatShadow()
1927
- }
1928
- });
1929
1752
  var elevationSystem = {
1930
1753
  // Deep inset (recessed input fields, deeply pressed buttons)
1931
1754
  [-2]: {
@@ -1954,7 +1777,13 @@ var elevationSystem = {
1954
1777
  // Level 1: Subtle elevation (outline cards, subtle containers)
1955
1778
  [1]: {
1956
1779
  name: "subtle",
1957
- colorAdjustment: 0.01,
1780
+ // The whole ladder was re-spaced in TD-07.16. It used to run
1781
+ // 0.01/0.02/0.04/0.06/0.08, where the first step was ~2 RGB values — under
1782
+ // the perceptual floor, so level 1 existed in the type system and nowhere on
1783
+ // screen. With drop-shadow now gated off below FLOATING_ELEVATION_MIN, TONE
1784
+ // is the only thing separating 0-3, so every step has to actually land.
1785
+ // Even 0.025 spacing, verified in elevation.test.ts as ΔL* > 1 per step.
1786
+ colorAdjustment: 0.025,
1958
1787
  shadowIntensity: "subtle",
1959
1788
  shadowStyle: "raised",
1960
1789
  description: "Subtle elevation (outline cards, subtle containers)"
@@ -1962,7 +1791,7 @@ var elevationSystem = {
1962
1791
  // Level 2: Standard elevation (default cards, buttons)
1963
1792
  [2]: {
1964
1793
  name: "standard",
1965
- colorAdjustment: 0.02,
1794
+ colorAdjustment: 0.05,
1966
1795
  shadowIntensity: "medium",
1967
1796
  shadowStyle: "raised",
1968
1797
  description: "Standard elevation (default cards, raised buttons)"
@@ -1970,7 +1799,7 @@ var elevationSystem = {
1970
1799
  // Level 3: Prominent elevation (important cards, modals)
1971
1800
  [3]: {
1972
1801
  name: "prominent",
1973
- colorAdjustment: 0.04,
1802
+ colorAdjustment: 0.075,
1974
1803
  shadowIntensity: "strong",
1975
1804
  shadowStyle: "raised",
1976
1805
  description: "Prominent elevation (important cards, modals, dropdowns)"
@@ -1978,7 +1807,7 @@ var elevationSystem = {
1978
1807
  // Level 4: High elevation (overlays, popovers)
1979
1808
  [4]: {
1980
1809
  name: "high",
1981
- colorAdjustment: 0.06,
1810
+ colorAdjustment: 0.1,
1982
1811
  shadowIntensity: "strong",
1983
1812
  shadowStyle: "raised",
1984
1813
  description: "High elevation (overlays, popovers, tooltips)"
@@ -1986,7 +1815,7 @@ var elevationSystem = {
1986
1815
  // Level 5: Floating (toasts, floating action buttons)
1987
1816
  [5]: {
1988
1817
  name: "floating",
1989
- colorAdjustment: 0.08,
1818
+ colorAdjustment: 0.13,
1990
1819
  shadowIntensity: "strong",
1991
1820
  shadowStyle: "raised",
1992
1821
  description: "Floating elevation (toasts, floating action buttons, highest z-index)"
@@ -2102,12 +1931,12 @@ function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
2102
1931
  const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
2103
1932
  const rimLightColor = calculateRimLightColor(baseColor, level);
2104
1933
  const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
2105
- const intensityConfig2 = {
1934
+ const intensityConfig = {
2106
1935
  subtle: { offset: 1, blur: 2 },
2107
1936
  medium: { offset: 2, blur: 4 },
2108
1937
  strong: { offset: 2, blur: 5 }
2109
1938
  };
2110
- const { offset, blur } = intensityConfig2[config.shadowIntensity];
1939
+ const { offset, blur } = intensityConfig[config.shadowIntensity];
2111
1940
  const rimConfig = getRimLightConfig();
2112
1941
  if (config.shadowStyle === "pressed") {
2113
1942
  if (isHovered) {
@@ -2163,12 +1992,13 @@ function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
2163
1992
  });
2164
1993
  }
2165
1994
  }
1995
+ var FLOATING_ELEVATION_MIN = 4;
2166
1996
  function getElevationShadow(baseColor, level, theme, isHovered = false) {
2167
1997
  const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
2168
1998
  if (elevationShadowCache.has(cacheKey)) {
2169
1999
  return elevationShadowCache.get(cacheKey);
2170
2000
  }
2171
- const result = calculateElevationShadow(baseColor, level, theme, isHovered);
2001
+ const result = level > 0 && level < FLOATING_ELEVATION_MIN ? {} : calculateElevationShadow(baseColor, level, theme, isHovered);
2172
2002
  if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
2173
2003
  const firstKey = elevationShadowCache.keys().next().value;
2174
2004
  elevationShadowCache.delete(firstKey);
@@ -2254,12 +2084,12 @@ function useTheme() {
2254
2084
  var variantStyles = {
2255
2085
  elevated: "",
2256
2086
  // Will be set dynamically via elevation system
2257
- outline: "border-2 border-border-strong",
2087
+ outline: "border-2 border-hairline-strong",
2258
2088
  // Thicker border with stronger contrast
2259
2089
  filled: "",
2260
2090
  // Will be set dynamically via elevation system
2261
- accent: "border border-border",
2262
- subtle: "border border-border-subtle"
2091
+ accent: "border border-hairline",
2092
+ subtle: "border border-hairline-subtle"
2263
2093
  };
2264
2094
  function Card({
2265
2095
  variant = "elevated",
@@ -2379,7 +2209,7 @@ var solidVariantColors = {
2379
2209
  success: t2["status-success"],
2380
2210
  warning: t2["status-warning"],
2381
2211
  error: t2["status-error"],
2382
- neutral: "#6B7280"
2212
+ neutral: greyRamp[500]
2383
2213
  };
2384
2214
  var ringVariantStyles = {
2385
2215
  "on-track": {
@@ -2417,10 +2247,10 @@ var iconColors = {
2417
2247
  success: "#0A5C52",
2418
2248
  warning: "#6B4000",
2419
2249
  error: "#5C1A1A",
2420
- neutral: "#D1D5DB",
2250
+ neutral: greyRamp[200],
2421
2251
  "on-track": t2["status-success"],
2422
2252
  deviation: t2["status-warning"],
2423
- future: "#6B7280"
2253
+ future: greyRamp[500]
2424
2254
  };
2425
2255
  var sizeDimensions = {
2426
2256
  sm: { size: 8, showIcon: false },
@@ -2489,7 +2319,7 @@ function StatusDot({
2489
2319
  /* @__PURE__ */ jsx(
2490
2320
  reactNative.Text,
2491
2321
  {
2492
- style: { fontSize: 12, lineHeight: 16, color: "#9CA3AF" },
2322
+ style: { fontSize: 12, lineHeight: 16, color: greyRamp[400] },
2493
2323
  accessibilityElementsHidden: true,
2494
2324
  children: label
2495
2325
  }
@@ -2904,7 +2734,7 @@ function SummaryCards({ summary }) {
2904
2734
  return /* @__PURE__ */ jsxs(
2905
2735
  reactNative.View,
2906
2736
  {
2907
- className: "bg-surface-elevated border-border",
2737
+ className: "bg-surface-elevated border-hairline",
2908
2738
  style: {
2909
2739
  flexGrow: 1,
2910
2740
  flexBasis: "46%",
@@ -3045,7 +2875,7 @@ function TrainingStatusPage({
3045
2875
  /* @__PURE__ */ jsxs(
3046
2876
  reactNative.View,
3047
2877
  {
3048
- className: "bg-surface-elevated border-border",
2878
+ className: "bg-surface-elevated border-hairline",
3049
2879
  style: {
3050
2880
  borderWidth: 1,
3051
2881
  borderRadius: 12,