@retray-dev/ui-kit 6.1.0 → 7.0.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 (321) hide show
  1. package/COMPONENTS.md +447 -13
  2. package/EXAMPLES.md +248 -0
  3. package/README.md +11 -10
  4. package/dist/Accordion.d.mts +28 -0
  5. package/dist/Accordion.d.ts +28 -0
  6. package/dist/Accordion.js +340 -0
  7. package/dist/Accordion.mjs +6 -0
  8. package/dist/AlertBanner.d.mts +16 -0
  9. package/dist/AlertBanner.d.ts +16 -0
  10. package/dist/AlertBanner.js +247 -0
  11. package/dist/AlertBanner.mjs +5 -0
  12. package/dist/Avatar.d.mts +20 -0
  13. package/dist/Avatar.d.ts +20 -0
  14. package/dist/Avatar.js +234 -0
  15. package/dist/Avatar.mjs +3 -0
  16. package/dist/Badge.d.mts +26 -0
  17. package/dist/Badge.d.ts +26 -0
  18. package/dist/Badge.js +247 -0
  19. package/dist/Badge.mjs +4 -0
  20. package/dist/Button.d.mts +25 -0
  21. package/dist/Button.d.ts +25 -0
  22. package/dist/Button.js +414 -0
  23. package/dist/Button.mjs +8 -0
  24. package/dist/ButtonGroup.d.mts +26 -0
  25. package/dist/ButtonGroup.d.ts +26 -0
  26. package/dist/ButtonGroup.js +52 -0
  27. package/dist/ButtonGroup.mjs +2 -0
  28. package/dist/Card.d.mts +39 -0
  29. package/dist/Card.d.ts +39 -0
  30. package/dist/Card.js +329 -0
  31. package/dist/Card.mjs +7 -0
  32. package/dist/CategoryStrip.d.mts +26 -0
  33. package/dist/CategoryStrip.d.ts +26 -0
  34. package/dist/CategoryStrip.js +396 -0
  35. package/dist/CategoryStrip.mjs +9 -0
  36. package/dist/Checkbox.d.mts +14 -0
  37. package/dist/Checkbox.d.ts +14 -0
  38. package/dist/Checkbox.js +304 -0
  39. package/dist/Checkbox.mjs +7 -0
  40. package/dist/Chip.d.mts +31 -0
  41. package/dist/Chip.d.ts +31 -0
  42. package/dist/Chip.js +370 -0
  43. package/dist/Chip.mjs +8 -0
  44. package/dist/ConfirmDialog.d.mts +15 -0
  45. package/dist/ConfirmDialog.d.ts +15 -0
  46. package/dist/ConfirmDialog.js +530 -0
  47. package/dist/ConfirmDialog.mjs +9 -0
  48. package/dist/CurrencyDisplay.d.mts +24 -0
  49. package/dist/CurrencyDisplay.d.ts +24 -0
  50. package/dist/CurrencyDisplay.js +189 -0
  51. package/dist/CurrencyDisplay.mjs +3 -0
  52. package/dist/CurrencyInput.d.mts +26 -0
  53. package/dist/CurrencyInput.d.ts +26 -0
  54. package/dist/CurrencyInput.js +404 -0
  55. package/dist/CurrencyInput.mjs +7 -0
  56. package/dist/DetailRow.d.mts +32 -0
  57. package/dist/DetailRow.d.ts +32 -0
  58. package/dist/DetailRow.js +275 -0
  59. package/dist/DetailRow.mjs +4 -0
  60. package/dist/EmptyState.d.mts +27 -0
  61. package/dist/EmptyState.d.ts +27 -0
  62. package/dist/EmptyState.js +503 -0
  63. package/dist/EmptyState.mjs +9 -0
  64. package/dist/Form.d.mts +52 -0
  65. package/dist/Form.d.ts +52 -0
  66. package/dist/Form.js +204 -0
  67. package/dist/Form.mjs +3 -0
  68. package/dist/IconButton.d.mts +22 -0
  69. package/dist/IconButton.d.ts +22 -0
  70. package/dist/IconButton.js +383 -0
  71. package/dist/IconButton.mjs +7 -0
  72. package/dist/Input.d.mts +23 -0
  73. package/dist/Input.d.ts +23 -0
  74. package/dist/Input.js +351 -0
  75. package/dist/Input.mjs +6 -0
  76. package/dist/LabelValue.d.mts +16 -0
  77. package/dist/LabelValue.d.ts +16 -0
  78. package/dist/LabelValue.js +225 -0
  79. package/dist/LabelValue.mjs +4 -0
  80. package/dist/ListGroup.d.mts +34 -0
  81. package/dist/ListGroup.d.ts +34 -0
  82. package/dist/ListGroup.js +217 -0
  83. package/dist/ListGroup.mjs +4 -0
  84. package/dist/ListItem.d.mts +64 -0
  85. package/dist/ListItem.d.ts +64 -0
  86. package/dist/ListItem.js +430 -0
  87. package/dist/ListItem.mjs +8 -0
  88. package/dist/MediaCard.d.mts +39 -0
  89. package/dist/MediaCard.d.ts +39 -0
  90. package/dist/MediaCard.js +427 -0
  91. package/dist/MediaCard.mjs +8 -0
  92. package/dist/MenuGroup.d.mts +34 -0
  93. package/dist/MenuGroup.d.ts +34 -0
  94. package/dist/MenuGroup.js +217 -0
  95. package/dist/MenuGroup.mjs +4 -0
  96. package/dist/MenuItem.d.mts +48 -0
  97. package/dist/MenuItem.d.ts +48 -0
  98. package/dist/MenuItem.js +403 -0
  99. package/dist/MenuItem.mjs +8 -0
  100. package/dist/MonthPicker.d.mts +20 -0
  101. package/dist/MonthPicker.d.ts +20 -0
  102. package/dist/MonthPicker.js +234 -0
  103. package/dist/MonthPicker.mjs +4 -0
  104. package/dist/Pressable.d.mts +34 -0
  105. package/dist/Pressable.d.ts +34 -0
  106. package/dist/Pressable.js +132 -0
  107. package/dist/Pressable.mjs +4 -0
  108. package/dist/Progress.d.mts +14 -0
  109. package/dist/Progress.d.ts +14 -0
  110. package/dist/Progress.js +191 -0
  111. package/dist/Progress.mjs +4 -0
  112. package/dist/RadioGroup.d.mts +19 -0
  113. package/dist/RadioGroup.d.ts +19 -0
  114. package/dist/RadioGroup.js +341 -0
  115. package/dist/RadioGroup.mjs +7 -0
  116. package/dist/Select.d.mts +22 -0
  117. package/dist/Select.d.ts +22 -0
  118. package/dist/Select.js +441 -0
  119. package/dist/Select.mjs +6 -0
  120. package/dist/Separator.d.mts +10 -0
  121. package/dist/Separator.d.ts +10 -0
  122. package/dist/Separator.js +156 -0
  123. package/dist/Separator.mjs +2 -0
  124. package/dist/Sheet.d.mts +81 -0
  125. package/dist/Sheet.d.ts +81 -0
  126. package/dist/Sheet.js +340 -0
  127. package/dist/Sheet.mjs +4 -0
  128. package/dist/Skeleton.d.mts +17 -0
  129. package/dist/Skeleton.d.ts +17 -0
  130. package/dist/Skeleton.js +205 -0
  131. package/dist/Skeleton.mjs +4 -0
  132. package/dist/Slider.d.mts +20 -0
  133. package/dist/Slider.d.ts +20 -0
  134. package/dist/Slider.js +232 -0
  135. package/dist/Slider.mjs +4 -0
  136. package/dist/Spinner.d.mts +12 -0
  137. package/dist/Spinner.d.ts +12 -0
  138. package/dist/Spinner.js +172 -0
  139. package/dist/Spinner.mjs +3 -0
  140. package/dist/Switch.d.mts +13 -0
  141. package/dist/Switch.d.ts +13 -0
  142. package/dist/Switch.js +261 -0
  143. package/dist/Switch.mjs +5 -0
  144. package/dist/Tabs.d.mts +27 -0
  145. package/dist/Tabs.d.ts +27 -0
  146. package/dist/Tabs.js +389 -0
  147. package/dist/Tabs.mjs +6 -0
  148. package/dist/Text.d.mts +12 -0
  149. package/dist/Text.d.ts +12 -0
  150. package/dist/Text.js +311 -0
  151. package/dist/Text.mjs +4 -0
  152. package/dist/Textarea.d.mts +16 -0
  153. package/dist/Textarea.d.ts +16 -0
  154. package/dist/Textarea.js +333 -0
  155. package/dist/Textarea.mjs +6 -0
  156. package/dist/Toast.d.mts +47 -0
  157. package/dist/Toast.d.ts +47 -0
  158. package/dist/Toast.js +185 -0
  159. package/dist/Toast.mjs +3 -0
  160. package/dist/Toggle.d.mts +33 -0
  161. package/dist/Toggle.d.ts +33 -0
  162. package/dist/Toggle.js +397 -0
  163. package/dist/Toggle.mjs +8 -0
  164. package/dist/VirtualList.d.mts +19 -0
  165. package/dist/VirtualList.d.ts +19 -0
  166. package/dist/VirtualList.js +38 -0
  167. package/dist/VirtualList.mjs +1 -0
  168. package/dist/chunk-2CE3TQVY.mjs +11 -0
  169. package/dist/chunk-2UYENBLV.mjs +49 -0
  170. package/dist/chunk-3BBOZ3OQ.mjs +41 -0
  171. package/dist/chunk-5IKW3VNC.mjs +43 -0
  172. package/dist/chunk-63357L2X.mjs +51 -0
  173. package/dist/chunk-6LQYY7HC.mjs +127 -0
  174. package/dist/chunk-6Q64UFIA.mjs +71 -0
  175. package/dist/chunk-76PFOSM2.mjs +41 -0
  176. package/dist/chunk-7H2OR44A.mjs +14 -0
  177. package/dist/chunk-A4MDAP7G.mjs +42 -0
  178. package/dist/chunk-AU2VDY4P.mjs +190 -0
  179. package/dist/chunk-BRKYVJVV.mjs +60 -0
  180. package/dist/chunk-CRYBX2CM.mjs +146 -0
  181. package/dist/chunk-DITNP6PL.mjs +106 -0
  182. package/dist/chunk-FTLJOUOQ.mjs +97 -0
  183. package/dist/chunk-GCWOGZYL.mjs +104 -0
  184. package/dist/chunk-GNGLDL6Z.mjs +60 -0
  185. package/dist/chunk-GPOUINK5.mjs +148 -0
  186. package/dist/chunk-HSPSMN6U.mjs +115 -0
  187. package/dist/chunk-IRRY3CRZ.mjs +82 -0
  188. package/dist/chunk-JB67UOB5.mjs +92 -0
  189. package/dist/chunk-JBLL7U3U.mjs +64 -0
  190. package/dist/chunk-KWCPOM6W.mjs +136 -0
  191. package/dist/chunk-KZJRQOIU.mjs +64 -0
  192. package/dist/chunk-L7E7TVEZ.mjs +145 -0
  193. package/dist/chunk-LG4DO3DK.mjs +174 -0
  194. package/dist/chunk-LWG526VX.mjs +139 -0
  195. package/dist/chunk-MN7OG7IY.mjs +96 -0
  196. package/dist/chunk-MX6HRKMI.mjs +29 -0
  197. package/dist/chunk-NC5ZTR2Y.mjs +32 -0
  198. package/dist/chunk-NQGVLMWG.mjs +90 -0
  199. package/dist/chunk-QCNARS3X.mjs +46 -0
  200. package/dist/chunk-QXGYKWI7.mjs +134 -0
  201. package/dist/chunk-QY3X2UYR.mjs +191 -0
  202. package/dist/chunk-RKLHUDZS.mjs +92 -0
  203. package/dist/chunk-RMMK64W5.mjs +54 -0
  204. package/dist/chunk-RR2VQLKE.mjs +190 -0
  205. package/dist/chunk-RTC3CFXF.mjs +29 -0
  206. package/dist/chunk-SBZYEV4S.mjs +61 -0
  207. package/dist/chunk-SOA2Z4RB.mjs +82 -0
  208. package/dist/chunk-SOYNZDVY.mjs +151 -0
  209. package/dist/chunk-T7XZ7H7Y.mjs +57 -0
  210. package/dist/chunk-TAJ2PQ2O.mjs +163 -0
  211. package/dist/chunk-U4N7WF4Z.mjs +108 -0
  212. package/dist/chunk-URDE3EUU.mjs +132 -0
  213. package/dist/chunk-URLL5JBR.mjs +245 -0
  214. package/dist/chunk-XDMN67KV.mjs +59 -0
  215. package/dist/chunk-Y6MXOREN.mjs +120 -0
  216. package/dist/chunk-YZJAFS4P.mjs +131 -0
  217. package/dist/index.d.mts +94 -852
  218. package/dist/index.d.ts +94 -852
  219. package/dist/index.js +1387 -942
  220. package/dist/index.mjs +50 -3844
  221. package/package.json +23 -14
  222. package/src/assets/fonts/Sohne-Bold.otf +0 -0
  223. package/src/assets/fonts/Sohne-BoldItalic.otf +0 -0
  224. package/src/assets/fonts/Sohne-ExtraBold.otf +0 -0
  225. package/src/assets/fonts/Sohne-ExtraBoldItalic.otf +0 -0
  226. package/src/assets/fonts/Sohne-ExtraLight.otf +0 -0
  227. package/src/assets/fonts/Sohne-ExtraLightItalic.otf +0 -0
  228. package/src/assets/fonts/Sohne-Italic.otf +0 -0
  229. package/src/assets/fonts/Sohne-Light.otf +0 -0
  230. package/src/assets/fonts/Sohne-LightItalic.otf +0 -0
  231. package/src/assets/fonts/Sohne-Medium.otf +0 -0
  232. package/src/assets/fonts/Sohne-MediumItalic.otf +0 -0
  233. package/src/assets/fonts/Sohne-Regular.otf +0 -0
  234. package/src/assets/fonts/Sohne-SemiBold.otf +0 -0
  235. package/src/assets/fonts/Sohne-SemiBoldItalic.otf +0 -0
  236. package/src/assets/fonts/SohneMono-Bold.otf +0 -0
  237. package/src/assets/fonts/SohneMono-BoldItalic.otf +0 -0
  238. package/src/assets/fonts/SohneMono-ExtraBold.otf +0 -0
  239. package/src/assets/fonts/SohneMono-ExtraBoldItalic.otf +0 -0
  240. package/src/assets/fonts/SohneMono-ExtraLight.otf +0 -0
  241. package/src/assets/fonts/SohneMono-ExtraLightItalic.otf +0 -0
  242. package/src/assets/fonts/SohneMono-Italic.otf +0 -0
  243. package/src/assets/fonts/SohneMono-Light.otf +0 -0
  244. package/src/assets/fonts/SohneMono-LightItalic.otf +0 -0
  245. package/src/assets/fonts/SohneMono-Medium.otf +0 -0
  246. package/src/assets/fonts/SohneMono-MediumItalic.otf +0 -0
  247. package/src/assets/fonts/SohneMono-Regular.otf +0 -0
  248. package/src/assets/fonts/SohneMono-SemiBold.otf +0 -0
  249. package/src/assets/fonts/SohneMono-SemiBoldItalic.otf +0 -0
  250. package/src/components/Accordion/Accordion.tsx +13 -15
  251. package/src/components/AlertBanner/AlertBanner.tsx +33 -12
  252. package/src/components/Avatar/Avatar.tsx +4 -2
  253. package/src/components/Badge/Badge.tsx +4 -2
  254. package/src/components/Button/Button.tsx +30 -29
  255. package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
  256. package/src/components/Card/Card.tsx +36 -65
  257. package/src/components/CategoryStrip/CategoryStrip.tsx +68 -58
  258. package/src/components/Checkbox/Checkbox.tsx +41 -55
  259. package/src/components/Chip/Chip.tsx +49 -84
  260. package/src/components/ConfirmDialog/ConfirmDialog.tsx +2 -2
  261. package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +4 -2
  262. package/src/components/CurrencyInput/CurrencyInput.tsx +2 -2
  263. package/src/components/DetailRow/DetailRow.tsx +9 -7
  264. package/src/components/EmptyState/EmptyState.tsx +2 -2
  265. package/src/components/Form/Form.tsx +149 -0
  266. package/src/components/Form/index.ts +1 -0
  267. package/src/components/IconButton/IconButton.tsx +24 -20
  268. package/src/components/Input/Input.tsx +63 -50
  269. package/src/components/LabelValue/LabelValue.tsx +6 -4
  270. package/src/components/ListGroup/ListGroup.tsx +145 -0
  271. package/src/components/ListGroup/index.ts +1 -0
  272. package/src/components/ListItem/ListItem.tsx +30 -43
  273. package/src/components/MediaCard/MediaCard.tsx +31 -29
  274. package/src/components/MenuGroup/MenuGroup.tsx +145 -0
  275. package/src/components/MenuGroup/index.ts +1 -0
  276. package/src/components/MenuItem/MenuItem.tsx +29 -40
  277. package/src/components/MonthPicker/MonthPicker.tsx +14 -4
  278. package/src/components/Pressable/Pressable.tsx +27 -46
  279. package/src/components/Progress/Progress.tsx +21 -12
  280. package/src/components/RadioGroup/RadioGroup.tsx +55 -32
  281. package/src/components/Select/Select.tsx +23 -21
  282. package/src/components/Separator/Separator.tsx +1 -3
  283. package/src/components/Sheet/Sheet.tsx +85 -18
  284. package/src/components/Skeleton/Skeleton.tsx +25 -14
  285. package/src/components/Slider/Slider.tsx +13 -3
  286. package/src/components/Spinner/Spinner.tsx +1 -1
  287. package/src/components/Switch/Switch.tsx +70 -52
  288. package/src/components/Tabs/Tabs.tsx +59 -47
  289. package/src/components/Text/Text.tsx +3 -1
  290. package/src/components/Textarea/Textarea.tsx +44 -23
  291. package/src/components/Toast/Toast.tsx +6 -6
  292. package/src/components/Toggle/Toggle.tsx +86 -68
  293. package/src/components/VirtualList/VirtualList.tsx +60 -0
  294. package/src/components/VirtualList/index.ts +1 -0
  295. package/src/fonts.ts +38 -20
  296. package/src/index.ts +5 -1
  297. package/src/theme/colors.ts +53 -39
  298. package/src/theme/types.ts +3 -0
  299. package/src/tokens.ts +49 -39
  300. package/src/utils/animations.ts +58 -0
  301. package/src/utils/icons.ts +47 -20
  302. package/src/utils/useColorTransition.ts +40 -0
  303. package/src/utils/usePressScale.ts +75 -0
  304. package/src/assets/fonts/Poppins-Black.ttf +0 -0
  305. package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
  306. package/src/assets/fonts/Poppins-Bold.ttf +0 -0
  307. package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
  308. package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
  309. package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
  310. package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
  311. package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
  312. package/src/assets/fonts/Poppins-Italic.ttf +0 -0
  313. package/src/assets/fonts/Poppins-Light.ttf +0 -0
  314. package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
  315. package/src/assets/fonts/Poppins-Medium.ttf +0 -0
  316. package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
  317. package/src/assets/fonts/Poppins-Regular.ttf +0 -0
  318. package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
  319. package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
  320. package/src/assets/fonts/Poppins-Thin.ttf +0 -0
  321. package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var React26 = require('react');
4
4
  var reactNative = require('react-native');
5
+ var Animated9 = require('react-native-reanimated');
5
6
  var reactNativeSizeMatters = require('react-native-size-matters');
6
7
  var AntDesign = require('@expo/vector-icons/AntDesign');
7
8
  var Entypo = require('@expo/vector-icons/Entypo');
@@ -11,7 +12,6 @@ var MaterialIcons = require('@expo/vector-icons/MaterialIcons');
11
12
  var Ionicons = require('@expo/vector-icons/Ionicons');
12
13
  var vectorIcons = require('@expo/vector-icons');
13
14
  var expoLinearGradient = require('expo-linear-gradient');
14
- var Animated12 = require('react-native-reanimated');
15
15
  var RNSlider = require('@react-native-community/slider');
16
16
  var bottomSheet = require('@gorhom/bottom-sheet');
17
17
  var reactNativeSafeAreaContext = require('react-native-safe-area-context');
@@ -21,13 +21,13 @@ var sonnerNative = require('sonner-native');
21
21
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
22
22
 
23
23
  var React26__default = /*#__PURE__*/_interopDefault(React26);
24
+ var Animated9__default = /*#__PURE__*/_interopDefault(Animated9);
24
25
  var AntDesign__default = /*#__PURE__*/_interopDefault(AntDesign);
25
26
  var Entypo__default = /*#__PURE__*/_interopDefault(Entypo);
26
27
  var Feather__default = /*#__PURE__*/_interopDefault(Feather);
27
28
  var FontAwesome5__default = /*#__PURE__*/_interopDefault(FontAwesome5);
28
29
  var MaterialIcons__default = /*#__PURE__*/_interopDefault(MaterialIcons);
29
30
  var Ionicons__default = /*#__PURE__*/_interopDefault(Ionicons);
30
- var Animated12__default = /*#__PURE__*/_interopDefault(Animated12);
31
31
  var RNSlider__default = /*#__PURE__*/_interopDefault(RNSlider);
32
32
 
33
33
  // src/theme/ThemeProvider.tsx
