@titan-design/react-ui 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/dist/bodymap.js +173 -343
  2. package/dist/bodymap.js.map +1 -1
  3. package/dist/bodymap.mjs +173 -343
  4. package/dist/bodymap.mjs.map +1 -1
  5. package/dist/index.d.mts +27 -22
  6. package/dist/index.d.ts +27 -22
  7. package/dist/index.js +366 -561
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +360 -553
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/pages.js +242 -407
  12. package/dist/pages.js.map +1 -1
  13. package/dist/pages.mjs +242 -407
  14. package/dist/pages.mjs.map +1 -1
  15. package/dist/theme/index.d.mts +250 -1157
  16. package/dist/theme/index.d.ts +250 -1157
  17. package/dist/theme/index.js +234 -408
  18. package/dist/theme/index.js.map +1 -1
  19. package/dist/theme/index.mjs +227 -399
  20. package/dist/theme/index.mjs.map +1 -1
  21. package/dist/theme/tokens-css.js +141 -140
  22. package/dist/theme/tokens-css.js.map +1 -1
  23. package/dist/theme/tokens-css.mjs +141 -140
  24. package/dist/theme/tokens-css.mjs.map +1 -1
  25. package/dist/theme/tokens.d.mts +904 -0
  26. package/dist/theme/tokens.d.ts +904 -0
  27. package/dist/theme/tokens.js +856 -0
  28. package/dist/theme/tokens.js.map +1 -0
  29. package/dist/theme/tokens.mjs +833 -0
  30. package/dist/theme/tokens.mjs.map +1 -0
  31. package/package.json +7 -1
  32. package/src/arch/Architecture.stories.tsx +9 -9
  33. package/src/components/custom/DateTime/DateTime.stories.tsx +1 -1
  34. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +3 -3
  35. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  36. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +3 -3
  37. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +1 -1
  38. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +2 -2
  39. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  40. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +4 -4
  41. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +3 -3
  42. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  43. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -12
  44. package/src/components/custom/Sidebar/Sidebar.tsx +4 -4
  45. package/src/components/custom/Table/Table.tsx +2 -2
  46. package/src/components/custom/Workout/ActiveWorkoutPage.tsx +3 -3
  47. package/src/components/custom/Workout/BaseBadge.test.tsx +6 -1
  48. package/src/components/custom/Workout/BaseBadge.tsx +1 -1
  49. package/src/components/custom/Workout/BodyMap.tsx +2 -2
  50. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +2 -2
  51. package/src/components/custom/Workout/DeviationBar.test.tsx +2 -1
  52. package/src/components/custom/Workout/DeviationBar.tsx +3 -2
  53. package/src/components/custom/Workout/ExerciseCard.test.tsx +3 -3
  54. package/src/components/custom/Workout/ExerciseCard.tsx +2 -2
  55. package/src/components/custom/Workout/ExerciseDetailPage.tsx +4 -4
  56. package/src/components/custom/Workout/InputBar.tsx +2 -2
  57. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +1 -1
  58. package/src/components/custom/Workout/LiveAuraFrame.test.tsx +1 -1
  59. package/src/components/custom/Workout/LiveAuraFrame.tsx +3 -3
  60. package/src/components/custom/Workout/MesoCard.tsx +3 -1
  61. package/src/components/custom/Workout/MuscleGroupChip.tsx +4 -3
  62. package/src/components/custom/Workout/PrHistoryModal.tsx +2 -2
  63. package/src/components/custom/Workout/ProgramPlanningPage.tsx +1 -1
  64. package/src/components/custom/Workout/README.md +1 -1
  65. package/src/components/custom/Workout/ReadinessCheck.tsx +2 -2
  66. package/src/components/custom/Workout/RestTimer.tsx +2 -2
  67. package/src/components/custom/Workout/S3SetTypes.stories.tsx +3 -3
  68. package/src/components/custom/Workout/SessionHeader.stories.tsx +2 -2
  69. package/src/components/custom/Workout/SessionHeader.tsx +1 -1
  70. package/src/components/custom/Workout/SessionRail.stories.tsx +2 -2
  71. package/src/components/custom/Workout/SessionRail.tsx +13 -5
  72. package/src/components/custom/Workout/SetBar.tsx +3 -3
  73. package/src/components/custom/Workout/SetRow.test.tsx +6 -3
  74. package/src/components/custom/Workout/StatusDot.tsx +5 -4
  75. package/src/components/custom/Workout/StrengthTrendChart.tsx +1 -1
  76. package/src/components/custom/Workout/TrainingStatusPage.tsx +2 -2
  77. package/src/components/custom/Workout/VelocityStrip.test.tsx +5 -2
  78. package/src/components/custom/Workout/VelocityStrip.tsx +4 -4
  79. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +3 -3
  80. package/src/components/custom/Workout/WeightBadge.test.tsx +6 -1
  81. package/src/components/custom/Workout/WeightBadge.tsx +2 -1
  82. package/src/components/custom/Workout/WorkoutCard.tsx +3 -1
  83. package/src/components/custom/Workout/WorkoutPill.tsx +5 -2
  84. package/src/components/custom/Workout/ZoneTrack.tsx +4 -4
  85. package/src/components/custom/Workout/setHeadingKit.tsx +14 -8
  86. package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
  87. package/src/components/custom/charts/SetBarChart.tsx +3 -3
  88. package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
  89. package/src/components/custom/stepper/Stepper.tsx +3 -3
  90. package/src/components/shell/DeviceMenu.tsx +2 -2
  91. package/src/components/shell/README.md +1 -1
  92. package/src/components/shell/SessionRailSpecimen.stories.tsx +1 -1
  93. package/src/components/shell/SideNav.tsx +1 -1
  94. package/src/components/shell/TopBar.tsx +1 -1
  95. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +1 -1
  96. package/src/components/ui/autocomplete/Autocomplete.tsx +1 -1
  97. package/src/components/ui/avatar/Avatar.tsx +2 -2
  98. package/src/components/ui/badge/Badge.tsx +2 -2
  99. package/src/components/ui/card/Card.tsx +3 -3
  100. package/src/components/ui/checkbox/Checkbox.tsx +1 -1
  101. package/src/components/ui/collapse/Collapse.tsx +1 -1
  102. package/src/components/ui/data-row/DataRow.stories.tsx +1 -1
  103. package/src/components/ui/drawer/Drawer.tsx +3 -3
  104. package/src/components/ui/form-field/FormField.tsx +1 -1
  105. package/src/components/ui/help-tip/HelpTip.tsx +1 -1
  106. package/src/components/ui/menu/Menu.tsx +2 -2
  107. package/src/components/ui/pill/Pill.tsx +2 -2
  108. package/src/components/ui/popover/Popover.stories.tsx +2 -2
  109. package/src/components/ui/popover/Popover.tsx +1 -1
  110. package/src/components/ui/progress/Progress.tsx +3 -3
  111. package/src/components/ui/radio/Radio.stories.tsx +1 -1
  112. package/src/components/ui/radio/Radio.tsx +4 -4
  113. package/src/components/ui/select/Select.tsx +3 -3
  114. package/src/components/ui/surface/Surface.stories.tsx +3 -3
  115. package/src/components/ui/surface/Surface.test.tsx +32 -19
  116. package/src/components/ui/surface/Surface.tsx +3 -3
  117. package/src/components/ui/surface/SurfaceContext.ts +19 -29
  118. package/src/components/ui/surface/surface.contract.test.ts +58 -45
  119. package/src/components/ui/switch/Switch.tsx +1 -1
  120. package/src/components/ui/tabs/Tabs.tsx +2 -2
  121. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +5 -5
  122. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +1 -1
  123. package/src/components/ui/toolbar-button/ToolbarButton.tsx +36 -22
  124. package/src/stories/PresetShowcase.stories.tsx +21 -21
  125. package/src/theme/ColorPalettes.stories.tsx +41 -38
  126. package/src/theme/ColorPrimitives.stories.tsx +89 -41
  127. package/src/theme/Depth.stories.tsx +312 -0
  128. package/src/theme/DepthCalibration.stories.tsx +655 -0
  129. package/src/theme/ThemeProvider.tsx +1 -1
  130. package/src/theme/barrel.ts +7 -14
  131. package/src/theme/color-stories.coverage.test.ts +15 -20
  132. package/src/theme/color-story-kit.tsx +1 -1
  133. package/src/theme/color-utils.ts +197 -0
  134. package/src/theme/config.ts +0 -8
  135. package/src/theme/depth-calibration.test.tsx +97 -0
  136. package/src/theme/elevation.test.ts +62 -1
  137. package/src/theme/elevation.ts +34 -8
  138. package/src/theme/global.css +47 -53
  139. package/src/theme/grey-ramp.test.ts +166 -0
  140. package/src/theme/materials.test.ts +106 -0
  141. package/src/theme/materials.ts +211 -0
  142. package/src/theme/presets/audiobook.ts +4 -4
  143. package/src/theme/presets/types.ts +3 -3
  144. package/src/theme/semantic-contrast.test.ts +83 -0
  145. package/src/theme/token-export-guard.test.ts +104 -0
  146. package/src/theme/tokens/primitives.ts +63 -116
  147. package/src/theme/tokens/semantic.ts +130 -82
  148. package/src/utils/colors.ts +1 -1
  149. package/tailwind.config.js +2 -5
  150. package/src/theme/bar-paper.ts +0 -59
  151. package/src/theme/shadows.stories.tsx +0 -523
  152. package/src/theme/shadows.ts +0 -439
