@titan-design/react-ui 0.11.0 → 0.12.1

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