@@ -87,19 +87,21 @@ function darken(hex, amount) {
87
87
  // src/theme/colors.ts
88
88
  var defaultLight = {
89
89
  background: "#ffffff",
90
- foreground: "#222222",
91
- // Airbnb ink — deep near-black, never pure black
90
+ foreground: "#1a1a1a",
92
91
  card: "#ffffff",
93
92
  primary: "#1a1a1a",
94
- // Near-black primary — clean, premium default
95
93
  primaryForeground: "#ffffff",
94
+ // AUDIT FIX: brand accent — was undefined; falls back to primary when omitted
95
+ accent: "#d4561d",
96
+ accentForeground: "#ffffff",
96
97
  border: "#dddddd",
97
- // Airbnb hairlinelight, airy
98
- destructive: "#e53935",
98
+ // AUDIT FIX: was #e53935 (4.22:1 on white fails AA); #c72828 = 5.59:1 ✓
99
+ destructive: "#c72828",
99
100
  destructiveForeground: "#ffffff",
100
101
  success: "#1a7a45",
101
102
  successForeground: "#ffffff",
102
- warning: "#e67e00",
103
+ // AUDIT FIX: was #e67e00 (2.86:1 — severe fail); #9a5200 = 5.86:1 ✓ AAA-near
104
+ warning: "#9a5200",
103
105
  warningForeground: "#ffffff"
104
106
  };
105
107
  var defaultDark = {
@@ -108,19 +110,24 @@ var defaultDark = {
108
110
  card: "#1c1c1c",
109
111
  primary: "#fafafa",
110
112
  primaryForeground: "#0f0f0f",
113
+ // AUDIT FIX: lighter accent for dark surfaces (warm amber-orange)
114
+ accent: "#e87645",
115
+ accentForeground: "#ffffff",
111
116
  border: "#303030",
112
117
  destructive: "#ef5350",
113
118
  destructiveForeground: "#ffffff",
114
119
  success: "#2e7d52",
115
120
  successForeground: "#ffffff",
116
- warning: "#f57c00",
117
- warningForeground: "#ffffff"
121
+ // AUDIT FIX: brighter amber for dark-bg visibility; dark text for contrast
122
+ // #f5a623 on #0f0f0f = 8.6:1 ✓ as indicator; #0f0f0f text on #f5a623 = 8.6:1 ✓
123
+ warning: "#f5a623",
124
+ warningForeground: "#0f0f0f"
118
125
  };
119
126
  function deriveColors(t, scheme) {
120
127
  const dark = scheme === "dark";
121
128
  const bg = t.background;
122
- const foregroundSubtle = mixWithBackground(t.foreground, bg, 0.55);
123
- const foregroundMuted = mixWithBackground(t.foreground, bg, 0.38);
129
+ const foregroundSubtle = mixWithBackground(t.foreground, bg, 0.7);
130
+ const foregroundMuted = mixWithBackground(t.foreground, bg, 0.62);
124
131
  const surface = dark ? lighten(bg, -0.06) : darken(bg, 0.04);
125
132
  const surfaceStrong = dark ? lighten(bg, -0.12) : darken(bg, 0.08);
126
133
  const destructiveTint = dark ? withAlphaOnDark(t.destructive, 0.15, bg) : withAlphaOnWhite(t.destructive, 0.08);
@@ -144,10 +151,9 @@ function deriveColors(t, scheme) {
144
151
  overlay: t.overlay ?? "rgba(0,0,0,0.45)",
145
152
  accentResolved: t.accent ?? t.primary,
146
153
  accentForegroundResolved: t.accentForeground ?? t.primaryForeground,
147
- ring: t.primary,
148
- // focus ring always = primary
149
- input: t.border
150
- // input border always = border
154
+ ring: t.accent ?? t.primary,
155
+ input: t.border,
156
+ separator: dark ? lighten(t.border, 0.22) : darken(t.border, 0.16)
151
157
  };
152
158
  }
153
159
 
@@ -203,20 +209,27 @@ var s = isWeb ? (n) => n : reactNativeSizeMatters.scale;
203
209
  var vs = isWeb ? (n) => n : reactNativeSizeMatters.verticalScale;
204
210
  var ms = isWeb ? (n, _factor) => n : reactNativeSizeMatters.moderateScale;
205
211
  var mvs = isWeb ? (n, _factor) => n : reactNativeSizeMatters.moderateVerticalScale;
206
- var ICON_FAMILIES = [
207
- { name: "Ionicons", component: Ionicons__default.default, glyphMap: Ionicons__default.default.glyphMap },
208
- { name: "MaterialIcons", component: MaterialIcons__default.default, glyphMap: MaterialIcons__default.default.glyphMap },
209
- { name: "FontAwesome5", component: FontAwesome5__default.default, glyphMap: FontAwesome5__default.default.glyphMap },
210
- { name: "Entypo", component: Entypo__default.default, glyphMap: Entypo__default.default.glyphMap },
211
- { name: "AntDesign", component: AntDesign__default.default, glyphMap: AntDesign__default.default.glyphMap },
212
- { name: "Feather", component: Feather__default.default, glyphMap: Feather__default.default.glyphMap }
212
+ var glyphMapOf = (mod) => mod.glyphMap ?? {};
213
+ var ALL_FAMILIES = [
214
+ { name: "Ionicons", component: Ionicons__default.default, getGlyphMap: () => glyphMapOf(Ionicons__default.default) },
215
+ { name: "MaterialIcons", component: MaterialIcons__default.default, getGlyphMap: () => glyphMapOf(MaterialIcons__default.default) },
216
+ { name: "FontAwesome5", component: FontAwesome5__default.default, getGlyphMap: () => glyphMapOf(FontAwesome5__default.default) },
217
+ { name: "Entypo", component: Entypo__default.default, getGlyphMap: () => glyphMapOf(Entypo__default.default) },
218
+ { name: "AntDesign", component: AntDesign__default.default, getGlyphMap: () => glyphMapOf(AntDesign__default.default) },
219
+ { name: "Feather", component: Feather__default.default, getGlyphMap: () => glyphMapOf(Feather__default.default) }
213
220
  ];
221
+ var activeFamilies = ALL_FAMILIES;
214
222
  var resolvedCache = null;
223
+ function configureIconFamilies(families) {
224
+ const order = families.map((n) => ALL_FAMILIES.find((f) => f.name === n)).filter((f) => f !== void 0);
225
+ activeFamilies = order.length > 0 ? order : ALL_FAMILIES;
226
+ resolvedCache = null;
227
+ }
215
228
  function buildCache() {
216
229
  const cache = /* @__PURE__ */ new Map();
217
- for (const family of ICON_FAMILIES) {
218
- if (!family.glyphMap) continue;
219
- for (const iconName of Object.keys(family.glyphMap)) {
230
+ for (const family of activeFamilies) {
231
+ const glyphMap = family.getGlyphMap();
232
+ for (const iconName of Object.keys(glyphMap)) {
220
233
  cache.set(iconName, family);
221
234
  }
222
235
  }
@@ -231,7 +244,7 @@ function resolveFamily(name) {
231
244
  function Icon({ name, size, color, family }) {
232
245
  let resolved = null;
233
246
  if (family) {
234
- resolved = ICON_FAMILIES.find((f) => f.name === family) ?? null;
247
+ resolved = ALL_FAMILIES.find((f) => f.name === family) ?? null;
235
248
  } else {
236
249
  resolved = resolveFamily(name);
237
250
  }
@@ -306,122 +319,213 @@ var BREAKPOINTS = {
306
319
  };
307
320
  var TYPOGRAPHY = {
308
321
  "display-hero": {
309
- fontFamily: "Poppins-Bold",
322
+ fontFamily: "Sohne-Bold",
310
323
  fontSize: 64,
311
324
  fontWeight: "700",
312
325
  lineHeight: 70,
313
326
  letterSpacing: -1
314
327
  },
315
328
  "display-xl": {
316
- fontFamily: "Poppins-Bold",
329
+ fontFamily: "Sohne-Bold",
317
330
  fontSize: 28,
318
331
  fontWeight: "700",
319
332
  lineHeight: 40,
320
333
  letterSpacing: 0
321
334
  },
335
+ // AUDIT FIX: was 22px/500 — raised to 24px/600; removes weight inversion vs display-md
322
336
  "display-lg": {
323
- fontFamily: "Poppins-Medium",
324
- fontSize: 22,
325
- fontWeight: "500",
326
- lineHeight: 26,
327
- letterSpacing: -0.44
337
+ fontFamily: "Sohne-SemiBold",
338
+ fontSize: 24,
339
+ fontWeight: "600",
340
+ lineHeight: 32,
341
+ letterSpacing: -0.3
328
342
  },
343
+ // AUDIT FIX: was 21px/700 — lowered to 20px/600; weight normalised, 4px gap preserved
329
344
  "display-md": {
330
- fontFamily: "Poppins-Bold",
331
- fontSize: 21,
332
- fontWeight: "700",
333
- lineHeight: 30,
345
+ fontFamily: "Sohne-SemiBold",
346
+ fontSize: 20,
347
+ fontWeight: "600",
348
+ lineHeight: 28,
334
349
  letterSpacing: 0
335
350
  },
336
351
  "display-sm": {
337
- fontFamily: "Poppins-SemiBold",
338
- fontSize: 20,
352
+ fontFamily: "Sohne-SemiBold",
353
+ fontSize: 18,
339
354
  fontWeight: "600",
340
355
  lineHeight: 24,
341
356
  letterSpacing: -0.18
342
357
  },
358
+ // AUDIT FIX: was 16px — raised to 17px so title-md > title-sm is size-visible
343
359
  "title-md": {
344
- fontFamily: "Poppins-SemiBold",
345
- fontSize: 16,
360
+ fontFamily: "Sohne-SemiBold",
361
+ fontSize: 17,
346
362
  fontWeight: "600",
347
- lineHeight: 20,
363
+ lineHeight: 22,
348
364
  letterSpacing: 0
349
365
  },
366
+ // AUDIT FIX: was 16px — lowered to 15px; now distinct from title-md
350
367
  "title-sm": {
351
- fontFamily: "Poppins-Medium",
352
- fontSize: 16,
368
+ fontFamily: "Sohne-Medium",
369
+ fontSize: 15,
353
370
  fontWeight: "500",
354
371
  lineHeight: 20,
355
372
  letterSpacing: 0
356
373
  },
357
374
  "body-md": {
358
- fontFamily: "Poppins-Regular",
375
+ fontFamily: "Sohne-Regular",
359
376
  fontSize: 16,
360
377
  fontWeight: "400",
361
378
  lineHeight: 24,
362
379
  letterSpacing: 0
363
380
  },
364
381
  "body-sm": {
365
- fontFamily: "Poppins-Regular",
382
+ fontFamily: "Sohne-Regular",
366
383
  fontSize: 14,
367
384
  fontWeight: "400",
368
385
  lineHeight: 20,
369
386
  letterSpacing: 0
370
387
  },
371
- caption: {
372
- fontFamily: "Poppins-Medium",
388
+ "caption": {
389
+ fontFamily: "Sohne-Medium",
373
390
  fontSize: 14,
374
391
  fontWeight: "500",
375
392
  lineHeight: 18,
376
393
  letterSpacing: 0
377
394
  },
378
395
  "caption-sm": {
379
- fontFamily: "Poppins-Regular",
396
+ fontFamily: "Sohne-Regular",
380
397
  fontSize: 13,
381
398
  fontWeight: "400",
382
399
  lineHeight: 16,
383
400
  letterSpacing: 0
384
401
  },
385
402
  "badge-text": {
386
- fontFamily: "Poppins-SemiBold",
403
+ fontFamily: "Sohne-SemiBold",
387
404
  fontSize: 11,
388
405
  fontWeight: "600",
389
- lineHeight: 13,
406
+ lineHeight: 14,
407
+ letterSpacing: 0
408
+ },
409
+ // AUDIT FIX: added badge-text-md so Badge md size has a canonical token
410
+ "badge-text-md": {
411
+ fontFamily: "Sohne-SemiBold",
412
+ fontSize: 13,
413
+ fontWeight: "600",
414
+ lineHeight: 16,
390
415
  letterSpacing: 0
391
416
  },
392
417
  "micro-label": {
393
- fontFamily: "Poppins-Bold",
418
+ fontFamily: "Sohne-Bold",
394
419
  fontSize: 12,
395
420
  fontWeight: "700",
396
421
  lineHeight: 16,
397
422
  letterSpacing: 0
398
423
  },
424
+ // AUDIT FIX: was 10px/0.8 letterSpacing — raised to 11px/0.6; minimum mobile readability
399
425
  "uppercase-tag": {
400
- fontFamily: "Poppins-Bold",
401
- fontSize: 10,
426
+ fontFamily: "Sohne-Bold",
427
+ fontSize: 11,
402
428
  fontWeight: "700",
403
- lineHeight: 13,
404
- letterSpacing: 0.8,
429
+ lineHeight: 14,
430
+ letterSpacing: 0.6,
405
431
  textTransform: "uppercase"
406
432
  },
407
433
  "button-lg": {
408
- fontFamily: "Poppins-Medium",
434
+ fontFamily: "Sohne-Medium",
409
435
  fontSize: 16,
410
436
  fontWeight: "500",
411
437
  lineHeight: 22,
412
438
  letterSpacing: 0
413
439
  },
414
440
  "button-sm": {
415
- fontFamily: "Poppins-Medium",
441
+ fontFamily: "Sohne-Medium",
416
442
  fontSize: 14,
417
443
  fontWeight: "500",
418
444
  lineHeight: 18,
419
445
  letterSpacing: 0
420
446
  }
421
447
  };
448
+ var SPRINGS = {
449
+ /** Tight, premium press feel — Buttons, Toggle, Tabs triggers. */
450
+ pressIn: { stiffness: 600, damping: 35, mass: 0.8 },
451
+ pressOut: { stiffness: 280, damping: 22, mass: 0.8 },
452
+ /** Slightly softer for larger surfaces — Card, ListItem, MenuItem. */
453
+ surfacePressIn: { stiffness: 380, damping: 30, mass: 0.95 },
454
+ surfacePressOut: { stiffness: 220, damping: 20, mass: 0.95 },
455
+ /** Settled transitions for moving indicators — Tabs pill, Switch thumb. */
456
+ glide: { stiffness: 380, damping: 38, mass: 1 },
457
+ /** Elastic indicator — Switch thumb, RadioGroup dot. */
458
+ elastic: { stiffness: 320, damping: 22, mass: 0.7 }
459
+ };
460
+ var TIMINGS = {
461
+ /** Color/opacity transitions on toggles, checkboxes, switches. */
462
+ state: { duration: 160 },
463
+ /** Focus ring on inputs. */
464
+ focusIn: { duration: 140 },
465
+ focusOut: { duration: 100 },
466
+ /** Accordion / collapsible content. */
467
+ expand: { duration: 240 },
468
+ collapse: { duration: 200 },
469
+ /** Skeleton shimmer cycle (full pass). */
470
+ shimmer: { duration: 1400 }
471
+ };
472
+ var EASINGS = {
473
+ /** Material-style ease-out — natural deceleration for state changes. */
474
+ standard: Animated9.Easing.bezier(0.2, 0, 0, 1),
475
+ /** Strong ease-out for expanding surfaces (Accordion open). */
476
+ expand: Animated9.Easing.bezier(0.23, 1, 0.32, 1),
477
+ /** Quick ease-in for collapsing. */
478
+ collapse: Animated9.Easing.in(Animated9.Easing.ease)
479
+ };
480
+ var PRESS_SCALE = {
481
+ button: 0.95,
482
+ card: 0.98,
483
+ row: 0.97,
484
+ chip: 0.94
485
+ };
486
+ function useHover() {
487
+ const [hovered, setHovered] = React26.useState(false);
488
+ const onMouseEnter = React26.useCallback(() => setHovered(true), []);
489
+ const onMouseLeave = React26.useCallback(() => setHovered(false), []);
490
+ if (reactNative.Platform.OS !== "web") {
491
+ return { hovered: false, hoverHandlers: {} };
492
+ }
493
+ return { hovered, hoverHandlers: { onMouseEnter, onMouseLeave } };
494
+ }
495
+
496
+ // src/utils/usePressScale.ts
497
+ function usePressScale({
498
+ pressScale = PRESS_SCALE.button,
499
+ hoverScale = 1.02,
500
+ pressInSpring = SPRINGS.pressIn,
501
+ pressOutSpring = SPRINGS.pressOut,
502
+ disabled = false
503
+ } = {}) {
504
+ const scale2 = Animated9.useSharedValue(1);
505
+ const { hovered, hoverHandlers } = useHover();
506
+ const onPressIn = React26.useCallback(() => {
507
+ if (disabled) return;
508
+ scale2.value = Animated9.withSpring(pressScale, pressInSpring);
509
+ }, [disabled, pressScale, pressInSpring, scale2]);
510
+ const onPressOut = React26.useCallback(() => {
511
+ if (disabled) return;
512
+ scale2.value = Animated9.withSpring(1, pressOutSpring);
513
+ }, [disabled, pressOutSpring, scale2]);
514
+ const hoverActive = reactNative.Platform.OS === "web" && hovered && hoverScale !== 1 && !disabled;
515
+ const animatedStyle = Animated9.useAnimatedStyle(() => ({
516
+ transform: [
517
+ { scale: scale2.value * (hoverActive ? hoverScale : 1) }
518
+ ]
519
+ }));
520
+ return {
521
+ animatedStyle,
522
+ onPressIn,
523
+ onPressOut,
524
+ hoverHandlers
525
+ };
526
+ }
422
527
 
423
528
  // src/components/Button/Button.tsx
424
- var nativeDriver = reactNative.Platform.OS !== "web";
425
529
  var containerSizeStyles = {
426
530
  sm: { paddingHorizontal: s(16), paddingVertical: vs(10), minHeight: 40 },
427
531
  md: { paddingHorizontal: s(24), paddingVertical: vs(14), minHeight: 48 },
@@ -433,7 +537,7 @@ var labelSizeStyles = {
433
537
  lg: { ...TYPOGRAPHY["button-lg"], fontSize: ms(TYPOGRAPHY["button-lg"].fontSize + 1), lineHeight: mvs(24) }
434
538
  };
435
539
  var iconSizeMap = { sm: 16, md: 18, lg: 20 };
436
- function Button({
540
+ function ButtonBase({
437
541
  label,
438
542
  variant = "primary",
439
543
  size = "md",
@@ -446,18 +550,16 @@ function Button({
446
550
  disabled,
447
551
  style,
448
552
  onPress,
553
+ accessibilityLabel,
554
+ accessibilityHint,
449
555
  ...props
450
556
  }) {
451
557
  const { colors } = useTheme();
452
558
  const isDisabled = disabled || loading;
453
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
454
- const handlePressIn = () => {
455
- if (isDisabled) return;
456
- reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver, stiffness: 600, damping: 35, mass: 0.8 }).start();
457
- };
458
- const handlePressOut = () => {
459
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver, stiffness: 280, damping: 22, mass: 0.8 }).start();
460
- };
559
+ const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
560
+ pressScale: PRESS_SCALE.button,
561
+ disabled: isDisabled
562
+ });
461
563
  const handlePress = (e) => {
462
564
  impactMedium();
463
565
  onPress?.(e);
@@ -471,57 +573,71 @@ function Button({
471
573
  const labelVariantStyle = {
472
574
  primary: { color: colors.primaryForeground },
473
575
  secondary: { color: colors.primary },
474
- text: { color: colors.foreground },
576
+ // AUDIT FIX: was colors.foreground — visually indistinguishable from plain text,
577
+ // no affordance that it's a CTA. Now uses accentResolved so text-only buttons
578
+ // carry the brand voltage. Falls back to primary when no accent is defined.
579
+ text: { color: colors.accentResolved },
475
580
  destructive: { color: colors.destructiveForeground }
476
581
  }[variant];
477
582
  const textColor = iconColor ?? labelVariantStyle.color;
478
583
  const effectiveIcon = iconName ? renderIcon(iconName, iconSizeMap[size], textColor) : typeof icon === "function" ? icon({ label, size, variant, color: textColor }) : icon;
479
- const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" ? colors.primaryForeground : colors.foreground;
584
+ const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" ? colors.primaryForeground : colors.accentResolved;
480
585
  const styleArray = Array.isArray(style) ? style : style ? [style] : [];
481
586
  const flatStyle = reactNative.StyleSheet.flatten(styleArray);
482
587
  const { flex, ...restStyle } = flatStyle || {};
483
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [fullWidth && styles.fullWidth, flex !== void 0 && { flex }, { transform: [{ scale: scale2 }] }] }, /* @__PURE__ */ React26__default.default.createElement(
484
- reactNative.TouchableOpacity,
588
+ return /* @__PURE__ */ React26__default.default.createElement(
589
+ Animated9__default.default.View,
485
590
  {
486
- style: [
487
- styles.base,
488
- containerVariantStyle,
489
- containerSizeStyles[size],
490
- fullWidth && styles.fullWidth,
491
- isDisabled && styles.disabled,
492
- restStyle
493
- ],
494
- disabled: isDisabled,
495
- activeOpacity: 1,
496
- touchSoundDisabled: true,
497
- onPress: handlePress,
498
- onPressIn: handlePressIn,
499
- onPressOut: handlePressOut,
500
- ...props
591
+ style: [fullWidth && styles.fullWidth, flex !== void 0 && { flex }, animatedStyle],
592
+ ...hoverHandlers
501
593
  },
502
- loading ? /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, /* @__PURE__ */ React26__default.default.createElement(reactNative.ActivityIndicator, { size: "small", color: spinnerColor, style: { marginRight: s(6) } }), /* @__PURE__ */ React26__default.default.createElement(
503
- reactNative.Text,
504
- {
505
- style: [styles.label, labelVariantStyle, labelSizeStyles[size], styles.labelLoading],
506
- allowFontScaling: true,
507
- numberOfLines: 1
508
- },
509
- label
510
- )) : /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon && iconPosition === "left" && /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon), /* @__PURE__ */ React26__default.default.createElement(
511
- reactNative.Text,
594
+ /* @__PURE__ */ React26__default.default.createElement(
595
+ reactNative.TouchableOpacity,
512
596
  {
513
- style: [styles.label, labelVariantStyle, labelSizeStyles[size], effectiveIcon ? styles.labelWithIcon : void 0],
514
- allowFontScaling: true,
515
- numberOfLines: 1
597
+ style: [
598
+ styles.base,
599
+ containerVariantStyle,
600
+ containerSizeStyles[size],
601
+ fullWidth && styles.fullWidth,
602
+ isDisabled && styles.disabled,
603
+ restStyle
604
+ ],
605
+ disabled: isDisabled,
606
+ activeOpacity: 1,
607
+ touchSoundDisabled: true,
608
+ onPress: handlePress,
609
+ onPressIn,
610
+ onPressOut,
611
+ accessibilityRole: "button",
612
+ accessibilityLabel: accessibilityLabel ?? label,
613
+ accessibilityHint,
614
+ accessibilityState: { disabled: isDisabled, busy: loading },
615
+ ...props
516
616
  },
517
- label
518
- ), effectiveIcon && iconPosition === "right" && /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon))
519
- ));
617
+ loading ? /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, /* @__PURE__ */ React26__default.default.createElement(reactNative.ActivityIndicator, { size: "small", color: spinnerColor, style: { marginRight: s(6) } }), /* @__PURE__ */ React26__default.default.createElement(
618
+ reactNative.Text,
619
+ {
620
+ style: [styles.label, labelVariantStyle, labelSizeStyles[size], styles.labelLoading],
621
+ allowFontScaling: true,
622
+ numberOfLines: 1
623
+ },
624
+ label
625
+ )) : /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon && iconPosition === "left" && /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon), /* @__PURE__ */ React26__default.default.createElement(
626
+ reactNative.Text,
627
+ {
628
+ style: [styles.label, labelVariantStyle, labelSizeStyles[size], effectiveIcon ? styles.labelWithIcon : void 0],
629
+ allowFontScaling: true,
630
+ numberOfLines: 1
631
+ },
632
+ label
633
+ ), effectiveIcon && iconPosition === "right" && /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon))
634
+ )
635
+ );
520
636
  }
637
+ var Button = React26__default.default.memo(ButtonBase);
521
638
  var styles = reactNative.StyleSheet.create({
522
639
  base: {
523
640
  borderRadius: RADIUS.md,
524
- // 14px — Airbnb-aligned rounded rect (not pill)
525
641
  alignItems: "center",
526
642
  justifyContent: "center",
527
643
  flexDirection: "row"
@@ -533,7 +649,7 @@ var styles = reactNative.StyleSheet.create({
533
649
  opacity: 0.45
534
650
  },
535
651
  label: {
536
- fontFamily: "Poppins-Medium",
652
+ fontFamily: "Sohne-Medium",
537
653
  flexShrink: 1
538
654
  },
539
655
  labelWithIcon: {
@@ -554,15 +670,17 @@ function ButtonGroup({ children, gap = 12, vertical = false, style }) {
554
670
  style
555
671
  ]
556
672
  },
557
- React26__default.default.Children.map(
558
- children,
559
- (child) => React26__default.default.isValidElement(child) ? React26__default.default.cloneElement(child, {
560
- style: [
561
- child.props.style,
562
- { flex: 1 }
563
- ]
564
- }) : child
565
- )
673
+ React26__default.default.Children.map(children, (child) => {
674
+ if (!React26__default.default.isValidElement(child)) return child;
675
+ const childProps = child.props;
676
+ const extraProps = {
677
+ style: [child.props.style, { flex: 1 }]
678
+ };
679
+ if (!vertical && "label" in childProps && childProps["size"] === void 0) {
680
+ extraProps["size"] = "sm";
681
+ }
682
+ return React26__default.default.cloneElement(child, extraProps);
683
+ })
566
684
  );
567
685
  }
568
686
  var styles2 = reactNative.StyleSheet.create({
@@ -576,13 +694,12 @@ var styles2 = reactNative.StyleSheet.create({
576
694
  flexDirection: "column"
577
695
  }
578
696
  });
579
- var nativeDriver2 = reactNative.Platform.OS !== "web";
580
697
  var sizeMap = {
581
698
  sm: { container: s(32), icon: 16 },
582
699
  md: { container: s(44), icon: 20 },
583
700
  lg: { container: s(52), icon: 24 }
584
701
  };
585
- function IconButton({
702
+ function IconButtonBase({
586
703
  iconName,
587
704
  icon,
588
705
  iconColor,
@@ -593,18 +710,16 @@ function IconButton({
593
710
  disabled,
594
711
  style,
595
712
  onPress,
713
+ accessibilityLabel,
714
+ accessibilityHint,
596
715
  ...props
597
716
  }) {
598
717
  const { colors } = useTheme();
599
718
  const isDisabled = disabled || loading;
600
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
601
- const handlePressIn = () => {
602
- if (isDisabled) return;
603
- reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver2, speed: 40, bounciness: 0 }).start();
604
- };
605
- const handlePressOut = () => {
606
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver2, speed: 40, bounciness: 4 }).start();
607
- };
719
+ const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
720
+ pressScale: PRESS_SCALE.button,
721
+ disabled: isDisabled
722
+ });
608
723
  const handlePress = (e) => {
609
724
  impactLight();
610
725
  onPress?.(e);
@@ -629,31 +744,44 @@ function IconButton({
629
744
  const showBadge = badge !== void 0 && badge !== false && badge !== 0;
630
745
  const badgeCount = typeof badge === "number" ? Math.min(badge, 99) : null;
631
746
  const showCount = typeof badge === "number" && badge > 0;
632
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [styles3.wrapper, { transform: [{ scale: scale2 }] }] }, /* @__PURE__ */ React26__default.default.createElement(
633
- reactNative.TouchableOpacity,
747
+ return /* @__PURE__ */ React26__default.default.createElement(
748
+ Animated9__default.default.View,
634
749
  {
635
- style: [
636
- styles3.base,
637
- containerVariantStyle,
638
- { width: containerSize, height: containerSize },
639
- isDisabled && styles3.disabled,
640
- style
641
- ],
642
- disabled: isDisabled,
643
- activeOpacity: 1,
644
- touchSoundDisabled: true,
645
- onPress: handlePress,
646
- onPressIn: handlePressIn,
647
- onPressOut: handlePressOut,
648
- ...props
750
+ style: [styles3.wrapper, animatedStyle],
751
+ ...hoverHandlers
649
752
  },
650
- loading ? /* @__PURE__ */ React26__default.default.createElement(reactNative.ActivityIndicator, { size: "small", color: spinnerColor }) : resolvedIcon
651
- ), showBadge && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
652
- styles3.badge,
653
- { backgroundColor: colors.primary },
654
- showCount ? styles3.badgeCount : styles3.badgeDot
655
- ] }, showCount && /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles3.badgeText, { color: colors.primaryForeground }] }, badgeCount)));
753
+ /* @__PURE__ */ React26__default.default.createElement(
754
+ reactNative.TouchableOpacity,
755
+ {
756
+ style: [
757
+ styles3.base,
758
+ containerVariantStyle,
759
+ { width: containerSize, height: containerSize },
760
+ isDisabled && styles3.disabled,
761
+ style
762
+ ],
763
+ disabled: isDisabled,
764
+ activeOpacity: 1,
765
+ touchSoundDisabled: true,
766
+ onPress: handlePress,
767
+ onPressIn,
768
+ onPressOut,
769
+ accessibilityRole: "button",
770
+ accessibilityLabel: accessibilityLabel ?? iconName ?? "icon button",
771
+ accessibilityHint,
772
+ accessibilityState: { disabled: isDisabled, busy: loading },
773
+ ...props
774
+ },
775
+ loading ? /* @__PURE__ */ React26__default.default.createElement(reactNative.ActivityIndicator, { size: "small", color: spinnerColor }) : resolvedIcon
776
+ ),
777
+ showBadge && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
778
+ styles3.badge,
779
+ { backgroundColor: colors.primary },
780
+ showCount ? styles3.badgeCount : styles3.badgeDot
781
+ ] }, showCount && /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles3.badgeText, { color: colors.primaryForeground }] }, badgeCount))
782
+ );
656
783
  }
