@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/index.js CHANGED
@@ -267,93 +267,50 @@ function AlertDescription({ children, className }) {
267
267
 
268
268
  // src/theme/tokens/primitives.ts
269
269
  var primitiveColors = {
270
- // Blue scale
271
- blue: {
272
- 50: "#EFF6FF",
273
- 100: "#DBEAFE",
274
- 200: "#BFDBFE",
275
- 300: "#93C5FD",
276
- 400: "#60A5FA",
277
- 500: "#3B82F6",
278
- 600: "#5048E5",
279
- 700: "#3832A0",
280
- 800: "#1E40AF",
281
- 900: "#1E3A8A"
282
- },
283
- // Red scale
284
- red: {
285
- 50: "#FEF2F2",
286
- 100: "#FEE2E2",
287
- 200: "#FECACA",
288
- 300: "#FCA5A5",
289
- 400: "#DA6868",
290
- 500: "#EF4444",
291
- 600: "#D14343",
292
- 700: "#922E2E",
293
- 800: "#991B1B",
294
- 900: "#7F1D1D"
295
- },
296
- // Vivid red scale
297
- redVivid: {
298
- 50: "#FFECEE",
299
- 100: "#FFD6DB",
300
- 200: "#FFB3BC",
301
- 300: "#FF8593",
302
- 400: "#FF6070",
303
- 500: "#FF4757",
304
- 600: "#E63548",
305
- 700: "#C42539",
306
- 800: "#9E1C2C",
307
- 900: "#7A1520"
308
- },
309
- // Neutral/Gray scale
310
- neutral: {
311
- 50: "#FAFAFA",
312
- 100: "#F3F4F6",
313
- 200: "#E5E7EB",
314
- 300: "#D1D5DB",
315
- 400: "#9CA3AF",
316
- 500: "#6B7280",
317
- 600: "#4B5563",
318
- 700: "#374151",
319
- 800: "#1F2937",
320
- 900: "#111827",
321
- 950: "#030712"
322
- },
323
- // Charcoal scale (dark backgrounds)
324
- charcoal: {
325
- 0: "#6E6E6E",
326
- 50: "#5D5D5D",
327
- 100: "#4C4C4C",
328
- 200: "#3C3C3C",
329
- 300: "#2C2C2C",
330
- 400: "#1F1F1F",
331
- 500: "#1C1C1C",
332
- 600: "#191919",
333
- 700: "#161616",
334
- 800: "#131313",
335
- 900: "#101010"
336
- },
337
- // Pure colors
338
270
  white: "#FFFFFF",
339
271
  black: "#000000",
340
272
  transparent: "transparent"
341
273
  };
342
- var surfaceRampDark = {
343
- inset: "#13100D",
344
- // L*4.5 — sub-shell well / pressed
345
- background: "#1C1916",
346
- // L*9 — shell / frame
347
- base: "#252321",
348
- // L*13.5 main content plane
349
- elevated: "#2C2A28",
350
- // L*17 — nav / rail
351
- raised: "#31302F",
352
- // L*20 — cards
353
- overlay: "#373635"
354
- // L*22.5 — hero / popover
274
+ var greyRamp = {
275
+ 50: "#F9F6F3",
276
+ // L*97.0 W6
277
+ 100: "#EDEAE7",
278
+ // L*92.8 W6
279
+ 200: "#D4D1CE",
280
+ // L*84.0 W6 warm silver
281
+ 300: "#BDBAB7",
282
+ // L*75.7 W6
283
+ 400: "#A29F9D",
284
+ // L*65.7 W5
285
+ 500: "#888684",
286
+ // L*56.0 W4
287
+ 600: "#72716F",
288
+ // L*47.7 W3
289
+ 700: "#5A5958",
290
+ // L*37.9 W2
291
+ 800: "#424140",
292
+ // L*27.6 W2 — generated bridge
293
+ 850: "#373635",
294
+ // L*22.7 W2 — surface overlay
295
+ 875: "#31302F",
296
+ // L*19.9 W2 — surface raised
297
+ 900: "#2C2A28",
298
+ // L*17.2 W4 — surface elevated
299
+ 925: "#252321",
300
+ // L*13.9 W4 — surface base
301
+ 950: "#1C1916",
302
+ // L*9.0 W6 — background base / shell
303
+ 975: "#100D0A"
304
+ // L*3.8 W6 — background frame / bezel
305
+ };
306
+ var SURFACE_PLANE_STEPS = {
307
+ frame: 975,
308
+ background: 950,
309
+ base: 925,
310
+ elevated: 900,
311
+ raised: 875,
312
+ overlay: 850
355
313
  };
356
- var backgroundFrameDark = "#100D0A";
357
314
  var primitiveRamps = {
358
315
  red: {
359
316
  50: "#FFF4F4",
@@ -504,8 +461,8 @@ var sequentialEffort = [
504
461
  ];
505
462
  function bestTextColor(hex) {
506
463
  const [r, g, b] = [0, 2, 4].map((i) => {
507
- const c = parseInt(hex.replace("#", "").slice(i, i + 2), 16) / 255;
508
- return c >= 0.04045 ? ((c + 0.055) / 1.055) ** 2.4 : c / 12.92;
464
+ const c2 = parseInt(hex.replace("#", "").slice(i, i + 2), 16) / 255;
465
+ return c2 >= 0.04045 ? ((c2 + 0.055) / 1.055) ** 2.4 : c2 / 12.92;
509
466
  });
510
467
  const l = 0.2126 * r + 0.7152 * g + 0.0722 * b;
511
468
  return (l + 0.05) / 0.05 >= 1.05 / (l + 0.05) ? "#000000" : "#FFFFFF";
@@ -681,16 +638,6 @@ var primitiveBorderRadius = {
681
638
  "2xl": "24px",
682
639
  full: "9999px"
683
640
  };
684
- var primitiveShadows = {
685
- none: "none",
686
- sm: "0px 1px 2px rgba(100, 116, 139, 0.12)",
687
- DEFAULT: "0px 1px 3px rgba(100, 116, 139, 0.12), 0px 1px 2px rgba(100, 116, 139, 0.24)",
688
- md: "0px 4px 6px rgba(100, 116, 139, 0.12)",
689
- lg: "0px 10px 15px rgba(100, 116, 139, 0.12)",
690
- xl: "0px 20px 25px rgba(100, 116, 139, 0.12)",
691
- "2xl": "0px 25px 50px rgba(100, 116, 139, 0.25)",
692
- inner: "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)"
693
- };
694
641
  var primitiveBreakpoints = {
695
642
  xs: 0,
696
643
  sm: 600,
@@ -746,10 +693,10 @@ var semanticColorsLight = {
746
693
  "status-error-light": primitiveRamps.red[500],
747
694
  "status-error-dark": primitiveRamps.red[700],
748
695
  "status-error-subtle": primitiveRamps.red[50],
749
- "status-error-vivid": primitiveColors.redVivid[500],
696
+ "status-error-vivid": primitiveRamps.red[600],
750
697
  // vivid alert red
751
- "status-error-vivid-light": primitiveColors.redVivid[400],
752
- "status-error-vivid-dark": primitiveColors.redVivid[700],
698
+ "status-error-vivid-light": primitiveRamps.red[500],
699
+ "status-error-vivid-dark": primitiveRamps.red[700],
753
700
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
754
701
  "status-warning": primitiveRamps.amber[300],
755
702
  "status-warning-light": primitiveRamps.amber[200],
@@ -776,7 +723,7 @@ var semanticColorsLight = {
776
723
  "result-inconclusive": "#9E9A97",
777
724
  // Gray - no clear result
778
725
  "result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
779
- "result-neutral": primitiveColors.neutral[500],
726
+ "result-neutral": greyRamp[600],
780
727
  // Neutral baseline
781
728
  // Text on result backgrounds (on-result-*)
782
729
  "on-result-improve": primitiveColors.white,
@@ -807,47 +754,38 @@ var semanticColorsLight = {
807
754
  // Text colors (text-*)
808
755
  "text-primary": "#121828",
809
756
  "text-secondary": "#65748B",
810
- "text-tertiary": primitiveColors.neutral[400],
757
+ "text-tertiary": greyRamp[400],
811
758
  "text-disabled": "rgba(55, 65, 81, 0.48)",
812
759
  "text-inverse": primitiveColors.white,
813
- "text-link": primitiveColors.blue[600],
814
- "text-link-hover": primitiveColors.blue[700],
760
+ "text-link": primitiveRamps.blue[600],
761
+ "text-link-hover": primitiveRamps.blue[700],
815
762
  // Surface colors (surface-*) - for elevated containers
816
763
  "surface-base": primitiveColors.white,
817
- "surface-elevated": primitiveColors.neutral[50],
764
+ "surface-elevated": greyRamp[50],
818
765
  // slightly off-white for elevated cards
819
- "surface-raised": primitiveColors.neutral[100],
766
+ "surface-raised": greyRamp[100],
820
767
  // light gray for raised cards
821
768
  "surface-overlay": primitiveColors.white,
822
- "surface-input": primitiveColors.neutral[50],
769
+ "surface-input": greyRamp[50],
823
770
  // Input field background (filled variant)
824
- // Deepest pressed pit (TD-surface-tokens, S-3) — light-mode counterpart of
825
- // the dark ramp's `inset` plane; a placeholder pairing, not part of the
826
- // dark-ramp investigation (surface.contract.test.ts is dark-mode only).
827
- "surface-inset": primitiveColors.neutral[300],
828
771
  // Background colors (background-*)
829
772
  "background-base": "#EBEBEB",
830
773
  "background-default": primitiveColors.white,
831
- "background-subtle": primitiveColors.neutral[50],
832
- // Frame/bezel chrome (TD-surface-tokens, S-3) — top bar + side nav shell,
833
- // one step below `background-base` (darker still than `surface-inset`
834
- // above, mirroring the dark-mode ordering). Placeholder pairing for light
835
- // mode (see dark-mode note on `surface-inset` above).
836
- "background-frame": primitiveColors.neutral[400],
774
+ "background-subtle": greyRamp[50],
775
+ // Frame/bezel chrome — top bar + side nav shell, one step below
776
+ // `background-base`. Placeholder pairing for light mode, which is deferred.
777
+ "background-frame": greyRamp[400],
837
778
  // Border colors (border-*)
838
- "border-default": "#E8E9EB",
839
- "border-subtle": primitiveColors.neutral[100],
840
- "border-strong": primitiveColors.neutral[300],
841
- "border-prominent": primitiveColors.neutral[400],
779
+ "border-prominent": greyRamp[400],
842
780
  // high-visibility divider
843
- "border-focus": primitiveColors.blue[600],
844
- "border-input": primitiveColors.neutral[300],
781
+ "border-focus": primitiveRamps.blue[600],
782
+ "border-input": greyRamp[200],
845
783
  // Input field border
846
- "border-input-hover": primitiveColors.neutral[400],
784
+ "border-input-hover": greyRamp[400],
847
785
  // Input field border on hover
848
- "border-input-focus": primitiveColors.blue[600],
786
+ "border-input-focus": primitiveRamps.blue[600],
849
787
  // Input field border on focus
850
- "border-input-error": primitiveColors.red[600],
788
+ "border-input-error": primitiveRamps.red[600],
851
789
  // Input field border on error
852
790
  // Alpha hairline separators (surface-independent — composite toward black on
853
791
  // light surfaces, mirroring the dark-mode white-alpha family). See §4/S-2.
@@ -864,7 +802,7 @@ var semanticColorsLight = {
864
802
  // Divider
865
803
  "divider": "#E8E9EB",
866
804
  // Avatar default
867
- "avatar-background": primitiveColors.neutral[500],
805
+ "avatar-background": greyRamp[600],
868
806
  "avatar-text": primitiveColors.white
869
807
  };
870
808
  var semanticColorsDark = {
@@ -896,9 +834,9 @@ var semanticColorsDark = {
896
834
  "status-error-light": primitiveRamps.red[500],
897
835
  "status-error-dark": primitiveRamps.red[700],
898
836
  "status-error-subtle": "rgba(209, 67, 67, 0.12)",
899
- "status-error-vivid": primitiveColors.redVivid[500],
900
- "status-error-vivid-light": primitiveColors.redVivid[400],
901
- "status-error-vivid-dark": primitiveColors.redVivid[700],
837
+ "status-error-vivid": primitiveRamps.red[600],
838
+ "status-error-vivid-light": primitiveRamps.red[500],
839
+ "status-error-vivid-dark": primitiveRamps.red[700],
902
840
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
903
841
  "status-warning": primitiveRamps.amber[300],
904
842
  "status-warning-light": primitiveRamps.amber[200],
@@ -922,7 +860,7 @@ var semanticColorsDark = {
922
860
  "result-degrade-dark": "#b30000",
923
861
  "result-inconclusive": "#9E9A97",
924
862
  "result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
925
- "result-neutral": primitiveColors.neutral[400],
863
+ "result-neutral": greyRamp[400],
926
864
  // Text on result backgrounds
927
865
  "on-result-improve": primitiveColors.white,
928
866
  "on-result-degrade": primitiveColors.white,
@@ -939,74 +877,106 @@ var semanticColorsDark = {
939
877
  "data-9": discreteRainbow[3],
940
878
  "data-10": discreteRainbow[22],
941
879
  // Text colors - inverted for dark mode
942
- "text-primary": primitiveColors.neutral[100],
943
- "text-secondary": primitiveColors.neutral[400],
944
- "text-tertiary": primitiveColors.neutral[500],
880
+ "text-primary": greyRamp[50],
881
+ "text-secondary": greyRamp[400],
882
+ // Deliberately ONE step lighter than the L*-nearest match (`greyRamp[600]`).
883
+ // The colour this replaced failed WCAG large-text outright on the three
884
+ // lightest planes — 2.96 / 2.72 / 2.49 against elevated / raised / overlay —
885
+ // and `600` carried that failure forward almost exactly (2.93 / 2.70 / 2.47).
886
+ // `500` clears 3:1 everywhere (3.32–5.34). Contrast beats colour fidelity for
887
+ // text roles; borders and surfaces still use strict L*-nearest. See
888
+ // semantic-contrast.test.ts, which fails if this is moved back down.
889
+ "text-tertiary": greyRamp[500],
945
890
  "text-disabled": "rgba(255, 255, 255, 0.38)",
946
- "text-inverse": primitiveColors.neutral[900],
891
+ "text-inverse": greyRamp[950],
947
892
  "text-link": "#828DF8",
948
- "text-link-hover": primitiveColors.blue[400],
893
+ "text-link-hover": primitiveRamps.blue[400],
949
894
  // Surface colors - dark backgrounds — warm-tapered DERIVED ramp (TD-surface-tokens,
950
895
  // S-1, re-spaced S-3). Shipped verbatim from `deriveSurfaceRamp()` — see
951
896
  // `surfaceRampDark` in primitives.ts for the full derivation note. `surface-overlay`
952
897
  // and `surface-elevated` are distinct (were both #191919 pre-S-1); `surface-input`
953
898
  // tracks one plane above `surface-base`, same relative position as before the remap.
954
899
  // `background-base` backs `Surface level="background"` (SurfaceContext.SURFACE_LEVEL_TOKEN),
955
- // so it takes the ramp's `background` (shell/frame) role, NOT `inset`. The ramp's
956
- // deepest `inset` plane is now promoted to `surface-inset` below (S-3) still no
957
- // `SurfaceLevel` member for it (follow-up, alongside the elevation.ts -1/-2 pressed
958
- // levels — parallel workstream, not this branch).
959
- "surface-base": surfaceRampDark.base,
960
- // main surface (#252321, L*13.5)
961
- "surface-elevated": surfaceRampDark.elevated,
962
- // elevated surface (#2C2A28, L*17 nav/rail)
963
- "surface-raised": surfaceRampDark.raised,
964
- // raised surface (#31302F, L*20 cards)
965
- "surface-overlay": surfaceRampDark.overlay,
966
- // overlay surface (#373635, L*22.5 — hero/popover)
967
- "surface-input": surfaceRampDark.elevated,
900
+ // so it takes the ramp's shell role. The deepest plane is `background-frame`,
901
+ // which is also the `SurfaceLevel` floor a pressed surface clamps at.
902
+ "surface-base": greyRamp[925],
903
+ // main surface (#252321, L*13.9)
904
+ "surface-elevated": greyRamp[900],
905
+ // elevated surface (#2C2A28, L*17.2 — nav/rail)
906
+ "surface-raised": greyRamp[875],
907
+ // raised surface (#31302F, L*19.9 cards)
908
+ "surface-overlay": greyRamp[850],
909
+ // overlay surface (#373635, L*22.7 hero/popover)
910
+ "surface-input": greyRamp[900],
968
911
  // input surface (#2C2A28 — one plane above base)
969
- "surface-inset": surfaceRampDark.inset,
970
- // deepest pressed pit (#13100D, L*4.5 — sub-shell well)
971
912
  // Background colors — same ramp, the frame/shell end of it.
972
- "background-base": surfaceRampDark.background,
973
- // shell / frame (#1C1916, L*9 — Surface level="background")
974
- "background-default": surfaceRampDark.base,
975
- // main background (#252321, L*13.5 — matches surface-base)
976
- "background-subtle": surfaceRampDark.elevated,
977
- // subtle background (#2C2A28, L*17 — matches surface-elevated)
978
- // Frame/bezel chrome (S-3) — the top bar + side nav shell; one step BELOW
979
- // `background-base`, darker even than `surface-inset` it exits the content
980
- // ramp entirely rather than sitting in it. See `backgroundFrameDark` in
981
- // primitives.ts.
982
- "background-frame": backgroundFrameDark,
983
- // frame / bezel (#100D0A, L*3.79)
984
- // Border colors `border-subtle` (#1C1C1C) previously collided with
985
- // `surface-raised` (also #1C1C1C, an invisible border on raised cards). The
986
- // re-spaced ramp above moved `surface-raised` to #2D2C2B, so this value is now
987
- // distinct from every surface hex without needing to change it see
988
- // `surface.contract.test.ts` R2/R4.
989
- "border-default": primitiveColors.charcoal[400],
990
- // default border
991
- "border-subtle": primitiveColors.charcoal[500],
992
- // subtle border
993
- "border-strong": primitiveColors.charcoal[300],
994
- // strong border
995
- "border-prominent": primitiveColors.charcoal[200],
913
+ "background-base": greyRamp[950],
914
+ // shell (#1C1916, L*9 — Surface level="background")
915
+ "background-default": greyRamp[925],
916
+ // main background (#252321, L*13.9 — matches surface-base)
917
+ "background-subtle": greyRamp[900],
918
+ // subtle background (#2C2A28, L*17.2 — matches surface-elevated)
919
+ // Frame/bezel chrome — the top bar + side nav shell, one step BELOW
920
+ // `background-base`. It used to be described as sitting OUTSIDE the ramp; it
921
+ // is simply the ramp's last step now, and the floor `<Surface pressed>` clamps at.
922
+ "background-frame": greyRamp[975],
923
+ // frame / bezel (#100D0A, L*3.8)
924
+ // Border colors — solid dark borders are RETIRED (TD-07.14). Not a preference — a structural
925
+ // consequence of one ramp. Every step from 850 to 975 is now a surface plane,
926
+ // so a solid border dark enough to read as a border necessarily equals some
927
+ // plane's fill, which is exactly the collision `surface.contract.test.ts` R2
928
+ // forbids. The only non-plane steps left in that band are 800 and 700, and
929
+ // borders there jump from L*~10-25 to L*~28-38 — a restyle, not a migration.
930
+ //
931
+ // So separation moves to the alpha hairlines, which dark mode already called
932
+ // "the primary separation cue". Being alpha, they composite against whatever
933
+ // plane they land on and cannot collide with any of them — the problem stops
934
+ // existing rather than being re-solved per plane. The three solid tokens were
935
+ // deleted outright; consumers point at the `hairline-*` family below.
936
+ //
937
+ // `border-prominent` stays SOLID: it is the one border meant to be seen
938
+ // outright (4 call sites, high-visibility dividers), and grey-800 is not a
939
+ // plane, so it keeps its job without collision.
940
+ "border-prominent": greyRamp[800],
996
941
  // high-visibility divider
997
942
  "border-focus": "#828DF8",
998
- "border-input": primitiveColors.neutral[600],
999
- "border-input-hover": primitiveColors.neutral[500],
943
+ "border-input": greyRamp[700],
944
+ "border-input-hover": greyRamp[600],
1000
945
  "border-input-focus": "#828DF8",
1001
- "border-input-error": primitiveColors.red[500],
946
+ "border-input-error": primitiveRamps.red[500],
1002
947
  // Alpha hairline separators — the primary separation cue (§4/S-2). Self-
1003
948
  // normalizing: composites toward white by ~the same amount on ANY plane, so
1004
949
  // one family works at every elevation instead of per-surface border tokens.
1005
950
  // Shadows are demoted to floating-overlay use only (not shipped as a fill
1006
951
  // separator here — see elevation.ts, follow-up S-4).
1007
- "hairline-subtle": "rgba(255, 255, 255, 0.06)",
1008
- "hairline-default": "rgba(255, 255, 255, 0.09)",
1009
- "hairline-strong": "rgba(255, 255, 255, 0.14)",
952
+ //
953
+ // RETUNED on the wall (VW-99, S-6). The original .06/.09/.14 were set at a
954
+ // desk. On the panel at ~3 m `subtle` rendered but was indiscernible, and
955
+ // `default` — the load-bearing one, with no solid-border fallback since
956
+ // TD-07.14 — went weak on the lightest plane. `strong` read cleanly with room
957
+ // to spare, which is what made raising the whole family viable.
958
+ //
959
+ // Each tier steps up onto the next MEASURED-GOOD rung rather than an
960
+ // interpolated one: the new `subtle` is the old `default`, and the new
961
+ // `default` is the old `strong` — a value just confirmed legible on all four
962
+ // planes. Spacing goes 1 : 1.56 : 2.33, against the original 1 : 1.5 : 2.33.
963
+ //
964
+ // RUN 2 (VW-99): all three tiers were seen on all four planes — the retune
965
+ // worked — but `subtle` was still "a bit hard to read", so the whole family
966
+ // took a further +.01. That is a comfort margin on a passing row, not a fix
967
+ // for a failing one, which is why it is a flat offset: the 1 : 1.56 : 2.33
968
+ // spacing that the run validated is preserved rather than re-derived.
969
+ //
970
+ // Keep these to TWO decimals. react-native-web quantises alpha to 8 bits, so
971
+ // a 3-decimal value silently rounds on the way to the DOM (.135 renders as
972
+ // .13) — the token would say one thing and paint another.
973
+ //
974
+ // DARK ONLY. The light family above composites toward BLACK on light planes,
975
+ // which this run says nothing about — do not mirror these numbers into it
976
+ // without its own verification.
977
+ "hairline-subtle": "rgba(255, 255, 255, 0.10)",
978
+ "hairline-default": "rgba(255, 255, 255, 0.15)",
979
+ "hairline-strong": "rgba(255, 255, 255, 0.22)",
1010
980
  // Interactive states
1011
981
  "interactive-hover": "rgba(255, 255, 255, 0.04)",
1012
982
  "interactive-focus": "rgba(255, 255, 255, 0.12)",
@@ -1015,10 +985,9 @@ var semanticColorsDark = {
1015
985
  "interactive-disabled": "rgba(255, 255, 255, 0.12)",
1016
986
  "interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
1017
987
  // Divider
1018
- "divider": primitiveColors.charcoal[400],
1019
- // divider color
988
+ "divider": "rgba(255, 255, 255, 0.09)",
1020
989
  // Avatar default
1021
- "avatar-background": primitiveColors.neutral[600],
990
+ "avatar-background": greyRamp[700],
1022
991
  "avatar-text": primitiveColors.white
1023
992
  };
1024
993
  var semanticTypography = {
@@ -1536,14 +1505,10 @@ var lightThemeCSSVars = {
1536
1505
  "--color-surface-base": semanticColorsLight["surface-base"],
1537
1506
  "--color-surface-elevated": semanticColorsLight["surface-elevated"],
1538
1507
  "--color-surface-raised": semanticColorsLight["surface-raised"],
1539
- "--color-surface-inset": semanticColorsLight["surface-inset"],
1540
1508
  "--color-background-base": semanticColorsLight["background-base"],
1541
1509
  "--color-background-default": semanticColorsLight["background-default"],
1542
1510
  "--color-background-subtle": semanticColorsLight["background-subtle"],
1543
1511
  "--color-background-frame": semanticColorsLight["background-frame"],
1544
- "--color-border-default": semanticColorsLight["border-default"],
1545
- "--color-border-subtle": semanticColorsLight["border-subtle"],
1546
- "--color-border-strong": semanticColorsLight["border-strong"],
1547
1512
  "--color-border-prominent": semanticColorsLight["border-prominent"],
1548
1513
  "--color-border-focus": semanticColorsLight["border-focus"],
1549
1514
  "--color-interactive-hover": semanticColorsLight["interactive-hover"],
@@ -1639,14 +1604,10 @@ var darkThemeCSSVars = {
1639
1604
  "--color-surface-base": semanticColorsDark["surface-base"],
1640
1605
  "--color-surface-elevated": semanticColorsDark["surface-elevated"],
1641
1606
  "--color-surface-raised": semanticColorsDark["surface-raised"],
1642
- "--color-surface-inset": semanticColorsDark["surface-inset"],
1643
1607
  "--color-background-base": semanticColorsDark["background-base"],
1644
1608
  "--color-background-default": semanticColorsDark["background-default"],
1645
1609
  "--color-background-subtle": semanticColorsDark["background-subtle"],
1646
1610
  "--color-background-frame": semanticColorsDark["background-frame"],
1647
- "--color-border-default": semanticColorsDark["border-default"],
1648
- "--color-border-subtle": semanticColorsDark["border-subtle"],
1649
- "--color-border-strong": semanticColorsDark["border-strong"],
1650
1611
  "--color-border-prominent": semanticColorsDark["border-prominent"],
1651
1612
  "--color-border-focus": semanticColorsDark["border-focus"],
1652
1613
  "--color-interactive-hover": semanticColorsDark["interactive-hover"],
@@ -1779,6 +1740,54 @@ var gluestackConfig = {
1779
1740
  rounded: "borderRadius"
1780
1741
  }
1781
1742
  };
1743
+
1744
+ // src/theme/materials.ts
1745
+ var c = getSemanticColors("dark");
1746
+ function parseHex(hex) {
1747
+ const h = hex.replace("#", "");
1748
+ const full = h.length === 3 ? h.split("").map((ch) => ch + ch).join("") : h;
1749
+ const rgb = [
1750
+ parseInt(full.slice(0, 2), 16),
1751
+ parseInt(full.slice(2, 4), 16),
1752
+ parseInt(full.slice(4, 6), 16)
1753
+ ];
1754
+ return rgb.some(Number.isNaN) ? null : rgb;
1755
+ }
1756
+ function perceivedLuminance(hex) {
1757
+ const rgb = parseHex(hex);
1758
+ if (!rgb) return 0.5;
1759
+ const [r, g, b] = rgb;
1760
+ return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
1761
+ }
1762
+ function grainOpacityForTone(baseColor) {
1763
+ return Math.min(0.24, Math.max(0.04, 0.02 + 0.31 * perceivedLuminance(baseColor)));
1764
+ }
1765
+ function grainForTone(baseColor) {
1766
+ const op = grainOpacityForTone(baseColor).toFixed(3);
1767
+ return `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='${op}'/%3E%3C/svg%3E")`;
1768
+ }
1769
+ function paperSheet(tone = c["surface-raised"]) {
1770
+ return {
1771
+ backgroundColor: tone,
1772
+ // Grain alone. The dither went with the gradient it protected — see header.
1773
+ backgroundImage: grainForTone(tone),
1774
+ boxShadow: "inset 0 1px 0 rgba(255,255,255,0.20), 0 8px 22px rgba(0,0,0,0.50)"
1775
+ };
1776
+ }
1777
+ function insetWell(tone = c["surface-input"]) {
1778
+ return {
1779
+ backgroundColor: tone,
1780
+ boxShadow: "inset 0 2px 6px rgba(0,0,0,0.55), inset 0 -1px 0 rgba(255,255,255,0.12)"
1781
+ };
1782
+ }
1783
+ function barPaper(color, flip = false) {
1784
+ return {
1785
+ backgroundImage: grainForTone(color),
1786
+ boxShadow: flip ? "0 -6px 16px rgba(0,0,0,0.45)" : "inset 0 1.5px 0 rgba(255,255,255,0.22), 0 6px 16px rgba(0,0,0,0.45)"
1787
+ };
1788
+ }
1789
+
1790
+ // src/theme/color-utils.ts
1782
1791
  function hexToRgb(hex) {
1783
1792
  const cleaned = hex.replace("#", "");
1784
1793
  let r, g, b;
@@ -1818,32 +1827,32 @@ function rgbToHsv(r, g, b) {
1818
1827
  return { h, s, v };
1819
1828
  }
1820
1829
  function hsvToRgb(h, s, v) {
1821
- const c = v * s;
1822
- const x = c * (1 - Math.abs(h / 60 % 2 - 1));
1823
- const m = v - c;
1830
+ const c2 = v * s;
1831
+ const x = c2 * (1 - Math.abs(h / 60 % 2 - 1));
1832
+ const m = v - c2;
1824
1833
  let rPrime, gPrime, bPrime;
1825
1834
  if (h >= 0 && h < 60) {
1826
- rPrime = c;
1835
+ rPrime = c2;
1827
1836
  gPrime = x;
1828
1837
  bPrime = 0;
1829
1838
  } else if (h >= 60 && h < 120) {
1830
1839
  rPrime = x;
1831
- gPrime = c;
1840
+ gPrime = c2;
1832
1841
  bPrime = 0;
1833
1842
  } else if (h >= 120 && h < 180) {
1834
1843
  rPrime = 0;
1835
- gPrime = c;
1844
+ gPrime = c2;
1836
1845
  bPrime = x;
1837
1846
  } else if (h >= 180 && h < 240) {
1838
1847
  rPrime = 0;
1839
1848
  gPrime = x;
1840
- bPrime = c;
1849
+ bPrime = c2;
1841
1850
  } else if (h >= 240 && h < 300) {
1842
1851
  rPrime = x;
1843
1852
  gPrime = 0;
1844
- bPrime = c;
1853
+ bPrime = c2;
1845
1854
  } else {
1846
- rPrime = c;
1855
+ rPrime = c2;
1847
1856
  gPrime = 0;
1848
1857
  bPrime = x;
1849
1858
  }
@@ -1896,194 +1905,6 @@ function isDark(hex) {
1896
1905
  const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
1897
1906
  return hsv.v < 0.6;
1898
1907
  }
1899
- var shadowColors = {
1900
- // For charcoal surfaces (~#2C2C2C to #3C3C3C)
1901
- charcoal: {
1902
- dark: "rgba(0, 0, 0, 0.5)",
1903
- light: "rgba(255, 255, 255, 0.12)",
1904
- // brighter for crisp rim light
1905
- darker: "rgba(0, 0, 0, 0.6)"
1906
- },
1907
- // For neutral dark surfaces (~#1F2937)
1908
- neutralDark: {
1909
- dark: "rgba(0, 0, 0, 0.4)",
1910
- light: "rgba(255, 255, 255, 0.08)",
1911
- darker: "rgba(0, 0, 0, 0.5)"
1912
- },
1913
- // For light surfaces (white/light gray backgrounds)
1914
- neutralLight: {
1915
- dark: "rgba(0, 0, 0, 0.15)",
1916
- // Visible dark shadow for depth on light backgrounds
1917
- light: "rgba(255, 255, 255, 1)",
1918
- // Bright highlight for raised effect (visible on light gray)
1919
- darker: "rgba(0, 0, 0, 0.2)"
1920
- // Deeper shadow for pressed states
1921
- }
1922
- };
1923
- var intensityConfig = {
1924
- subtle: { offset: 1, blur: 2 },
1925
- // very light, barely visible
1926
- medium: { offset: 2, blur: 4 },
1927
- // noticeable but restrained
1928
- strong: { offset: 2, blur: 5 }
1929
- // slightly deeper blur, same offset as medium
1930
- };
1931
- function createRaisedShadow(surface = "charcoal", intensity = "medium") {
1932
- const colors = shadowColors[surface];
1933
- const { offset, blur } = intensityConfig[intensity];
1934
- const rimBlur = 1;
1935
- return reactNative.Platform.select({
1936
- web: {
1937
- boxShadow: `${offset}px ${offset}px ${blur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
1938
- },
1939
- default: {
1940
- // React Native shadow approximation (limited compared to web)
1941
- shadowColor: "#000",
1942
- shadowOffset: { width: offset, height: offset },
1943
- shadowOpacity: 0.3,
1944
- shadowRadius: blur / 2,
1945
- elevation: offset
1946
- }
1947
- });
1948
- }
1949
- function createPressedShadow(surface = "charcoal", intensity = "medium") {
1950
- const colors = shadowColors[surface];
1951
- const { offset, blur } = intensityConfig[intensity];
1952
- const rimOffset = 1;
1953
- const rimBlur = 1;
1954
- return reactNative.Platform.select({
1955
- web: {
1956
- boxShadow: `inset ${offset}px ${offset}px ${blur}px ${colors.darker}, inset -${rimOffset}px -${rimOffset}px ${rimBlur}px ${colors.light}`
1957
- },
1958
- default: {
1959
- // React Native doesn't support inset shadows, approximate with darker bg
1960
- shadowOpacity: 0,
1961
- elevation: 0
1962
- }
1963
- });
1964
- }
1965
- function createFlatShadow() {
1966
- return reactNative.Platform.select({
1967
- web: {
1968
- boxShadow: "none"
1969
- },
1970
- default: {
1971
- shadowOpacity: 0,
1972
- elevation: 0
1973
- }
1974
- });
1975
- }
1976
- function createRaisedHoverShadow(surface = "charcoal", intensity = "medium") {
1977
- const colors = shadowColors[surface];
1978
- const { offset, blur } = intensityConfig[intensity];
1979
- const hoverOffset = Math.max(1, Math.round(offset / 2));
1980
- const hoverBlur = Math.max(1, Math.round(blur / 2));
1981
- const rimBlur = 1;
1982
- return reactNative.Platform.select({
1983
- web: {
1984
- // Keep same offsets as normal state for rim to prevent "shrinking" effect
1985
- boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
1986
- },
1987
- default: {
1988
- shadowColor: "#000",
1989
- shadowOffset: { width: hoverOffset, height: hoverOffset },
1990
- shadowOpacity: 0.2,
1991
- shadowRadius: hoverBlur / 2,
1992
- elevation: hoverOffset
1993
- }
1994
- });
1995
- }
1996
- function createPressedHoverShadow(surface = "charcoal", intensity = "medium") {
1997
- const colors = shadowColors[surface];
1998
- const { offset, blur } = intensityConfig[intensity];
1999
- const hoverOffset = Math.max(1, Math.round(offset / 2));
2000
- const hoverBlur = Math.max(1, Math.round(blur / 2));
2001
- const rimBlur = 1;
2002
- return reactNative.Platform.select({
2003
- web: {
2004
- // Keep rim offset at 1px (same as pressed normal) to prevent "shrinking" effect
2005
- boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.darker}, inset -1px -1px ${rimBlur}px ${colors.light}`
2006
- },
2007
- default: {
2008
- shadowOpacity: 0,
2009
- elevation: 0
2010
- }
2011
- });
2012
- }
2013
- var neumorphicShadows = {
2014
- // Charcoal surface shadows (for dark toolbars, cards)
2015
- charcoal: {
2016
- raised: {
2017
- subtle: createRaisedShadow("charcoal", "subtle"),
2018
- medium: createRaisedShadow("charcoal", "medium"),
2019
- strong: createRaisedShadow("charcoal", "strong")
2020
- },
2021
- raisedHover: {
2022
- subtle: createRaisedHoverShadow("charcoal", "subtle"),
2023
- medium: createRaisedHoverShadow("charcoal", "medium"),
2024
- strong: createRaisedHoverShadow("charcoal", "strong")
2025
- },
2026
- pressed: {
2027
- subtle: createPressedShadow("charcoal", "subtle"),
2028
- medium: createPressedShadow("charcoal", "medium"),
2029
- strong: createPressedShadow("charcoal", "strong")
2030
- },
2031
- pressedHover: {
2032
- subtle: createPressedHoverShadow("charcoal", "subtle"),
2033
- medium: createPressedHoverShadow("charcoal", "medium"),
2034
- strong: createPressedHoverShadow("charcoal", "strong")
2035
- },
2036
- flat: createFlatShadow()
2037
- },
2038
- // Neutral dark surface shadows
2039
- neutralDark: {
2040
- raised: {
2041
- subtle: createRaisedShadow("neutralDark", "subtle"),
2042
- medium: createRaisedShadow("neutralDark", "medium"),
2043
- strong: createRaisedShadow("neutralDark", "strong")
2044
- },
2045
- raisedHover: {
2046
- subtle: createRaisedHoverShadow("neutralDark", "subtle"),
2047
- medium: createRaisedHoverShadow("neutralDark", "medium"),
2048
- strong: createRaisedHoverShadow("neutralDark", "strong")
2049
- },
2050
- pressed: {
2051
- subtle: createPressedShadow("neutralDark", "subtle"),
2052
- medium: createPressedShadow("neutralDark", "medium"),
2053
- strong: createPressedShadow("neutralDark", "strong")
2054
- },
2055
- pressedHover: {
2056
- subtle: createPressedHoverShadow("neutralDark", "subtle"),
2057
- medium: createPressedHoverShadow("neutralDark", "medium"),
2058
- strong: createPressedHoverShadow("neutralDark", "strong")
2059
- },
2060
- flat: createFlatShadow()
2061
- },
2062
- // Neutral light surface shadows
2063
- neutralLight: {
2064
- raised: {
2065
- subtle: createRaisedShadow("neutralLight", "subtle"),
2066
- medium: createRaisedShadow("neutralLight", "medium"),
2067
- strong: createRaisedShadow("neutralLight", "strong")
2068
- },
2069
- raisedHover: {
2070
- subtle: createRaisedHoverShadow("neutralLight", "subtle"),
2071
- medium: createRaisedHoverShadow("neutralLight", "medium"),
2072
- strong: createRaisedHoverShadow("neutralLight", "strong")
2073
- },
2074
- pressed: {
2075
- subtle: createPressedShadow("neutralLight", "subtle"),
2076
- medium: createPressedShadow("neutralLight", "medium"),
2077
- strong: createPressedShadow("neutralLight", "strong")
2078
- },
2079
- pressedHover: {
2080
- subtle: createPressedHoverShadow("neutralLight", "subtle"),
2081
- medium: createPressedHoverShadow("neutralLight", "medium"),
2082
- strong: createPressedHoverShadow("neutralLight", "strong")
2083
- },
2084
- flat: createFlatShadow()
2085
- }
2086
- };
2087
1908
  var elevationSystem = {
2088
1909
  // Deep inset (recessed input fields, deeply pressed buttons)
2089
1910
  [-2]: {
@@ -2112,7 +1933,13 @@ var elevationSystem = {
2112
1933
  // Level 1: Subtle elevation (outline cards, subtle containers)
2113
1934
  [1]: {
2114
1935
  name: "subtle",
2115
- colorAdjustment: 0.01,
1936
+ // The whole ladder was re-spaced in TD-07.16. It used to run
1937
+ // 0.01/0.02/0.04/0.06/0.08, where the first step was ~2 RGB values — under
1938
+ // the perceptual floor, so level 1 existed in the type system and nowhere on
1939
+ // screen. With drop-shadow now gated off below FLOATING_ELEVATION_MIN, TONE
1940
+ // is the only thing separating 0-3, so every step has to actually land.
1941
+ // Even 0.025 spacing, verified in elevation.test.ts as ΔL* > 1 per step.
1942
+ colorAdjustment: 0.025,
2116
1943
  shadowIntensity: "subtle",
2117
1944
  shadowStyle: "raised",
2118
1945
  description: "Subtle elevation (outline cards, subtle containers)"
@@ -2120,7 +1947,7 @@ var elevationSystem = {
2120
1947
  // Level 2: Standard elevation (default cards, buttons)
2121
1948
  [2]: {
2122
1949
  name: "standard",
2123
- colorAdjustment: 0.02,
1950
+ colorAdjustment: 0.05,
2124
1951
  shadowIntensity: "medium",
2125
1952
  shadowStyle: "raised",
2126
1953
  description: "Standard elevation (default cards, raised buttons)"
@@ -2128,7 +1955,7 @@ var elevationSystem = {
2128
1955
  // Level 3: Prominent elevation (important cards, modals)
2129
1956
  [3]: {
2130
1957
  name: "prominent",
2131
- colorAdjustment: 0.04,
1958
+ colorAdjustment: 0.075,
2132
1959
  shadowIntensity: "strong",
2133
1960
  shadowStyle: "raised",
2134
1961
  description: "Prominent elevation (important cards, modals, dropdowns)"
@@ -2136,7 +1963,7 @@ var elevationSystem = {
2136
1963
  // Level 4: High elevation (overlays, popovers)
2137
1964
  [4]: {
2138
1965
  name: "high",
2139
- colorAdjustment: 0.06,
1966
+ colorAdjustment: 0.1,
2140
1967
  shadowIntensity: "strong",
2141
1968
  shadowStyle: "raised",
2142
1969
  description: "High elevation (overlays, popovers, tooltips)"
@@ -2144,7 +1971,7 @@ var elevationSystem = {
2144
1971
  // Level 5: Floating (toasts, floating action buttons)
2145
1972
  [5]: {
2146
1973
  name: "floating",
2147
- colorAdjustment: 0.08,
1974
+ colorAdjustment: 0.13,
2148
1975
  shadowIntensity: "strong",
2149
1976
  shadowStyle: "raised",
2150
1977
  description: "Floating elevation (toasts, floating action buttons, highest z-index)"
@@ -2263,12 +2090,12 @@ function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
2263
2090
  const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
2264
2091
  const rimLightColor = calculateRimLightColor(baseColor, level);
2265
2092
  const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
2266
- const intensityConfig2 = {
2093
+ const intensityConfig = {
2267
2094
  subtle: { offset: 1, blur: 2 },
2268
2095
  medium: { offset: 2, blur: 4 },
2269
2096
  strong: { offset: 2, blur: 5 }
2270
2097
  };
2271
- const { offset, blur } = intensityConfig2[config.shadowIntensity];
2098
+ const { offset, blur } = intensityConfig[config.shadowIntensity];
2272
2099
  const rimConfig = getRimLightConfig();
2273
2100
  if (config.shadowStyle === "pressed") {
2274
2101
  if (isHovered) {
@@ -2324,12 +2151,13 @@ function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
2324
2151
  });
2325
2152
  }
2326
2153
  }
2154
+ var FLOATING_ELEVATION_MIN = 4;
2327
2155
  function getElevationShadow(baseColor, level, theme, isHovered = false) {
2328
2156
  const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
2329
2157
  if (elevationShadowCache.has(cacheKey)) {
2330
2158
  return elevationShadowCache.get(cacheKey);
2331
2159
  }
2332
- const result = calculateElevationShadow(baseColor, level, theme, isHovered);
2160
+ const result = level > 0 && level < FLOATING_ELEVATION_MIN ? {} : calculateElevationShadow(baseColor, level, theme, isHovered);
2333
2161
  if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
2334
2162
  const firstKey = elevationShadowCache.keys().next().value;
2335
2163
  elevationShadowCache.delete(firstKey);
@@ -2599,7 +2427,7 @@ var audiobookPreset = {
2599
2427
  "text-primary": "#f4f3f1",
2600
2428
  "text-secondary": "#b5b3af",
2601
2429
  "text-tertiary": "#7a7875",
2602
- // Surfaces: warm charcoals (not pure gray)
2430
+ // Surfaces: warm greys (not pure gray)
2603
2431
  "surface-base": "#101114",
2604
2432
  "surface-elevated": "#15171c",
2605
2433
  "surface-raised": "#1a1d24",
@@ -2610,9 +2438,9 @@ var audiobookPreset = {
2610
2438
  "background-default": "#101114",
2611
2439
  "background-subtle": "#1a1d24",
2612
2440
  // Borders
2613
- "border-default": "rgba(255, 255, 255, 0.06)",
2614
- "border-subtle": "rgba(255, 255, 255, 0.03)",
2615
- "border-strong": "#2d323d",
2441
+ "hairline-default": "rgba(255, 255, 255, 0.06)",
2442
+ "hairline-subtle": "rgba(255, 255, 255, 0.03)",
2443
+ "hairline-strong": "#2d323d",
2616
2444
  "border-focus": "#d4782a",
2617
2445
  "border-input": "#2d323d",
2618
2446
  "border-input-hover": "#454c5c",
@@ -2637,13 +2465,14 @@ var audiobookPreset = {
2637
2465
  rootClasses: ["atmosphere-warm", "grain"]
2638
2466
  };
2639
2467
  var SURFACE_LEVEL_TOKEN = {
2468
+ frame: "background-frame",
2640
2469
  background: "background-base",
2641
2470
  base: "surface-base",
2642
2471
  elevated: "surface-elevated",
2643
2472
  raised: "surface-raised",
2644
2473
  overlay: "surface-overlay"
2645
2474
  };
2646
- var PRESSED_RAMP = ["inset", "background", "base", "elevated", "raised", "overlay"];
2475
+ var PRESSED_RAMP = ["frame", "background", "base", "elevated", "raised", "overlay"];
2647
2476
  var ON_SURFACE_TOKEN = {
2648
2477
  primary: "text-primary",
2649
2478
  secondary: "text-secondary",
@@ -2658,22 +2487,17 @@ function useSurfaceMode() {
2658
2487
  return React25.useContext(SurfaceContext).mode;
2659
2488
  }
2660
2489
  function onSurfaceColors(mode) {
2661
- const c = getSemanticColors(mode);
2490
+ const c2 = getSemanticColors(mode);
2662
2491
  return {
2663
- primary: c[ON_SURFACE_TOKEN.primary],
2664
- secondary: c[ON_SURFACE_TOKEN.secondary],
2665
- tertiary: c[ON_SURFACE_TOKEN.tertiary]
2492
+ primary: c2[ON_SURFACE_TOKEN.primary],
2493
+ secondary: c2[ON_SURFACE_TOKEN.secondary],
2494
+ tertiary: c2[ON_SURFACE_TOKEN.tertiary]
2666
2495
  };
2667
2496
  }
2668
2497
  function useOnSurfaceColor(role = "primary") {
2669
2498
  return getSemanticColors(useSurfaceMode())[ON_SURFACE_TOKEN[role]];
2670
2499
  }
2671
- function insetFloor(mode) {
2672
- const colors = getSemanticColors(mode);
2673
- return colors["surface-inset"] ?? surfaceRampDark.inset;
2674
- }
2675
2500
  function surfaceBackground(level, mode) {
2676
- if (level === "inset") return insetFloor(mode);
2677
2501
  return getSemanticColors(mode)[SURFACE_LEVEL_TOKEN[level]];
2678
2502
  }
2679
2503
  function pressedLevel(parent) {
@@ -2724,12 +2548,12 @@ function useTheme() {
2724
2548
  var variantStyles3 = {
2725
2549
  elevated: "",
2726
2550
  // Will be set dynamically via elevation system
2727
- outline: "border-2 border-border-strong",
2551
+ outline: "border-2 border-hairline-strong",
2728
2552
  // Thicker border with stronger contrast
2729
2553
  filled: "",
2730
2554
  // Will be set dynamically via elevation system
2731
- accent: "border border-border",
2732
- subtle: "border border-border-subtle"
2555
+ accent: "border border-hairline",
2556
+ subtle: "border border-hairline-subtle"
2733
2557
  };
2734
2558
  function Card({
2735
2559
  variant = "elevated",
@@ -2964,7 +2788,7 @@ function Indicator({
2964
2788
  // src/components/ui/badge/Badge.tsx
2965
2789
  var variantColorStyles = {
2966
2790
  solid: {
2967
- default: "bg-border-strong text-text-inverse",
2791
+ default: "bg-hairline-strong text-text-inverse",
2968
2792
  primary: "bg-brand-primary text-text-inverse",
2969
2793
  secondary: "bg-brand-secondary text-text-inverse",
2970
2794
  success: "bg-status-success text-text-inverse",
@@ -2982,7 +2806,7 @@ var variantColorStyles = {
2982
2806
  info: "bg-status-info-subtle text-status-info"
2983
2807
  },
2984
2808
  outline: {
2985
- default: "border border-border-strong text-text-secondary",
2809
+ default: "border border-hairline-strong text-text-secondary",
2986
2810
  primary: "border border-brand-primary text-brand-primary",
2987
2811
  secondary: "border border-brand-secondary text-brand-secondary",
2988
2812
  success: "border border-status-success text-status-success",
@@ -3128,7 +2952,7 @@ function Avatar({
3128
2952
  accessibilityLabel: alt || resolvedFallback || "Avatar",
3129
2953
  className: cn(
3130
2954
  "items-center justify-center rounded-full overflow-hidden",
3131
- !nameColor && "bg-border-strong",
2955
+ !nameColor && "bg-hairline-strong",
3132
2956
  styles2.container,
3133
2957
  className
3134
2958
  ),
@@ -3149,7 +2973,7 @@ var badgeColors = {
3149
2973
  success: "bg-status-success",
3150
2974
  error: "bg-status-error",
3151
2975
  warning: "bg-status-warning",
3152
- default: "bg-border-strong"
2976
+ default: "bg-hairline-strong"
3153
2977
  };
3154
2978
  function AvatarBadge({ color = "success", className }) {
3155
2979
  return /* @__PURE__ */ jsx(
@@ -3267,7 +3091,7 @@ var Checkbox = React25.forwardRef(function Checkbox2({
3267
3091
  className: cn(
3268
3092
  "items-center justify-center rounded border-2 transition-colors",
3269
3093
  styles2.box,
3270
- isChecked || isIndeterminate ? "bg-brand-primary border-brand-primary" : "bg-transparent border-border",
3094
+ isChecked || isIndeterminate ? "bg-brand-primary border-brand-primary" : "bg-transparent border-hairline",
3271
3095
  isInvalid && "border-status-error",
3272
3096
  !isDisabled && "web:hover:border-brand-primary"
3273
3097
  ),
@@ -3331,7 +3155,7 @@ var Switch = React25.forwardRef(function Switch2({
3331
3155
  className: cn(
3332
3156
  "rounded-full p-0.5 transition-colors",
3333
3157
  styles2.track,
3334
- isChecked ? "bg-brand-primary" : "bg-border-strong"
3158
+ isChecked ? "bg-brand-primary" : "bg-hairline-strong"
3335
3159
  ),
3336
3160
  children: /* @__PURE__ */ jsx(
3337
3161
  reactNative.View,
@@ -3651,7 +3475,7 @@ function Tabs({
3651
3475
  function TabList({ children, className }) {
3652
3476
  const { variant, orientation } = React25.useContext(TabsContext);
3653
3477
  const variantStyles5 = {
3654
- line: orientation === "horizontal" ? "border-b border-border" : "border-r border-border",
3478
+ line: orientation === "horizontal" ? "border-b border-hairline" : "border-r border-hairline",
3655
3479
  enclosed: "bg-surface-raised rounded-lg p-1",
3656
3480
  "soft-rounded": "bg-surface-raised rounded-full p-1"
3657
3481
  };
@@ -4137,7 +3961,7 @@ function Accordion({
4137
3961
  return newSet;
4138
3962
  });
4139
3963
  };
4140
- return /* @__PURE__ */ jsx(AccordionContext.Provider, { value: { openIndices, toggleIndex, allowMultiple }, children: /* @__PURE__ */ jsx(reactNative.View, { className: cn("w-full divide-y divide-border", className), ...props, children: React25__default.default.Children.map(children, (child, index) => {
3964
+ return /* @__PURE__ */ jsx(AccordionContext.Provider, { value: { openIndices, toggleIndex, allowMultiple }, children: /* @__PURE__ */ jsx(reactNative.View, { className: cn("w-full divide-y divide-hairline", className), ...props, children: React25__default.default.Children.map(children, (child, index) => {
4141
3965
  if (React25__default.default.isValidElement(child)) {
4142
3966
  return React25__default.default.cloneElement(child, { index });
4143
3967
  }
@@ -4367,7 +4191,7 @@ function PopoverContent({ children, className }) {
4367
4191
  {
4368
4192
  className: cn(
4369
4193
  "absolute z-50 min-w-[200px]",
4370
- "bg-surface-elevated rounded-lg shadow-lg border border-border",
4194
+ "bg-surface-elevated rounded-lg shadow-lg border border-hairline",
4371
4195
  "p-4",
4372
4196
  placementStyles3[placement],
4373
4197
  className
@@ -4461,7 +4285,7 @@ function MenuList({ children, className }) {
4461
4285
  {
4462
4286
  className: cn(
4463
4287
  "absolute z-50 top-full left-0 mt-1 min-w-[160px]",
4464
- "bg-surface-elevated rounded-lg shadow-lg border border-border",
4288
+ "bg-surface-elevated rounded-lg shadow-lg border border-hairline",
4465
4289
  "py-1 overflow-hidden",
4466
4290
  className
4467
4291
  ),
@@ -4515,7 +4339,7 @@ function MenuItem({
4515
4339
  );
4516
4340
  }
4517
4341
  function MenuDivider({ className }) {
4518
- return /* @__PURE__ */ jsx(reactNative.View, { className: cn("h-px bg-border my-1", className) });
4342
+ return /* @__PURE__ */ jsx(reactNative.View, { className: cn("h-px bg-hairline my-1", className) });
4519
4343
  }
4520
4344
  function MenuGroup({ label, children, className }) {
4521
4345
  return /* @__PURE__ */ jsxs(reactNative.View, { className, children: [
@@ -4593,7 +4417,7 @@ function Select({
4593
4417
  className: cn(
4594
4418
  "flex-row items-center justify-between px-4 py-2.5 rounded-md border",
4595
4419
  variant === "filled" ? "bg-black/30" : "bg-surface-base",
4596
- isInvalid ? "border-border-input-error" : variant === "filled" ? "border-border-subtle" : "border-border-input",
4420
+ isInvalid ? "border-border-input-error" : variant === "filled" ? "border-hairline-subtle" : "border-border-input",
4597
4421
  !isDisabled && !isInvalid && "web:hover:border-border-input-hover",
4598
4422
  isOpen && "border-border-input-focus",
4599
4423
  isDisabled && "opacity-50 cursor-not-allowed"
@@ -4640,7 +4464,7 @@ function Select({
4640
4464
  {
4641
4465
  className: cn(
4642
4466
  "absolute z-50 top-full left-0 right-0 mt-1",
4643
- "bg-surface-elevated rounded-md shadow-lg border border-border",
4467
+ "bg-surface-elevated rounded-md shadow-lg border border-hairline",
4644
4468
  "max-h-60 overflow-hidden"
4645
4469
  ),
4646
4470
  children: /* @__PURE__ */ jsx(reactNative.ScrollView, { className: "py-1", children: options.map((option) => /* @__PURE__ */ jsx(SelectOption, { option }, option.value)) })
@@ -4671,7 +4495,7 @@ function SelectOption({ option }) {
4671
4495
  {
4672
4496
  className: cn(
4673
4497
  "w-4 h-4 mr-3 rounded border",
4674
- selected ? "bg-brand-primary border-brand-primary" : "border-border-strong"
4498
+ selected ? "bg-brand-primary border-brand-primary" : "border-hairline-strong"
4675
4499
  ),
4676
4500
  children: selected && /* @__PURE__ */ jsx(reactNative.Text, { className: "text-white text-xs text-center", children: "\u2713" })
4677
4501
  }
@@ -4686,8 +4510,11 @@ var ToolbarButtonContext = React25.createContext({
4686
4510
  setIsOpen: () => {
4687
4511
  }
4688
4512
  });
4689
- var BUTTON_BG = "#3C3C3C";
4690
- var MENU_BG = "#2C2C2C";
4513
+ var SEMANTIC = getSemanticColors("dark");
4514
+ var BUTTON_BG = greyRamp[800];
4515
+ var MENU_BG = greyRamp[900];
4516
+ var EDGE = { borderWidth: 1, borderColor: SEMANTIC["hairline-default"] };
4517
+ var EDGE_PRESSED = { borderWidth: 1, borderColor: SEMANTIC["hairline-strong"] };
4691
4518
  var hoverColors = getHoverColors(BUTTON_BG, "medium");
4692
4519
  var sizeStyles10 = {
4693
4520
  sm: "px-2 py-1 min-h-[26px]",
@@ -4705,7 +4532,7 @@ function ToolbarButton({
4705
4532
  isActive,
4706
4533
  isDisabled = false,
4707
4534
  size = "md",
4708
- variant = "neumorphic",
4535
+ variant = "raised",
4709
4536
  tooltip,
4710
4537
  showLabel = true,
4711
4538
  onPress,
@@ -4732,22 +4559,20 @@ function ToolbarButton({
4732
4559
  if (isActive === true) return resolveColor("brand-primary");
4733
4560
  return showActive ? "#FFFFFF" : "#D1D1D1";
4734
4561
  };
4735
- const getNeumorphicStyle = () => {
4562
+ const getRaisedStyle = () => {
4736
4563
  if (isDisabled) {
4737
4564
  return styles.disabledBg;
4738
4565
  }
4739
- const shadows = neumorphicShadows.charcoal;
4740
4566
  if (showActive) {
4741
4567
  return {
4742
- backgroundColor: isHovered ? hoverColors.pressed : BUTTON_BG,
4743
- ...isHovered ? shadows.pressedHover.subtle : shadows.pressed.subtle
4744
- };
4745
- } else {
4746
- return {
4747
- backgroundColor: isHovered ? hoverColors.raised : BUTTON_BG,
4748
- ...isHovered ? shadows.raisedHover.subtle : shadows.raised.subtle
4568
+ backgroundColor: isHovered ? hoverColors.pressed : greyRamp[900],
4569
+ ...EDGE_PRESSED
4749
4570
  };
4750
4571
  }
4572
+ return {
4573
+ backgroundColor: isHovered ? hoverColors.raised : BUTTON_BG,
4574
+ ...EDGE
4575
+ };
4751
4576
  };
4752
4577
  return /* @__PURE__ */ jsx(ToolbarButtonContext.Provider, { value: { isOpen, setIsOpen }, children: /* @__PURE__ */ jsxs(reactNative.View, { className: "relative", ...props, children: [
4753
4578
  /* @__PURE__ */ jsxs(
@@ -4772,9 +4597,9 @@ function ToolbarButton({
4772
4597
  className
4773
4598
  ),
4774
4599
  style: [
4775
- variant === "neumorphic" && getNeumorphicStyle(),
4600
+ variant === "raised" && getRaisedStyle(),
4776
4601
  variant === "default" && {
4777
- backgroundColor: showActive ? BUTTON_BG : "#6E6E6E"
4602
+ backgroundColor: showActive ? BUTTON_BG : greyRamp[600]
4778
4603
  }
4779
4604
  ],
4780
4605
  children: [
@@ -4819,7 +4644,7 @@ function ToolbarButton({
4819
4644
  {
4820
4645
  className: cn(
4821
4646
  "absolute z-50 top-full left-0 mt-1",
4822
- "rounded-lg shadow-lg border border-border",
4647
+ "rounded-lg shadow-lg border border-hairline",
4823
4648
  "min-w-[150px] overflow-hidden",
4824
4649
  `bg-[${MENU_BG}]`
4825
4650
  ),
@@ -4918,10 +4743,10 @@ var sizeConfig = {
4918
4743
  lg: { outer: "w-6 h-6", inner: "w-3 h-3", text: "text-lg" }
4919
4744
  };
4920
4745
  var colorStyles4 = {
4921
- primary: { checked: "border-brand-primary bg-brand-primary", unchecked: "border-border-strong" },
4922
- secondary: { checked: "border-brand-secondary bg-brand-secondary", unchecked: "border-border-strong" },
4923
- success: { checked: "border-status-success bg-status-success", unchecked: "border-border-strong" },
4924
- error: { checked: "border-status-error bg-status-error", unchecked: "border-border-strong" }
4746
+ primary: { checked: "border-brand-primary bg-brand-primary", unchecked: "border-hairline-strong" },
4747
+ secondary: { checked: "border-brand-secondary bg-brand-secondary", unchecked: "border-hairline-strong" },
4748
+ success: { checked: "border-status-success bg-status-success", unchecked: "border-hairline-strong" },
4749
+ error: { checked: "border-status-error bg-status-error", unchecked: "border-hairline-strong" }
4925
4750
  };
4926
4751
  function Radio({
4927
4752
  value,
@@ -5061,7 +4886,7 @@ function Drawer({
5061
4886
  accessibilityRole: "dialog",
5062
4887
  ...props,
5063
4888
  children: [
5064
- (title || showCloseButton) && /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center justify-between px-4 py-3 border-b border-border", children: [
4889
+ (title || showCloseButton) && /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center justify-between px-4 py-3 border-b border-hairline", children: [
5065
4890
  title && /* @__PURE__ */ jsx(reactNative.Text, { className: "text-lg font-semibold text-text-primary", children: title }),
5066
4891
  showCloseButton && /* @__PURE__ */ jsx(
5067
4892
  reactNative.Pressable,
@@ -5085,7 +4910,7 @@ function DrawerHeader({ className, children, ...props }) {
5085
4910
  return /* @__PURE__ */ jsx(
5086
4911
  reactNative.View,
5087
4912
  {
5088
- className: cn("px-4 py-3 border-b border-border", className),
4913
+ className: cn("px-4 py-3 border-b border-hairline", className),
5089
4914
  ...props,
5090
4915
  children
5091
4916
  }
@@ -5110,7 +4935,7 @@ function DrawerFooter({ className, children, ...props }) {
5110
4935
  {
5111
4936
  className: cn(
5112
4937
  "flex-row items-center justify-end gap-3",
5113
- "px-4 py-3 border-t border-border",
4938
+ "px-4 py-3 border-t border-hairline",
5114
4939
  className
5115
4940
  ),
5116
4941
  ...props,
@@ -5249,7 +5074,7 @@ function CircularProgress({
5249
5074
  cy: center,
5250
5075
  r: radius,
5251
5076
  fill: "none",
5252
- stroke: "var(--color-border-default)",
5077
+ stroke: "var(--color-hairline-default)",
5253
5078
  strokeWidth
5254
5079
  }
5255
5080
  ),
@@ -5318,7 +5143,7 @@ function ProgressSteps({
5318
5143
  className: cn(
5319
5144
  "rounded-full",
5320
5145
  dot,
5321
- index <= currentStep ? colorStyles5[color] : "bg-border-strong"
5146
+ index <= currentStep ? colorStyles5[color] : "bg-hairline-strong"
5322
5147
  )
5323
5148
  }
5324
5149
  ),
@@ -5328,7 +5153,7 @@ function ProgressSteps({
5328
5153
  className: cn(
5329
5154
  "flex-1 mx-1",
5330
5155
  connector,
5331
- index < currentStep ? colorStyles5[color] : "bg-border-strong"
5156
+ index < currentStep ? colorStyles5[color] : "bg-hairline-strong"
5332
5157
  )
5333
5158
  }
5334
5159
  )
@@ -5662,7 +5487,7 @@ function Autocomplete({
5662
5487
  {
5663
5488
  className: cn(
5664
5489
  "absolute z-50 top-full left-0 right-0 mt-1",
5665
- "bg-surface-elevated rounded-md shadow-lg border border-border",
5490
+ "bg-surface-elevated rounded-md shadow-lg border border-hairline",
5666
5491
  "max-h-60 overflow-hidden"
5667
5492
  ),
5668
5493
  children: /* @__PURE__ */ jsxs(reactNative.ScrollView, { className: "py-1", children: [
@@ -5815,7 +5640,7 @@ function HelpTip({
5815
5640
  className: cn(
5816
5641
  "absolute z-50",
5817
5642
  "bg-surface-elevated rounded-lg shadow-lg",
5818
- "border border-border",
5643
+ "border border-hairline",
5819
5644
  "px-3 py-2",
5820
5645
  placementStyles2[placement],
5821
5646
  tooltipClassName
@@ -5991,7 +5816,7 @@ function FormActions({
5991
5816
  {
5992
5817
  className: cn(
5993
5818
  "flex-row items-center gap-3 pt-4",
5994
- "border-t border-border mt-4",
5819
+ "border-t border-hairline mt-4",
5995
5820
  alignStyles[align],
5996
5821
  className
5997
5822
  ),
@@ -6210,7 +6035,7 @@ function ListItemDivider({ inset = true, className, ...props }) {
6210
6035
  }
6211
6036
  var variantColorStyles2 = {
6212
6037
  subtle: {
6213
- default: "bg-surface-raised border-border-subtle text-text-secondary",
6038
+ default: "bg-surface-raised border-hairline-subtle text-text-secondary",
6214
6039
  primary: "bg-brand-primary/10 border-brand-primary/25 text-brand-primary",
6215
6040
  secondary: "bg-brand-secondary/10 border-brand-secondary/25 text-brand-secondary",
6216
6041
  success: "bg-status-success/10 border-status-success/25 text-status-success",
@@ -6219,7 +6044,7 @@ var variantColorStyles2 = {
6219
6044
  info: "bg-status-info/10 border-status-info/25 text-status-info"
6220
6045
  },
6221
6046
  outline: {
6222
- default: "border-border text-text-secondary",
6047
+ default: "border-hairline text-text-secondary",
6223
6048
  primary: "border-brand-primary text-brand-primary",
6224
6049
  secondary: "border-brand-secondary text-brand-secondary",
6225
6050
  success: "border-status-success text-status-success",
@@ -6430,7 +6255,7 @@ function Sidebar({
6430
6255
  {
6431
6256
  style: { width: currentWidth },
6432
6257
  className: cn(
6433
- "h-full flex-col bg-surface-base border-r border-border transition-all duration-200",
6258
+ "h-full flex-col bg-surface-base border-r border-hairline transition-all duration-200",
6434
6259
  className
6435
6260
  ),
6436
6261
  ...props,
@@ -6439,7 +6264,7 @@ function Sidebar({
6439
6264
  ) });
6440
6265
  }
6441
6266
  function SidebarHeader({ children, className }) {
6442
- return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-4 py-4 border-b border-border-subtle", className), children });
6267
+ return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-4 py-4 border-b border-hairline-subtle", className), children });
6443
6268
  }
6444
6269
  function SidebarContent({ children, className }) {
6445
6270
  return /* @__PURE__ */ jsx(
@@ -6452,7 +6277,7 @@ function SidebarContent({ children, className }) {
6452
6277
  );
6453
6278
  }
6454
6279
  function SidebarFooter({ children, className }) {
6455
- return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-2 py-4 border-t border-border-subtle", className), children });
6280
+ return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-2 py-4 border-t border-hairline-subtle", className), children });
6456
6281
  }
6457
6282
  function SidebarSection({ title, children, className }) {
6458
6283
  const { isCollapsed } = React25.useContext(SidebarContext);
@@ -6522,7 +6347,7 @@ function SidebarItem({
6522
6347
  );
6523
6348
  }
6524
6349
  function SidebarDivider({ className }) {
6525
- return /* @__PURE__ */ jsx(reactNative.View, { className: cn("h-px mx-4 my-2 bg-border-subtle", className) });
6350
+ return /* @__PURE__ */ jsx(reactNative.View, { className: cn("h-px mx-4 my-2 bg-hairline-subtle", className) });
6526
6351
  }
6527
6352
  var TableContext = React25.createContext({
6528
6353
  sortDirection: null,
@@ -6919,7 +6744,7 @@ function StepConnector({ index }) {
6919
6744
  {
6920
6745
  className: cn(
6921
6746
  "flex-1 h-0.5 mx-2",
6922
- isCompleted ? "bg-brand-primary" : "bg-border"
6747
+ isCompleted ? "bg-brand-primary" : "bg-hairline"
6923
6748
  )
6924
6749
  }
6925
6750
  );
@@ -6929,7 +6754,7 @@ function StepConnector({ index }) {
6929
6754
  {
6930
6755
  className: cn(
6931
6756
  "w-0.5 h-8 ml-4 my-1",
6932
- isCompleted ? "bg-brand-primary" : "bg-border"
6757
+ isCompleted ? "bg-brand-primary" : "bg-hairline"
6933
6758
  )
6934
6759
  }
6935
6760
  );
@@ -6965,7 +6790,7 @@ function StepIndicator({
6965
6790
  const statusStyles2 = {
6966
6791
  completed: "bg-brand-primary border-brand-primary",
6967
6792
  active: "bg-brand-primary border-brand-primary",
6968
- upcoming: "bg-surface-base border-border-strong",
6793
+ upcoming: "bg-surface-base border-hairline-strong",
6969
6794
  error: "bg-status-error border-status-error"
6970
6795
  };
6971
6796
  return /* @__PURE__ */ jsx(
@@ -7363,7 +7188,7 @@ var baseBadgeSizeConfig = {
7363
7188
  lg: { fontSize: 12, paddingH: 10, paddingV: 4, iconSize: 14 }
7364
7189
  };
7365
7190
  var variantColors = {
7366
- plain: { backgroundColor: t["surface-raised"], borderColor: "#1F1F1F" },
7191
+ plain: { backgroundColor: t["surface-raised"], borderColor: t["hairline-default"] },
7367
7192
  pr: {
7368
7193
  backgroundColor: "rgba(255, 121, 0, 0.12)",
7369
7194
  borderColor: "rgba(255, 121, 0, 0.3)"
@@ -7447,7 +7272,7 @@ function WeightBadge({
7447
7272
  ...props
7448
7273
  }) {
7449
7274
  const config = baseBadgeSizeConfig[size];
7450
- const textColor = isPr ? getSemanticColors("dark")["brand-primary"] : "#9CA3AF";
7275
+ const textColor = isPr ? getSemanticColors("dark")["brand-primary"] : greyRamp[400];
7451
7276
  const iconColor = textColor;
7452
7277
  const repMaxClause = reps != null ? `${reps} rep max` : "Estimated one rep max";
7453
7278
  const deltaLabel = delta != null ? `, ${delta >= 0 ? "+" : ""}${delta}% change` : "";
@@ -7608,7 +7433,7 @@ var solidVariantColors = {
7608
7433
  success: t2["status-success"],
7609
7434
  warning: t2["status-warning"],
7610
7435
  error: t2["status-error"],
7611
- neutral: "#6B7280"
7436
+ neutral: greyRamp[500]
7612
7437
  };
7613
7438
  var ringVariantStyles = {
7614
7439
  "on-track": {
@@ -7646,10 +7471,10 @@ var iconColors2 = {
7646
7471
  success: "#0A5C52",
7647
7472
  warning: "#6B4000",
7648
7473
  error: "#5C1A1A",
7649
- neutral: "#D1D5DB",
7474
+ neutral: greyRamp[200],
7650
7475
  "on-track": t2["status-success"],
7651
7476
  deviation: t2["status-warning"],
7652
- future: "#6B7280"
7477
+ future: greyRamp[500]
7653
7478
  };
7654
7479
  var sizeDimensions = {
7655
7480
  sm: { size: 8, showIcon: false },
@@ -7718,7 +7543,7 @@ function StatusDot({
7718
7543
  /* @__PURE__ */ jsx(
7719
7544
  reactNative.Text,
7720
7545
  {
7721
- style: { fontSize: 12, lineHeight: 16, color: "#9CA3AF" },
7546
+ style: { fontSize: 12, lineHeight: 16, color: greyRamp[400] },
7722
7547
  accessibilityElementsHidden: true,
7723
7548
  children: label
7724
7549
  }
@@ -8050,7 +7875,7 @@ function LiveTempoCell({
8050
7875
  alignItems: "center",
8051
7876
  justifyContent: "center"
8052
7877
  };
8053
- const num = (c, text) => /* @__PURE__ */ jsx(reactNative.Text, { style: { fontFamily: MONO, fontSize, color: c, fontWeight: "700" }, children: text });
7878
+ const num = (c2, text) => /* @__PURE__ */ jsx(reactNative.Text, { style: { fontFamily: MONO, fontSize, color: c2, fontWeight: "700" }, children: text });
8054
7879
  if (status === "upcoming") {
8055
7880
  const targetText = targetMs != null ? (targetMs / 1e3).toFixed(1) : String(value);
8056
7881
  return /* @__PURE__ */ jsx(reactNative.View, { style: wrap, children: num(color, targetText) });
@@ -8263,7 +8088,7 @@ var t4 = getSemanticColors("dark");
8263
8088
  function getDotColor(deviation) {
8264
8089
  const abs = Math.abs(deviation);
8265
8090
  if (deviation < -0.3) return t4["status-success"];
8266
- if (abs <= 0.3) return "#6B7280";
8091
+ if (abs <= 0.3) return greyRamp[500];
8267
8092
  if (abs <= 0.7) return t4["status-warning"];
8268
8093
  return t4["status-error"];
8269
8094
  }
@@ -8320,7 +8145,7 @@ function DeviationBar({
8320
8145
  height: dotSize,
8321
8146
  borderRadius: 9999,
8322
8147
  borderWidth: 1.5,
8323
- borderColor: "#F3F4F6",
8148
+ borderColor: greyRamp[50],
8324
8149
  boxShadow: "0 0 4px rgba(0,0,0,0.5)",
8325
8150
  backgroundColor: getDotColor(clamped),
8326
8151
  left: Math.max(0, Math.min(dotPosition - dotSize / 2, resolvedWidth - dotSize)),
@@ -8514,6 +8339,7 @@ var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
8514
8339
  var WORKOUT_PILL_DELOAD = primitiveRamps.magenta[600];
8515
8340
 
8516
8341
  // src/components/custom/Workout/WorkoutPill.tsx
8342
+ var HAIRLINE_DEFAULT = getSemanticColors("dark")["hairline-default"];
8517
8343
  var t6 = getSemanticColors("dark");
8518
8344
  var statusBgColors = {
8519
8345
  completed: "rgba(46,213,115,0.15)",
@@ -8527,7 +8353,7 @@ var statusBorderStyles = {
8527
8353
  completed: { borderWidth: 1, borderColor: "rgba(46,213,115,0.3)" },
8528
8354
  current: { borderWidth: 1, borderColor: "rgba(255,121,0,0.3)" },
8529
8355
  next: { borderWidth: 1, borderColor: "rgba(255,121,0,0.4)" },
8530
- upcoming: { borderWidth: 1, borderColor: "#1F1F1F" },
8356
+ upcoming: { borderWidth: 1, borderColor: HAIRLINE_DEFAULT },
8531
8357
  missed: { borderWidth: 1, borderColor: "rgba(209,67,67,0.25)" },
8532
8358
  deload: { borderWidth: 1, borderColor: "rgba(186,41,150,0.3)" }
8533
8359
  };
@@ -8535,7 +8361,7 @@ var textColors = {
8535
8361
  completed: t6["status-success"],
8536
8362
  current: t6["brand-primary"],
8537
8363
  next: t6["brand-primary"],
8538
- upcoming: "#6B7280",
8364
+ upcoming: greyRamp[500],
8539
8365
  missed: "rgba(209,67,67,0.7)",
8540
8366
  deload: WORKOUT_PILL_DELOAD
8541
8367
  };
@@ -8667,28 +8493,6 @@ function WorkoutPill({
8667
8493
  }
8668
8494
  return pill;
8669
8495
  }
8670
-
8671
- // src/theme/bar-paper.ts
8672
- function grainOpacityForColor(hex) {
8673
- const h = hex.replace("#", "");
8674
- const full = h.length === 3 ? h.split("").map((ch) => ch + ch).join("") : h;
8675
- const r = parseInt(full.slice(0, 2), 16);
8676
- const g = parseInt(full.slice(2, 4), 16);
8677
- const b = parseInt(full.slice(4, 6), 16);
8678
- if ([r, g, b].some(Number.isNaN)) return 0.14;
8679
- const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
8680
- return Math.min(0.24, Math.max(0.04, 0.02 + 0.31 * lum));
8681
- }
8682
- function barGrain(color) {
8683
- const op = grainOpacityForColor(color).toFixed(3);
8684
- return `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='${op}'/%3E%3C/svg%3E")`;
8685
- }
8686
- function barPaper(color, flip = false) {
8687
- return {
8688
- backgroundImage: barGrain(color),
8689
- boxShadow: flip ? "0 -6px 16px rgba(0,0,0,0.45)" : "inset 0 1.5px 0 rgba(255,255,255,0.22), 0 6px 16px rgba(0,0,0,0.45)"
8690
- };
8691
- }
8692
8496
  var ANIMATION_EASING = reactNative.Easing.bezier(0.22, 1, 0.36, 1);
8693
8497
  var PEAK_OVERSHOOT = 1.12;
8694
8498
  function getReducedMotionPreference() {
@@ -9228,7 +9032,7 @@ function setAccessibilityLabel(set, repCount) {
9228
9032
  }
9229
9033
  var EXPANDED_HEIGHT = 60;
9230
9034
  var COMPACT_HEIGHT = 8;
9231
- var HERO_REFERENCE_COLOR = primitiveColors.charcoal[0];
9035
+ var HERO_REFERENCE_COLOR = greyRamp[600];
9232
9036
  function DashedReferenceLine({
9233
9037
  anchor,
9234
9038
  offset,
@@ -9900,7 +9704,7 @@ function VelocityStrip({
9900
9704
  }
9901
9705
  var t7 = getSemanticColors("dark");
9902
9706
  var dotColorMap = {
9903
- untrained: "#2C2C2C",
9707
+ untrained: greyRamp[900],
9904
9708
  behind: t7["brand-secondary"],
9905
9709
  ontrack: t7["status-success"],
9906
9710
  target: t7["brand-primary"],
@@ -9913,12 +9717,12 @@ function MuscleGroupChip({
9913
9717
  className,
9914
9718
  ...props
9915
9719
  }) {
9916
- const dotColor = volumeStatus ? dotColorMap[volumeStatus] : "#2C2C2C";
9720
+ const dotColor = volumeStatus ? dotColorMap[volumeStatus] : greyRamp[900];
9917
9721
  const statusLabel = volumeStatus ?? "no status";
9918
9722
  const content = /* @__PURE__ */ jsxs(
9919
9723
  reactNative.View,
9920
9724
  {
9921
- className: ["bg-surface-raised border-border", className].filter(Boolean).join(" "),
9725
+ className: ["bg-surface-raised border-hairline", className].filter(Boolean).join(" "),
9922
9726
  style: {
9923
9727
  flexDirection: "row",
9924
9728
  alignItems: "center",
@@ -10219,7 +10023,7 @@ function SetRow(set) {
10219
10023
  );
10220
10024
  }
10221
10025
  var BRAND_PRIMARY3 = getSemanticColors("dark")["brand-primary"];
10222
- var INPUT_CLASSNAME = "bg-surface-raised border-border-strong text-text-primary";
10026
+ var INPUT_CLASSNAME = "bg-surface-raised border-hairline-strong text-text-primary";
10223
10027
  var inputStyle = {
10224
10028
  fontSize: 14,
10225
10029
  fontWeight: "600",
@@ -10252,7 +10056,7 @@ function InputBar({
10252
10056
  style: {
10253
10057
  width: "100%",
10254
10058
  borderTopWidth: 1,
10255
- borderTopColor: resolveColor("border-default"),
10059
+ borderTopColor: resolveColor("hairline-default"),
10256
10060
  paddingTop: 10,
10257
10061
  paddingHorizontal: 16,
10258
10062
  paddingBottom: 12,
@@ -10515,7 +10319,7 @@ function RestTimer({
10515
10319
  style: {
10516
10320
  width: "100%",
10517
10321
  borderTopWidth: 1,
10518
- borderTopColor: resolveColor("border-default"),
10322
+ borderTopColor: resolveColor("hairline-default"),
10519
10323
  paddingVertical: 12,
10520
10324
  paddingHorizontal: 16
10521
10325
  },
@@ -10584,7 +10388,7 @@ function RestTimer({
10584
10388
  /* @__PURE__ */ jsx(
10585
10389
  reactNative.View,
10586
10390
  {
10587
- className: "bg-border",
10391
+ className: "bg-hairline",
10588
10392
  style: {
10589
10393
  height: 3,
10590
10394
  borderRadius: 2,
@@ -10845,7 +10649,7 @@ var SET_STRIP_ZONES = {
10845
10649
  fast: primitiveRamps.amber[300],
10846
10650
  fastest: primitiveRamps.green[300]
10847
10651
  };
10848
- var TODO_COLOR = primitiveColors.charcoal[300];
10652
+ var TODO_COLOR = greyRamp[900];
10849
10653
  var SET_STRIP_VARIABLE_COLOR = primitiveRamps.cyan[900];
10850
10654
  var NOTCH_GAP = 2;
10851
10655
  var CLUSTER_GAP = 3;
@@ -11295,7 +11099,7 @@ function CollapsedCard({
11295
11099
  );
11296
11100
  }
11297
11101
  var DARK2 = getSemanticColors("dark");
11298
- var BODY_DIVIDER = DARK2["border-subtle"];
11102
+ var BODY_DIVIDER = DARK2["hairline-subtle"];
11299
11103
  function deriveHeaderSetStates(sets) {
11300
11104
  return sets.map((set) => {
11301
11105
  switch (set.state) {
@@ -11329,7 +11133,7 @@ function ExpandedCard({
11329
11133
  return /* @__PURE__ */ jsxs(
11330
11134
  reactNative.View,
11331
11135
  {
11332
- className: "bg-surface-elevated border-border",
11136
+ className: "bg-surface-elevated border-hairline",
11333
11137
  style: {
11334
11138
  borderWidth: 1,
11335
11139
  ...borderRadius,
@@ -11561,7 +11365,8 @@ function SessionHeader({
11561
11365
  }
11562
11366
  );
11563
11367
  }
11564
- var DIVIDER = primitiveColors.charcoal[300];
11368
+ var SEMANTIC2 = getSemanticColors("dark");
11369
+ var DIVIDER = greyRamp[875];
11565
11370
  var DEFAULT_WIDTH = 246;
11566
11371
  function SessionRail({
11567
11372
  title,
@@ -11605,8 +11410,8 @@ function SessionRail({
11605
11410
  /* @__PURE__ */ jsx(
11606
11411
  Surface,
11607
11412
  {
11608
- level: "elevated",
11609
- style: [{ flex: 1 }, neumorphicShadows.charcoal.pressed.subtle],
11413
+ level: "base",
11414
+ style: [{ flex: 1 }, insetWell(SEMANTIC2["surface-base"])],
11610
11415
  testID: "session-rail-list",
11611
11416
  children: exercises.map((ex, i) => /* @__PURE__ */ jsx(
11612
11417
  reactNative.View,
@@ -11919,11 +11724,12 @@ function WeekRow({
11919
11724
  }
11920
11725
  );
11921
11726
  }
11727
+ var HAIRLINE_DEFAULT2 = getSemanticColors("dark")["hairline-default"];
11922
11728
  var t10 = getSemanticColors("dark");
11923
11729
  var COLORS = {
11924
11730
  statusSuccess: t10["status-success"],
11925
11731
  brandPrimary: t10["brand-primary"],
11926
- borderDefault: "#1F1F1F",
11732
+ borderDefault: HAIRLINE_DEFAULT2,
11927
11733
  brandPrimarySubtle: "rgba(255,121,0,0.06)"
11928
11734
  };
11929
11735
  var statusBorderColors = {
@@ -12064,10 +11870,11 @@ function WorkoutCard({
12064
11870
  }
12065
11871
  );
12066
11872
  }
11873
+ var HAIRLINE_DEFAULT3 = getSemanticColors("dark")["hairline-default"];
12067
11874
  var BRAND_PRIMARY7 = getSemanticColors("dark")["brand-primary"];
12068
11875
  var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
12069
11876
  var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
12070
- var BORDER_DEFAULT = "#1F1F1F";
11877
+ var BORDER_DEFAULT = HAIRLINE_DEFAULT3;
12071
11878
  var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY7, BRAND_PRIMARY_LIGHT];
12072
11879
  function heatmapColor(percentage) {
12073
11880
  const clamped = Math.max(0, Math.min(100, percentage));
@@ -12223,7 +12030,7 @@ function MesoCard({
12223
12030
  var BRAND_PRIMARY8 = getSemanticColors("dark")["brand-primary"];
12224
12031
  var RECENT_BORDER = "rgba(249,180,21,0.3)";
12225
12032
  var RECENT_GLOW = "0 0 12px rgba(249,180,21,0.06)";
12226
- var BORDER_DEFAULT2 = resolveColor("border-default");
12033
+ var BORDER_DEFAULT2 = resolveColor("hairline-default");
12227
12034
  var TYPE_LABELS = {
12228
12035
  e1rm: "e1RM",
12229
12036
  weight: "Weight",
@@ -12336,7 +12143,7 @@ function PrHistoryModal({
12336
12143
  reactNative.View,
12337
12144
  {
12338
12145
  accessibilityElementsHidden: true,
12339
- className: "bg-border",
12146
+ className: "bg-hairline",
12340
12147
  style: {
12341
12148
  alignSelf: "center",
12342
12149
  width: 40,
@@ -12468,7 +12275,7 @@ function EmojiSlider({ factor }) {
12468
12275
  accessibilityLabel: `${factor.label} level ${level} of 5`,
12469
12276
  "aria-checked": selected,
12470
12277
  testID: "readiness-check-emoji",
12471
- className: selected ? void 0 : "border-border bg-surface-raised",
12278
+ className: selected ? void 0 : "border-hairline bg-surface-raised",
12472
12279
  style: ({ pressed }) => ({
12473
12280
  flex: 1,
12474
12281
  alignItems: "center",
@@ -12523,7 +12330,7 @@ function WarmUpCard({ validation }) {
12523
12330
  return /* @__PURE__ */ jsxs(
12524
12331
  reactNative.View,
12525
12332
  {
12526
- className: "border-border bg-surface-raised",
12333
+ className: "border-hairline bg-surface-raised",
12527
12334
  style: {
12528
12335
  marginTop: 16,
12529
12336
  padding: 12,
@@ -13058,11 +12865,11 @@ function ChartLine({
13058
12865
  dashed,
13059
12866
  testID
13060
12867
  }) {
13061
- return /* @__PURE__ */ jsx(jsxRuntime.Fragment, { children: coords.map((c, i) => {
12868
+ return /* @__PURE__ */ jsx(jsxRuntime.Fragment, { children: coords.map((c2, i) => {
13062
12869
  if (i === 0) return null;
13063
12870
  const prev = coords[i - 1];
13064
- const dx = c.x - prev.x;
13065
- const dy = c.y - prev.y;
12871
+ const dx = c2.x - prev.x;
12872
+ const dy = c2.y - prev.y;
13066
12873
  const length = Math.sqrt(dx * dx + dy * dy);
13067
12874
  const angle = Math.atan2(dy, dx) * (180 / Math.PI);
13068
12875
  return /* @__PURE__ */ jsx(
@@ -13265,21 +13072,21 @@ function StrengthTrendChart({
13265
13072
  }
13266
13073
  ),
13267
13074
  geometry.actual.map(
13268
- (c) => c.point.isPR ? /* @__PURE__ */ jsx(
13075
+ (c2) => c2.point.isPR ? /* @__PURE__ */ jsx(
13269
13076
  reactNative.Text,
13270
13077
  {
13271
13078
  accessibilityElementsHidden: true,
13272
13079
  testID: "strength-trend-chart-pr-star",
13273
13080
  style: {
13274
13081
  position: "absolute",
13275
- left: c.x - 7,
13276
- top: c.y - 20,
13082
+ left: c2.x - 7,
13083
+ top: c2.y - 20,
13277
13084
  fontSize: 12,
13278
13085
  color: STATUS_WARNING3
13279
13086
  },
13280
13087
  children: "\u2605"
13281
13088
  },
13282
- `star-${c.index}`
13089
+ `star-${c2.index}`
13283
13090
  ) : null
13284
13091
  )
13285
13092
  ]
@@ -13290,29 +13097,29 @@ function StrengthTrendChart({
13290
13097
  {
13291
13098
  style: { position: "absolute", top: 0, left: 0, width, height },
13292
13099
  testID: "strength-trend-chart-points",
13293
- children: geometry.actual.map((c) => {
13294
- const label = c.point.sessionLabel ?? c.point.date;
13100
+ children: geometry.actual.map((c2) => {
13101
+ const label = c2.point.sessionLabel ?? c2.point.date;
13295
13102
  return /* @__PURE__ */ jsx(
13296
13103
  reactNative.Pressable,
13297
13104
  {
13298
13105
  testID: "strength-trend-chart-point",
13299
13106
  accessibilityRole: "button",
13300
- accessibilityLabel: `${label}: ${formatValue(c.point.e1rm)} ${unit}${c.point.isPR ? ", personal record" : ""}`,
13107
+ accessibilityLabel: `${label}: ${formatValue(c2.point.e1rm)} ${unit}${c2.point.isPR ? ", personal record" : ""}`,
13301
13108
  onPress: () => {
13302
- setSelected(c.index);
13303
- onPointPress?.(c.point);
13109
+ setSelected(c2.index);
13110
+ onPointPress?.(c2.point);
13304
13111
  },
13305
13112
  style: {
13306
13113
  position: "absolute",
13307
- left: c.x - 4,
13308
- top: c.y - 4,
13114
+ left: c2.x - 4,
13115
+ top: c2.y - 4,
13309
13116
  width: 8,
13310
13117
  height: 8,
13311
13118
  borderRadius: 1,
13312
13119
  backgroundColor: BRAND_PRIMARY11
13313
13120
  }
13314
13121
  },
13315
- `point-${c.index}`
13122
+ `point-${c2.index}`
13316
13123
  );
13317
13124
  })
13318
13125
  }
@@ -13322,7 +13129,7 @@ function StrengthTrendChart({
13322
13129
  {
13323
13130
  testID: "strength-trend-chart-tooltip",
13324
13131
  accessibilityElementsHidden: true,
13325
- className: "bg-surface-elevated border-border-strong",
13132
+ className: "bg-surface-elevated border-hairline-strong",
13326
13133
  style: {
13327
13134
  position: "absolute",
13328
13135
  left: Math.max(
@@ -13849,7 +13656,7 @@ var t14 = getSemanticColors("dark");
13849
13656
  function glowShadow(color) {
13850
13657
  return `0 0 5px 1px ${alpha(color, 0.3)}, 0 0 10px 3px ${alpha(color, 0.12)}`;
13851
13658
  }
13852
- var DEFAULT_TRACK_COLOR = primitiveColors.charcoal[200];
13659
+ var DEFAULT_TRACK_COLOR = greyRamp[800];
13853
13660
  var DEFAULT_MARKER_COLOR2 = primitiveColors.white;
13854
13661
  var TICK_COLOR = t14["text-tertiary"];
13855
13662
  var ZONE_SIZES = {
@@ -14148,7 +13955,7 @@ function FatigueMeter({
14148
13955
  );
14149
13956
  }
14150
13957
  var HEAT = WORKOUT_TOKENS.heatmap;
14151
- var NEUTRAL_TRACK = primitiveColors.charcoal[200];
13958
+ var NEUTRAL_TRACK = greyRamp[800];
14152
13959
  var MONO2 = "monospace";
14153
13960
  var HEAT_BY_ZONE = {
14154
13961
  under: HEAT.under,
@@ -14345,7 +14152,7 @@ function LiveAuraFrame({
14345
14152
  borderRadius: 10,
14346
14153
  backgroundColor: t16["background-base"],
14347
14154
  borderWidth: 1,
14348
- borderColor: t16["border-default"]
14155
+ borderColor: t16["hairline-default"]
14349
14156
  },
14350
14157
  style
14351
14158
  ],
@@ -14405,32 +14212,32 @@ var STATE_LABEL = {
14405
14212
  var PHASE_AXIS_COLOR = {
14406
14213
  eccentric: primitiveRamps.magenta[800],
14407
14214
  concentric: primitiveRamps.cyan[800],
14408
- hold: primitiveColors.charcoal[100],
14409
- idle: primitiveColors.charcoal[200]
14215
+ hold: greyRamp[700],
14216
+ idle: greyRamp[800]
14410
14217
  };
14411
14218
  var PHASE_AXIS_BASE_COLOR = {
14412
14219
  eccentric: primitiveRamps.magenta[950],
14413
14220
  concentric: primitiveRamps.cyan[950],
14414
- hold: primitiveColors.charcoal[300],
14415
- idle: primitiveColors.charcoal[200]
14221
+ hold: greyRamp[900],
14222
+ idle: greyRamp[800]
14416
14223
  };
14417
14224
  var PACING_TONE = {
14418
14225
  ahead: primitiveRamps.amber[300],
14419
14226
  onPace: primitiveRamps.green[300],
14420
14227
  over: primitiveRamps.red[300]
14421
14228
  };
14422
- var SILVER = primitiveColors.neutral[300];
14229
+ var SILVER = greyRamp[200];
14423
14230
  var RED_LIGHT = primitiveRamps.red[400];
14424
14231
  var RED_MID = primitiveRamps.red[600];
14425
14232
  var RED_DEEP = primitiveRamps.red[800];
14426
14233
  var GRIND_THRESHOLD = 0.35;
14427
- var DRIFT_GREY = primitiveColors.neutral[600];
14234
+ var DRIFT_GREY = greyRamp[700];
14428
14235
  function clamp012(v) {
14429
14236
  return Math.min(1, Math.max(0, v));
14430
14237
  }
14431
14238
  function hexToRgb2(hex) {
14432
14239
  const h = hex.replace("#", "");
14433
- const f = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
14240
+ const f = h.length === 3 ? h.split("").map((c2) => c2 + c2).join("") : h;
14434
14241
  return [parseInt(f.slice(0, 2), 16), parseInt(f.slice(2, 4), 16), parseInt(f.slice(4, 6), 16)];
14435
14242
  }
14436
14243
  function mixHex2(a, b, ratio) {
@@ -14938,9 +14745,9 @@ function GhostSpark({
14938
14745
  ) }) });
14939
14746
  }
14940
14747
  const cur = curves[curves.length - 1];
14941
- const allSamples = curves.flatMap((c) => c.samples);
14748
+ const allSamples = curves.flatMap((c2) => c2.samples);
14942
14749
  const vmax = Math.max(0.01, ...allSamples.map((s) => s.velocityMps)) * 1.06;
14943
- const axisMaxT = Math.max(1, ...curves.map((c) => c.samples[c.samples.length - 1]?.tMs ?? 0)) * 1.04;
14750
+ const axisMaxT = Math.max(1, ...curves.map((c2) => c2.samples[c2.samples.length - 1]?.tMs ?? 0)) * 1.04;
14944
14751
  const bandBottom = h - padBot;
14945
14752
  const bandTop = bandBottom - BAND_H;
14946
14753
  const baseline = bandTop - BAND_GAP;
@@ -14949,7 +14756,7 @@ function GhostSpark({
14949
14756
  const mag = (v) => clamp012(v / vmax) * plotH;
14950
14757
  const lineTint = ghostLineColor(cur.tempoDeviation, cur.grindSignature);
14951
14758
  const curPts = cur.samples.map((s) => [x(s.tMs), mag(s.velocityMps)]);
14952
- const ghostPts = curves.slice(0, -1).map((c) => c.samples.map((s) => [x(s.tMs), mag(s.velocityMps)]));
14759
+ const ghostPts = curves.slice(0, -1).map((c2) => c2.samples.map((s) => [x(s.tMs), mag(s.velocityMps)]));
14953
14760
  return /* @__PURE__ */ jsx(reactNative.View, { testID: "ghost-spark", style: { paddingHorizontal: 4 }, children: /* @__PURE__ */ jsxs("svg", { width: w, height: h, children: [
14954
14761
  /* @__PURE__ */ jsx(
14955
14762
  GhostBloom,
@@ -15159,7 +14966,7 @@ function mergePhaseSegments(a, b) {
15159
14966
  return out;
15160
14967
  }
15161
14968
  function lastTMs(curves) {
15162
- return Math.max(0, ...curves.map((c) => c.samples[c.samples.length - 1]?.tMs ?? 0));
14969
+ return Math.max(0, ...curves.map((c2) => c2.samples[c2.samples.length - 1]?.tMs ?? 0));
15163
14970
  }
15164
14971
  function DualGhostSpark({
15165
14972
  left,
@@ -15185,12 +14992,12 @@ function DualGhostSpark({
15185
14992
  const baseUp = bandTop - BAND_GAP;
15186
14993
  const baseDown = mid + BAND_H / 2 + BAND_GAP;
15187
14994
  const wingH = Math.max(1, Math.min(baseUp - padTop, h - padBot - baseDown));
15188
- const allSamples = [...left, ...right].flatMap((c) => c.samples);
14995
+ const allSamples = [...left, ...right].flatMap((c2) => c2.samples);
15189
14996
  const vmax = Math.max(0.01, ...allSamples.map((s) => s.velocityMps)) * 1.06;
15190
14997
  const axisMaxT = Math.max(1, lastTMs(left), lastTMs(right)) * 1.04;
15191
14998
  const x = (ms) => padL + ms / axisMaxT * (w - padL - padR);
15192
14999
  const mag = (v) => clamp012(v / vmax) * wingH;
15193
- const toPts = (c) => c.samples.map((s) => [x(s.tMs), mag(s.velocityMps)]);
15000
+ const toPts = (c2) => c2.samples.map((s) => [x(s.tMs), mag(s.velocityMps)]);
15194
15001
  const wing = (curves) => {
15195
15002
  const cur = curves[curves.length - 1];
15196
15003
  return {
@@ -15776,7 +15583,7 @@ function DeviceMenu({
15776
15583
  const availCount = devices.filter((d) => !d.slot).length;
15777
15584
  return /* @__PURE__ */ jsxs(Popover, { placement: "bottom", isOpen, onOpenChange, className, children: [
15778
15585
  /* @__PURE__ */ jsx(PopoverTrigger, { children: /* @__PURE__ */ jsx(DeviceIndicator, { status }) }),
15779
- /* @__PURE__ */ jsxs(PopoverContent, { className: "right-0 left-auto mt-[10px] w-[326px] bg-surface-elevated border border-border-strong rounded-[10px] p-[7px]", children: [
15586
+ /* @__PURE__ */ jsxs(PopoverContent, { className: "right-0 left-auto mt-[10px] w-[326px] bg-surface-elevated border border-hairline-strong rounded-[10px] p-[7px]", children: [
15780
15587
  /* @__PURE__ */ jsxs(
15781
15588
  Typography,
15782
15589
  {
@@ -15792,7 +15599,7 @@ function DeviceMenu({
15792
15599
  ]
15793
15600
  }
15794
15601
  ),
15795
- devices.map((device, i) => /* @__PURE__ */ jsx(reactNative.View, { className: cn(i > 0 && "border-t border-border"), children: /* @__PURE__ */ jsx(
15602
+ devices.map((device, i) => /* @__PURE__ */ jsx(reactNative.View, { className: cn(i > 0 && "border-t border-hairline"), children: /* @__PURE__ */ jsx(
15796
15603
  DeviceRow,
15797
15604
  {
15798
15605
  device,
@@ -15824,7 +15631,7 @@ function TopBar({
15824
15631
  onLayout,
15825
15632
  style: surfaceGradient.chrome(),
15826
15633
  className: cn(
15827
- "h-[46px] flex-row items-center gap-[14px] px-4 bg-surface-elevated border-b border-border",
15634
+ "h-[46px] flex-row items-center gap-[14px] px-4 bg-surface-elevated border-b border-hairline",
15828
15635
  className
15829
15636
  ),
15830
15637
  children: [
@@ -15923,7 +15730,7 @@ function SideNav({
15923
15730
  {
15924
15731
  accessibilityRole: "tablist",
15925
15732
  className: cn(
15926
- "w-[60px] items-center gap-[6px] border-r border-border bg-background-base py-3",
15733
+ "w-[60px] items-center gap-[6px] border-r border-hairline bg-background-base py-3",
15927
15734
  className
15928
15735
  ),
15929
15736
  children: items.map((item) => /* @__PURE__ */ jsx(
@@ -16130,6 +15937,7 @@ exports.ExerciseCard = ExerciseCard;
16130
15937
  exports.ExerciseCardHeading = ExerciseCardHeading;
16131
15938
  exports.ExerciseHeading = ExerciseHeading;
16132
15939
  exports.ExerciseIndicator = ExerciseIndicator;
15940
+ exports.FLOATING_ELEVATION_MIN = FLOATING_ELEVATION_MIN;
16133
15941
  exports.FatigueLights = FatigueLights;
16134
15942
  exports.FatigueMeter = FatigueMeter;
16135
15943
  exports.FormActions = FormActions;
@@ -16217,6 +16025,7 @@ exports.SET_STRIP_ZONES = SET_STRIP_ZONES;
16217
16025
  exports.SILVER = SILVER;
16218
16026
  exports.STATE_LABEL = STATE_LABEL;
16219
16027
  exports.SURFACE_LEVEL_TOKEN = SURFACE_LEVEL_TOKEN;
16028
+ exports.SURFACE_PLANE_STEPS = SURFACE_PLANE_STEPS;
16220
16029
  exports.ScaleIcon = ScaleIcon;
16221
16030
  exports.Scatter = Scatter;
16222
16031
  exports.ScheduleTiles = ScheduleTiles;
@@ -16304,7 +16113,7 @@ exports.alpha = alpha;
16304
16113
  exports.applyThemePreset = applyThemePreset;
16305
16114
  exports.audiobookPreset = audiobookPreset;
16306
16115
  exports.auraForVerdict = auraForVerdict;
16307
- exports.backgroundFrameDark = backgroundFrameDark;
16116
+ exports.barPaper = barPaper;
16308
16117
  exports.bestTextColor = bestTextColor;
16309
16118
  exports.buttonSizes = buttonSizes;
16310
16119
  exports.calculateMeanVelocity = calculateMeanVelocity;
@@ -16314,11 +16123,6 @@ exports.cn = cn;
16314
16123
  exports.componentElevationRanges = componentElevationRanges;
16315
16124
  exports.composeValidators = composeValidators;
16316
16125
  exports.createFieldId = createFieldId;
16317
- exports.createFlatShadow = createFlatShadow;
16318
- exports.createPressedHoverShadow = createPressedHoverShadow;
16319
- exports.createPressedShadow = createPressedShadow;
16320
- exports.createRaisedHoverShadow = createRaisedHoverShadow;
16321
- exports.createRaisedShadow = createRaisedShadow;
16322
16126
  exports.darkThemeCSSVars = darkThemeCSSVars;
16323
16127
  exports.darken = darken;
16324
16128
  exports.defaultNavItems = defaultNavItems;
@@ -16353,10 +16157,14 @@ exports.getVelocityZoneColor = getVelocityZoneColor;
16353
16157
  exports.getVelocityZoneName = getVelocityZoneName;
16354
16158
  exports.ghostLineColor = ghostLineColor;
16355
16159
  exports.gluestackConfig = gluestackConfig;
16160
+ exports.grainForTone = grainForTone;
16161
+ exports.grainOpacityForTone = grainOpacityForTone;
16162
+ exports.greyRamp = greyRamp;
16356
16163
  exports.hasMaxLength = hasMaxLength;
16357
16164
  exports.hasMinLength = hasMinLength;
16358
16165
  exports.hexToRgb = hexToRgb;
16359
16166
  exports.hsvToRgb = hsvToRgb;
16167
+ exports.insetWell = insetWell;
16360
16168
  exports.isCssPropertyManifest = isCssPropertyManifest;
16361
16169
  exports.isDark = isDark;
16362
16170
  exports.isEmpty = isEmpty;
@@ -16366,16 +16174,15 @@ exports.lighten = lighten;
16366
16174
  exports.linearGradient = linearGradient;
16367
16175
  exports.liveAuraColor = liveAuraColor;
16368
16176
  exports.mergePhaseSegments = mergePhaseSegments;
16369
- exports.neumorphicShadows = neumorphicShadows;
16370
16177
  exports.onSurfaceColors = onSurfaceColors;
16371
16178
  exports.paceTone = paceTone;
16372
16179
  exports.paceToneColor = paceToneColor;
16180
+ exports.paperSheet = paperSheet;
16373
16181
  exports.pressedLevel = pressedLevel;
16374
16182
  exports.primitiveBorderRadius = primitiveBorderRadius;
16375
16183
  exports.primitiveBreakpoints = primitiveBreakpoints;
16376
16184
  exports.primitiveColors = primitiveColors;
16377
16185
  exports.primitiveRamps = primitiveRamps;
16378
- exports.primitiveShadows = primitiveShadows;
16379
16186
  exports.primitiveSpacing = primitiveSpacing;
16380
16187
  exports.primitiveTypography = primitiveTypography;
16381
16188
  exports.primitiveZIndex = primitiveZIndex;
@@ -16391,12 +16198,10 @@ exports.semanticColorsDark = semanticColorsDark;
16391
16198
  exports.semanticColorsLight = semanticColorsLight;
16392
16199
  exports.semanticTypography = semanticTypography;
16393
16200
  exports.sequentialEffort = sequentialEffort;
16394
- exports.shadowColors = shadowColors;
16395
16201
  exports.smoothPath = smoothPath;
16396
16202
  exports.statusPillColor = statusPillColor;
16397
16203
  exports.surfaceBackground = surfaceBackground;
16398
16204
  exports.surfaceGradient = surfaceGradient;
16399
- exports.surfaceRampDark = surfaceRampDark;
16400
16205
  exports.useOnSurfaceColor = useOnSurfaceColor;
16401
16206
  exports.useSurface = useSurface;
16402
16207
  exports.useSurfaceMode = useSurfaceMode;