@@ -1,51 +1,36 @@
1
1
  // src/theme/tokens/primitives.ts
2
2
  var primitiveColors = {
3
- // Blue scale
4
- blue: {
5
- 400: "#60A5FA",
6
- 600: "#5048E5",
7
- 700: "#3832A0"},
8
- // Red scale
9
- red: {
10
- 500: "#EF4444",
11
- 600: "#D14343"},
12
- // Vivid red scale
13
- redVivid: {
14
- 400: "#FF6070",
15
- 500: "#FF4757",
16
- 700: "#C42539"},
17
- // Neutral/Gray scale
18
- neutral: {
19
- 50: "#FAFAFA",
20
- 100: "#F3F4F6",
21
- 300: "#D1D5DB",
22
- 400: "#9CA3AF",
23
- 500: "#6B7280",
24
- 600: "#4B5563",
25
- 900: "#111827"},
26
- // Charcoal scale (dark backgrounds)
27
- charcoal: {
28
- 200: "#3C3C3C",
29
- 300: "#2C2C2C",
30
- 400: "#1F1F1F",
31
- 500: "#1C1C1C"},
32
- // Pure colors
33
3
  white: "#FFFFFF"};
34
- var surfaceRampDark = {
35
- inset: "#13100D",
36
- // L*4.5 — sub-shell well / pressed
37
- background: "#1C1916",
38
- // L*9 — shell / frame
39
- base: "#252321",
40
- // L*13.5 — main content plane
41
- elevated: "#2C2A28",
42
- // L*17 — nav / rail
43
- raised: "#31302F",
44
- // L*20 — cards
45
- overlay: "#373635"
46
- // L*22.5 — hero / popover
4
+ var greyRamp = {
5
+ 50: "#F9F6F3",
6
+ // L*97.0 W6
7
+ 100: "#EDEAE7",
8
+ // L*92.8 W6
9
+ 200: "#D4D1CE",
10
+ // L*75.7 W6
11
+ 400: "#A29F9D",
12
+ // L*65.7 W5
13
+ 500: "#888684",
14
+ // L*56.0 W4
15
+ 600: "#72716F",
16
+ // L*47.7 W3
17
+ 700: "#5A5958",
18
+ // L*37.9 W2
19
+ 800: "#424140",
20
+ // L*27.6 W2 — generated bridge
21
+ 850: "#373635",
22
+ // L*22.7 W2 — surface overlay
23
+ 875: "#31302F",
24
+ // L*19.9 W2 — surface raised
25
+ 900: "#2C2A28",
26
+ // L*17.2 W4 — surface elevated
27
+ 925: "#252321",
28
+ // L*13.9 W4 — surface base
29
+ 950: "#1C1916",
30
+ // L*9.0 W6 — background base / shell
31
+ 975: "#100D0A"
32
+ // L*3.8 W6 — background frame / bezel
47
33
  };
48
- var backgroundFrameDark = "#100D0A";
49
34
  var primitiveRamps = {
50
35
  red: {
51
36
  50: "#FFF4F4",
@@ -81,9 +66,11 @@ var primitiveRamps = {
81
66
  blue: {
82
67
  50: "#EFF8FF",
83
68
  300: "#78C2FF",
69
+ 400: "#3CA8FF",
84
70
  500: "#2196F3",
85
71
  // pin
86
- 600: "#1072CB"}};
72
+ 600: "#1072CB",
73
+ 700: "#135AA8"}};
87
74
  var discreteRainbow = [
88
75
  "#E8ECFB",
89
76
  "#D9CCE3",
@@ -146,10 +133,10 @@ var semanticColorsLight = {
146
133
  "status-error-light": primitiveRamps.red[500],
147
134
  "status-error-dark": primitiveRamps.red[700],
148
135
  "status-error-subtle": primitiveRamps.red[50],
149
- "status-error-vivid": primitiveColors.redVivid[500],
136
+ "status-error-vivid": primitiveRamps.red[600],
150
137
  // vivid alert red
151
- "status-error-vivid-light": primitiveColors.redVivid[400],
152
- "status-error-vivid-dark": primitiveColors.redVivid[700],
138
+ "status-error-vivid-light": primitiveRamps.red[500],
139
+ "status-error-vivid-dark": primitiveRamps.red[700],
153
140
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
154
141
  "status-warning": primitiveRamps.amber[300],
155
142
  "status-warning-light": primitiveRamps.amber[200],
@@ -176,7 +163,7 @@ var semanticColorsLight = {
176
163
  "result-inconclusive": "#9E9A97",
177
164
  // Gray - no clear result
178
165
  "result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
179
- "result-neutral": primitiveColors.neutral[500],
166
+ "result-neutral": greyRamp[600],
180
167
  // Neutral baseline
181
168
  // Text on result backgrounds (on-result-*)
182
169
  "on-result-improve": primitiveColors.white,
@@ -207,47 +194,38 @@ var semanticColorsLight = {
207
194
  // Text colors (text-*)
208
195
  "text-primary": "#121828",
209
196
  "text-secondary": "#65748B",
210
- "text-tertiary": primitiveColors.neutral[400],
197
+ "text-tertiary": greyRamp[400],
211
198
  "text-disabled": "rgba(55, 65, 81, 0.48)",
212
199
  "text-inverse": primitiveColors.white,
213
- "text-link": primitiveColors.blue[600],
214
- "text-link-hover": primitiveColors.blue[700],
200
+ "text-link": primitiveRamps.blue[600],
201
+ "text-link-hover": primitiveRamps.blue[700],
215
202
  // Surface colors (surface-*) - for elevated containers
216
203
  "surface-base": primitiveColors.white,
217
- "surface-elevated": primitiveColors.neutral[50],
204
+ "surface-elevated": greyRamp[50],
218
205
  // slightly off-white for elevated cards
219
- "surface-raised": primitiveColors.neutral[100],
206
+ "surface-raised": greyRamp[100],
220
207
  // light gray for raised cards
221
208
  "surface-overlay": primitiveColors.white,
222
- "surface-input": primitiveColors.neutral[50],
209
+ "surface-input": greyRamp[50],
223
210
  // Input field background (filled variant)
224
- // Deepest pressed pit (TD-surface-tokens, S-3) — light-mode counterpart of
225
- // the dark ramp's `inset` plane; a placeholder pairing, not part of the
226
- // dark-ramp investigation (surface.contract.test.ts is dark-mode only).
227
- "surface-inset": primitiveColors.neutral[300],
228
211
  // Background colors (background-*)
229
212
  "background-base": "#EBEBEB",
230
213
  "background-default": primitiveColors.white,
231
- "background-subtle": primitiveColors.neutral[50],
232
- // Frame/bezel chrome (TD-surface-tokens, S-3) — top bar + side nav shell,
233
- // one step below `background-base` (darker still than `surface-inset`
234
- // above, mirroring the dark-mode ordering). Placeholder pairing for light
235
- // mode (see dark-mode note on `surface-inset` above).
236
- "background-frame": primitiveColors.neutral[400],
214
+ "background-subtle": greyRamp[50],
215
+ // Frame/bezel chrome — top bar + side nav shell, one step below
216
+ // `background-base`. Placeholder pairing for light mode, which is deferred.
217
+ "background-frame": greyRamp[400],
237
218
  // Border colors (border-*)
238
- "border-default": "#E8E9EB",
239
- "border-subtle": primitiveColors.neutral[100],
240
- "border-strong": primitiveColors.neutral[300],
241
- "border-prominent": primitiveColors.neutral[400],
219
+ "border-prominent": greyRamp[400],
242
220
  // high-visibility divider
243
- "border-focus": primitiveColors.blue[600],
244
- "border-input": primitiveColors.neutral[300],
221
+ "border-focus": primitiveRamps.blue[600],
222
+ "border-input": greyRamp[200],
245
223
  // Input field border
246
- "border-input-hover": primitiveColors.neutral[400],
224
+ "border-input-hover": greyRamp[400],
247
225
  // Input field border on hover
248
- "border-input-focus": primitiveColors.blue[600],
226
+ "border-input-focus": primitiveRamps.blue[600],
249
227
  // Input field border on focus
250
- "border-input-error": primitiveColors.red[600],
228
+ "border-input-error": primitiveRamps.red[600],
251
229
  // Input field border on error
252
230
  // Alpha hairline separators (surface-independent — composite toward black on
253
231
  // light surfaces, mirroring the dark-mode white-alpha family). See §4/S-2.
@@ -264,7 +242,7 @@ var semanticColorsLight = {
264
242
  // Divider
265
243
  "divider": "#E8E9EB",
266
244
  // Avatar default
267
- "avatar-background": primitiveColors.neutral[500],
245
+ "avatar-background": greyRamp[600],
268
246
  "avatar-text": primitiveColors.white
269
247
  };
270
248
  var semanticColorsDark = {
@@ -296,9 +274,9 @@ var semanticColorsDark = {
296
274
  "status-error-light": primitiveRamps.red[500],
297
275
  "status-error-dark": primitiveRamps.red[700],
298
276
  "status-error-subtle": "rgba(209, 67, 67, 0.12)",
299
- "status-error-vivid": primitiveColors.redVivid[500],
300
- "status-error-vivid-light": primitiveColors.redVivid[400],
301
- "status-error-vivid-dark": primitiveColors.redVivid[700],
277
+ "status-error-vivid": primitiveRamps.red[600],
278
+ "status-error-vivid-light": primitiveRamps.red[500],
279
+ "status-error-vivid-dark": primitiveRamps.red[700],
302
280
  "status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
303
281
  "status-warning": primitiveRamps.amber[300],
304
282
  "status-warning-light": primitiveRamps.amber[200],
@@ -322,7 +300,7 @@ var semanticColorsDark = {
322
300
  "result-degrade-dark": "#b30000",
323
301
  "result-inconclusive": "#9E9A97",
324
302
  "result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
325
- "result-neutral": primitiveColors.neutral[400],
303
+ "result-neutral": greyRamp[400],
326
304
  // Text on result backgrounds
327
305
  "on-result-improve": primitiveColors.white,
328
306
  "on-result-degrade": primitiveColors.white,
@@ -339,74 +317,106 @@ var semanticColorsDark = {
339
317
  "data-9": discreteRainbow[3],
340
318
  "data-10": discreteRainbow[22],
341
319
  // Text colors - inverted for dark mode
342
- "text-primary": primitiveColors.neutral[100],
343
- "text-secondary": primitiveColors.neutral[400],
344
- "text-tertiary": primitiveColors.neutral[500],
320
+ "text-primary": greyRamp[50],
321
+ "text-secondary": greyRamp[400],
322
+ // Deliberately ONE step lighter than the L*-nearest match (`greyRamp[600]`).
323
+ // The colour this replaced failed WCAG large-text outright on the three
324
+ // lightest planes — 2.96 / 2.72 / 2.49 against elevated / raised / overlay —
325
+ // and `600` carried that failure forward almost exactly (2.93 / 2.70 / 2.47).
326
+ // `500` clears 3:1 everywhere (3.32–5.34). Contrast beats colour fidelity for
327
+ // text roles; borders and surfaces still use strict L*-nearest. See
328
+ // semantic-contrast.test.ts, which fails if this is moved back down.
329
+ "text-tertiary": greyRamp[500],
345
330
  "text-disabled": "rgba(255, 255, 255, 0.38)",
346
- "text-inverse": primitiveColors.neutral[900],
331
+ "text-inverse": greyRamp[950],
347
332
  "text-link": "#828DF8",
348
- "text-link-hover": primitiveColors.blue[400],
333
+ "text-link-hover": primitiveRamps.blue[400],
349
334
  // Surface colors - dark backgrounds — warm-tapered DERIVED ramp (TD-surface-tokens,
350
335
  // S-1, re-spaced S-3). Shipped verbatim from `deriveSurfaceRamp()` — see
351
336
  // `surfaceRampDark` in primitives.ts for the full derivation note. `surface-overlay`
352
337
  // and `surface-elevated` are distinct (were both #191919 pre-S-1); `surface-input`
353
338
  // tracks one plane above `surface-base`, same relative position as before the remap.
354
339
  // `background-base` backs `Surface level="background"` (SurfaceContext.SURFACE_LEVEL_TOKEN),
355
- // so it takes the ramp's `background` (shell/frame) role, NOT `inset`. The ramp's
356
- // deepest `inset` plane is now promoted to `surface-inset` below (S-3) still no
357
- // `SurfaceLevel` member for it (follow-up, alongside the elevation.ts -1/-2 pressed
358
- // levels — parallel workstream, not this branch).
359
- "surface-base": surfaceRampDark.base,
360
- // main surface (#252321, L*13.5)
361
- "surface-elevated": surfaceRampDark.elevated,
362
- // elevated surface (#2C2A28, L*17 nav/rail)
363
- "surface-raised": surfaceRampDark.raised,
364
- // raised surface (#31302F, L*20 cards)
365
- "surface-overlay": surfaceRampDark.overlay,
366
- // overlay surface (#373635, L*22.5 — hero/popover)
367
- "surface-input": surfaceRampDark.elevated,
340
+ // so it takes the ramp's shell role. The deepest plane is `background-frame`,
341
+ // which is also the `SurfaceLevel` floor a pressed surface clamps at.
342
+ "surface-base": greyRamp[925],
343
+ // main surface (#252321, L*13.9)
344
+ "surface-elevated": greyRamp[900],
345
+ // elevated surface (#2C2A28, L*17.2 — nav/rail)
346
+ "surface-raised": greyRamp[875],
347
+ // raised surface (#31302F, L*19.9 cards)
348
+ "surface-overlay": greyRamp[850],
349
+ // overlay surface (#373635, L*22.7 hero/popover)
350
+ "surface-input": greyRamp[900],
368
351
  // input surface (#2C2A28 — one plane above base)
369
- "surface-inset": surfaceRampDark.inset,
370
- // deepest pressed pit (#13100D, L*4.5 — sub-shell well)
371
352
  // Background colors — same ramp, the frame/shell end of it.
372
- "background-base": surfaceRampDark.background,
373
- // shell / frame (#1C1916, L*9 — Surface level="background")
374
- "background-default": surfaceRampDark.base,
375
- // main background (#252321, L*13.5 — matches surface-base)
376
- "background-subtle": surfaceRampDark.elevated,
377
- // subtle background (#2C2A28, L*17 — matches surface-elevated)
378
- // Frame/bezel chrome (S-3) — the top bar + side nav shell; one step BELOW
379
- // `background-base`, darker even than `surface-inset` it exits the content
380
- // ramp entirely rather than sitting in it. See `backgroundFrameDark` in
381
- // primitives.ts.
382
- "background-frame": backgroundFrameDark,
383
- // frame / bezel (#100D0A, L*3.79)
384
- // Border colors `border-subtle` (#1C1C1C) previously collided with
385
- // `surface-raised` (also #1C1C1C, an invisible border on raised cards). The
386
- // re-spaced ramp above moved `surface-raised` to #2D2C2B, so this value is now
387
- // distinct from every surface hex without needing to change it see
388
- // `surface.contract.test.ts` R2/R4.
389
- "border-default": primitiveColors.charcoal[400],
390
- // default border
391
- "border-subtle": primitiveColors.charcoal[500],
392
- // subtle border
393
- "border-strong": primitiveColors.charcoal[300],
394
- // strong border
395
- "border-prominent": primitiveColors.charcoal[200],
353
+ "background-base": greyRamp[950],
354
+ // shell (#1C1916, L*9 — Surface level="background")
355
+ "background-default": greyRamp[925],
356
+ // main background (#252321, L*13.9 — matches surface-base)
357
+ "background-subtle": greyRamp[900],
358
+ // subtle background (#2C2A28, L*17.2 — matches surface-elevated)
359
+ // Frame/bezel chrome — the top bar + side nav shell, one step BELOW
360
+ // `background-base`. It used to be described as sitting OUTSIDE the ramp; it
361
+ // is simply the ramp's last step now, and the floor `<Surface pressed>` clamps at.
362
+ "background-frame": greyRamp[975],
363
+ // frame / bezel (#100D0A, L*3.8)
364
+ // Border colors — solid dark borders are RETIRED (TD-07.14). Not a preference — a structural
365
+ // consequence of one ramp. Every step from 850 to 975 is now a surface plane,
366
+ // so a solid border dark enough to read as a border necessarily equals some
367
+ // plane's fill, which is exactly the collision `surface.contract.test.ts` R2
368
+ // forbids. The only non-plane steps left in that band are 800 and 700, and
369
+ // borders there jump from L*~10-25 to L*~28-38 — a restyle, not a migration.
370
+ //
371
+ // So separation moves to the alpha hairlines, which dark mode already called
372
+ // "the primary separation cue". Being alpha, they composite against whatever
373
+ // plane they land on and cannot collide with any of them — the problem stops
374
+ // existing rather than being re-solved per plane. The three solid tokens were
375
+ // deleted outright; consumers point at the `hairline-*` family below.
376
+ //
377
+ // `border-prominent` stays SOLID: it is the one border meant to be seen
378
+ // outright (4 call sites, high-visibility dividers), and grey-800 is not a
379
+ // plane, so it keeps its job without collision.
380
+ "border-prominent": greyRamp[800],
396
381
  // high-visibility divider
397
382
  "border-focus": "#828DF8",
398
- "border-input": primitiveColors.neutral[600],
399
- "border-input-hover": primitiveColors.neutral[500],
383
+ "border-input": greyRamp[700],
384
+ "border-input-hover": greyRamp[600],
400
385
  "border-input-focus": "#828DF8",
401
- "border-input-error": primitiveColors.red[500],
386
+ "border-input-error": primitiveRamps.red[500],
402
387
  // Alpha hairline separators — the primary separation cue (§4/S-2). Self-
403
388
  // normalizing: composites toward white by ~the same amount on ANY plane, so
404
389
  // one family works at every elevation instead of per-surface border tokens.
405
390
  // Shadows are demoted to floating-overlay use only (not shipped as a fill
406
391
  // separator here — see elevation.ts, follow-up S-4).
407
- "hairline-subtle": "rgba(255, 255, 255, 0.06)",
408
- "hairline-default": "rgba(255, 255, 255, 0.09)",
409
- "hairline-strong": "rgba(255, 255, 255, 0.14)",
392
+ //
393
+ // RETUNED on the wall (VW-99, S-6). The original .06/.09/.14 were set at a
394
+ // desk. On the panel at ~3 m `subtle` rendered but was indiscernible, and
395
+ // `default` — the load-bearing one, with no solid-border fallback since
396
+ // TD-07.14 — went weak on the lightest plane. `strong` read cleanly with room
397
+ // to spare, which is what made raising the whole family viable.
398
+ //
399
+ // Each tier steps up onto the next MEASURED-GOOD rung rather than an
400
+ // interpolated one: the new `subtle` is the old `default`, and the new
401
+ // `default` is the old `strong` — a value just confirmed legible on all four
402
+ // planes. Spacing goes 1 : 1.56 : 2.33, against the original 1 : 1.5 : 2.33.
403
+ //
404
+ // RUN 2 (VW-99): all three tiers were seen on all four planes — the retune
405
+ // worked — but `subtle` was still "a bit hard to read", so the whole family
406
+ // took a further +.01. That is a comfort margin on a passing row, not a fix
407
+ // for a failing one, which is why it is a flat offset: the 1 : 1.56 : 2.33
408
+ // spacing that the run validated is preserved rather than re-derived.
409
+ //
410
+ // Keep these to TWO decimals. react-native-web quantises alpha to 8 bits, so
411
+ // a 3-decimal value silently rounds on the way to the DOM (.135 renders as
412
+ // .13) — the token would say one thing and paint another.
413
+ //
414
+ // DARK ONLY. The light family above composites toward BLACK on light planes,
415
+ // which this run says nothing about — do not mirror these numbers into it
416
+ // without its own verification.
417
+ "hairline-subtle": "rgba(255, 255, 255, 0.10)",
418
+ "hairline-default": "rgba(255, 255, 255, 0.15)",
419
+ "hairline-strong": "rgba(255, 255, 255, 0.22)",
410
420
  // Interactive states
411
421
  "interactive-hover": "rgba(255, 255, 255, 0.04)",
412
422
  "interactive-focus": "rgba(255, 255, 255, 0.12)",
@@ -415,10 +425,9 @@ var semanticColorsDark = {
415
425
  "interactive-disabled": "rgba(255, 255, 255, 0.12)",
416
426
  "interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
417
427
  // Divider
418
- "divider": primitiveColors.charcoal[400],
419
- // divider color
428
+ "divider": "rgba(255, 255, 255, 0.09)",
420
429
  // Avatar default
421
- "avatar-background": primitiveColors.neutral[600],
430
+ "avatar-background": greyRamp[700],
422
431
  "avatar-text": primitiveColors.white
423
432
  };
424
433
 
@@ -480,14 +489,10 @@ var lightThemeCSSVars = {
480
489
  "--color-surface-base": semanticColorsLight["surface-base"],
481
490
  "--color-surface-elevated": semanticColorsLight["surface-elevated"],
482
491
  "--color-surface-raised": semanticColorsLight["surface-raised"],
483
- "--color-surface-inset": semanticColorsLight["surface-inset"],
484
492
  "--color-background-base": semanticColorsLight["background-base"],
485
493
  "--color-background-default": semanticColorsLight["background-default"],
486
494
  "--color-background-subtle": semanticColorsLight["background-subtle"],
487
495
  "--color-background-frame": semanticColorsLight["background-frame"],
488
- "--color-border-default": semanticColorsLight["border-default"],
489
- "--color-border-subtle": semanticColorsLight["border-subtle"],
490
- "--color-border-strong": semanticColorsLight["border-strong"],
491
496
  "--color-border-prominent": semanticColorsLight["border-prominent"],
492
497
  "--color-border-focus": semanticColorsLight["border-focus"],
493
498
  "--color-interactive-hover": semanticColorsLight["interactive-hover"],
@@ -583,14 +588,10 @@ var darkThemeCSSVars = {
583
588
  "--color-surface-base": semanticColorsDark["surface-base"],
584
589
  "--color-surface-elevated": semanticColorsDark["surface-elevated"],
585
590
  "--color-surface-raised": semanticColorsDark["surface-raised"],
586
- "--color-surface-inset": semanticColorsDark["surface-inset"],
587
591
  "--color-background-base": semanticColorsDark["background-base"],
588
592
  "--color-background-default": semanticColorsDark["background-default"],
589
593
  "--color-background-subtle": semanticColorsDark["background-subtle"],
590
594
  "--color-background-frame": semanticColorsDark["background-frame"],
591
- "--color-border-default": semanticColorsDark["border-default"],
592
- "--color-border-subtle": semanticColorsDark["border-subtle"],
593
- "--color-border-strong": semanticColorsDark["border-strong"],
594
595
  "--color-border-prominent": semanticColorsDark["border-prominent"],
595
596
  "--color-border-focus": semanticColorsDark["border-focus"],
596
597
  "--color-interactive-hover": semanticColorsDark["interactive-hover"],