784
+ var IconButton = React26__default.default.memo(IconButtonBase);
657
785
  var styles3 = reactNative.StyleSheet.create({
658
786
  wrapper: {
659
787
  alignSelf: "flex-start"
@@ -685,7 +813,7 @@ var styles3 = reactNative.StyleSheet.create({
685
813
  paddingHorizontal: 3
686
814
  },
687
815
  badgeText: {
688
- fontFamily: "Poppins-Bold",
816
+ fontFamily: "Sohne-Bold",
689
817
  fontSize: ms(9),
690
818
  lineHeight: 14
691
819
  }
@@ -727,7 +855,7 @@ var defaultColorVariant = {
727
855
  "button-lg": "foreground",
728
856
  "button-sm": "foreground"
729
857
  };
730
- function Text3({ variant = "body-md", color, style, children, ...props }) {
858
+ function TextBase({ variant = "body-md", color, style, children, ...props }) {
731
859
  const { colors } = useTheme();
732
860
  const colorKey = defaultColorVariant[variant] ?? "foreground";
733
861
  const resolvedColor = color ?? colors[colorKey];
@@ -741,63 +869,90 @@ function Text3({ variant = "body-md", color, style, children, ...props }) {
741
869
  children
742
870
  );
743
871
  }
872
+ var Text3 = React26__default.default.memo(TextBase);
873
+ function useColorTransition(active, options = {}) {
874
+ const { duration = TIMINGS.state.duration } = options;
875
+ const progress = Animated9.useSharedValue(active ? 1 : 0);
876
+ React26.useEffect(() => {
877
+ progress.value = Animated9.withTiming(active ? 1 : 0, { duration, easing: EASINGS.standard });
878
+ }, [active, duration, progress]);
879
+ return progress;
880
+ }
881
+
882
+ // src/components/Input/Input.tsx
744
883
  var webInputResetStyle = reactNative.Platform.OS === "web" ? { outlineStyle: "none", outlineWidth: 0, outlineColor: "transparent", boxShadow: "none" } : {};
745
- function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = "text", containerStyle, inputWrapperStyle, style, onFocus, onBlur, secureTextEntry, editable, ...props }) {
884
+ function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = "text", containerStyle, inputWrapperStyle, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }) {
746
885
  const { colors } = useTheme();
747
886
  const [focused, setFocused] = React26.useState(false);
748
887
  const [showPassword, setShowPassword] = React26.useState(false);
749
- const focusAnim = React26.useRef(new reactNative.Animated.Value(0)).current;
888
+ const focusProgress = useColorTransition(focused, {
889
+ duration: focused ? TIMINGS.focusIn.duration : TIMINGS.focusOut.duration
890
+ });
750
891
  const isDisabled = disabled || editable === false;
751
892
  const isPassword = type === "password";
752
893
  const effectiveSecure = isPassword ? !showPassword : secureTextEntry;
753
894
  const effectivePrefix = prefixIcon ? renderIcon(prefixIcon, 20, prefixIconColor ?? colors.foregroundMuted) : prefix;
754
- const effectiveSuffix = isPassword && !suffix && !suffixIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.TouchableOpacity, { onPress: () => setShowPassword(!showPassword), style: styles4.passwordToggle, activeOpacity: 0.6 }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.AntDesign, { name: showPassword ? "eye" : "eye-invisible", size: 20, color: colors.foregroundMuted })) : suffixIcon ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted) : suffix;
895
+ const effectiveSuffix = isPassword && !suffix && !suffixIcon ? /* @__PURE__ */ React26__default.default.createElement(
896
+ reactNative.TouchableOpacity,
897
+ {
898
+ onPress: () => setShowPassword(!showPassword),
899
+ style: styles4.passwordToggle,
900
+ activeOpacity: 0.6,
901
+ accessibilityRole: "button",
902
+ accessibilityLabel: showPassword ? "Hide password" : "Show password"
903
+ },
904
+ /* @__PURE__ */ React26__default.default.createElement(vectorIcons.AntDesign, { name: showPassword ? "eye" : "eye-invisible", size: 20, color: colors.foregroundMuted })
905
+ ) : suffixIcon ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted) : suffix;
906
+ const borderAnimStyle = Animated9.useAnimatedStyle(() => ({
907
+ borderColor: error ? colors.destructive : Animated9.interpolateColor(focusProgress.value, [0, 1], [colors.border, colors.primary]),
908
+ borderWidth: error ? 2 : Animated9.interpolate(focusProgress.value, [0, 1], [1, 2])
909
+ }));
755
910
  return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles4.container, isDisabled && styles4.containerDisabled, containerStyle] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React26__default.default.createElement(
756
- reactNative.Animated.View,
911
+ Animated9__default.default.View,
757
912
  {
758
913
  style: [
759
914
  styles4.inputWrapper,
760
- {
761
- borderColor: error ? colors.destructive : focusAnim.interpolate({
762
- inputRange: [0, 1],
763
- outputRange: [colors.border, colors.primary]
764
- }),
765
- backgroundColor: isDisabled ? colors.surface : colors.background
766
- },
915
+ { backgroundColor: isDisabled ? colors.surface : colors.background },
767
916
  inputWrapperStyle
768
917
  ]
769
918
  },
919
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles4.borderOverlay, borderAnimStyle], pointerEvents: "none" }),
770
920
  effectivePrefix ? typeof effectivePrefix === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.prefixText, { color: colors.foregroundMuted }, prefixStyle], allowFontScaling: true }, effectivePrefix) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles4.prefixContainer }, effectivePrefix) : null,
771
921
  /* @__PURE__ */ React26__default.default.createElement(
772
922
  reactNative.TextInput,
773
923
  {
774
924
  style: [
775
925
  styles4.input,
776
- {
777
- color: colors.foreground
778
- },
926
+ { color: colors.foreground },
779
927
  webInputResetStyle,
780
928
  style
781
929
  ],
782
930
  onFocus: (e) => {
783
931
  setFocused(true);
784
- reactNative.Animated.timing(focusAnim, { toValue: 1, duration: 120, easing: reactNative.Easing.out(reactNative.Easing.ease), useNativeDriver: false }).start();
785
932
  onFocus?.(e);
786
933
  },
787
934
  onBlur: (e) => {
788
935
  setFocused(false);
789
- reactNative.Animated.timing(focusAnim, { toValue: 0, duration: 80, easing: reactNative.Easing.out(reactNative.Easing.ease), useNativeDriver: false }).start();
790
936
  onBlur?.(e);
791
937
  },
792
938
  placeholderTextColor: colors.foregroundMuted,
793
939
  allowFontScaling: true,
794
940
  secureTextEntry: effectiveSecure,
795
941
  editable: isDisabled ? false : editable,
942
+ accessibilityLabel: accessibilityLabel ?? label,
796
943
  ...props
797
944
  }
798
945
  ),
799
946
  effectiveSuffix ? typeof effectiveSuffix === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.suffixText, { color: colors.foregroundMuted }, suffixStyle], allowFontScaling: true }, effectiveSuffix) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles4.suffixContainer }, effectiveSuffix) : null
800
- ), error ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.helperText, { color: colors.destructive }], allowFontScaling: true }, error) : null, !error && hint ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null);
947
+ ), error ? /* @__PURE__ */ React26__default.default.createElement(
948
+ reactNative.Text,
949
+ {
950
+ style: [styles4.helperText, { color: colors.destructive }],
951
+ allowFontScaling: true,
952
+ accessibilityLiveRegion: "polite"
953
+ },
954
+ error
955
+ ) : null, !error && hint ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null);
801
956
  }
802
957
  var styles4 = reactNative.StyleSheet.create({
803
958
  container: {
@@ -807,21 +962,25 @@ var styles4 = reactNative.StyleSheet.create({
807
962
  opacity: 0.6
808
963
  },
809
964
  label: {
810
- fontFamily: "Poppins-Medium",
965
+ fontFamily: "Sohne-Medium",
811
966
  fontSize: ms(14)
812
- // caption size for input labels
813
967
  },
814
968
  inputWrapper: {
815
969
  flexDirection: "row",
816
970
  alignItems: "center",
817
- borderWidth: 2,
971
+ // Border lives on borderOverlay (absolute) so its 1px→2px focus change
972
+ // never resizes this box. Wrapper itself carries no border.
818
973
  borderRadius: 8,
819
974
  paddingHorizontal: s(14),
820
975
  paddingVertical: vs(11),
821
976
  minHeight: 48
822
977
  },
978
+ borderOverlay: {
979
+ ...reactNative.StyleSheet.absoluteFillObject,
980
+ borderRadius: 8
981
+ },
823
982
  input: {
824
- fontFamily: "Poppins-Regular",
983
+ fontFamily: "Sohne-Regular",
825
984
  flex: 1,
826
985
  fontSize: ms(16),
827
986
  paddingVertical: vs(2),
@@ -831,7 +990,7 @@ var styles4 = reactNative.StyleSheet.create({
831
990
  marginRight: s(8)
832
991
  },
833
992
  prefixText: {
834
- fontFamily: "Poppins-Regular",
993
+ fontFamily: "Sohne-Regular",
835
994
  fontSize: ms(15),
836
995
  marginRight: s(8)
837
996
  },
@@ -839,15 +998,18 @@ var styles4 = reactNative.StyleSheet.create({
839
998
  marginLeft: s(8)
840
999
  },
841
1000
  suffixText: {
842
- fontFamily: "Poppins-Regular",
1001
+ fontFamily: "Sohne-Regular",
843
1002
  fontSize: ms(15),
844
1003
  marginLeft: s(8)
845
1004
  },
1005
+ // AUDIT FIX: was padding: s(4) → ~28px tap target. Now 12px padding → ~44px.
1006
+ // Negative margin compensates so the visual icon position is unchanged.
846
1007
  passwordToggle: {
847
- padding: s(4)
1008
+ padding: s(12),
1009
+ margin: -s(8)
848
1010
  },
849
1011
  helperText: {
850
- fontFamily: "Poppins-Regular",
1012
+ fontFamily: "Sohne-Regular",
851
1013
  fontSize: ms(13)
852
1014
  }
853
1015
  });
@@ -867,7 +1029,7 @@ var sizeIconGap = {
867
1029
  lg: s(6)
868
1030
  };
869
1031
  var sizeIconSize = { sm: 10, md: 12, lg: 14 };
870
- function Badge({ label, children, variant = "default", size = "md", icon, iconName, iconColor, style }) {
1032
+ function BadgeBase({ label, children, variant = "default", size = "md", icon, iconName, iconColor, style }) {
871
1033
  const { colors } = useTheme();
872
1034
  const containerStyle = {
873
1035
  default: { backgroundColor: colors.primary },
@@ -895,6 +1057,7 @@ function Badge({ label, children, variant = "default", size = "md", icon, iconNa
895
1057
  const content = children ?? label;
896
1058
  return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles5.container, containerStyle, sizePadding[size], { gap: sizeIconGap[size] }, style] }, effectiveIcon, typeof content === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles5.label, { color: textColor }, sizeFontSize[size]], allowFontScaling: true }, content) : content);
897
1059
  }
1060
+ var Badge = React26__default.default.memo(BadgeBase);
898
1061
  var styles5 = reactNative.StyleSheet.create({
899
1062
  container: {
900
1063
  borderRadius: 9999,
@@ -903,33 +1066,17 @@ var styles5 = reactNative.StyleSheet.create({
903
1066
  alignItems: "center"
904
1067
  },
905
1068
  label: {
906
- fontFamily: "Poppins-Medium"
1069
+ fontFamily: "Sohne-Medium"
907
1070
  }
908
1071
  });
909
- var nativeDriver3 = reactNative.Platform.OS !== "web";
910
- function Card({ children, variant = "elevated", onPress, style }) {
1072
+ function Card({ children, variant = "elevated", onPress, style, accessibilityLabel }) {
911
1073
  const { colors } = useTheme();
912
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
913
- const handlePressIn = () => {
914
- if (!onPress) return;
915
- reactNative.Animated.spring(scale2, {
916
- toValue: 0.98,
917
- useNativeDriver: nativeDriver3,
918
- stiffness: 400,
919
- damping: 30,
920
- mass: 1
921
- }).start();
922
- };
923
- const handlePressOut = () => {
924
- if (!onPress) return;
925
- reactNative.Animated.spring(scale2, {
926
- toValue: 1,
927
- useNativeDriver: nativeDriver3,
928
- stiffness: 250,
929
- damping: 24,
930
- mass: 1
931
- }).start();
932
- };
1074
+ const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
1075
+ pressScale: PRESS_SCALE.card,
1076
+ pressInSpring: SPRINGS.surfacePressIn,
1077
+ pressOutSpring: SPRINGS.surfacePressOut,
1078
+ disabled: !onPress
1079
+ });
933
1080
  const handlePress = () => {
934
1081
  if (!onPress) return;
935
1082
  impactLight();
@@ -938,11 +1085,14 @@ function Card({ children, variant = "elevated", onPress, style }) {
938
1085
  const variantStyle = {
939
1086
  elevated: {
940
1087
  backgroundColor: colors.card,
941
- borderColor: colors.border,
1088
+ // AUDIT FIX: removed borderColor — shadow is the depth signal; a border on
1089
+ // top of a shadow creates redundant double-framing that reads as "heavy"
1090
+ // rather than "elevated". borderWidth: 0 overrides the base style's borderWidth: 1.
1091
+ borderWidth: 0,
942
1092
  shadowColor: "#000",
943
- shadowOffset: { width: 0, height: 6 },
944
- shadowOpacity: 0.1,
945
- shadowRadius: 16,
1093
+ shadowOffset: { width: 0, height: 4 },
1094
+ shadowOpacity: 0.09,
1095
+ shadowRadius: 14,
946
1096
  elevation: 4
947
1097
  },
948
1098
  outlined: {
@@ -960,14 +1110,16 @@ function Card({ children, variant = "elevated", onPress, style }) {
960
1110
  }[variant];
961
1111
  const cardContent = /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles6.card, variantStyle, style] }, children);
962
1112
  if (onPress) {
963
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React26__default.default.createElement(
1113
+ return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: animatedStyle, ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
964
1114
  reactNative.TouchableOpacity,
965
1115
  {
966
1116
  onPress: handlePress,
967
- onPressIn: handlePressIn,
968
- onPressOut: handlePressOut,
1117
+ onPressIn,
1118
+ onPressOut,
969
1119
  activeOpacity: 1,
970
- touchSoundDisabled: true
1120
+ touchSoundDisabled: true,
1121
+ accessibilityRole: "button",
1122
+ accessibilityLabel
971
1123
  },
972
1124
  cardContent
973
1125
  ));
@@ -983,7 +1135,7 @@ function CardTitle({ children, style }) {
983
1135
  }
984
1136
  function CardDescription({ children, style }) {
985
1137
  const { colors } = useTheme();
986
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles6.description, { color: colors.foregroundMuted }, style], allowFontScaling: true }, children);
1138
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles6.description, { color: colors.foregroundSubtle }, style], allowFontScaling: true }, children);
987
1139
  }
988
1140
  function CardContent({ children, style }) {
989
1141
  return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles6.content, style] }, children);
@@ -994,7 +1146,6 @@ function CardFooter({ children, style }) {
994
1146
  var styles6 = reactNative.StyleSheet.create({
995
1147
  card: {
996
1148
  borderRadius: RADIUS.md,
997
- // 14px — Airbnb property card spec
998
1149
  borderWidth: 1
999
1150
  },
1000
1151
  header: {
@@ -1003,12 +1154,14 @@ var styles6 = reactNative.StyleSheet.create({
1003
1154
  gap: vs(4)
1004
1155
  },
1005
1156
  title: {
1006
- fontFamily: "Poppins-SemiBold",
1157
+ fontFamily: "Sohne-SemiBold",
1007
1158
  fontSize: ms(16),
1008
1159
  lineHeight: mvs(22)
1009
1160
  },
1161
+ // AUDIT FIX: was foregroundMuted (2.2:1 fail) — description text now uses
1162
+ // foregroundSubtle (5.9:1 ✓) which is readable while still visually secondary.
1010
1163
  description: {
1011
- fontFamily: "Poppins-Regular",
1164
+ fontFamily: "Sohne-Regular",
1012
1165
  fontSize: ms(13),
1013
1166
  lineHeight: mvs(18)
1014
1167
  },
@@ -1031,7 +1184,7 @@ function Separator({ orientation = "horizontal", style }) {
1031
1184
  {
1032
1185
  style: [
1033
1186
  orientation === "horizontal" ? styles7.horizontal : styles7.vertical,
1034
- { backgroundColor: colors.border },
1187
+ { backgroundColor: colors.separator },
1035
1188
  style
1036
1189
  ]
1037
1190
  }
@@ -1040,13 +1193,11 @@ function Separator({ orientation = "horizontal", style }) {
1040
1193
  var styles7 = reactNative.StyleSheet.create({
1041
1194
  horizontal: {
1042
1195
  height: 1,
1043
- width: "100%",
1044
- opacity: 0.7
1196
+ width: "100%"
1045
1197
  },
1046
1198
  vertical: {
1047
1199
  width: 1,
1048
- height: "100%",
1049
- opacity: 0.7
1200
+ height: "100%"
1050
1201
  }
1051
1202
  });
1052
1203
  var sizeMap2 = {
@@ -1079,7 +1230,7 @@ var styles8 = reactNative.StyleSheet.create({
1079
1230
  gap: vs(6)
1080
1231
  },
1081
1232
  label: {
1082
- fontFamily: "Poppins-Regular",
1233
+ fontFamily: "Sohne-Regular",
1083
1234
  lineHeight: mvs(18)
1084
1235
  }
1085
1236
  });
@@ -1092,20 +1243,19 @@ function Skeleton({
1092
1243
  style
1093
1244
  }) {
1094
1245
  const { colors, colorScheme } = useTheme();
1095
- const shimmerAnim = React26.useRef(new reactNative.Animated.Value(0)).current;
1246
+ const shimmer = Animated9.useSharedValue(0);
1096
1247
  const [containerWidth, setContainerWidth] = React26.useState(300);
1097
1248
  const shimmerHighlight = colorScheme === "dark" ? "rgba(255,255,255,0.08)" : "rgba(255,255,255,0.7)";
1098
1249
  React26.useEffect(() => {
1099
- const animation = reactNative.Animated.loop(
1100
- reactNative.Animated.timing(shimmerAnim, { toValue: 1, duration: 1200, useNativeDriver: true })
1250
+ shimmer.value = Animated9.withRepeat(
1251
+ Animated9.withTiming(1, { duration: TIMINGS.shimmer.duration, easing: Animated9.Easing.linear }),
1252
+ -1,
1253
+ false
1101
1254
  );
1102
- animation.start();
1103
- return () => animation.stop();
1104
- }, [shimmerAnim]);
1105
- const translateX = shimmerAnim.interpolate({
1106
- inputRange: [0, 1],
1107
- outputRange: [-containerWidth, containerWidth]
1108
- });
1255
+ }, [shimmer]);
1256
+ const shimmerStyle = Animated9.useAnimatedStyle(() => ({
1257
+ transform: [{ translateX: -containerWidth + shimmer.value * (containerWidth * 2) }]
1258
+ }));
1109
1259
  const resolvedWidth = preset === "circle" ? s(diameter) : preset === "text" ? "60%" : width;
1110
1260
  const resolvedHeight = preset === "circle" ? s(diameter) : preset === "text" ? 14 : height;
1111
1261
  const resolvedRadius = preset === "circle" ? 9999 : preset === "text" ? 4 : borderRadius;
@@ -1117,9 +1267,12 @@ function Skeleton({
1117
1267
  { width: resolvedWidth, height: resolvedHeight, borderRadius: resolvedRadius, backgroundColor: colors.surface },
1118
1268
  style
1119
1269
  ],
1120
- onLayout: (e) => setContainerWidth(e.nativeEvent.layout.width)
1270
+ onLayout: (e) => setContainerWidth(e.nativeEvent.layout.width),
1271
+ accessibilityRole: "progressbar",
1272
+ accessibilityLabel: "Loading",
1273
+ accessibilityState: { busy: true }
1121
1274
  },
1122
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [reactNative.StyleSheet.absoluteFill, { transform: [{ translateX }] }] }, /* @__PURE__ */ React26__default.default.createElement(
1275
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [reactNative.StyleSheet.absoluteFill, shimmerStyle] }, /* @__PURE__ */ React26__default.default.createElement(
1123
1276
  expoLinearGradient.LinearGradient,
1124
1277
  {
1125
1278
  colors: ["transparent", shimmerHighlight, "transparent"],
@@ -1162,7 +1315,7 @@ function getInitials(fallback, fallbackText) {
1162
1315
  }
1163
1316
  return "?";
1164
1317
  }
1165
- function Avatar({ src, fallback, fallbackText, size = "md", status, style }) {
1318
+ function AvatarBase({ src, fallback, fallbackText, size = "md", status, style }) {
1166
1319
  const { colors } = useTheme();
1167
1320
  const [imageError, setImageError] = React26.useState(false);
1168
1321
  const dimension = typeof size === "number" ? size : sizeMap3[size];
@@ -1213,6 +1366,7 @@ function Avatar({ src, fallback, fallbackText, size = "md", status, style }) {
1213
1366
  }
1214
1367
  ));
1215
1368
  }
1369
+ var Avatar = React26__default.default.memo(AvatarBase);
1216
1370
  var styles10 = reactNative.StyleSheet.create({
1217
1371
  wrapper: {
1218
1372
  alignSelf: "flex-start",
@@ -1223,7 +1377,7 @@ var styles10 = reactNative.StyleSheet.create({
1223
1377
  justifyContent: "center"
1224
1378
  },
1225
1379
  fallback: {
1226
- fontFamily: "Poppins-Medium"
1380
+ fontFamily: "Sohne-Medium"
1227
1381
  },
1228
1382
  statusDot: {
1229
1383
  position: "absolute",
@@ -1232,11 +1386,30 @@ var styles10 = reactNative.StyleSheet.create({
1232
1386
  }
1233
1387
  });
1234
1388
  function AlertBanner({ title, description, variant = "default", icon, iconName, iconColor, style }) {
1235
- const { colors } = useTheme();
1236
- const accentColor = variant === "destructive" ? colors.destructive : variant === "success" ? colors.success : variant === "warning" ? colors.warning : colors.primary;
1237
- const defaultIcon = variant === "success" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "check-circle", size: ms(16), color: accentColor }) : variant === "destructive" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.MaterialIcons, { name: "error-outline", size: ms(17), color: accentColor }) : variant === "warning" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.MaterialIcons, { name: "warning-amber", size: ms(17), color: accentColor }) : /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "info-with-circle", size: ms(16), color: accentColor });
1389
+ const { colors, colorScheme } = useTheme();
1390
+ const isDark = colorScheme === "dark";
1391
+ const accentColor = variant === "destructive" ? colors.destructive : variant === "success" ? colors.success : variant === "warning" ? colors.warning : colors.foreground;
1392
+ const bgColor = variant === "destructive" ? isDark ? "rgba(239, 83, 80, 0.15)" : "rgba(199, 40, 40, 0.10)" : variant === "success" ? isDark ? "rgba(46, 125, 82, 0.15)" : "rgba(26, 122, 69, 0.10)" : variant === "warning" ? isDark ? "rgba(245, 166, 35, 0.15)" : "rgba(154, 82, 0, 0.10)" : colors.surface;
1393
+ const borderColor = variant === "destructive" ? isDark ? "rgba(239, 83, 80, 0.30)" : "rgba(199, 40, 40, 0.25)" : variant === "success" ? isDark ? "rgba(46, 125, 82, 0.30)" : "rgba(26, 122, 69, 0.25)" : variant === "warning" ? isDark ? "rgba(245, 166, 35, 0.30)" : "rgba(154, 82, 0, 0.25)" : colors.border;
1394
+ const defaultIcon = variant === "success" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "check-circle", size: ms(16), color: accentColor }) : variant === "destructive" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.MaterialIcons, { name: "error-outline", size: ms(17), color: accentColor }) : variant === "warning" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.MaterialIcons, { name: "warning-amber", size: ms(17), color: accentColor }) : (
1395
+ // AUDIT FIX: default variant previously used colors.primary (near-black)
1396
+ // as the info icon tint — ambiguous and heavy. accentResolved gives it
1397
+ // a meaningful chromatic signal when an accent is defined.
1398
+ /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "info-with-circle", size: ms(16), color: accentColor })
1399
+ );
1238
1400
  const effectiveIcon = iconName ? renderIcon(iconName, ms(16), iconColor ?? accentColor) : icon ?? defaultIcon;
1239
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles11.container, { backgroundColor: colors.card }, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles11.iconSlot }, effectiveIcon), /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles11.content }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles11.title, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles11.description, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null));
1401
+ return /* @__PURE__ */ React26__default.default.createElement(
1402
+ reactNative.View,
1403
+ {
1404
+ style: [
1405
+ styles11.container,
1406
+ { backgroundColor: bgColor, borderWidth: 1, borderColor },
1407
+ style
1408
+ ]
1409
+ },
1410
+ /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles11.iconSlot }, effectiveIcon),
1411
+ /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles11.content }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles11.title, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles11.description, { color: colors.foreground, opacity: 0.85 }], allowFontScaling: true }, description) : null)
1412
+ );
1240
1413
  }
1241
1414
  var styles11 = reactNative.StyleSheet.create({
1242
1415
  container: {
@@ -1244,8 +1417,8 @@ var styles11 = reactNative.StyleSheet.create({
1244
1417
  alignItems: "flex-start",
1245
1418
  borderRadius: RADIUS.lg,
1246
1419
  gap: s(8),
1247
- paddingVertical: vs(8),
1248
- paddingHorizontal: s(10)
1420
+ paddingVertical: vs(10),
1421
+ paddingHorizontal: s(12)
1249
1422
  },
1250
1423
  iconSlot: {
1251
1424
  marginTop: vs(1)
@@ -1255,41 +1428,40 @@ var styles11 = reactNative.StyleSheet.create({
1255
1428
  gap: vs(2)
1256
1429
  },
1257
1430
  title: {
1258
- fontFamily: "Poppins-Medium",
1259
- fontSize: ms(13),
1260
- lineHeight: ms(19)
1431
+ fontFamily: "Sohne-Medium",
1432
+ fontSize: ms(13)
1261
1433
  },
1262
1434
  description: {
1263
- fontFamily: "Poppins-Regular",
1264
- fontSize: ms(12),
1265
- lineHeight: ms(17)
1435
+ fontFamily: "Sohne-Regular",
1436
+ fontSize: ms(12)
1266
1437
  }
1267
1438
  });
1268
- function Progress({ value = 0, max = 100, variant = "default", style }) {
1439
+ function Progress({ value = 0, max = 100, variant = "default", style, accessibilityLabel }) {
1269
1440
  const { colors } = useTheme();
1270
1441
  const percent = Math.min(Math.max(value / max * 100, 0), 100);
1271
1442
  const [trackWidth, setTrackWidth] = React26.useState(0);
1272
- const animatedWidth = React26.useRef(new reactNative.Animated.Value(0)).current;
1443
+ const animatedWidth = Animated9.useSharedValue(0);
1273
1444
  React26.useEffect(() => {
1274
1445
  if (trackWidth === 0) return;
1275
- reactNative.Animated.spring(animatedWidth, {
1276
- toValue: percent / 100 * trackWidth,
1277
- useNativeDriver: false,
1278
- speed: 20,
1279
- bounciness: 0
1280
- }).start();
1281
- }, [percent, trackWidth]);
1446
+ animatedWidth.value = Animated9.withSpring(percent / 100 * trackWidth, SPRINGS.glide);
1447
+ }, [percent, trackWidth, animatedWidth]);
1448
+ const indicatorAnimatedStyle = Animated9.useAnimatedStyle(() => ({
1449
+ width: animatedWidth.value
1450
+ }));
1282
1451
  const indicatorColor = variant === "success" ? colors.success : variant === "warning" ? colors.warning : variant === "destructive" ? colors.destructive : colors.primary;
1283
1452
  return /* @__PURE__ */ React26__default.default.createElement(
1284
1453
  reactNative.View,
1285
1454
  {
1286
1455
  style: [styles12.track, { backgroundColor: colors.surface }, style],
1287
- onLayout: (e) => setTrackWidth(e.nativeEvent.layout.width)
1456
+ onLayout: (e) => setTrackWidth(e.nativeEvent.layout.width),
1457
+ accessibilityRole: "progressbar",
1458
+ accessibilityLabel,
1459
+ accessibilityValue: { min: 0, max: 100, now: Math.round(percent) }
1288
1460
  },
1289
1461
  /* @__PURE__ */ React26__default.default.createElement(
1290
- reactNative.Animated.View,
1462
+ Animated9__default.default.View,
1291
1463
  {
1292
- style: [styles12.indicator, { width: animatedWidth, backgroundColor: indicatorColor }]
1464
+ style: [styles12.indicator, { backgroundColor: indicatorColor }, indicatorAnimatedStyle]
1293
1465
  }
1294
1466
  )
1295
1467
  );
@@ -1373,7 +1545,7 @@ var styles13 = reactNative.StyleSheet.create({
1373
1545
  marginTop: vs(16)
1374
1546
  },
1375
1547
  title: {
1376
- fontFamily: "Poppins-Medium",
1548
+ fontFamily: "Sohne-Medium",
1377
1549
  fontSize: ms(18),
1378
1550
  textAlign: "center"
1379
1551
  },
@@ -1382,7 +1554,7 @@ var styles13 = reactNative.StyleSheet.create({
1382
1554
  marginTop: vs(10)
1383
1555
  },
1384
1556
  description: {
1385
- fontFamily: "Poppins-Regular",
1557
+ fontFamily: "Sohne-Regular",
1386
1558
  fontSize: ms(14),
1387
1559
  lineHeight: mvs(20),
1388
1560
  textAlign: "center"
@@ -1406,22 +1578,28 @@ function Textarea({
1406
1578
  style,
1407
1579
  onFocus,
1408
1580
  onBlur,
1581
+ accessibilityLabel,
1409
1582
  ...props
1410
1583
  }) {
1411
1584
  const { colors } = useTheme();
1412
1585
  const [focused, setFocused] = React26.useState(false);
1586
+ const focusProgress = useColorTransition(focused, {
1587
+ duration: focused ? TIMINGS.focusIn.duration : TIMINGS.focusOut.duration
1588
+ });
1413
1589
  const resolvedPrefixIcon = prefixIcon ? renderIcon(prefixIcon, ms(16), prefixIconColor ?? colors.foregroundMuted) : prefixIconNode;
1590
+ const borderAnimStyle = Animated9.useAnimatedStyle(() => ({
1591
+ borderColor: error ? colors.destructive : Animated9.interpolateColor(focusProgress.value, [0, 1], [colors.border, colors.primary]),
1592
+ borderWidth: error ? 2 : Animated9.interpolate(focusProgress.value, [0, 1], [1, 2])
1593
+ }));
1414
1594
  return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles14.container, containerStyle] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles14.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React26__default.default.createElement(
1415
- reactNative.View,
1595
+ Animated9__default.default.View,
1416
1596
  {
1417
1597
  style: [
1418
1598
  styles14.inputWrapper,
1419
- {
1420
- borderColor: error ? colors.destructive : focused ? colors.ring ?? colors.primary : colors.border,
1421
- backgroundColor: colors.background
1422
- }
1599
+ { backgroundColor: colors.background }
1423
1600
  ]
1424
1601
  },
1602
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles14.borderOverlay, borderAnimStyle], pointerEvents: "none" }),
1425
1603
  resolvedPrefixIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles14.prefixIcon }, resolvedPrefixIcon) : null,
1426
1604
  /* @__PURE__ */ React26__default.default.createElement(
1427
1605
  reactNative.TextInput,
@@ -1448,124 +1626,113 @@ function Textarea({
1448
1626
  },
1449
1627
  placeholderTextColor: colors.foregroundMuted,
1450
1628
  allowFontScaling: true,
1629
+ accessibilityLabel: accessibilityLabel ?? label,
1451
1630
  ...props
1452
1631
  }
1453
1632
  )
1454
- ), error ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles14.helperText, { color: colors.destructive }], allowFontScaling: true }, error) : null, !error && hint ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles14.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null);
1633
+ ), error ? /* @__PURE__ */ React26__default.default.createElement(
1634
+ reactNative.Text,
1635
+ {
1636
+ style: [styles14.helperText, { color: colors.destructive }],
1637
+ allowFontScaling: true,
1638
+ accessibilityLiveRegion: "polite"
1639
+ },
1640
+ error
1641
+ ) : null, !error && hint ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles14.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null);
1455
1642
  }
1456
1643
  var styles14 = reactNative.StyleSheet.create({
1457
1644
  container: {
1458
1645
  gap: vs(4)
1459
1646
  },
1460
1647
  label: {
1461
- fontFamily: "Poppins-Medium",
1648
+ fontFamily: "Sohne-Medium",
1462
1649
  fontSize: ms(13),
1463
1650
  lineHeight: vs(18),
1464
1651
  marginBottom: vs(2)
1465
1652
  },
1466
1653
  inputWrapper: {
1467
- borderWidth: 1,
1654
+ // Border lives on borderOverlay (absolute); wrapper carries none so the
1655
+ // focus weight change never reflows content.
1468
1656
  borderRadius: 8,
1469
1657
  paddingHorizontal: s(14),
1470
1658
  paddingVertical: vs(11),
1471
1659
  gap: s(8)
1472
1660
  },
1661
+ borderOverlay: {
1662
+ ...reactNative.StyleSheet.absoluteFillObject,
1663
+ borderRadius: 8
1664
+ },
1473
1665
  prefixIcon: {
1474
1666
  alignItems: "flex-start",
1475
1667
  justifyContent: "flex-start",
1476
1668
  paddingTop: vs(2)
1477
1669
  },
1478
1670
  input: {
1479
- fontFamily: "Poppins-Regular",
1671
+ fontFamily: "Sohne-Regular",
1480
1672
  fontSize: ms(14),
1481
1673
  lineHeight: vs(22),
1482
1674
  padding: 0,
1483
1675
  margin: 0
1484
1676
  },
1485
1677
  helperText: {
1486
- fontFamily: "Poppins-Regular",
1678
+ fontFamily: "Sohne-Regular",
1487
1679
  fontSize: ms(12),
1488
1680
  lineHeight: vs(16),
1489
1681
  marginTop: vs(4)
1490
1682
  }
1491
1683
  });
1492
- var nativeDriver4 = reactNative.Platform.OS !== "web";
1493
1684
  function Checkbox({
1494
1685
  checked = false,
1495
1686
  onCheckedChange,
1496
1687
  label,
1497
1688
  disabled,
1498
- style
1689
+ style,
1690
+ accessibilityLabel
1499
1691
  }) {
1500
1692
  const { colors } = useTheme();
1501
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
1502
- const bgOpacity = React26.useRef(new reactNative.Animated.Value(checked ? 1 : 0)).current;
1503
- const checkOpacity = React26.useRef(new reactNative.Animated.Value(checked ? 1 : 0)).current;
1504
- React26.useEffect(() => {
1505
- reactNative.Animated.parallel([
1506
- reactNative.Animated.timing(bgOpacity, {
1507
- toValue: checked ? 1 : 0,
1508
- duration: 150,
1509
- useNativeDriver: false
1510
- }),
1511
- reactNative.Animated.timing(checkOpacity, {
1512
- toValue: checked ? 1 : 0,
1513
- duration: 120,
1514
- useNativeDriver: false
1515
- })
1516
- ]).start();
1517
- }, [checked, bgOpacity, checkOpacity]);
1518
- const borderColor = bgOpacity.interpolate({
1519
- inputRange: [0, 1],
1520
- outputRange: [colors.border, colors.primary]
1693
+ const { animatedStyle: scaleStyle, onPressIn, onPressOut } = usePressScale({
1694
+ pressScale: PRESS_SCALE.button,
1695
+ disabled
1521
1696
  });
1522
- const backgroundColor = bgOpacity.interpolate({
1523
- inputRange: [0, 1],
1524
- outputRange: ["transparent", colors.primary]
1525
- });
1526
- const handlePressIn = () => {
1527
- if (disabled) return;
1528
- reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver4, speed: 40, bounciness: 0 }).start();
1529
- };
1530
- const handlePressOut = () => {
1531
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver4, speed: 40, bounciness: 0 }).start();
1532
- };
1533
- return /* @__PURE__ */ React26__default.default.createElement(
1534
- reactNative.TouchableOpacity,
1535
- {
1536
- style: [styles15.row, style],
1537
- onPress: () => {
1538
- selectionAsync();
1539
- onCheckedChange?.(!checked);
1540
- },
1541
- onPressIn: handlePressIn,
1542
- onPressOut: handlePressOut,
1543
- disabled,
1544
- activeOpacity: 1,
1545
- touchSoundDisabled: true
1546
- },
1547
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React26__default.default.createElement(
1548
- reactNative.Animated.View,
1549
- {
1550
- style: [
1551
- styles15.box,
1552
- {
1553
- borderColor,
1554
- backgroundColor,
1555
- opacity: disabled ? 0.45 : 1
1556
- }
1557
- ]
1558
- },
1559
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { opacity: checkOpacity } }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles15.checkmark, { borderColor: colors.primaryForeground }] }))
1560
- )),
1561
- label ? /* @__PURE__ */ React26__default.default.createElement(
1562
- reactNative.Text,
1697
+ const progress = useColorTransition(checked);
1698
+ const boxStyle = Animated9.useAnimatedStyle(() => ({
1699
+ borderColor: Animated9.interpolateColor(progress.value, [0, 1], [colors.border, colors.primary]),
1700
+ backgroundColor: Animated9.interpolateColor(progress.value, [0, 1], ["transparent", colors.primary])
1701
+ }));
1702
+ const checkStyle = Animated9.useAnimatedStyle(() => ({
1703
+ opacity: Animated9.withTiming(checked ? 1 : 0, { duration: TIMINGS.state.duration, easing: EASINGS.standard })
1704
+ }));
1705
+ return (
1706
+ // AUDIT FIX: opacity was applied only to the box, leaving the label at full
1707
+ // opacity when disabled — a contradictory visual signal. Now the entire row
1708
+ // dims uniformly so label and control communicate the same disabled state.
1709
+ /* @__PURE__ */ React26__default.default.createElement(
1710
+ reactNative.TouchableOpacity,
1563
1711
  {
1564
- style: [styles15.label, { color: disabled ? colors.foregroundMuted : colors.foreground }],
1565
- allowFontScaling: true
1712
+ style: [styles15.row, disabled && styles15.rowDisabled, style],
1713
+ onPress: () => {
1714
+ selectionAsync();
1715
+ onCheckedChange?.(!checked);
1716
+ },
1717
+ onPressIn,
1718
+ onPressOut,
1719
+ disabled,
1720
+ activeOpacity: 1,
1721
+ touchSoundDisabled: true,
1722
+ accessibilityRole: "checkbox",
1723
+ accessibilityLabel: accessibilityLabel ?? label,
1724
+ accessibilityState: { checked, disabled: !!disabled }
1566
1725
  },
1567
- label
1568
- ) : null
1726
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: scaleStyle }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles15.box, boxStyle] }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: checkStyle }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles15.checkmark, { borderColor: colors.primaryForeground }] })))),
1727
+ label ? /* @__PURE__ */ React26__default.default.createElement(
1728
+ reactNative.Text,
1729
+ {
1730
+ style: [styles15.label, { color: colors.foreground }],
1731
+ allowFontScaling: true
1732
+ },
1733
+ label
1734
+ ) : null
1735
+ )
1569
1736
  );
1570
1737
  }
1571
1738
  var styles15 = reactNative.StyleSheet.create({
@@ -1574,6 +1741,10 @@ var styles15 = reactNative.StyleSheet.create({
1574
1741
  alignItems: "center",
1575
1742
  gap: s(12)
1576
1743
  },
1744
+ // AUDIT FIX: was inline opacity on the box only
1745
+ rowDisabled: {
1746
+ opacity: 0.45
1747
+ },
1577
1748
  box: {
1578
1749
  width: s(24),
1579
1750
  height: s(24),
@@ -1590,53 +1761,48 @@ var styles15 = reactNative.StyleSheet.create({
1590
1761
  transform: [{ rotate: "-45deg" }, { translateY: -1 }]
1591
1762
  },
1592
1763
  label: {
1593
- fontFamily: "Poppins-Regular",
1764
+ fontFamily: "Sohne-Regular",
1594
1765
  fontSize: ms(14),
1595
1766
  lineHeight: mvs(20)
1596
1767
  }
1597
1768
  });
1598
- var nativeDriver5 = reactNative.Platform.OS !== "web";
1599
1769
  var TRACK_WIDTH = s(52);
1600
1770
  var TRACK_HEIGHT = s(30);
1601
1771
  var THUMB_SIZE = s(24);
1602
1772
  var THUMB_OFFSET = s(3);
1603
1773
  var THUMB_TRAVEL = TRACK_WIDTH - THUMB_SIZE - THUMB_OFFSET * 2;
1604
1774
  var ICON_SIZE = s(13);
1605
- function Switch({ checked = false, onCheckedChange, disabled, style }) {
1775
+ function Switch({ checked = false, onCheckedChange, disabled, style, accessibilityLabel }) {
1606
1776
  const { colors } = useTheme();
1607
- const translateX = React26.useRef(new reactNative.Animated.Value(checked ? THUMB_TRAVEL : 0)).current;
1608
- const trackOpacity = React26.useRef(new reactNative.Animated.Value(checked ? 1 : 0)).current;
1609
- const checkOpacity = React26.useRef(new reactNative.Animated.Value(checked ? 1 : 0)).current;
1610
- const crossOpacity = React26.useRef(new reactNative.Animated.Value(checked ? 0 : 1)).current;
1777
+ const progress = Animated9.useSharedValue(checked ? 1 : 0);
1611
1778
  React26.useEffect(() => {
1612
- reactNative.Animated.parallel([
1613
- reactNative.Animated.spring(translateX, {
1614
- toValue: checked ? THUMB_TRAVEL : 0,
1615
- useNativeDriver: nativeDriver5,
1616
- bounciness: 4
1617
- }),
1618
- reactNative.Animated.timing(trackOpacity, {
1619
- toValue: checked ? 1 : 0,
1620
- duration: 150,
1621
- useNativeDriver: false
1622
- }),
1623
- reactNative.Animated.timing(checkOpacity, {
1624
- toValue: checked ? 1 : 0,
1625
- duration: 120,
1626
- useNativeDriver: true
1627
- }),
1628
- reactNative.Animated.timing(crossOpacity, {
1629
- toValue: checked ? 0 : 1,
1630
- duration: 120,
1631
- useNativeDriver: true
1632
- })
1633
- ]).start();
1634
- }, [checked, translateX, trackOpacity, checkOpacity, crossOpacity]);
1635
- const trackColor = trackOpacity.interpolate({
1636
- inputRange: [0, 1],
1637
- outputRange: [colors.surface, colors.primary]
1638
- });
1639
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [{ opacity: disabled ? 0.45 : 1 }, style] }, /* @__PURE__ */ React26__default.default.createElement(
1779
+ progress.value = Animated9.withSpring(checked ? 1 : 0, SPRINGS.elastic);
1780
+ }, [checked, progress]);
1781
+ const thumbStyle = Animated9.useAnimatedStyle(() => ({
1782
+ transform: [{ translateX: progress.value * THUMB_TRAVEL }]
1783
+ }));
1784
+ const trackStyle = Animated9.useAnimatedStyle(() => ({
1785
+ backgroundColor: Animated9.interpolateColor(
1786
+ progress.value,
1787
+ [0, 1],
1788
+ [colors.surfaceStrong, colors.primary]
1789
+ )
1790
+ }));
1791
+ const trackBorderStyle = Animated9.useAnimatedStyle(() => ({
1792
+ borderWidth: 1.5,
1793
+ borderColor: Animated9.interpolateColor(
1794
+ progress.value,
1795
+ [0, 1],
1796
+ [colors.border, "transparent"]
1797
+ )
1798
+ }));
1799
+ const checkIconStyle = Animated9.useAnimatedStyle(() => ({
1800
+ opacity: Animated9.withTiming(checked ? 1 : 0, { duration: TIMINGS.state.duration, easing: EASINGS.standard })
1801
+ }));
1802
+ const crossIconStyle = Animated9.useAnimatedStyle(() => ({
1803
+ opacity: Animated9.withTiming(checked ? 0 : 1, { duration: TIMINGS.state.duration, easing: EASINGS.standard })
1804
+ }));
1805
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [{ opacity: disabled ? 0.45 : 1, alignSelf: "flex-start" }, style] }, /* @__PURE__ */ React26__default.default.createElement(
1640
1806
  reactNative.TouchableOpacity,
1641
1807
  {
1642
1808
  onPress: () => {
@@ -1646,29 +1812,33 @@ function Switch({ checked = false, onCheckedChange, disabled, style }) {
1646
1812
  disabled,
1647
1813
  activeOpacity: 0.8,
1648
1814
  touchSoundDisabled: true,
1649
- style: styles16.wrapper
1815
+ accessibilityRole: "switch",
1816
+ accessibilityLabel,
1817
+ accessibilityState: { checked, disabled: !!disabled },
1818
+ style: styles16.touchable
1650
1819
  },
1651
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [styles16.track, { backgroundColor: trackColor }] }, /* @__PURE__ */ React26__default.default.createElement(
1652
- reactNative.Animated.View,
1820
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles16.track, trackStyle] }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles16.trackBorder, trackBorderStyle], pointerEvents: "none" }), /* @__PURE__ */ React26__default.default.createElement(
1821
+ Animated9__default.default.View,
1653
1822
  {
1654
- style: [
1655
- styles16.thumb,
1656
- { backgroundColor: colors.primaryForeground, transform: [{ translateX }] }
1657
- ]
1823
+ style: [styles16.thumb, { backgroundColor: colors.primaryForeground }, thumbStyle]
1658
1824
  },
1659
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [styles16.iconWrapper, { opacity: checkOpacity }] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Feather, { name: "check", size: ICON_SIZE, color: colors.primary })),
1660
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [styles16.iconWrapper, { opacity: crossOpacity }] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Feather, { name: "x", size: ICON_SIZE, color: colors.foregroundMuted }))
1825
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles16.iconWrapper, checkIconStyle] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Feather, { name: "check", size: ICON_SIZE, color: colors.primary })),
1826
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles16.iconWrapper, crossIconStyle] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Feather, { name: "x", size: ICON_SIZE, color: colors.foregroundMuted }))
1661
1827
  ))
1662
1828
  ));
1663
1829
  }
1664
1830
  var styles16 = reactNative.StyleSheet.create({
1665
- wrapper: {},
1831
+ touchable: {
1832
+ alignSelf: "flex-start"
1833
+ },
1666
1834
  track: {
1667
1835
  width: TRACK_WIDTH,
1668
1836
  height: TRACK_HEIGHT,
1669
1837
  borderRadius: TRACK_HEIGHT / 2
1670
- // No justifyContent/alignItems — thumb uses absolute positioning
1671
- // so the track's flex layout doesn't interfere with translateX animation
1838
+ },
1839
+ trackBorder: {
1840
+ ...reactNative.StyleSheet.absoluteFillObject,
1841
+ borderRadius: TRACK_HEIGHT / 2
1672
1842
  },
1673
1843
  thumb: {
1674
1844
  position: "absolute",
@@ -1686,10 +1856,28 @@ var styles16 = reactNative.StyleSheet.create({
1686
1856
  justifyContent: "center"
1687
1857
  },
1688
1858
  iconWrapper: {
1689
- position: "absolute"
1859
+ position: "absolute",
1860
+ alignItems: "center",
1861
+ justifyContent: "center"
1690
1862
  }
1691
1863
  });
1692
- var nativeDriver6 = reactNative.Platform.OS !== "web";
1864
+ function ToggleIcon({ pressed, iconName, activeIconName, icon, activeIcon, iconColor, activeIconColor, iconSize, primaryColor, mutedColor }) {
1865
+ const renderProp = (prop) => {
1866
+ if (!prop) return null;
1867
+ if (typeof prop === "function") return prop(pressed);
1868
+ return prop;
1869
+ };
1870
+ if (pressed) {
1871
+ if (activeIconName) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, renderIcon(activeIconName, iconSize, activeIconColor ?? primaryColor));
1872
+ const active = renderProp(activeIcon);
1873
+ if (active) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, active);
1874
+ return /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "check-circle", size: iconSize, color: primaryColor });
1875
+ }
1876
+ if (iconName) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, renderIcon(iconName, iconSize, iconColor ?? mutedColor));
1877
+ const custom = renderProp(icon);
1878
+ if (custom) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, custom);
1879
+ return /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "circle", size: iconSize, color: mutedColor });
1880
+ }
1693
1881
  var sizeStyles = {
1694
1882
  sm: { paddingHorizontal: s(12), paddingVertical: vs(8), minWidth: s(40), minHeight: vs(40) },
1695
1883
  md: { paddingHorizontal: s(16), paddingVertical: vs(12), minWidth: s(44), minHeight: vs(44) },
@@ -1710,82 +1898,75 @@ function Toggle({
1710
1898
  activeIconColor,
1711
1899
  disabled,
1712
1900
  style,
1901
+ accessibilityLabel,
1713
1902
  ...props
1714
1903
  }) {
1715
1904
  const { colors } = useTheme();
1716
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
1717
- const pressAnim = React26.useRef(new reactNative.Animated.Value(pressed ? 1 : 0)).current;
1718
- React26.useEffect(() => {
1719
- reactNative.Animated.timing(pressAnim, {
1720
- toValue: pressed ? 1 : 0,
1721
- duration: 150,
1722
- easing: reactNative.Easing.out(reactNative.Easing.ease),
1723
- useNativeDriver: false
1724
- }).start();
1725
- }, [pressed, pressAnim]);
1726
- const handlePressIn = () => {
1727
- if (disabled) return;
1728
- reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver6, stiffness: 600, damping: 35, mass: 0.8 }).start();
1729
- };
1730
- const handlePressOut = () => {
1731
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver6, stiffness: 280, damping: 22, mass: 0.8 }).start();
1732
- };
1733
- const borderColor = pressAnim.interpolate({
1734
- inputRange: [0, 1],
1735
- outputRange: [variant === "outline" ? colors.border : "transparent", colors.primary]
1736
- });
1737
- const backgroundColor = pressAnim.interpolate({
1738
- inputRange: [0, 1],
1739
- outputRange: ["transparent", colors.surfaceStrong]
1740
- });
1741
- const textColor = pressAnim.interpolate({
1742
- inputRange: [0, 1],
1743
- outputRange: [colors.foreground, colors.primary]
1905
+ const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
1906
+ pressScale: PRESS_SCALE.button,
1907
+ disabled
1744
1908
  });
1909
+ const progress = useColorTransition(pressed);
1910
+ const inactiveBorder = variant === "outline" ? colors.border : "transparent";
1911
+ const surfaceStyle = Animated9.useAnimatedStyle(() => ({
1912
+ borderColor: Animated9.interpolateColor(progress.value, [0, 1], [inactiveBorder, colors.primary]),
1913
+ backgroundColor: Animated9.interpolateColor(progress.value, [0, 1], ["transparent", colors.surfaceStrong])
1914
+ }));
1915
+ const textStyle = Animated9.useAnimatedStyle(() => ({
1916
+ color: Animated9.interpolateColor(progress.value, [0, 1], [colors.foreground, colors.primary])
1917
+ }));
1745
1918
  const iconSize = iconSizeMap2[size];
1746
- const LeftIcon = () => {
1747
- const renderProp = (prop) => {
1748
- if (!prop) return null;
1749
- if (typeof prop === "function") return prop(pressed);
1750
- return prop;
1751
- };
1752
- if (pressed) {
1753
- if (activeIconName) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, renderIcon(activeIconName, iconSize, activeIconColor ?? colors.primary));
1754
- const active = renderProp(activeIcon);
1755
- if (active) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, active);
1756
- return /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "check-circle", size: iconSize, color: colors.primary });
1757
- }
1758
- if (iconName) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, renderIcon(iconName, iconSize, iconColor ?? colors.foregroundMuted));
1759
- const custom = renderProp(icon);
1760
- if (custom) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, custom);
1761
- return /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "circle", size: iconSize, color: colors.foregroundMuted });
1762
- };
1763
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [{ transform: [{ scale: scale2 }] }, disabled && styles17.disabled, style] }, /* @__PURE__ */ React26__default.default.createElement(
1764
- reactNative.TouchableOpacity,
1919
+ return /* @__PURE__ */ React26__default.default.createElement(
1920
+ Animated9__default.default.View,
1765
1921
  {
1766
- onPress: () => {
1767
- selectionAsync();
1768
- onPressedChange?.(!pressed);
1769
- },
1770
- onPressIn: handlePressIn,
1771
- onPressOut: handlePressOut,
1772
- disabled,
1773
- activeOpacity: 1,
1774
- touchSoundDisabled: true,
1775
- ...props
1922
+ style: [scaleStyle, disabled && styles17.disabled, style],
1923
+ ...hoverHandlers
1776
1924
  },
1777
1925
  /* @__PURE__ */ React26__default.default.createElement(
1778
- reactNative.Animated.View,
1926
+ reactNative.TouchableOpacity,
1779
1927
  {
1780
- style: [
1781
- styles17.base,
1782
- sizeStyles[size],
1783
- { borderColor, backgroundColor, borderWidth: 2 }
1784
- ]
1928
+ onPress: () => {
1929
+ selectionAsync();
1930
+ onPressedChange?.(!pressed);
1931
+ },
1932
+ onPressIn,
1933
+ onPressOut,
1934
+ disabled,
1935
+ activeOpacity: 1,
1936
+ touchSoundDisabled: true,
1937
+ accessibilityRole: "button",
1938
+ accessibilityLabel: accessibilityLabel ?? label,
1939
+ accessibilityState: { selected: pressed, disabled: !!disabled },
1940
+ ...props
1785
1941
  },
1786
- /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles17.inner }, /* @__PURE__ */ React26__default.default.createElement(LeftIcon, null), label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.Text, { style: [styles17.label, { color: textColor }], allowFontScaling: true }, label) : null)
1942
+ /* @__PURE__ */ React26__default.default.createElement(
1943
+ Animated9__default.default.View,
1944
+ {
1945
+ style: [
1946
+ styles17.base,
1947
+ sizeStyles[size],
1948
+ { borderWidth: 2 },
1949
+ surfaceStyle
1950
+ ]
1951
+ },
1952
+ /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles17.inner }, /* @__PURE__ */ React26__default.default.createElement(
1953
+ ToggleIcon,
1954
+ {
1955
+ pressed,
1956
+ iconName,
1957
+ activeIconName,
1958
+ icon,
1959
+ activeIcon,
1960
+ iconColor,
1961
+ activeIconColor,
1962
+ iconSize,
1963
+ primaryColor: colors.primary,
1964
+ mutedColor: colors.foregroundMuted
1965
+ }
1966
+ ), label ? /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.Text, { style: [styles17.label, textStyle], allowFontScaling: true }, label) : null)
1967
+ )
1787
1968
  )
1788
- ));
1969
+ );
1789
1970
  }
1790
1971
  var styles17 = reactNative.StyleSheet.create({
1791
1972
  base: {
@@ -1801,65 +1982,64 @@ var styles17 = reactNative.StyleSheet.create({
1801
1982
  opacity: 0.45
1802
1983
  },
1803
1984
  label: {
1804
- fontFamily: "Poppins-Medium",
1985
+ fontFamily: "Sohne-Medium",
1805
1986
  fontSize: ms(14)
1806
1987
  }
1807
1988
  });
1808
- var nativeDriver7 = reactNative.Platform.OS !== "web";
1809
1989
  function RadioItem({
1810
1990
  option,
1811
1991
  selected,
1812
1992
  onSelect
1813
1993
  }) {
1814
1994
  const { colors } = useTheme();
1815
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
1816
- const handlePressIn = () => {
1817
- if (option.disabled) return;
1818
- reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver7, speed: 40, bounciness: 0 }).start();
1819
- };
1820
- const handlePressOut = () => {
1821
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver7, speed: 40, bounciness: 4 }).start();
1822
- };
1823
- return /* @__PURE__ */ React26__default.default.createElement(
1824
- reactNative.TouchableOpacity,
1825
- {
1826
- style: styles18.row,
1827
- onPress: () => {
1828
- if (!option.disabled) {
1829
- selectionAsync();
1830
- onSelect();
1831
- }
1832
- },
1833
- onPressIn: handlePressIn,
1834
- onPressOut: handlePressOut,
1835
- activeOpacity: 1,
1836
- touchSoundDisabled: true,
1837
- disabled: option.disabled
1838
- },
1995
+ const { animatedStyle: scaleStyle, onPressIn, onPressOut } = usePressScale({
1996
+ pressScale: PRESS_SCALE.button,
1997
+ disabled: option.disabled
1998
+ });
1999
+ const colorProgress = useColorTransition(selected);
2000
+ const dotScale = Animated9.useSharedValue(selected ? 1 : 0);
2001
+ React26.useEffect(() => {
2002
+ dotScale.value = Animated9.withSpring(selected ? 1 : 0, SPRINGS.elastic);
2003
+ }, [selected, dotScale]);
2004
+ const radioStyle = Animated9.useAnimatedStyle(() => ({
2005
+ borderColor: Animated9.interpolateColor(colorProgress.value, [0, 1], [colors.border, colors.primary])
2006
+ }));
2007
+ const dotStyle = Animated9.useAnimatedStyle(() => ({
2008
+ transform: [{ scale: dotScale.value }],
2009
+ opacity: dotScale.value
2010
+ }));
2011
+ return (
2012
+ // AUDIT FIX: opacity was applied only to the radio circle, leaving the label
2013
+ // at full opacity when disabled. The whole row now dims uniformly so users
2014
+ // get a single, consistent disabled signal across the entire item.
1839
2015
  /* @__PURE__ */ React26__default.default.createElement(
1840
- reactNative.Animated.View,
2016
+ reactNative.TouchableOpacity,
1841
2017
  {
1842
- style: [
1843
- styles18.radio,
1844
- {
1845
- borderColor: selected ? colors.primary : colors.border,
1846
- opacity: option.disabled ? 0.45 : 1,
1847
- transform: [{ scale: scale2 }]
2018
+ style: [styles18.row, option.disabled && styles18.rowDisabled],
2019
+ onPress: () => {
2020
+ if (!option.disabled) {
2021
+ selectionAsync();
2022
+ onSelect();
1848
2023
  }
1849
- ]
1850
- },
1851
- selected ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles18.dot, { backgroundColor: colors.primary }] }) : null
1852
- ),
1853
- /* @__PURE__ */ React26__default.default.createElement(
1854
- reactNative.Text,
1855
- {
1856
- style: [
1857
- styles18.label,
1858
- { color: option.disabled ? colors.foregroundMuted : colors.foreground }
1859
- ],
1860
- allowFontScaling: true
2024
+ },
2025
+ onPressIn,
2026
+ onPressOut,
2027
+ activeOpacity: 1,
2028
+ touchSoundDisabled: true,
2029
+ disabled: option.disabled,
2030
+ accessibilityRole: "radio",
2031
+ accessibilityLabel: option.label,
2032
+ accessibilityState: { checked: selected, disabled: !!option.disabled }
1861
2033
  },
1862
- option.label
2034
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: scaleStyle }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles18.radio, radioStyle] }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles18.dot, { backgroundColor: colors.primary }, dotStyle] }))),
2035
+ /* @__PURE__ */ React26__default.default.createElement(
2036
+ reactNative.Text,
2037
+ {
2038
+ style: [styles18.label, { color: colors.foreground }],
2039
+ allowFontScaling: true
2040
+ },
2041
+ option.label
2042
+ )
1863
2043
  )
1864
2044
  );
1865
2045
  }
@@ -1868,17 +2048,26 @@ function RadioGroup({
1868
2048
  value,
1869
2049
  onValueChange,
1870
2050
  orientation = "vertical",
1871
- style
2051
+ style,
2052
+ accessibilityLabel
1872
2053
  }) {
1873
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles18.container, orientation === "horizontal" && styles18.horizontal, style] }, options.map((option) => /* @__PURE__ */ React26__default.default.createElement(
1874
- RadioItem,
2054
+ return /* @__PURE__ */ React26__default.default.createElement(
2055
+ reactNative.View,
1875
2056
  {
1876
- key: option.value,
1877
- option,
1878
- selected: option.value === value,
1879
- onSelect: () => onValueChange?.(option.value)
1880
- }
1881
- )));
2057
+ style: [styles18.container, orientation === "horizontal" && styles18.horizontal, style],
2058
+ accessibilityRole: "radiogroup",
2059
+ accessibilityLabel
2060
+ },
2061
+ options.map((option) => /* @__PURE__ */ React26__default.default.createElement(
2062
+ RadioItem,
2063
+ {
2064
+ key: option.value,
2065
+ option,
2066
+ selected: option.value === value,
2067
+ onSelect: () => onValueChange?.(option.value)
2068
+ }
2069
+ ))
2070
+ );
1882
2071
  }
1883
2072
  var styles18 = reactNative.StyleSheet.create({
1884
2073
  container: {
@@ -1893,6 +2082,10 @@ var styles18 = reactNative.StyleSheet.create({
1893
2082
  alignItems: "center",
1894
2083
  gap: s(12)
1895
2084
  },
2085
+ // AUDIT FIX: was opacity on the inner circle only
2086
+ rowDisabled: {
2087
+ opacity: 0.45
2088
+ },
1896
2089
  radio: {
1897
2090
  width: s(24),
1898
2091
  height: s(24),
@@ -1907,12 +2100,11 @@ var styles18 = reactNative.StyleSheet.create({
1907
2100
  borderRadius: s(5)
1908
2101
  },
1909
2102
  label: {
1910
- fontFamily: "Poppins-Regular",
2103
+ fontFamily: "Sohne-Regular",
1911
2104
  fontSize: ms(14),
1912
2105
  lineHeight: mvs(20)
1913
2106
  }
1914
2107
  });
1915
- var nativeDriver8 = reactNative.Platform.OS !== "web";
1916
2108
  function TabTrigger({
1917
2109
  tab,
1918
2110
  isActive,
@@ -1921,13 +2113,9 @@ function TabTrigger({
1921
2113
  variant
1922
2114
  }) {
1923
2115
  const { colors } = useTheme();
1924
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
1925
- const handlePressIn = () => {
1926
- reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver8, stiffness: 600, damping: 35, mass: 0.8 }).start();
1927
- };
1928
- const handlePressOut = () => {
1929
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver8, stiffness: 280, damping: 22, mass: 0.8 }).start();
1930
- };
2116
+ const { animatedStyle, onPressIn, onPressOut } = usePressScale({
2117
+ pressScale: PRESS_SCALE.button
2118
+ });
1931
2119
  const isUnderline = variant === "underline";
1932
2120
  return /* @__PURE__ */ React26__default.default.createElement(
1933
2121
  reactNative.TouchableOpacity,
@@ -1938,19 +2126,25 @@ function TabTrigger({
1938
2126
  isUnderline && isActive && { borderBottomColor: colors.primary }
1939
2127
  ],
1940
2128
  onPress,
1941
- onPressIn: handlePressIn,
1942
- onPressOut: handlePressOut,
2129
+ onPressIn,
2130
+ onPressOut,
1943
2131
  onLayout,
1944
2132
  activeOpacity: 1,
1945
- touchSoundDisabled: true
2133
+ touchSoundDisabled: true,
2134
+ accessibilityRole: "tab",
2135
+ accessibilityState: { selected: isActive },
2136
+ accessibilityLabel: tab.label
1946
2137
  },
1947
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles19.triggerInner }, tab.icon ? typeof tab.icon === "function" ? tab.icon(isActive) : tab.icon : null, /* @__PURE__ */ React26__default.default.createElement(
2138
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: animatedStyle }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles19.triggerInner }, tab.icon ? typeof tab.icon === "function" ? tab.icon(isActive) : tab.icon : null, /* @__PURE__ */ React26__default.default.createElement(
1948
2139
  reactNative.Text,
1949
2140
  {
1950
2141
  style: [
1951
2142
  styles19.triggerLabel,
1952
- { color: isActive ? colors.foreground : colors.foregroundMuted },
1953
- isActive && (isUnderline ? styles19.activeTriggerLabelUnderline : styles19.activeTriggerLabel)
2143
+ // AUDIT FIX: active state now only changes color, never font metrics.
2144
+ // Previously: inactive=Regular, active=Medium (pill) or SemiBold+fontSize14 (underline)
2145
+ // The weight/size change caused measurable layout reflow every tab switch.
2146
+ // Solution: all labels render at SemiBold always; active = foreground, inactive = foregroundMuted.
2147
+ { color: isActive ? colors.foreground : colors.foregroundMuted }
1954
2148
  ],
1955
2149
  allowFontScaling: true
1956
2150
  },
@@ -1963,75 +2157,85 @@ function Tabs({ tabs, variant = "pill", value, onValueChange, children, style })
1963
2157
  const { colors } = useTheme();
1964
2158
  const active = value ?? internal;
1965
2159
  const tabLayouts = React26.useRef({});
1966
- const pillX = React26.useRef(new reactNative.Animated.Value(0)).current;
1967
- const pillWidth = React26.useRef(new reactNative.Animated.Value(0)).current;
2160
+ const pillX = Animated9.useSharedValue(0);
2161
+ const pillWidth = Animated9.useSharedValue(0);
1968
2162
  const initialised = React26.useRef(false);
1969
- const animatePill = (tabValue, animate) => {
2163
+ const animatePill = React26.useCallback((tabValue, animate) => {
1970
2164
  const layout = tabLayouts.current[tabValue];
1971
2165
  if (!layout) return;
1972
2166
  if (animate) {
1973
- reactNative.Animated.parallel([
1974
- reactNative.Animated.spring(pillX, { toValue: layout.x, useNativeDriver: false, stiffness: 380, damping: 38, mass: 1 }),
1975
- reactNative.Animated.spring(pillWidth, { toValue: layout.width, useNativeDriver: false, stiffness: 380, damping: 38, mass: 1 })
1976
- ]).start();
2167
+ pillX.value = Animated9.withSpring(layout.x, SPRINGS.glide);
2168
+ pillWidth.value = Animated9.withSpring(layout.width, SPRINGS.glide);
1977
2169
  } else {
1978
- pillX.setValue(layout.x);
1979
- pillWidth.setValue(layout.width);
2170
+ pillX.value = layout.x;
2171
+ pillWidth.value = layout.width;
1980
2172
  }
1981
- };
2173
+ }, [pillX, pillWidth]);
1982
2174
  React26.useEffect(() => {
1983
2175
  if (initialised.current) animatePill(active, true);
1984
- }, [active]);
2176
+ }, [active, animatePill]);
1985
2177
  const handlePress = (v) => {
1986
2178
  selectionAsync();
1987
2179
  if (!value) setInternal(v);
1988
2180
  onValueChange?.(v);
1989
2181
  };
1990
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
1991
- variant === "pill" ? [styles19.list, { backgroundColor: colors.surface }] : styles19.listUnderline
1992
- ] }, variant === "pill" && /* @__PURE__ */ React26__default.default.createElement(
1993
- reactNative.Animated.View,
2182
+ const pillAnimatedStyle = Animated9.useAnimatedStyle(() => ({
2183
+ transform: [{ translateX: pillX.value }],
2184
+ width: pillWidth.value
2185
+ }));
2186
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style }, /* @__PURE__ */ React26__default.default.createElement(
2187
+ reactNative.View,
1994
2188
  {
1995
2189
  style: [
1996
- styles19.pill,
1997
- {
1998
- backgroundColor: colors.background,
1999
- position: "absolute",
2000
- top: 4,
2001
- bottom: 4,
2002
- left: pillX,
2003
- width: pillWidth,
2004
- borderRadius: 8,
2005
- shadowColor: "#000",
2006
- shadowOffset: { width: 0, height: 1 },
2007
- shadowOpacity: 0.08,
2008
- shadowRadius: 2,
2009
- elevation: 2
2010
- }
2011
- ]
2012
- }
2013
- ), tabs.map((tab) => /* @__PURE__ */ React26__default.default.createElement(
2014
- TabTrigger,
2015
- {
2016
- key: tab.value,
2017
- tab,
2018
- isActive: tab.value === active,
2019
- onPress: () => handlePress(tab.value),
2020
- variant,
2021
- onLayout: (e) => {
2022
- const { x, width } = e.nativeEvent.layout;
2023
- tabLayouts.current[tab.value] = { x, width };
2024
- if (tab.value === active) {
2025
- animatePill(tab.value, false);
2026
- initialised.current = true;
2190
+ variant === "pill" ? [styles19.list, { backgroundColor: colors.surface }] : styles19.listUnderline
2191
+ ],
2192
+ accessibilityRole: "tablist"
2193
+ },
2194
+ variant === "pill" && /* @__PURE__ */ React26__default.default.createElement(
2195
+ Animated9__default.default.View,
2196
+ {
2197
+ style: [
2198
+ styles19.pill,
2199
+ {
2200
+ backgroundColor: colors.background,
2201
+ position: "absolute",
2202
+ top: 4,
2203
+ bottom: 4,
2204
+ left: 0,
2205
+ borderRadius: 8,
2206
+ shadowColor: "#000",
2207
+ shadowOffset: { width: 0, height: 1 },
2208
+ shadowOpacity: 0.08,
2209
+ shadowRadius: 2,
2210
+ elevation: 2
2211
+ },
2212
+ pillAnimatedStyle
2213
+ ]
2214
+ }
2215
+ ),
2216
+ tabs.map((tab) => /* @__PURE__ */ React26__default.default.createElement(
2217
+ TabTrigger,
2218
+ {
2219
+ key: tab.value,
2220
+ tab,
2221
+ isActive: tab.value === active,
2222
+ onPress: () => handlePress(tab.value),
2223
+ variant,
2224
+ onLayout: (e) => {
2225
+ const { x, width } = e.nativeEvent.layout;
2226
+ tabLayouts.current[tab.value] = { x, width };
2227
+ if (tab.value === active) {
2228
+ animatePill(tab.value, false);
2229
+ initialised.current = true;
2230
+ }
2027
2231
  }
2028
2232
  }
2029
- }
2030
- ))), children);
2233
+ ))
2234
+ ), children);
2031
2235
  }
2032
2236
  function TabsContent({ value, activeValue, children, style }) {
2033
2237
  if (value !== activeValue) return null;
2034
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style }, children);
2238
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style, accessibilityRole: "none" }, children);
2035
2239
  }
2036
2240
  var styles19 = reactNative.StyleSheet.create({
2037
2241
  list: {
@@ -2042,6 +2246,8 @@ var styles19 = reactNative.StyleSheet.create({
2042
2246
  },
2043
2247
  listUnderline: {
2044
2248
  flexDirection: "row",
2249
+ // AUDIT FIX: was missing borderBottomColor — the 1px hairline would render
2250
+ // as transparent on some platforms. Explicit token reference ensures visibility.
2045
2251
  borderBottomWidth: 1
2046
2252
  },
2047
2253
  pill: {},
@@ -2068,20 +2274,16 @@ var styles19 = reactNative.StyleSheet.create({
2068
2274
  justifyContent: "center",
2069
2275
  gap: s(4)
2070
2276
  },
2277
+ // AUDIT FIX: was Sohne-Regular at rest, Sohne-Medium/SemiBold when active.
2278
+ // Font-weight changes at runtime cause advance-width shifts → the tab bar would
2279
+ // visibly jump/reflow on every selection. Now always SemiBold; active state
2280
+ // is communicated by color alone (foreground vs foregroundMuted). The pill
2281
+ // indicator provides additional active signal without text layout side-effects.
2071
2282
  triggerLabel: {
2072
- fontFamily: "Poppins-Regular",
2283
+ fontFamily: "Sohne-SemiBold",
2073
2284
  fontSize: ms(13)
2074
- },
2075
- activeTriggerLabel: {
2076
- fontFamily: "Poppins-Medium"
2077
- },
2078
- activeTriggerLabelUnderline: {
2079
- fontFamily: "Poppins-SemiBold",
2080
- fontSize: ms(14)
2081
2285
  }
2082
2286
  });
2083
- var easingExpand = Animated12.Easing.bezier(0.23, 1, 0.32, 1);
2084
- var easingCollapse = Animated12.Easing.in(Animated12.Easing.ease);
2085
2287
  function AccordionItemComponent({
2086
2288
  item,
2087
2289
  isOpen,
@@ -2089,28 +2291,28 @@ function AccordionItemComponent({
2089
2291
  }) {
2090
2292
  const { colors } = useTheme();
2091
2293
  const resolvedIcon = item.iconName ? renderIcon(item.iconName, ms(16), item.iconColor ?? colors.foregroundMuted) : item.icon;
2092
- const isExpanded = Animated12.useSharedValue(isOpen);
2093
- const height = Animated12.useSharedValue(0);
2294
+ const isExpanded = Animated9.useSharedValue(isOpen);
2295
+ const height = Animated9.useSharedValue(0);
2094
2296
  React26__default.default.useEffect(() => {
2095
2297
  isExpanded.value = isOpen;
2096
- }, [isOpen]);
2097
- const derivedHeight = Animated12.useDerivedValue(
2098
- () => Animated12.withTiming(height.value * Number(isExpanded.value), {
2099
- duration: 220,
2100
- easing: isExpanded.value ? easingExpand : easingCollapse
2298
+ }, [isOpen, isExpanded]);
2299
+ const derivedHeight = Animated9.useDerivedValue(
2300
+ () => Animated9.withTiming(height.value * Number(isExpanded.value), {
2301
+ duration: isExpanded.value ? TIMINGS.expand.duration : TIMINGS.collapse.duration,
2302
+ easing: isExpanded.value ? EASINGS.expand : EASINGS.collapse
2101
2303
  })
2102
2304
  );
2103
- const derivedRotation = Animated12.useDerivedValue(
2104
- () => Animated12.withTiming(isExpanded.value ? 1 : 0, {
2105
- duration: 220,
2106
- easing: isExpanded.value ? easingExpand : easingCollapse
2305
+ const derivedRotation = Animated9.useDerivedValue(
2306
+ () => Animated9.withTiming(isExpanded.value ? 1 : 0, {
2307
+ duration: isExpanded.value ? TIMINGS.expand.duration : TIMINGS.collapse.duration,
2308
+ easing: isExpanded.value ? EASINGS.expand : EASINGS.collapse
2107
2309
  })
2108
2310
  );
2109
- const bodyStyle = Animated12.useAnimatedStyle(() => ({
2311
+ const bodyStyle = Animated9.useAnimatedStyle(() => ({
2110
2312
  height: derivedHeight.value,
2111
2313
  overflow: "hidden"
2112
2314
  }));
2113
- const rotationStyle = Animated12.useAnimatedStyle(() => ({
2315
+ const rotationStyle = Animated9.useAnimatedStyle(() => ({
2114
2316
  transform: [{ rotate: `${derivedRotation.value * 180}deg` }]
2115
2317
  }));
2116
2318
  return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles20.item, { backgroundColor: colors.card, borderColor: colors.border }] }, /* @__PURE__ */ React26__default.default.createElement(
@@ -2120,11 +2322,14 @@ function AccordionItemComponent({
2120
2322
  onPress: () => {
2121
2323
  selectionAsync();
2122
2324
  onToggle();
2123
- }
2325
+ },
2326
+ accessibilityRole: "button",
2327
+ accessibilityState: { expanded: isOpen },
2328
+ accessibilityLabel: item.trigger
2124
2329
  },
2125
2330
  /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles20.triggerContent }, resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles20.icon }, resolvedIcon) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles20.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger)),
2126
- /* @__PURE__ */ React26__default.default.createElement(Animated12__default.default.View, { style: [styles20.chevron, rotationStyle] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "chevron-down", size: 18, color: colors.foregroundMuted }))
2127
- ), /* @__PURE__ */ React26__default.default.createElement(Animated12__default.default.View, { style: bodyStyle }, /* @__PURE__ */ React26__default.default.createElement(
2331
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles20.chevron, rotationStyle] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "chevron-down", size: 18, color: colors.foregroundMuted }))
2332
+ ), /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: bodyStyle }, /* @__PURE__ */ React26__default.default.createElement(
2128
2333
  reactNative.View,
2129
2334
  {
2130
2335
  style: styles20.content,
@@ -2186,7 +2391,7 @@ var styles20 = reactNative.StyleSheet.create({
2186
2391
  justifyContent: "center"
2187
2392
  },
2188
2393
  triggerText: {
2189
- fontFamily: "Poppins-Medium",
2394
+ fontFamily: "Sohne-Medium",
2190
2395
  fontSize: ms(14)
2191
2396
  },
2192
2397
  chevron: {
@@ -2195,7 +2400,7 @@ var styles20 = reactNative.StyleSheet.create({
2195
2400
  // position:'absolute' is the key — the inner View escapes the animated wrapper's
2196
2401
  // clipped height so onLayout always reports the true content height.
2197
2402
  content: {
2198
- paddingHorizontal: s(14),
2403
+ paddingHorizontal: s(8),
2199
2404
  paddingBottom: vs(12),
2200
2405
  position: "absolute",
2201
2406
  width: "100%"
@@ -2224,23 +2429,38 @@ function Slider({
2224
2429
  }
2225
2430
  onValueChange?.(v);
2226
2431
  };
2227
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles21.wrapper, style], accessibilityLabel }, label || showValue ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles21.header }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles21.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, showValue ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles21.valueText, { color: colors.foregroundMuted }], allowFontScaling: true }, formatValue2(value)) : null) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: disabled ? styles21.disabled : void 0 }, /* @__PURE__ */ React26__default.default.createElement(
2228
- RNSlider__default.default,
2432
+ return /* @__PURE__ */ React26__default.default.createElement(
2433
+ reactNative.View,
2229
2434
  {
2230
- value,
2231
- minimumValue,
2232
- maximumValue,
2233
- step: step || 0,
2234
- disabled,
2235
- onValueChange: handleValueChange,
2236
- onSlidingComplete,
2237
- minimumTrackTintColor: colors.primary,
2238
- maximumTrackTintColor: colors.surface,
2239
- thumbTintColor: colors.primary,
2240
- style: styles21.slider,
2241
- accessibilityLabel
2242
- }
2243
- )));
2435
+ style: [styles21.wrapper, style],
2436
+ accessibilityRole: "adjustable",
2437
+ accessibilityLabel: accessibilityLabel ?? label,
2438
+ accessibilityValue: {
2439
+ min: minimumValue,
2440
+ max: maximumValue,
2441
+ now: value,
2442
+ text: formatValue2(value)
2443
+ }
2444
+ },
2445
+ label || showValue ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles21.header }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles21.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, showValue ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles21.valueText, { color: colors.foregroundMuted }], allowFontScaling: true }, formatValue2(value)) : null) : null,
2446
+ /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: disabled ? styles21.disabled : void 0 }, /* @__PURE__ */ React26__default.default.createElement(
2447
+ RNSlider__default.default,
2448
+ {
2449
+ value,
2450
+ minimumValue,
2451
+ maximumValue,
2452
+ step: step || 0,
2453
+ disabled,
2454
+ onValueChange: handleValueChange,
2455
+ onSlidingComplete,
2456
+ minimumTrackTintColor: colors.primary,
2457
+ maximumTrackTintColor: colors.surface,
2458
+ thumbTintColor: colors.primary,
2459
+ style: styles21.slider,
2460
+ accessibilityLabel
2461
+ }
2462
+ ))
2463
+ );
2244
2464
  }
2245
2465
  var styles21 = reactNative.StyleSheet.create({
2246
2466
  wrapper: {
@@ -2252,11 +2472,11 @@ var styles21 = reactNative.StyleSheet.create({
2252
2472
  alignItems: "center"
2253
2473
  },
2254
2474
  label: {
2255
- fontFamily: "Poppins-Medium",
2475
+ fontFamily: "Sohne-Medium",
2256
2476
  fontSize: ms(15)
2257
2477
  },
2258
2478
  valueText: {
2259
- fontFamily: "Poppins-Medium",
2479
+ fontFamily: "Sohne-Medium",
2260
2480
  fontSize: ms(14)
2261
2481
  },
2262
2482
  slider: {
@@ -2270,6 +2490,16 @@ var styles21 = reactNative.StyleSheet.create({
2270
2490
  var SCREEN_HEIGHT = reactNative.Dimensions.get("window").height;
2271
2491
  var DEFAULT_MAX_HEIGHT = SCREEN_HEIGHT * 0.85;
2272
2492
  var isAndroid = reactNative.Platform.OS === "android";
2493
+ function SheetHeader({ children, style }) {
2494
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles22.header, style] }, children);
2495
+ }
2496
+ function SheetContent({ children, style }) {
2497
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles22.sheetContent, style] }, children);
2498
+ }
2499
+ function SheetFooter({ children, style }) {
2500
+ const { colors } = useTheme();
2501
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles22.sheetFooter, { backgroundColor: colors.card, borderTopColor: colors.border }, style] }, children);
2502
+ }
2273
2503
  function Sheet({
2274
2504
  open,
2275
2505
  onClose,
@@ -2310,22 +2540,34 @@ function Sheet({
2310
2540
  pressBehavior: "close"
2311
2541
  }
2312
2542
  ), []);
2313
- const renderFooter = React26.useCallback((props) => {
2314
- if (!footer) return null;
2315
- return /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetFooter, { ...props }, footer);
2316
- }, [footer]);
2543
+ const childArray = React26__default.default.Children.toArray(children);
2544
+ const customHeader = childArray.find((child) => React26__default.default.isValidElement(child) && child.type === SheetHeader);
2545
+ const customContent = childArray.find((child) => React26__default.default.isValidElement(child) && child.type === SheetContent);
2546
+ const customFooter = childArray.find((child) => React26__default.default.isValidElement(child) && child.type === SheetFooter);
2547
+ const filteredChildren = customHeader || customContent || customFooter ? childArray.filter(
2548
+ (child) => !React26__default.default.isValidElement(child) || child.type !== SheetHeader && child.type !== SheetContent && child.type !== SheetFooter
2549
+ ) : children;
2317
2550
  const effectiveSubtitle = subtitle ?? description;
2318
- const showHeader = !!(title || effectiveSubtitle || showCloseButton);
2319
- const headerNode = showHeader ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles22.header }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles22.headerRow }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles22.title, { color: colors.foreground }], allowFontScaling: true }, title) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: { flex: 1 } }), showCloseButton ? /* @__PURE__ */ React26__default.default.createElement(
2551
+ const showHeader = !!(title || effectiveSubtitle || showCloseButton) && !customHeader;
2552
+ const headerNode = customHeader ? customHeader : showHeader ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles22.header, accessibilityRole: "header" }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles22.headerRow }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles22.title, { color: colors.foreground }], allowFontScaling: true }, title) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: { flex: 1 } }), showCloseButton ? /* @__PURE__ */ React26__default.default.createElement(
2320
2553
  reactNative.TouchableOpacity,
2321
2554
  {
2322
2555
  onPress: onClose,
2323
2556
  style: styles22.closeButton,
2324
2557
  activeOpacity: 0.6,
2325
- touchSoundDisabled: true
2558
+ touchSoundDisabled: true,
2559
+ accessibilityRole: "button",
2560
+ accessibilityLabel: "Close",
2561
+ hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }
2326
2562
  },
2327
2563
  /* @__PURE__ */ React26__default.default.createElement(vectorIcons.AntDesign, { name: "close", size: ms(18), color: colors.foregroundMuted })
2328
2564
  ) : null), effectiveSubtitle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles22.subtitle, { color: colors.foregroundMuted }], allowFontScaling: true }, effectiveSubtitle) : null) : null;
2565
+ const contentNode = customContent ? customContent : filteredChildren;
2566
+ const effectiveFooter = customFooter ? customFooter : footer;
2567
+ const renderFooter = React26.useCallback((props) => {
2568
+ if (!effectiveFooter) return null;
2569
+ return /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetFooter, { ...props }, effectiveFooter);
2570
+ }, [effectiveFooter]);
2329
2571
  const useScroll = scrollable || !!maxHeight;
2330
2572
  const effectiveMaxHeight = maxHeight ?? DEFAULT_MAX_HEIGHT;
2331
2573
  const useDynamicSizing = !snapPoints;
@@ -2338,7 +2580,7 @@ function Sheet({
2338
2580
  maxDynamicContentSize: useDynamicSizing ? effectiveMaxHeight : void 0,
2339
2581
  onDismiss: onClose,
2340
2582
  backdropComponent: renderBackdrop,
2341
- footerComponent: footer ? renderFooter : void 0,
2583
+ footerComponent: effectiveFooter ? renderFooter : void 0,
2342
2584
  backgroundStyle: [styles22.background, { backgroundColor: colors.card }],
2343
2585
  handleIndicatorStyle: [styles22.handle, { backgroundColor: colors.border }],
2344
2586
  enablePanDownToClose: true,
@@ -2361,10 +2603,13 @@ function Sheet({
2361
2603
  persistentScrollbar: isAndroid
2362
2604
  },
2363
2605
  headerNode,
2364
- children
2365
- ) : /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetView, { style: [styles22.content, contentStyle, style] }, headerNode, children)
2606
+ contentNode
2607
+ ) : /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetView, { style: [styles22.content, contentStyle, style] }, headerNode, contentNode)
2366
2608
  );
2367
2609
  }
2610
+ Sheet.Header = SheetHeader;
2611
+ Sheet.Content = SheetContent;
2612
+ Sheet.Footer = SheetFooter;
2368
2613
  var styles22 = reactNative.StyleSheet.create({
2369
2614
  background: {
2370
2615
  borderTopLeftRadius: ms(16),
@@ -2387,12 +2632,12 @@ var styles22 = reactNative.StyleSheet.create({
2387
2632
  justifyContent: "space-between"
2388
2633
  },
2389
2634
  title: {
2390
- fontFamily: "Poppins-SemiBold",
2635
+ fontFamily: "Sohne-SemiBold",
2391
2636
  fontSize: ms(18),
2392
2637
  flex: 1
2393
2638
  },
2394
2639
  subtitle: {
2395
- fontFamily: "Poppins-Regular",
2640
+ fontFamily: "Sohne-Regular",
2396
2641
  fontSize: ms(14),
2397
2642
  lineHeight: mvs(20)
2398
2643
  },
@@ -2408,12 +2653,21 @@ var styles22 = reactNative.StyleSheet.create({
2408
2653
  paddingHorizontal: s(16),
2409
2654
  paddingBottom: vs(32),
2410
2655
  paddingRight: s(16)
2656
+ },
2657
+ sheetContent: {
2658
+ gap: vs(16)
2659
+ },
2660
+ sheetFooter: {
2661
+ paddingHorizontal: s(16),
2662
+ paddingVertical: vs(16),
2663
+ borderTopWidth: 1,
2664
+ flexDirection: "row",
2665
+ gap: s(12)
2411
2666
  }
2412
2667
  });
2413
2668
  var isIOS = reactNative.Platform.OS === "ios";
2414
2669
  var isAndroid2 = reactNative.Platform.OS === "android";
2415
2670
  var isWeb2 = reactNative.Platform.OS === "web";
2416
- var nativeDriver9 = reactNative.Platform.OS !== "web";
2417
2671
  function Select({
2418
2672
  options,
2419
2673
  value,
@@ -2422,21 +2676,18 @@ function Select({
2422
2676
  label,
2423
2677
  error,
2424
2678
  disabled,
2425
- style
2679
+ style,
2680
+ accessibilityLabel
2426
2681
  }) {
2427
2682
  const { colors } = useTheme();
2428
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
2683
+ const { animatedStyle, onPressIn, onPressOut } = usePressScale({
2684
+ pressScale: PRESS_SCALE.button,
2685
+ disabled
2686
+ });
2429
2687
  const [pickerVisible, setPickerVisible] = React26.useState(false);
2430
2688
  const [pendingValue, setPendingValue] = React26.useState(value);
2431
2689
  const pickerRef = React26.useRef(null);
2432
2690
  const selected = options.find((o) => o.value === value);
2433
- const handlePressIn = () => {
2434
- if (disabled) return;
2435
- reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver9, speed: 40, bounciness: 0 }).start();
2436
- };
2437
- const handlePressOut = () => {
2438
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver9, speed: 40, bounciness: 4 }).start();
2439
- };
2440
2691
  const handleOpen = () => {
2441
2692
  if (disabled) return;
2442
2693
  selectionAsync();
@@ -2444,7 +2695,7 @@ function Select({
2444
2695
  setPendingValue(value);
2445
2696
  setPickerVisible(true);
2446
2697
  } else if (isAndroid2) {
2447
- pickerRef.current?.focus();
2698
+ pickerRef.current?.focus?.();
2448
2699
  }
2449
2700
  };
2450
2701
  const handleDismiss = () => {
@@ -2457,7 +2708,7 @@ function Select({
2457
2708
  }
2458
2709
  setPickerVisible(false);
2459
2710
  };
2460
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles23.container, style] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles23.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, !isWeb2 ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale: scale2 }], opacity: disabled ? 0.45 : 1 } }, /* @__PURE__ */ React26__default.default.createElement(
2711
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles23.container, style] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles23.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, !isWeb2 ? /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [animatedStyle, { opacity: disabled ? 0.45 : 1 }] }, /* @__PURE__ */ React26__default.default.createElement(
2461
2712
  reactNative.TouchableOpacity,
2462
2713
  {
2463
2714
  style: [
@@ -2468,10 +2719,14 @@ function Select({
2468
2719
  }
2469
2720
  ],
2470
2721
  onPress: handleOpen,
2471
- onPressIn: handlePressIn,
2472
- onPressOut: handlePressOut,
2722
+ onPressIn,
2723
+ onPressOut,
2473
2724
  activeOpacity: 1,
2474
- touchSoundDisabled: true
2725
+ touchSoundDisabled: true,
2726
+ accessibilityRole: "combobox",
2727
+ accessibilityLabel: accessibilityLabel ?? label,
2728
+ accessibilityValue: { text: selected?.label ?? placeholder },
2729
+ accessibilityState: { disabled: !!disabled, expanded: pickerVisible }
2475
2730
  },
2476
2731
  /* @__PURE__ */ React26__default.default.createElement(
2477
2732
  reactNative.Text,
@@ -2577,7 +2832,7 @@ var styles23 = reactNative.StyleSheet.create({
2577
2832
  gap: vs(8)
2578
2833
  },
2579
2834
  label: {
2580
- fontFamily: "Poppins-Medium",
2835
+ fontFamily: "Sohne-Medium",
2581
2836
  fontSize: ms(13)
2582
2837
  },
2583
2838
  trigger: {
@@ -2590,7 +2845,7 @@ var styles23 = reactNative.StyleSheet.create({
2590
2845
  paddingVertical: vs(11)
2591
2846
  },
2592
2847
  triggerText: {
2593
- fontFamily: "Poppins-Regular",
2848
+ fontFamily: "Sohne-Regular",
2594
2849
  fontSize: ms(15),
2595
2850
  flex: 1
2596
2851
  },
@@ -2598,7 +2853,7 @@ var styles23 = reactNative.StyleSheet.create({
2598
2853
  marginLeft: s(8)
2599
2854
  },
2600
2855
  helperText: {
2601
- fontFamily: "Poppins-Regular",
2856
+ fontFamily: "Sohne-Regular",
2602
2857
  fontSize: ms(13)
2603
2858
  },
2604
2859
  iosBackdrop: {
@@ -2619,14 +2874,14 @@ var styles23 = reactNative.StyleSheet.create({
2619
2874
  borderBottomWidth: 1
2620
2875
  },
2621
2876
  iosToolbarTitle: {
2622
- fontFamily: "Poppins-SemiBold",
2877
+ fontFamily: "Sohne-SemiBold",
2623
2878
  fontSize: ms(17)
2624
2879
  },
2625
2880
  iosDoneBtn: {
2626
2881
  padding: s(4)
2627
2882
  },
2628
2883
  iosDoneBtnText: {
2629
- fontFamily: "Poppins-SemiBold",
2884
+ fontFamily: "Sohne-SemiBold",
2630
2885
  fontSize: ms(17)
2631
2886
  },
2632
2887
  androidHiddenPicker: {
@@ -2656,7 +2911,7 @@ function ToastProvider({ children }) {
2656
2911
  {
2657
2912
  theme: colorScheme,
2658
2913
  position: "top-center",
2659
- richColors: false,
2914
+ richColors: true,
2660
2915
  gap: vs(8),
2661
2916
  offset: insets.top + vs(8),
2662
2917
  visibleToasts: 3,
@@ -2670,11 +2925,11 @@ function ToastProvider({ children }) {
2670
2925
  paddingVertical: vs(10)
2671
2926
  },
2672
2927
  titleStyle: {
2673
- fontFamily: "Poppins-Medium",
2928
+ fontFamily: "Sohne-Medium",
2674
2929
  fontSize: ms(13)
2675
2930
  },
2676
2931
  descriptionStyle: {
2677
- fontFamily: "Poppins-Regular",
2932
+ fontFamily: "Sohne-Regular",
2678
2933
  fontSize: ms(12),
2679
2934
  opacity: 0.85
2680
2935
  }
@@ -2712,7 +2967,7 @@ function CurrencyInput({
2712
2967
  const raw = parseFloat(formatted.replace(separatorRegex, "") || "0");
2713
2968
  onChangeValue?.(isNaN(raw) ? 0 : raw);
2714
2969
  };
2715
- const inputStyle = size === "large" ? { fontFamily: "Poppins-Regular", fontSize: ms(36) } : { fontFamily: "Poppins-Regular" };
2970
+ const inputStyle = size === "large" ? { fontFamily: "Sohne-Regular", fontSize: ms(36) } : { fontFamily: "Sohne-Regular" };
2716
2971
  const dollarIcon = renderIcon("dollar-sign", size === "large" ? 24 : 16, colors.foregroundMuted);
2717
2972
  const displayValue = value && prefix && value.startsWith(prefix) ? value.slice(prefix.length) : value;
2718
2973
  return /* @__PURE__ */ React26__default.default.createElement(
@@ -2757,7 +3012,7 @@ function formatValue(value, prefix, showDecimals) {
2757
3012
  }
2758
3013
  return `${sign}${prefix}${intPart}`;
2759
3014
  }
2760
- function CurrencyDisplay({ value, prefix = "$", showDecimals = false, textColor, variant, autoScale, maxFontSize, style }) {
3015
+ function CurrencyDisplayBase({ value, prefix = "$", showDecimals = false, textColor, variant, autoScale, maxFontSize, style }) {
2761
3016
  const { colors } = useTheme();
2762
3017
  const formatted = formatValue(value, prefix, showDecimals);
2763
3018
  const baseFontSize = variant ? variantFontSize[variant] : ms(56);
@@ -2775,18 +3030,18 @@ function CurrencyDisplay({ value, prefix = "$", showDecimals = false, textColor,
2775
3030
  formatted
2776
3031
  ));
2777
3032
  }
3033
+ var CurrencyDisplay = React26__default.default.memo(CurrencyDisplayBase);
2778
3034
  var styles24 = reactNative.StyleSheet.create({
2779
3035
  container: {
2780
3036
  alignSelf: "flex-start"
2781
3037
  },
2782
3038
  amount: {
2783
- fontFamily: "Poppins-Bold",
3039
+ fontFamily: "Sohne-Bold",
2784
3040
  includeFontPadding: false,
2785
3041
  textAlignVertical: "top"
2786
3042
  }
2787
3043
  });
2788
- var nativeDriver10 = reactNative.Platform.OS !== "web";
2789
- function ListItem({
3044
+ function ListItemBase({
2790
3045
  leftRender,
2791
3046
  rightRender,
2792
3047
  trailing,
@@ -2806,29 +3061,16 @@ function ListItem({
2806
3061
  style,
2807
3062
  titleStyle,
2808
3063
  subtitleStyle,
2809
- captionStyle
3064
+ captionStyle,
3065
+ accessibilityLabel
2810
3066
  }) {
2811
3067
  const { colors } = useTheme();
2812
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
2813
- const handlePressIn = () => {
2814
- if (!onPress || disabled) return;
2815
- reactNative.Animated.spring(scale2, {
2816
- toValue: 0.97,
2817
- useNativeDriver: nativeDriver10,
2818
- stiffness: 350,
2819
- damping: 28,
2820
- mass: 0.9
2821
- }).start();
2822
- };
2823
- const handlePressOut = () => {
2824
- reactNative.Animated.spring(scale2, {
2825
- toValue: 1,
2826
- useNativeDriver: nativeDriver10,
2827
- stiffness: 220,
2828
- damping: 20,
2829
- mass: 0.9
2830
- }).start();
2831
- };
3068
+ const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
3069
+ pressScale: PRESS_SCALE.row,
3070
+ pressInSpring: SPRINGS.surfacePressIn,
3071
+ pressOutSpring: SPRINGS.surfacePressOut,
3072
+ disabled: !onPress || disabled
3073
+ });
2832
3074
  const handlePress = () => {
2833
3075
  selectionAsync();
2834
3076
  onPress?.();
@@ -2846,16 +3088,20 @@ function ListItem({
2846
3088
  shadowRadius: 6,
2847
3089
  elevation: 2
2848
3090
  } : {};
2849
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [{ transform: [{ scale: scale2 }] }, disabled && styles25.disabled] }, /* @__PURE__ */ React26__default.default.createElement(
3091
+ const a11yLabel = accessibilityLabel ?? [title, subtitle, caption].filter(Boolean).join(". ");
3092
+ return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [animatedStyle, disabled && styles25.disabled], ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
2850
3093
  reactNative.TouchableOpacity,
2851
3094
  {
2852
3095
  style: [styles25.container, cardStyle, style],
2853
3096
  onPress: onPress ? handlePress : void 0,
2854
- onPressIn: handlePressIn,
2855
- onPressOut: handlePressOut,
3097
+ onPressIn,
3098
+ onPressOut,
2856
3099
  disabled,
2857
3100
  activeOpacity: 1,
2858
- touchSoundDisabled: true
3101
+ touchSoundDisabled: true,
3102
+ accessibilityRole: onPress ? "button" : void 0,
3103
+ accessibilityLabel: onPress ? a11yLabel : void 0,
3104
+ accessibilityState: onPress ? { disabled: !!disabled } : void 0
2859
3105
  },
2860
3106
  effectiveLeft ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles25.leftContainer }, effectiveLeft) : null,
2861
3107
  /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles25.content }, /* @__PURE__ */ React26__default.default.createElement(
@@ -2896,19 +3142,17 @@ function ListItem({
2896
3142
  {
2897
3143
  style: [
2898
3144
  styles25.separator,
2899
- {
2900
- backgroundColor: colors.border,
2901
- marginLeft: effectiveLeft ? s(44) + s(12) : 0
2902
- }
3145
+ { backgroundColor: colors.separator }
2903
3146
  ]
2904
3147
  }
2905
3148
  ) : null);
2906
3149
  }
3150
+ var ListItem = React26__default.default.memo(ListItemBase);
2907
3151
  var styles25 = reactNative.StyleSheet.create({
2908
3152
  container: {
2909
3153
  flexDirection: "row",
2910
3154
  alignItems: "center",
2911
- paddingHorizontal: 0,
3155
+ paddingHorizontal: s(16),
2912
3156
  paddingVertical: vs(10),
2913
3157
  gap: s(12)
2914
3158
  },
@@ -2924,17 +3168,17 @@ var styles25 = reactNative.StyleSheet.create({
2924
3168
  gap: vs(4)
2925
3169
  },
2926
3170
  title: {
2927
- fontFamily: "Poppins-Medium",
3171
+ fontFamily: "Sohne-Medium",
2928
3172
  fontSize: ms(15),
2929
3173
  lineHeight: mvs(22)
2930
3174
  },
2931
3175
  subtitle: {
2932
- fontFamily: "Poppins-Regular",
3176
+ fontFamily: "Sohne-Regular",
2933
3177
  fontSize: ms(13),
2934
3178
  lineHeight: mvs(18)
2935
3179
  },
2936
3180
  caption: {
2937
- fontFamily: "Poppins-Regular",
3181
+ fontFamily: "Sohne-Regular",
2938
3182
  fontSize: ms(12),
2939
3183
  lineHeight: mvs(16),
2940
3184
  opacity: 0.7
@@ -2946,12 +3190,9 @@ var styles25 = reactNative.StyleSheet.create({
2946
3190
  maxWidth: s(160)
2947
3191
  },
2948
3192
  rightText: {
2949
- fontFamily: "Poppins-Regular",
3193
+ fontFamily: "Sohne-Regular",
2950
3194
  fontSize: ms(14)
2951
3195
  },
2952
- chevron: {
2953
- marginLeft: s(4)
2954
- },
2955
3196
  separator: {
2956
3197
  height: reactNative.StyleSheet.hairlineWidth,
2957
3198
  marginRight: 0
@@ -2960,8 +3201,81 @@ var styles25 = reactNative.StyleSheet.create({
2960
3201
  opacity: 0.45
2961
3202
  }
2962
3203
  });
2963
- var nativeDriver11 = reactNative.Platform.OS !== "web";
2964
- function MenuItem({
3204
+ function ListGroup({ children, variant = "plain", style }) {
3205
+ const { colors } = useTheme();
3206
+ const processedChildren = React26__default.default.Children.map(children, (child, index) => {
3207
+ if (!React26__default.default.isValidElement(child)) return child;
3208
+ if (child.type === ListGroupHeader || child.type === ListGroupFooter) {
3209
+ return child;
3210
+ }
3211
+ const childProps = child.props;
3212
+ const isListItem = "title" in childProps;
3213
+ if (!isListItem) return child;
3214
+ const isLast = index === React26__default.default.Children.count(children) - 1;
3215
+ if (childProps["showSeparator"] === void 0 && !isLast) {
3216
+ return React26__default.default.cloneElement(child, {
3217
+ showSeparator: true
3218
+ });
3219
+ }
3220
+ return child;
3221
+ });
3222
+ const cardStyle = variant === "card" ? {
3223
+ backgroundColor: colors.card,
3224
+ borderRadius: RADIUS.md,
3225
+ borderWidth: 1,
3226
+ borderColor: colors.border,
3227
+ shadowColor: "#000",
3228
+ shadowOffset: { width: 0, height: 2 },
3229
+ shadowOpacity: 0.06,
3230
+ shadowRadius: 6,
3231
+ elevation: 2,
3232
+ paddingVertical: vs(4)
3233
+ } : {};
3234
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.container, cardStyle, style] }, processedChildren);
3235
+ }
3236
+ function ListGroupHeader({ children, style }) {
3237
+ const { colors } = useTheme();
3238
+ if (typeof children === "string") {
3239
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.header, { borderBottomColor: colors.separator }, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles26.headerText, { color: colors.foregroundMuted }], allowFontScaling: true }, children));
3240
+ }
3241
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.header, { borderBottomColor: colors.separator }, style] }, children);
3242
+ }
3243
+ function ListGroupFooter({ children, style }) {
3244
+ const { colors } = useTheme();
3245
+ if (typeof children === "string") {
3246
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.footer, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles26.footerText, { color: colors.foregroundMuted }], allowFontScaling: true }, children));
3247
+ }
3248
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.footer, style] }, children);
3249
+ }
3250
+ ListGroup.Header = ListGroupHeader;
3251
+ ListGroup.Footer = ListGroupFooter;
3252
+ var styles26 = reactNative.StyleSheet.create({
3253
+ container: {
3254
+ overflow: "hidden"
3255
+ },
3256
+ header: {
3257
+ paddingHorizontal: s(16),
3258
+ paddingTop: vs(12),
3259
+ paddingBottom: vs(8),
3260
+ borderBottomWidth: reactNative.StyleSheet.hairlineWidth
3261
+ },
3262
+ headerText: {
3263
+ fontFamily: "Sohne-SemiBold",
3264
+ fontSize: 13,
3265
+ letterSpacing: 0.32,
3266
+ textTransform: "uppercase"
3267
+ },
3268
+ footer: {
3269
+ paddingHorizontal: s(16),
3270
+ paddingTop: vs(8),
3271
+ paddingBottom: vs(12)
3272
+ },
3273
+ footerText: {
3274
+ fontFamily: "Sohne-Regular",
3275
+ fontSize: 12
3276
+ }
3277
+ });
3278
+ function MenuItemBase({
2965
3279
  label,
2966
3280
  subtitle,
2967
3281
  iconName,
@@ -2974,29 +3288,16 @@ function MenuItem({
2974
3288
  variant = "plain",
2975
3289
  showSeparator = false,
2976
3290
  style,
2977
- labelStyle
3291
+ labelStyle,
3292
+ accessibilityLabel
2978
3293
  }) {
2979
3294
  const { colors } = useTheme();
2980
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
2981
- const handlePressIn = () => {
2982
- if (disabled) return;
2983
- reactNative.Animated.spring(scale2, {
2984
- toValue: 0.97,
2985
- useNativeDriver: nativeDriver11,
2986
- stiffness: 350,
2987
- damping: 28,
2988
- mass: 0.9
2989
- }).start();
2990
- };
2991
- const handlePressOut = () => {
2992
- reactNative.Animated.spring(scale2, {
2993
- toValue: 1,
2994
- useNativeDriver: nativeDriver11,
2995
- stiffness: 220,
2996
- damping: 20,
2997
- mass: 0.9
2998
- }).start();
2999
- };
3295
+ const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
3296
+ pressScale: PRESS_SCALE.row,
3297
+ pressInSpring: SPRINGS.surfacePressIn,
3298
+ pressOutSpring: SPRINGS.surfacePressOut,
3299
+ disabled
3300
+ });
3000
3301
  const handlePress = () => {
3001
3302
  selectionAsync();
3002
3303
  onPress();
@@ -3013,22 +3314,26 @@ function MenuItem({
3013
3314
  shadowRadius: 6,
3014
3315
  elevation: 2
3015
3316
  } : {};
3016
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [{ transform: [{ scale: scale2 }] }, disabled && styles26.disabled] }, /* @__PURE__ */ React26__default.default.createElement(
3317
+ const a11yLabel = accessibilityLabel ?? (subtitle ? `${label}. ${subtitle}` : label);
3318
+ return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [animatedStyle, disabled && styles27.disabled], ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
3017
3319
  reactNative.TouchableOpacity,
3018
3320
  {
3019
- style: [styles26.container, cardStyle, style],
3321
+ style: [styles27.container, cardStyle, style],
3020
3322
  onPress: handlePress,
3021
- onPressIn: handlePressIn,
3022
- onPressOut: handlePressOut,
3323
+ onPressIn,
3324
+ onPressOut,
3023
3325
  disabled,
3024
3326
  activeOpacity: 1,
3025
- touchSoundDisabled: true
3327
+ touchSoundDisabled: true,
3328
+ accessibilityRole: "button",
3329
+ accessibilityLabel: a11yLabel,
3330
+ accessibilityState: { disabled }
3026
3331
  },
3027
- resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles26.iconContainer }, resolvedIcon) : null,
3028
- /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles26.labelContainer }, /* @__PURE__ */ React26__default.default.createElement(
3332
+ resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles27.iconContainer }, resolvedIcon) : null,
3333
+ /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles27.labelContainer }, /* @__PURE__ */ React26__default.default.createElement(
3029
3334
  reactNative.Text,
3030
3335
  {
3031
- style: [styles26.label, { color: colors.foreground }, labelStyle],
3336
+ style: [styles27.label, { color: colors.foreground }, labelStyle],
3032
3337
  numberOfLines: 1,
3033
3338
  allowFontScaling: true
3034
3339
  },
@@ -3036,7 +3341,7 @@ function MenuItem({
3036
3341
  ), subtitle ? /* @__PURE__ */ React26__default.default.createElement(
3037
3342
  reactNative.Text,
3038
3343
  {
3039
- style: [styles26.subtitle, { color: colors.foregroundMuted }],
3344
+ style: [styles27.subtitle, { color: colors.foregroundMuted }],
3040
3345
  numberOfLines: 1,
3041
3346
  allowFontScaling: true
3042
3347
  },
@@ -3045,7 +3350,7 @@ function MenuItem({
3045
3350
  rightRender !== void 0 ? /* @__PURE__ */ React26__default.default.createElement(
3046
3351
  reactNative.View,
3047
3352
  {
3048
- style: styles26.rightContainer,
3353
+ style: styles27.rightContainer,
3049
3354
  onStartShouldSetResponder: () => true,
3050
3355
  onResponderRelease: () => {
3051
3356
  }
@@ -3056,21 +3361,18 @@ function MenuItem({
3056
3361
  reactNative.View,
3057
3362
  {
3058
3363
  style: [
3059
- styles26.separator,
3060
- {
3061
- backgroundColor: colors.border,
3062
- marginLeft: resolvedIcon ? s(22) + s(12) : 0,
3063
- opacity: 0.6
3064
- }
3364
+ styles27.separator,
3365
+ { backgroundColor: colors.separator }
3065
3366
  ]
3066
3367
  }
3067
3368
  ) : null);
3068
3369
  }
3069
- var styles26 = reactNative.StyleSheet.create({
3370
+ var MenuItem = React26__default.default.memo(MenuItemBase);
3371
+ var styles27 = reactNative.StyleSheet.create({
3070
3372
  container: {
3071
3373
  flexDirection: "row",
3072
3374
  alignItems: "center",
3073
- paddingHorizontal: 0,
3375
+ paddingHorizontal: s(16),
3074
3376
  paddingVertical: vs(16),
3075
3377
  minHeight: vs(54),
3076
3378
  gap: s(12)
@@ -3086,11 +3388,11 @@ var styles26 = reactNative.StyleSheet.create({
3086
3388
  justifyContent: "center"
3087
3389
  },
3088
3390
  label: {
3089
- fontFamily: "Poppins-Medium",
3391
+ fontFamily: "Sohne-Medium",
3090
3392
  fontSize: ms(15)
3091
3393
  },
3092
3394
  subtitle: {
3093
- fontFamily: "Poppins-Regular",
3395
+ fontFamily: "Sohne-Regular",
3094
3396
  fontSize: ms(12),
3095
3397
  marginTop: vs(1)
3096
3398
  },
@@ -3107,64 +3409,114 @@ var styles26 = reactNative.StyleSheet.create({
3107
3409
  opacity: 0.45
3108
3410
  }
3109
3411
  });
3110
- var nativeDriver12 = reactNative.Platform.OS !== "web";
3111
- function Chip({ label, selected = false, onPress, icon, iconName, style }) {
3412
+ function MenuGroup({ children, variant = "plain", style }) {
3112
3413
  const { colors } = useTheme();
3113
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
3114
- const pressAnim = React26.useRef(new reactNative.Animated.Value(selected ? 1 : 0)).current;
3115
- React26.useEffect(() => {
3116
- reactNative.Animated.timing(pressAnim, {
3117
- toValue: selected ? 1 : 0,
3118
- duration: 150,
3119
- easing: reactNative.Easing.out(reactNative.Easing.ease),
3120
- useNativeDriver: false
3121
- }).start();
3122
- }, [selected, pressAnim]);
3123
- const handlePressIn = () => {
3124
- reactNative.Animated.spring(scale2, {
3125
- toValue: 0.95,
3126
- useNativeDriver: nativeDriver12,
3127
- speed: 40,
3128
- bounciness: 0
3129
- }).start();
3130
- };
3131
- const handlePressOut = () => {
3132
- reactNative.Animated.spring(scale2, {
3133
- toValue: 1,
3134
- useNativeDriver: nativeDriver12,
3135
- speed: 40,
3136
- bounciness: 4
3137
- }).start();
3138
- };
3414
+ const processedChildren = React26__default.default.Children.map(children, (child, index) => {
3415
+ if (!React26__default.default.isValidElement(child)) return child;
3416
+ if (child.type === MenuGroupHeader || child.type === MenuGroupFooter) {
3417
+ return child;
3418
+ }
3419
+ const childProps = child.props;
3420
+ const isMenuItem = "onPress" in childProps;
3421
+ if (!isMenuItem) return child;
3422
+ const isLast = index === React26__default.default.Children.count(children) - 1;
3423
+ if (childProps["showSeparator"] === void 0 && !isLast) {
3424
+ return React26__default.default.cloneElement(child, {
3425
+ showSeparator: true
3426
+ });
3427
+ }
3428
+ return child;
3429
+ });
3430
+ const cardStyle = variant === "card" ? {
3431
+ backgroundColor: colors.card,
3432
+ borderRadius: RADIUS.md,
3433
+ borderWidth: 1,
3434
+ borderColor: colors.border,
3435
+ shadowColor: "#000",
3436
+ shadowOffset: { width: 0, height: 2 },
3437
+ shadowOpacity: 0.06,
3438
+ shadowRadius: 6,
3439
+ elevation: 2,
3440
+ paddingVertical: vs(4)
3441
+ } : {};
3442
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.container, cardStyle, style] }, processedChildren);
3443
+ }
3444
+ function MenuGroupHeader({ children, style }) {
3445
+ const { colors } = useTheme();
3446
+ if (typeof children === "string") {
3447
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.header, { borderBottomColor: colors.separator }, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles28.headerText, { color: colors.foregroundMuted }], allowFontScaling: true }, children));
3448
+ }
3449
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.header, { borderBottomColor: colors.separator }, style] }, children);
3450
+ }
3451
+ function MenuGroupFooter({ children, style }) {
3452
+ const { colors } = useTheme();
3453
+ if (typeof children === "string") {
3454
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.footer, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles28.footerText, { color: colors.foregroundMuted }], allowFontScaling: true }, children));
3455
+ }
3456
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.footer, style] }, children);
3457
+ }
3458
+ MenuGroup.Header = MenuGroupHeader;
3459
+ MenuGroup.Footer = MenuGroupFooter;
3460
+ var styles28 = reactNative.StyleSheet.create({
3461
+ container: {
3462
+ overflow: "hidden"
3463
+ },
3464
+ header: {
3465
+ paddingHorizontal: s(16),
3466
+ paddingTop: vs(12),
3467
+ paddingBottom: vs(8),
3468
+ borderBottomWidth: reactNative.StyleSheet.hairlineWidth
3469
+ },
3470
+ headerText: {
3471
+ fontFamily: "Sohne-SemiBold",
3472
+ fontSize: 13,
3473
+ letterSpacing: 0.32,
3474
+ textTransform: "uppercase"
3475
+ },
3476
+ footer: {
3477
+ paddingHorizontal: s(16),
3478
+ paddingTop: vs(8),
3479
+ paddingBottom: vs(12)
3480
+ },
3481
+ footerText: {
3482
+ fontFamily: "Sohne-Regular",
3483
+ fontSize: 12
3484
+ }
3485
+ });
3486
+ function ChipBase({ label, selected = false, onPress, icon, iconName, style, accessibilityLabel }) {
3487
+ const { colors } = useTheme();
3488
+ const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
3489
+ pressScale: PRESS_SCALE.chip
3490
+ });
3491
+ const colorProgress = useColorTransition(selected);
3492
+ const surfaceStyle = Animated9.useAnimatedStyle(() => ({
3493
+ backgroundColor: Animated9.interpolateColor(colorProgress.value, [0, 1], [colors.surface, colors.primary]),
3494
+ borderColor: Animated9.interpolateColor(colorProgress.value, [0, 1], [colors.border, colors.primary])
3495
+ }));
3496
+ const textStyle = Animated9.useAnimatedStyle(() => ({
3497
+ color: Animated9.interpolateColor(colorProgress.value, [0, 1], [colors.foreground, colors.primaryForeground])
3498
+ }));
3139
3499
  const handlePress = () => {
3140
3500
  selectionAsync();
3141
3501
  onPress?.();
3142
3502
  };
3143
- const backgroundColor = pressAnim.interpolate({
3144
- inputRange: [0, 1],
3145
- outputRange: [colors.surface, colors.primary]
3146
- });
3147
- const textColor = pressAnim.interpolate({
3148
- inputRange: [0, 1],
3149
- outputRange: [colors.foreground, colors.primaryForeground]
3150
- });
3151
- const borderColor = pressAnim.interpolate({
3152
- inputRange: [0, 1],
3153
- outputRange: [colors.border, colors.primary]
3154
- });
3155
3503
  const resolvedIcon = iconName ? renderIcon(iconName, ms(13), selected ? colors.primaryForeground : colors.foreground) : icon;
3156
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [styles27.wrapper, { transform: [{ scale: scale2 }] }, style] }, /* @__PURE__ */ React26__default.default.createElement(
3504
+ return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles29.wrapper, scaleStyle, style], ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
3157
3505
  reactNative.TouchableOpacity,
3158
3506
  {
3159
3507
  onPress: handlePress,
3160
- onPressIn: handlePressIn,
3161
- onPressOut: handlePressOut,
3508
+ onPressIn,
3509
+ onPressOut,
3162
3510
  activeOpacity: 1,
3163
- touchSoundDisabled: true
3511
+ touchSoundDisabled: true,
3512
+ accessibilityRole: "button",
3513
+ accessibilityLabel: accessibilityLabel ?? label,
3514
+ accessibilityState: { selected }
3164
3515
  },
3165
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [styles27.chip, { backgroundColor, borderColor }] }, resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles27.chipIcon }, resolvedIcon) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.Text, { style: [styles27.label, { color: textColor }], allowFontScaling: true }, label))
3516
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles29.chip, surfaceStyle] }, resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles29.chipIcon }, resolvedIcon) : null, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.Text, { style: [styles29.label, textStyle], allowFontScaling: true }, label))
3166
3517
  ));
3167
3518
  }
3519
+ var Chip = React26__default.default.memo(ChipBase);
3168
3520
  function ChipGroup({ options, value, onValueChange, multiSelect = false, style }) {
3169
3521
  const handlePress = (optionValue) => {
3170
3522
  if (!multiSelect) {
@@ -3173,21 +3525,14 @@ function ChipGroup({ options, value, onValueChange, multiSelect = false, style }
3173
3525
  }
3174
3526
  const currentArray = Array.isArray(value) ? value : value ? [value] : [];
3175
3527
  const isSelected2 = currentArray.includes(optionValue);
3176
- let newArray;
3177
- if (isSelected2) {
3178
- newArray = currentArray.filter((v) => v !== optionValue);
3179
- } else {
3180
- newArray = [...currentArray, optionValue];
3181
- }
3528
+ const newArray = isSelected2 ? currentArray.filter((v) => v !== optionValue) : [...currentArray, optionValue];
3182
3529
  onValueChange?.(newArray);
3183
3530
  };
3184
3531
  const isSelected = (optionValue) => {
3185
- if (Array.isArray(value)) {
3186
- return value.includes(optionValue);
3187
- }
3532
+ if (Array.isArray(value)) return value.includes(optionValue);
3188
3533
  return optionValue === value;
3189
3534
  };
3190
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles27.group, style] }, options.map((opt) => /* @__PURE__ */ React26__default.default.createElement(
3535
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles29.group, style] }, options.map((opt) => /* @__PURE__ */ React26__default.default.createElement(
3191
3536
  Chip,
3192
3537
  {
3193
3538
  key: opt.value,
@@ -3195,28 +3540,35 @@ function ChipGroup({ options, value, onValueChange, multiSelect = false, style }
3195
3540
  selected: isSelected(opt.value),
3196
3541
  onPress: opt.disabled ? void 0 : () => handlePress(opt.value),
3197
3542
  iconName: opt.iconName,
3198
- style: opt.disabled ? { opacity: 0.4 } : void 0
3543
+ style: opt.disabled ? styles29.chipDisabled : void 0,
3544
+ accessibilityLabel: opt.disabled ? `${opt.label}, unavailable` : opt.label
3199
3545
  }
3200
3546
  )));
3201
3547
  }
3202
- var styles27 = reactNative.StyleSheet.create({
3548
+ var styles29 = reactNative.StyleSheet.create({
3203
3549
  wrapper: {},
3204
3550
  chip: {
3205
3551
  borderRadius: 999,
3206
3552
  paddingHorizontal: s(14),
3207
- paddingVertical: vs(5),
3553
+ // AUDIT FIX: was vs(5) → ~28px total height — below WCAG 44px tap target.
3554
+ // vs(10) → ~44px total height meets WCAG 2.5.5 (AAA) minimum.
3555
+ paddingVertical: vs(10),
3556
+ minHeight: 44,
3208
3557
  borderWidth: 1,
3209
3558
  alignItems: "center",
3210
3559
  justifyContent: "center",
3211
3560
  flexDirection: "row",
3212
3561
  gap: s(5)
3213
3562
  },
3563
+ chipDisabled: {
3564
+ opacity: 0.4
3565
+ },
3214
3566
  chipIcon: {
3215
3567
  alignItems: "center",
3216
3568
  justifyContent: "center"
3217
3569
  },
3218
3570
  label: {
3219
- fontFamily: "Poppins-Medium",
3571
+ fontFamily: "Sohne-Medium",
3220
3572
  fontSize: ms(13),
3221
3573
  lineHeight: mvs(18)
3222
3574
  },
@@ -3262,11 +3614,11 @@ function ConfirmDialog({
3262
3614
  enableDynamicSizing: true,
3263
3615
  onDismiss: onCancel,
3264
3616
  backdropComponent: renderBackdrop,
3265
- backgroundStyle: [styles28.background, { backgroundColor: colors.card }],
3266
- handleIndicatorStyle: [styles28.handle, { backgroundColor: colors.border }],
3617
+ backgroundStyle: [styles30.background, { backgroundColor: colors.card }],
3618
+ handleIndicatorStyle: [styles30.handle, { backgroundColor: colors.border }],
3267
3619
  enablePanDownToClose: true
3268
3620
  },
3269
- /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetView, { style: styles28.content }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles28.title, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles28.description, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles28.actions }, /* @__PURE__ */ React26__default.default.createElement(
3621
+ /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetView, { style: styles30.content }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles30.title, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles30.description, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles30.actions }, /* @__PURE__ */ React26__default.default.createElement(
3270
3622
  Button,
3271
3623
  {
3272
3624
  label: confirmLabel,
@@ -3300,7 +3652,7 @@ function ConfirmDialog({
3300
3652
  )))
3301
3653
  );
3302
3654
  }
3303
- var styles28 = reactNative.StyleSheet.create({
3655
+ var styles30 = reactNative.StyleSheet.create({
3304
3656
  background: {
3305
3657
  borderTopLeftRadius: ms(16),
3306
3658
  borderTopRightRadius: ms(16)
@@ -3316,12 +3668,12 @@ var styles28 = reactNative.StyleSheet.create({
3316
3668
  gap: vs(12)
3317
3669
  },
3318
3670
  title: {
3319
- fontFamily: "Poppins-SemiBold",
3671
+ fontFamily: "Sohne-SemiBold",
3320
3672
  fontSize: ms(18),
3321
3673
  lineHeight: mvs(26)
3322
3674
  },
3323
3675
  description: {
3324
- fontFamily: "Poppins-Regular",
3676
+ fontFamily: "Sohne-Regular",
3325
3677
  fontSize: ms(15),
3326
3678
  lineHeight: mvs(22)
3327
3679
  },
@@ -3330,12 +3682,13 @@ var styles28 = reactNative.StyleSheet.create({
3330
3682
  marginTop: vs(8)
3331
3683
  }
3332
3684
  });
3333
- function LabelValue({ label, value, iconName, iconColor, style }) {
3685
+ function LabelValueBase({ label, value, iconName, iconColor, style }) {
3334
3686
  const { colors } = useTheme();
3335
3687
  const resolvedIcon = iconName ? renderIcon(iconName, ms(14), iconColor ?? colors.foregroundMuted) : null;
3336
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles29.container, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles29.labelSide }, resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles29.icon }, resolvedIcon) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles29.label, { color: colors.foregroundMuted }], allowFontScaling: true }, label)), typeof value === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles29.value, { color: colors.foreground }], allowFontScaling: true }, value) : value);
3688
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles31.container, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles31.labelSide }, resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles31.icon }, resolvedIcon) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles31.label, { color: colors.foregroundMuted }], allowFontScaling: true }, label)), typeof value === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles31.value, { color: colors.foreground }], allowFontScaling: true }, value) : value);
3337
3689
  }
3338
- var styles29 = reactNative.StyleSheet.create({
3690
+ var LabelValue = React26__default.default.memo(LabelValueBase);
3691
+ var styles31 = reactNative.StyleSheet.create({
3339
3692
  container: {
3340
3693
  flexDirection: "row",
3341
3694
  justifyContent: "space-between",
@@ -3352,12 +3705,12 @@ var styles29 = reactNative.StyleSheet.create({
3352
3705
  justifyContent: "center"
3353
3706
  },
3354
3707
  label: {
3355
- fontFamily: "Poppins-Regular",
3708
+ fontFamily: "Sohne-Regular",
3356
3709
  fontSize: ms(13),
3357
3710
  lineHeight: mvs(18)
3358
3711
  },
3359
3712
  value: {
3360
- fontFamily: "Poppins-Medium",
3713
+ fontFamily: "Sohne-Medium",
3361
3714
  fontSize: ms(14),
3362
3715
  lineHeight: mvs(20),
3363
3716
  textAlign: "right"
@@ -3392,27 +3745,41 @@ function MonthPicker({ value, onChange, locale = "en", formatLabel, style }) {
3392
3745
  onChange({ month: value.month + 1, year: value.year });
3393
3746
  }
3394
3747
  };
3395
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles30.container, style] }, /* @__PURE__ */ React26__default.default.createElement(
3748
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles32.container, style], accessibilityRole: "adjustable", accessibilityLabel: getLabel() }, /* @__PURE__ */ React26__default.default.createElement(
3396
3749
  reactNative.TouchableOpacity,
3397
3750
  {
3398
- style: styles30.arrow,
3751
+ style: styles32.arrow,
3399
3752
  onPress: handlePrev,
3400
3753
  activeOpacity: 0.6,
3401
- touchSoundDisabled: true
3754
+ touchSoundDisabled: true,
3755
+ accessibilityRole: "button",
3756
+ accessibilityLabel: "Previous month",
3757
+ hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }
3402
3758
  },
3403
3759
  /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "chevron-left", size: 22, color: colors.foreground })
3404
- ), /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles30.label, { color: colors.foreground }], allowFontScaling: true }, getLabel()), /* @__PURE__ */ React26__default.default.createElement(
3760
+ ), /* @__PURE__ */ React26__default.default.createElement(
3761
+ reactNative.Text,
3762
+ {
3763
+ style: [styles32.label, { color: colors.foreground }],
3764
+ allowFontScaling: true,
3765
+ accessibilityLiveRegion: "polite"
3766
+ },
3767
+ getLabel()
3768
+ ), /* @__PURE__ */ React26__default.default.createElement(
3405
3769
  reactNative.TouchableOpacity,
3406
3770
  {
3407
- style: styles30.arrow,
3771
+ style: styles32.arrow,
3408
3772
  onPress: handleNext,
3409
3773
  activeOpacity: 0.6,
3410
- touchSoundDisabled: true
3774
+ touchSoundDisabled: true,
3775
+ accessibilityRole: "button",
3776
+ accessibilityLabel: "Next month",
3777
+ hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }
3411
3778
  },
3412
3779
  /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "chevron-right", size: 22, color: colors.foreground })
3413
3780
  ));
3414
3781
  }
3415
- var styles30 = reactNative.StyleSheet.create({
3782
+ var styles32 = reactNative.StyleSheet.create({
3416
3783
  container: {
3417
3784
  flexDirection: "row",
3418
3785
  alignItems: "center",
@@ -3425,25 +3792,13 @@ var styles30 = reactNative.StyleSheet.create({
3425
3792
  justifyContent: "center"
3426
3793
  },
3427
3794
  label: {
3428
- fontFamily: "Poppins-Medium",
3795
+ fontFamily: "Sohne-Medium",
3429
3796
  fontSize: ms(17),
3430
3797
  lineHeight: mvs(24),
3431
3798
  textAlign: "center",
3432
3799
  minWidth: s(160)
3433
3800
  }
3434
3801
  });
3435
- function useHover() {
3436
- const [hovered, setHovered] = React26.useState(false);
3437
- const onMouseEnter = React26.useCallback(() => setHovered(true), []);
3438
- const onMouseLeave = React26.useCallback(() => setHovered(false), []);
3439
- if (reactNative.Platform.OS !== "web") {
3440
- return { hovered: false, hoverHandlers: {} };
3441
- }
3442
- return { hovered, hoverHandlers: { onMouseEnter, onMouseLeave } };
3443
- }
3444
-
3445
- // src/components/MediaCard/MediaCard.tsx
3446
- var nativeDriver13 = reactNative.Platform.OS !== "web";
3447
3802
  var aspectRatioMap = {
3448
3803
  "1:1": 1,
3449
3804
  "4:3": 3 / 4,
@@ -3451,7 +3806,7 @@ var aspectRatioMap = {
3451
3806
  "4:5": 5 / 4,
3452
3807
  "3:2": 2 / 3
3453
3808
  };
3454
- function MediaCard({
3809
+ function MediaCardBase({
3455
3810
  imageSource,
3456
3811
  aspectRatio = "4:3",
3457
3812
  badge,
@@ -3465,19 +3820,17 @@ function MediaCard({
3465
3820
  onPress,
3466
3821
  style,
3467
3822
  imageStyle,
3468
- footer
3823
+ footer,
3824
+ accessibilityLabel
3469
3825
  }) {
3470
3826
  const { colors } = useTheme();
3471
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
3472
3827
  const { hovered, hoverHandlers } = useHover();
3473
- const handlePressIn = () => {
3474
- if (!onPress) return;
3475
- reactNative.Animated.spring(scale2, { toValue: 0.98, useNativeDriver: nativeDriver13, speed: 40, bounciness: 0 }).start();
3476
- };
3477
- const handlePressOut = () => {
3478
- if (!onPress) return;
3479
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver13, speed: 40, bounciness: 4 }).start();
3480
- };
3828
+ const { animatedStyle, onPressIn, onPressOut } = usePressScale({
3829
+ pressScale: PRESS_SCALE.card,
3830
+ pressInSpring: SPRINGS.surfacePressIn,
3831
+ pressOutSpring: SPRINGS.surfacePressOut,
3832
+ disabled: !onPress
3833
+ });
3481
3834
  const handlePress = () => {
3482
3835
  if (!onPress) return;
3483
3836
  impactLight();
@@ -3485,62 +3838,67 @@ function MediaCard({
3485
3838
  };
3486
3839
  const ratio = aspectRatioMap[aspectRatio];
3487
3840
  const resolvedActionIcon = actionIconName ? renderIcon(actionIconName, 18, actionActive ? colors.primary : colors.background) : actionIcon ?? renderIcon("heart", 18, actionActive ? colors.primary : colors.background);
3841
+ const a11yLabel = accessibilityLabel ?? [title, subtitle].filter(Boolean).join(". ");
3488
3842
  const cardContent = /* @__PURE__ */ React26__default.default.createElement(
3489
3843
  reactNative.View,
3490
3844
  {
3491
3845
  style: [
3492
- styles31.card,
3493
- hovered && styles31.cardHovered,
3846
+ styles33.card,
3847
+ hovered && styles33.cardHovered,
3494
3848
  style
3495
3849
  ],
3496
3850
  ...reactNative.Platform.OS === "web" ? hoverHandlers : {}
3497
3851
  },
3498
- /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles31.imageContainer, imageStyle] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: { paddingTop: `${ratio * 100}%` } }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: reactNative.StyleSheet.absoluteFill }, imageSource ? /* @__PURE__ */ React26__default.default.createElement(
3852
+ /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles33.imageContainer, imageStyle] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: { paddingTop: `${ratio * 100}%` } }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: reactNative.StyleSheet.absoluteFill }, imageSource ? /* @__PURE__ */ React26__default.default.createElement(
3499
3853
  reactNative.Image,
3500
3854
  {
3501
3855
  source: imageSource,
3502
- style: styles31.image,
3856
+ style: styles33.image,
3503
3857
  resizeMode: "cover"
3504
3858
  }
3505
- ) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles31.imagePlaceholder, { backgroundColor: colors.surface }] }))), badge && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles31.badgeContainer }, badge), (onActionPress || actionIcon || actionIconName) && /* @__PURE__ */ React26__default.default.createElement(
3859
+ ) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles33.imagePlaceholder, { backgroundColor: colors.surface }] }))), badge && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.badgeContainer }, badge), (onActionPress || actionIcon || actionIconName) && /* @__PURE__ */ React26__default.default.createElement(
3506
3860
  reactNative.TouchableOpacity,
3507
3861
  {
3508
- style: [styles31.actionButton, { backgroundColor: "rgba(0,0,0,0.24)" }],
3862
+ style: [styles33.actionButton, { backgroundColor: "rgba(0,0,0,0.24)" }],
3509
3863
  onPress: () => {
3510
3864
  impactLight();
3511
3865
  onActionPress?.();
3512
3866
  },
3513
3867
  activeOpacity: 0.8,
3514
- touchSoundDisabled: true
3868
+ touchSoundDisabled: true,
3869
+ accessibilityRole: "button",
3870
+ accessibilityLabel: actionIconName ?? "action",
3871
+ accessibilityState: { selected: actionActive }
3515
3872
  },
3516
3873
  resolvedActionIcon
3517
3874
  )),
3518
- (title || subtitle || caption || footer) && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles31.meta }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles31.title, { color: colors.foreground }], numberOfLines: 2, allowFontScaling: true }, title) : null, subtitle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles31.subtitle, { color: colors.foregroundSubtle }], numberOfLines: 1, allowFontScaling: true }, subtitle) : null, caption ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles31.caption, { color: colors.foregroundMuted }], numberOfLines: 1, allowFontScaling: true }, caption) : null, footer)
3875
+ (title || subtitle || caption || footer) && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.meta }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles33.title, { color: colors.foreground }], numberOfLines: 2, allowFontScaling: true }, title) : null, subtitle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles33.subtitle, { color: colors.foregroundSubtle }], numberOfLines: 1, allowFontScaling: true }, subtitle) : null, caption ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles33.caption, { color: colors.foregroundMuted }], numberOfLines: 1, allowFontScaling: true }, caption) : null, footer)
3519
3876
  );
3520
3877
  if (onPress) {
3521
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React26__default.default.createElement(
3878
+ return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: animatedStyle }, /* @__PURE__ */ React26__default.default.createElement(
3522
3879
  reactNative.TouchableOpacity,
3523
3880
  {
3524
3881
  onPress: handlePress,
3525
- onPressIn: handlePressIn,
3526
- onPressOut: handlePressOut,
3882
+ onPressIn,
3883
+ onPressOut,
3527
3884
  activeOpacity: 1,
3528
- touchSoundDisabled: true
3885
+ touchSoundDisabled: true,
3886
+ accessibilityRole: "button",
3887
+ accessibilityLabel: a11yLabel
3529
3888
  },
3530
3889
  cardContent
3531
3890
  ));
3532
3891
  }
3533
3892
  return cardContent;
3534
3893
  }
3535
- var styles31 = reactNative.StyleSheet.create({
3894
+ var MediaCard = React26__default.default.memo(MediaCardBase);
3895
+ var styles33 = reactNative.StyleSheet.create({
3536
3896
  card: {
3537
3897
  borderRadius: RADIUS.md,
3538
- // 14px — Airbnb property card spec
3539
3898
  overflow: "hidden",
3540
3899
  backgroundColor: "transparent"
3541
3900
  },
3542
3901
  cardHovered: {
3543
- // Web hover: lift shadow
3544
3902
  ...SHADOWS.md
3545
3903
  },
3546
3904
  imageContainer: {
@@ -3576,98 +3934,99 @@ var styles31 = reactNative.StyleSheet.create({
3576
3934
  gap: vs(2)
3577
3935
  },
3578
3936
  title: {
3579
- fontFamily: "Poppins-SemiBold",
3937
+ fontFamily: "Sohne-SemiBold",
3580
3938
  fontSize: ms(14),
3581
3939
  lineHeight: mvs(20)
3582
3940
  },
3583
3941
  subtitle: {
3584
- fontFamily: "Poppins-Regular",
3942
+ fontFamily: "Sohne-Regular",
3585
3943
  fontSize: ms(13),
3586
3944
  lineHeight: mvs(18)
3587
3945
  },
3588
3946
  caption: {
3589
- fontFamily: "Poppins-Regular",
3947
+ fontFamily: "Sohne-Regular",
3590
3948
  fontSize: ms(12),
3591
3949
  lineHeight: mvs(16)
3592
3950
  }
3593
3951
  });
3594
- var nativeDriver14 = reactNative.Platform.OS !== "web";
3595
- function CategoryChip({
3952
+ var CategoryChip = React26__default.default.memo(function CategoryChip2({
3596
3953
  item,
3597
3954
  selected,
3598
- onPress
3955
+ onSelect
3599
3956
  }) {
3600
3957
  const { colors } = useTheme();
3601
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
3602
- const handlePressIn = () => {
3603
- reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver14, speed: 40, bounciness: 0 }).start();
3604
- };
3605
- const handlePressOut = () => {
3606
- reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver14, speed: 40, bounciness: 4 }).start();
3607
- };
3608
- const bgColor = selected ? colors.primary : colors.surface;
3609
- const textColor = selected ? colors.primaryForeground : colors.foregroundSubtle;
3610
- const borderColor = selected ? colors.primary : colors.border;
3611
- const resolvedIcon = typeof item.icon === "string" ? renderIcon(item.icon, 16, textColor) : item.icon ?? null;
3612
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React26__default.default.createElement(
3958
+ const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
3959
+ pressScale: PRESS_SCALE.chip
3960
+ });
3961
+ const progress = useColorTransition(selected);
3962
+ const surfaceStyle = Animated9.useAnimatedStyle(() => ({
3963
+ backgroundColor: Animated9.interpolateColor(progress.value, [0, 1], [colors.surface, colors.primary]),
3964
+ borderColor: Animated9.interpolateColor(progress.value, [0, 1], [colors.border, colors.primary])
3965
+ }));
3966
+ const textColorStyle = Animated9.useAnimatedStyle(() => ({
3967
+ color: Animated9.interpolateColor(progress.value, [0, 1], [colors.foregroundSubtle, colors.primaryForeground])
3968
+ }));
3969
+ const iconColor = selected ? colors.primaryForeground : colors.foregroundSubtle;
3970
+ const resolvedIcon = typeof item.icon === "string" ? renderIcon(item.icon, 16, iconColor) : item.icon ?? null;
3971
+ return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: scaleStyle, ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
3613
3972
  reactNative.TouchableOpacity,
3614
3973
  {
3615
- style: [
3616
- styles32.chip,
3617
- {
3618
- backgroundColor: bgColor,
3619
- borderColor
3620
- }
3621
- ],
3622
- onPress,
3623
- onPressIn: handlePressIn,
3624
- onPressOut: handlePressOut,
3974
+ onPress: () => onSelect(item.value),
3975
+ onPressIn,
3976
+ onPressOut,
3625
3977
  activeOpacity: 1,
3626
- touchSoundDisabled: true
3978
+ touchSoundDisabled: true,
3979
+ accessibilityRole: "button",
3980
+ accessibilityLabel: item.label,
3981
+ accessibilityState: { selected }
3627
3982
  },
3628
- resolvedIcon && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles32.chipIcon }, resolvedIcon),
3629
- /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles32.chipLabel, { color: textColor }], allowFontScaling: true }, item.label),
3630
- item.badge !== void 0 && item.badge > 0 && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles32.chipBadge, { backgroundColor: colors.primary }] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles32.chipBadgeText, { color: colors.primaryForeground }] }, Math.min(item.badge, 99)))
3983
+ /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles34.chip, surfaceStyle] }, resolvedIcon && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles34.chipIcon }, resolvedIcon), /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.Text, { style: [styles34.chipLabel, textColorStyle], allowFontScaling: true }, item.label), item.badge !== void 0 && item.badge > 0 && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles34.chipBadge, { backgroundColor: colors.primary }] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles34.chipBadgeText, { color: colors.primaryForeground }] }, Math.min(item.badge, 99))))
3631
3984
  ));
3632
- }
3985
+ });
3633
3986
  function CategoryStrip({
3634
3987
  categories,
3635
3988
  value,
3636
3989
  onValueChange,
3637
3990
  multiSelect = false,
3638
3991
  style,
3639
- itemStyle
3992
+ itemStyle,
3993
+ accessibilityLabel
3640
3994
  }) {
3641
3995
  const selected = Array.isArray(value) ? value : value ? [value] : [];
3642
- const handlePress = (v) => {
3643
- selectionAsync();
3644
- if (multiSelect) {
3645
- const current = Array.isArray(value) ? value : value ? [value] : [];
3646
- const next = current.includes(v) ? current.filter((x) => x !== v) : [...current, v];
3647
- onValueChange?.(next);
3648
- } else {
3649
- onValueChange?.(v === value ? "" : v);
3650
- }
3651
- };
3996
+ const handlePress = React26.useCallback(
3997
+ (v) => {
3998
+ selectionAsync();
3999
+ if (multiSelect) {
4000
+ const current = Array.isArray(value) ? value : value ? [value] : [];
4001
+ const next = current.includes(v) ? current.filter((x) => x !== v) : [...current, v];
4002
+ onValueChange?.(next);
4003
+ } else {
4004
+ onValueChange?.(v === value ? "" : v);
4005
+ }
4006
+ },
4007
+ [multiSelect, value, onValueChange]
4008
+ );
3652
4009
  return /* @__PURE__ */ React26__default.default.createElement(
3653
4010
  reactNative.ScrollView,
3654
4011
  {
3655
4012
  horizontal: true,
3656
4013
  showsHorizontalScrollIndicator: false,
3657
- contentContainerStyle: [styles32.container, style],
3658
- style: styles32.scroll
4014
+ contentContainerStyle: [styles34.container, style],
4015
+ style: styles34.scroll,
4016
+ accessibilityRole: multiSelect ? void 0 : "radiogroup",
4017
+ accessibilityLabel
3659
4018
  },
3660
4019
  categories.map((cat) => /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { key: cat.value, style: itemStyle }, /* @__PURE__ */ React26__default.default.createElement(
3661
4020
  CategoryChip,
3662
4021
  {
3663
4022
  item: cat,
3664
4023
  selected: selected.includes(cat.value),
3665
- onPress: () => handlePress(cat.value)
4024
+ onSelect: handlePress
3666
4025
  }
3667
4026
  )))
3668
4027
  );
3669
4028
  }
3670
- var styles32 = reactNative.StyleSheet.create({
4029
+ var styles34 = reactNative.StyleSheet.create({
3671
4030
  scroll: {
3672
4031
  flexGrow: 0
3673
4032
  },
@@ -3691,7 +4050,7 @@ var styles32 = reactNative.StyleSheet.create({
3691
4050
  justifyContent: "center"
3692
4051
  },
3693
4052
  chipLabel: {
3694
- fontFamily: "Poppins-Medium",
4053
+ fontFamily: "Sohne-Medium",
3695
4054
  fontSize: ms(13)
3696
4055
  },
3697
4056
  chipBadge: {
@@ -3703,67 +4062,50 @@ var styles32 = reactNative.StyleSheet.create({
3703
4062
  justifyContent: "center"
3704
4063
  },
3705
4064
  chipBadgeText: {
3706
- fontFamily: "Poppins-Bold",
4065
+ fontFamily: "Sohne-Bold",
3707
4066
  fontSize: ms(9),
3708
4067
  lineHeight: 14
3709
4068
  }
3710
4069
  });
3711
- var nativeDriver15 = reactNative.Platform.OS !== "web";
3712
4070
  function Pressable2({
3713
4071
  children,
3714
4072
  onPress,
3715
- pressScale = 0.98,
3716
- bounciness = 4,
4073
+ pressScale = PRESS_SCALE.card,
3717
4074
  haptics = true,
3718
4075
  style,
3719
4076
  disabled,
3720
4077
  hoverScale = 1.02,
3721
4078
  ...touchableProps
3722
4079
  }) {
3723
- const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
3724
- const { hovered, hoverHandlers } = useHover();
3725
- const handlePressIn = () => {
3726
- if (disabled) return;
3727
- reactNative.Animated.spring(scale2, {
3728
- toValue: pressScale,
3729
- useNativeDriver: nativeDriver15,
3730
- speed: 40,
3731
- bounciness: 0
3732
- }).start();
3733
- };
3734
- const handlePressOut = () => {
3735
- if (disabled) return;
3736
- reactNative.Animated.spring(scale2, {
3737
- toValue: 1,
3738
- useNativeDriver: nativeDriver15,
3739
- speed: 40,
3740
- bounciness
3741
- }).start();
3742
- };
4080
+ const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
4081
+ pressScale,
4082
+ hoverScale,
4083
+ pressInSpring: SPRINGS.surfacePressIn,
4084
+ pressOutSpring: SPRINGS.surfacePressOut,
4085
+ disabled
4086
+ });
3743
4087
  const handlePress = () => {
3744
4088
  if (disabled || !onPress) return;
3745
4089
  if (haptics) impactLight();
3746
4090
  onPress();
3747
4091
  };
3748
- const hoverScaleValue = hovered && hoverScale !== 1 ? hoverScale : 1;
3749
4092
  return /* @__PURE__ */ React26__default.default.createElement(
3750
- reactNative.Animated.View,
4093
+ Animated9__default.default.View,
3751
4094
  {
3752
- style: [
3753
- { transform: [{ scale: reactNative.Animated.multiply(scale2, hoverScaleValue) }] },
3754
- style
3755
- ],
4095
+ style: [animatedStyle, style],
3756
4096
  ...reactNative.Platform.OS === "web" ? hoverHandlers : {}
3757
4097
  },
3758
4098
  /* @__PURE__ */ React26__default.default.createElement(
3759
4099
  reactNative.TouchableOpacity,
3760
4100
  {
3761
4101
  onPress: handlePress,
3762
- onPressIn: handlePressIn,
3763
- onPressOut: handlePressOut,
4102
+ onPressIn,
4103
+ onPressOut,
3764
4104
  activeOpacity: 1,
3765
4105
  disabled,
3766
4106
  touchSoundDisabled: true,
4107
+ accessibilityRole: "button",
4108
+ accessibilityState: { disabled: !!disabled },
3767
4109
  ...touchableProps
3768
4110
  },
3769
4111
  children
@@ -3771,12 +4113,12 @@ function Pressable2({
3771
4113
  );
3772
4114
  }
3773
4115
  var weightMap = {
3774
- normal: "Poppins-Regular",
3775
- medium: "Poppins-Medium",
3776
- semibold: "Poppins-SemiBold",
3777
- bold: "Poppins-Bold"
4116
+ normal: "Sohne-Regular",
4117
+ medium: "Sohne-Medium",
4118
+ semibold: "Sohne-SemiBold",
4119
+ bold: "Sohne-Bold"
3778
4120
  };
3779
- function DetailRow({
4121
+ function DetailRowBase({
3780
4122
  label,
3781
4123
  value,
3782
4124
  separator = "dotted",
@@ -3802,23 +4144,24 @@ function DetailRow({
3802
4144
  borderColor: "rgba(128,128,128,0.3)",
3803
4145
  marginHorizontal: s(4)
3804
4146
  };
3805
- return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles33.row, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.labelSide }, resolvedLeftIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.icon }, resolvedLeftIcon) : null, typeof label === "string" ? /* @__PURE__ */ React26__default.default.createElement(
4147
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles35.row, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.labelSide }, resolvedLeftIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.icon }, resolvedLeftIcon) : null, typeof label === "string" ? /* @__PURE__ */ React26__default.default.createElement(
3806
4148
  reactNative.Text,
3807
4149
  {
3808
- style: [styles33.labelText, { color: colors.foregroundMuted, fontFamily: weightMap[labelWeight] }, labelStyle],
4150
+ style: [styles35.labelText, { color: colors.foregroundMuted, fontFamily: weightMap[labelWeight] }, labelStyle],
3809
4151
  allowFontScaling: true
3810
4152
  },
3811
4153
  label
3812
- ) : label), separatorStyle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: separatorStyle }) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.spacer }), /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.valueSide }, typeof value === "string" ? /* @__PURE__ */ React26__default.default.createElement(
4154
+ ) : label), separatorStyle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: separatorStyle }) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.spacer }), /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.valueSide }, typeof value === "string" ? /* @__PURE__ */ React26__default.default.createElement(
3813
4155
  reactNative.Text,
3814
4156
  {
3815
- style: [styles33.valueText, { color: valueColor ?? colors.foreground }, valueStyle],
4157
+ style: [styles35.valueText, { color: valueColor ?? colors.foreground }, valueStyle],
3816
4158
  allowFontScaling: true
3817
4159
  },
3818
4160
  value
3819
- ) : value, resolvedRightIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.icon }, resolvedRightIcon) : null));
4161
+ ) : value, resolvedRightIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.icon }, resolvedRightIcon) : null));
3820
4162
  }
3821
- var styles33 = reactNative.StyleSheet.create({
4163
+ var DetailRow = React26__default.default.memo(DetailRowBase);
4164
+ var styles35 = reactNative.StyleSheet.create({
3822
4165
  row: {
3823
4166
  flexDirection: "row",
3824
4167
  alignItems: "center",
@@ -3848,11 +4191,101 @@ var styles33 = reactNative.StyleSheet.create({
3848
4191
  flexShrink: 0
3849
4192
  },
3850
4193
  valueText: {
3851
- fontFamily: "Poppins-SemiBold",
4194
+ fontFamily: "Sohne-SemiBold",
3852
4195
  fontSize: ms(13),
3853
4196
  lineHeight: mvs(18)
3854
4197
  }
3855
4198
  });
4199
+ function Form({ children, style }) {
4200
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles36.form, style] }, children);
4201
+ }
4202
+ function FormField({
4203
+ children,
4204
+ label,
4205
+ error,
4206
+ required,
4207
+ style,
4208
+ labelStyle,
4209
+ errorStyle
4210
+ }) {
4211
+ const { colors } = useTheme();
4212
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles36.field, style] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles36.label, { color: colors.foreground }, labelStyle], allowFontScaling: true }, label, required ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: { color: colors.destructive } }, " *") : null) : null, children, error ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles36.error, { color: colors.destructive }, errorStyle], allowFontScaling: true }, error) : null);
4213
+ }
4214
+ function FormSection({ children, title, description, style }) {
4215
+ const { colors } = useTheme();
4216
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles36.section, style] }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles36.sectionHeader }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles36.sectionTitle, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles36.sectionDescription, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null) : null, children);
4217
+ }
4218
+ function FormFooter({ children, style }) {
4219
+ return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles36.footer, style] }, children);
4220
+ }
4221
+ Form.Field = FormField;
4222
+ Form.Section = FormSection;
4223
+ Form.Footer = FormFooter;
4224
+ var styles36 = reactNative.StyleSheet.create({
4225
+ form: {
4226
+ gap: vs(16)
4227
+ },
4228
+ field: {
4229
+ gap: vs(6)
4230
+ },
4231
+ label: {
4232
+ fontFamily: "Sohne-Medium",
4233
+ fontSize: 14,
4234
+ lineHeight: 20
4235
+ },
4236
+ error: {
4237
+ fontFamily: "Sohne-Regular",
4238
+ fontSize: 12,
4239
+ lineHeight: 16
4240
+ },
4241
+ section: {
4242
+ gap: vs(16)
4243
+ },
4244
+ sectionHeader: {
4245
+ gap: vs(4)
4246
+ },
4247
+ sectionTitle: {
4248
+ fontFamily: "Sohne-SemiBold",
4249
+ fontSize: 16,
4250
+ lineHeight: 24
4251
+ },
4252
+ sectionDescription: {
4253
+ fontFamily: "Sohne-Regular",
4254
+ fontSize: 14,
4255
+ lineHeight: 20
4256
+ },
4257
+ footer: {
4258
+ flexDirection: "row",
4259
+ gap: s(12),
4260
+ paddingTop: vs(8)
4261
+ }
4262
+ });
4263
+ var defaultKeyExtractor = (item, index) => {
4264
+ const id = item?.id;
4265
+ return id !== void 0 ? String(id) : String(index);
4266
+ };
4267
+ function VirtualListInner({ itemHeight, keyExtractor, renderItem, ...props }, ref) {
4268
+ const getItemLayout = React26.useCallback(
4269
+ (_data, index) => ({
4270
+ length: itemHeight ?? 0,
4271
+ offset: (itemHeight ?? 0) * index,
4272
+ index
4273
+ }),
4274
+ [itemHeight]
4275
+ );
4276
+ return /* @__PURE__ */ React26__default.default.createElement(
4277
+ reactNative.FlatList,
4278
+ {
4279
+ ref,
4280
+ keyExtractor: keyExtractor ?? defaultKeyExtractor,
4281
+ renderItem,
4282
+ getItemLayout: itemHeight !== void 0 ? getItemLayout : void 0,
4283
+ removeClippedSubviews: true,
4284
+ ...props
4285
+ }
4286
+ );
4287
+ }
4288
+ var VirtualList = React26__default.default.forwardRef(VirtualListInner);
3856
4289
 
3857
4290
  // src/utils/typography.ts
3858
4291
  function getResponsiveFontSize(text, maxSize, steps = [
@@ -3903,13 +4336,23 @@ exports.CurrencyInput = CurrencyInput;
3903
4336
  exports.CurrencyInputLarge = CurrencyInput;
3904
4337
  exports.DetailRow = DetailRow;
3905
4338
  exports.EmptyState = EmptyState;
4339
+ exports.Form = Form;
4340
+ exports.FormField = FormField;
4341
+ exports.FormFooter = FormFooter;
4342
+ exports.FormSection = FormSection;
3906
4343
  exports.ICON_SIZES = ICON_SIZES;
3907
4344
  exports.Icon = Icon;
3908
4345
  exports.IconButton = IconButton;
3909
4346
  exports.Input = Input;
3910
4347
  exports.LabelValue = LabelValue;
4348
+ exports.ListGroup = ListGroup;
4349
+ exports.ListGroupFooter = ListGroupFooter;
4350
+ exports.ListGroupHeader = ListGroupHeader;
3911
4351
  exports.ListItem = ListItem;
3912
4352
  exports.MediaCard = MediaCard;
4353
+ exports.MenuGroup = MenuGroup;
4354
+ exports.MenuGroupFooter = MenuGroupFooter;
4355
+ exports.MenuGroupHeader = MenuGroupHeader;
3913
4356
  exports.MenuItem = MenuItem;
3914
4357
  exports.MonthPicker = MonthPicker;
3915
4358
  exports.Pressable = Pressable2;
@@ -3933,6 +4376,8 @@ exports.Textarea = Textarea;
3933
4376
  exports.ThemeProvider = ThemeProvider;
3934
4377
  exports.ToastProvider = ToastProvider;
3935
4378
  exports.Toggle = Toggle;
4379
+ exports.VirtualList = VirtualList;
4380
+ exports.configureIconFamilies = configureIconFamilies;
3936
4381
  exports.defaultDark = defaultDark;
3937
4382
  exports.defaultLight = defaultLight;
3938
4383
  exports.deriveColors = deriveColors;