@krizaka/ui 3.2.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (498) hide show
  1. package/dist/activity-feed.d.ts +199 -0
  2. package/dist/activity-feed.js +155 -0
  3. package/dist/activity-feed.js.map +1 -0
  4. package/dist/argument-card.js +3 -3
  5. package/dist/{chunk-I5RVM5CW.js → chunk-2FRWNSRO.js} +2 -6
  6. package/dist/chunk-2FRWNSRO.js.map +1 -0
  7. package/dist/chunk-7Z4KHPFC.js +42 -0
  8. package/dist/chunk-7Z4KHPFC.js.map +1 -0
  9. package/dist/chunk-BTMFZ66D.js +135 -0
  10. package/dist/chunk-BTMFZ66D.js.map +1 -0
  11. package/dist/chunk-C2BRIFJG.js +13 -0
  12. package/dist/chunk-C2BRIFJG.js.map +1 -0
  13. package/dist/chunk-KDXRYUD3.js +39 -0
  14. package/dist/chunk-KDXRYUD3.js.map +1 -0
  15. package/dist/{chunk-2PUDI7JS.js → chunk-ZKVQGXLD.js} +5 -3
  16. package/dist/{chunk-2PUDI7JS.js.map → chunk-ZKVQGXLD.js.map} +1 -1
  17. package/dist/command.js +1 -1
  18. package/dist/confirm-button.js +1 -1
  19. package/dist/data-table.js +101 -133
  20. package/dist/data-table.js.map +1 -1
  21. package/dist/date-picker.d.ts +3 -1
  22. package/dist/date-picker.js +13 -13
  23. package/dist/date-picker.js.map +1 -1
  24. package/dist/description-list.d.ts +105 -0
  25. package/dist/description-list.js +49 -0
  26. package/dist/description-list.js.map +1 -0
  27. package/dist/dropdown-menu.js +1 -1
  28. package/dist/filter-bar.js +3 -2
  29. package/dist/form.d.ts +23 -12
  30. package/dist/form.js +11 -47
  31. package/dist/form.js.map +1 -1
  32. package/dist/glow-card.js +1 -1
  33. package/dist/image-cropper.js +3 -1
  34. package/dist/image-cropper.js.map +1 -1
  35. package/dist/index.js +13 -66
  36. package/dist/index.js.map +1 -1
  37. package/dist/kanban.d.ts +132 -0
  38. package/dist/kanban.js +187 -0
  39. package/dist/kanban.js.map +1 -0
  40. package/dist/list.d.ts +153 -0
  41. package/dist/list.js +130 -0
  42. package/dist/list.js.map +1 -0
  43. package/dist/map.d.ts +463 -0
  44. package/dist/map.js +952 -0
  45. package/dist/map.js.map +1 -0
  46. package/dist/marquee.js +1 -1
  47. package/dist/motion.css +12 -1
  48. package/dist/native/form.d.ts +60 -15
  49. package/dist/native/form.js +103 -42
  50. package/dist/native/form.js.map +1 -1
  51. package/dist/native/map.d.ts +200 -0
  52. package/dist/native/map.js +673 -0
  53. package/dist/native/map.js.map +1 -0
  54. package/dist/native/media-picker.d.ts +58 -0
  55. package/dist/native/media-picker.js +63 -0
  56. package/dist/native/media-picker.js.map +1 -0
  57. package/dist/native.d.ts +772 -6
  58. package/dist/native.js +2493 -741
  59. package/dist/native.js.map +1 -1
  60. package/dist/nav-bar.js +1 -1
  61. package/dist/page-hero.js +3 -3
  62. package/dist/popover.js +1 -1
  63. package/dist/radio-group.d.ts +66 -32
  64. package/dist/radio-group.js +54 -10
  65. package/dist/radio-group.js.map +1 -1
  66. package/dist/slider.d.ts +96 -35
  67. package/dist/slider.js +67 -13
  68. package/dist/slider.js.map +1 -1
  69. package/dist/stat.d.ts +31 -2
  70. package/dist/stat.js +21 -4
  71. package/dist/stat.js.map +1 -1
  72. package/dist/terminal-replay.js +34 -60
  73. package/dist/terminal-replay.js.map +1 -1
  74. package/dist/toast.js +1 -1
  75. package/dist/tooltip.js +1 -1
  76. package/dist/tree-view.d.ts +111 -0
  77. package/dist/tree-view.js +154 -0
  78. package/dist/tree-view.js.map +1 -0
  79. package/dist/video-player.js +3 -1
  80. package/dist/video-player.js.map +1 -1
  81. package/package.json +148 -11
  82. package/registry/achievement.json +1 -1
  83. package/registry/action-bar.json +1 -1
  84. package/registry/action-sheet.json +121 -0
  85. package/registry/activity-feed.json +468 -0
  86. package/registry/alert.json +1 -1
  87. package/registry/app-shell.json +1 -1
  88. package/registry/argument-card.json +1 -1
  89. package/registry/audio-player.json +1 -1
  90. package/registry/auth-layout.json +1 -1
  91. package/registry/avatar.json +58 -3
  92. package/registry/badge.json +1 -1
  93. package/registry/button.json +1 -1
  94. package/registry/card-grid.json +1 -1
  95. package/registry/card.json +1 -1
  96. package/registry/catalogue-page.json +1 -1
  97. package/registry/changelog-page.json +1 -1
  98. package/registry/checkbox.json +1 -1
  99. package/registry/chip-link.json +1 -1
  100. package/registry/chip.json +1 -1
  101. package/registry/choice-grid.json +1 -1
  102. package/registry/code-block.json +1 -1
  103. package/registry/combobox.json +226 -4
  104. package/registry/command.json +1 -1
  105. package/registry/component-page.json +1 -1
  106. package/registry/confirm-button.json +1 -1
  107. package/registry/contact-page.json +1 -1
  108. package/registry/continue-prompt.json +1 -1
  109. package/registry/countdown.json +1 -1
  110. package/registry/cta-panel.json +1 -1
  111. package/registry/dashboard-layout.json +1 -1
  112. package/registry/data-table.json +1 -1
  113. package/registry/date-picker.json +18 -4
  114. package/registry/decision-list.json +1 -1
  115. package/registry/description-list.json +232 -0
  116. package/registry/detail-layout.json +1 -1
  117. package/registry/dialog.json +75 -4
  118. package/registry/docs-article-page.json +1 -1
  119. package/registry/docs-hub-page.json +1 -1
  120. package/registry/docs-layout.json +1 -1
  121. package/registry/dropdown-menu.json +1 -1
  122. package/registry/empty-state.json +1 -1
  123. package/registry/error-page.json +1 -1
  124. package/registry/examples/action-sheet/native/video-actions.d.ts +4 -0
  125. package/registry/examples/action-sheet/native/video-actions.dark.png +0 -0
  126. package/registry/examples/action-sheet/native/video-actions.js +30 -0
  127. package/registry/examples/action-sheet/native/video-actions.light.png +0 -0
  128. package/registry/examples/action-sheet/native/video-actions.tsx +24 -0
  129. package/registry/examples/activity-feed/job-activity.d.ts +4 -0
  130. package/registry/examples/activity-feed/job-activity.js +21 -0
  131. package/registry/examples/activity-feed/job-activity.tsx +17 -0
  132. package/registry/examples/activity-feed/live.d.ts +4 -0
  133. package/registry/examples/activity-feed/live.js +23 -0
  134. package/registry/examples/activity-feed/live.tsx +24 -0
  135. package/registry/examples/activity-feed/native/notifications.d.ts +4 -0
  136. package/registry/examples/activity-feed/native/notifications.dark.png +0 -0
  137. package/registry/examples/activity-feed/native/notifications.js +18 -0
  138. package/registry/examples/activity-feed/native/notifications.light.png +0 -0
  139. package/registry/examples/activity-feed/native/notifications.tsx +18 -0
  140. package/registry/examples/activity-feed/timeline.d.ts +4 -0
  141. package/registry/examples/activity-feed/timeline.js +25 -0
  142. package/registry/examples/activity-feed/timeline.tsx +19 -0
  143. package/registry/examples/avatar/native/presence.d.ts +4 -0
  144. package/registry/examples/avatar/native/presence.dark.png +0 -0
  145. package/registry/examples/avatar/native/presence.js +18 -0
  146. package/registry/examples/avatar/native/presence.light.png +0 -0
  147. package/registry/examples/avatar/native/presence.tsx +15 -0
  148. package/registry/examples/combobox/native/multiple.d.ts +4 -0
  149. package/registry/examples/combobox/native/multiple.dark.png +0 -0
  150. package/registry/examples/combobox/native/multiple.js +15 -0
  151. package/registry/examples/combobox/native/multiple.light.png +0 -0
  152. package/registry/examples/combobox/native/multiple.tsx +15 -0
  153. package/registry/examples/combobox/native/search.d.ts +4 -0
  154. package/registry/examples/combobox/native/search.dark.png +0 -0
  155. package/registry/examples/combobox/native/search.js +15 -0
  156. package/registry/examples/combobox/native/search.light.png +0 -0
  157. package/registry/examples/combobox/native/search.tsx +15 -0
  158. package/registry/examples/description-list/job-details.d.ts +4 -0
  159. package/registry/examples/description-list/job-details.js +23 -0
  160. package/registry/examples/description-list/job-details.tsx +17 -0
  161. package/registry/examples/description-list/key-value-grid.d.ts +4 -0
  162. package/registry/examples/description-list/key-value-grid.js +22 -0
  163. package/registry/examples/description-list/key-value-grid.tsx +16 -0
  164. package/registry/examples/description-list/native/job-details.d.ts +4 -0
  165. package/registry/examples/description-list/native/job-details.dark.png +0 -0
  166. package/registry/examples/description-list/native/job-details.js +33 -0
  167. package/registry/examples/description-list/native/job-details.light.png +0 -0
  168. package/registry/examples/description-list/native/job-details.tsx +24 -0
  169. package/registry/examples/description-list/receipt.d.ts +4 -0
  170. package/registry/examples/description-list/receipt.js +23 -0
  171. package/registry/examples/description-list/receipt.tsx +17 -0
  172. package/registry/examples/dialog/native/sheet.d.ts +4 -0
  173. package/registry/examples/dialog/native/sheet.dark.png +0 -0
  174. package/registry/examples/dialog/native/sheet.js +21 -0
  175. package/registry/examples/dialog/native/sheet.light.png +0 -0
  176. package/registry/examples/dialog/native/sheet.tsx +18 -0
  177. package/registry/examples/fab/native/extended.d.ts +4 -0
  178. package/registry/examples/fab/native/extended.dark.png +0 -0
  179. package/registry/examples/fab/native/extended.js +18 -0
  180. package/registry/examples/fab/native/extended.light.png +0 -0
  181. package/registry/examples/fab/native/extended.tsx +23 -0
  182. package/registry/examples/field/native/select.d.ts +4 -0
  183. package/registry/examples/field/native/select.dark.png +0 -0
  184. package/registry/examples/field/native/select.js +29 -0
  185. package/registry/examples/field/native/select.light.png +0 -0
  186. package/registry/examples/field/native/select.tsx +25 -0
  187. package/registry/examples/form/native/audience.dark.png +0 -0
  188. package/registry/examples/form/native/audience.light.png +0 -0
  189. package/registry/examples/form/native/profile.dark.png +0 -0
  190. package/registry/examples/form/native/profile.light.png +0 -0
  191. package/registry/examples/form/native/settings.dark.png +0 -0
  192. package/registry/examples/form/native/settings.light.png +0 -0
  193. package/registry/examples/form/native/sign-up.dark.png +0 -0
  194. package/registry/examples/form/native/sign-up.light.png +0 -0
  195. package/registry/examples/form/native/upload.dark.png +0 -0
  196. package/registry/examples/form/native/upload.light.png +0 -0
  197. package/registry/examples/header/native/large-title.d.ts +4 -0
  198. package/registry/examples/header/native/large-title.dark.png +0 -0
  199. package/registry/examples/header/native/large-title.js +23 -0
  200. package/registry/examples/header/native/large-title.light.png +0 -0
  201. package/registry/examples/header/native/large-title.tsx +31 -0
  202. package/registry/examples/image-viewer/native/gallery.d.ts +4 -0
  203. package/registry/examples/image-viewer/native/gallery.dark.png +0 -0
  204. package/registry/examples/image-viewer/native/gallery.js +22 -0
  205. package/registry/examples/image-viewer/native/gallery.light.png +0 -0
  206. package/registry/examples/image-viewer/native/gallery.tsx +21 -0
  207. package/registry/examples/kanban/moderation.d.ts +4 -0
  208. package/registry/examples/kanban/moderation.js +35 -0
  209. package/registry/examples/kanban/moderation.tsx +37 -0
  210. package/registry/examples/list/jobs.d.ts +4 -0
  211. package/registry/examples/list/jobs.js +35 -0
  212. package/registry/examples/list/jobs.tsx +33 -0
  213. package/registry/examples/list/selectable.d.ts +4 -0
  214. package/registry/examples/list/selectable.js +33 -0
  215. package/registry/examples/list/selectable.tsx +30 -0
  216. package/registry/examples/list/virtualized.d.ts +4 -0
  217. package/registry/examples/list/virtualized.js +22 -0
  218. package/registry/examples/list/virtualized.tsx +17 -0
  219. package/registry/examples/loader/native/block.d.ts +4 -0
  220. package/registry/examples/loader/native/block.dark.png +0 -0
  221. package/registry/examples/loader/native/block.js +12 -0
  222. package/registry/examples/loader/native/block.light.png +0 -0
  223. package/registry/examples/loader/native/block.tsx +11 -0
  224. package/registry/examples/loader/native/job-wait.d.ts +4 -0
  225. package/registry/examples/loader/native/job-wait.dark.png +0 -0
  226. package/registry/examples/loader/native/job-wait.js +17 -0
  227. package/registry/examples/loader/native/job-wait.light.png +0 -0
  228. package/registry/examples/loader/native/job-wait.tsx +14 -0
  229. package/registry/examples/map/cluster.d.ts +4 -0
  230. package/registry/examples/map/cluster.js +16 -0
  231. package/registry/examples/map/cluster.tsx +18 -0
  232. package/registry/examples/map/location-picker.d.ts +4 -0
  233. package/registry/examples/map/location-picker.js +24 -0
  234. package/registry/examples/map/location-picker.tsx +22 -0
  235. package/registry/examples/map/native/location-picker.d.ts +4 -0
  236. package/registry/examples/map/native/location-picker.dark.png +0 -0
  237. package/registry/examples/map/native/location-picker.js +14 -0
  238. package/registry/examples/map/native/location-picker.light.png +0 -0
  239. package/registry/examples/map/native/location-picker.tsx +13 -0
  240. package/registry/examples/map/native/places.d.ts +4 -0
  241. package/registry/examples/map/native/places.dark.png +0 -0
  242. package/registry/examples/map/native/places.js +25 -0
  243. package/registry/examples/map/native/places.light.png +0 -0
  244. package/registry/examples/map/native/places.tsx +27 -0
  245. package/registry/examples/map/places.d.ts +4 -0
  246. package/registry/examples/map/places.js +28 -0
  247. package/registry/examples/map/places.tsx +28 -0
  248. package/registry/examples/map/static.d.ts +4 -0
  249. package/registry/examples/map/static.js +22 -0
  250. package/registry/examples/map/static.tsx +18 -0
  251. package/registry/examples/media-picker/native/story.d.ts +4 -0
  252. package/registry/examples/media-picker/native/story.dark.png +0 -0
  253. package/registry/examples/media-picker/native/story.js +30 -0
  254. package/registry/examples/media-picker/native/story.light.png +0 -0
  255. package/registry/examples/media-picker/native/story.tsx +26 -0
  256. package/registry/examples/meter/native/credits.d.ts +4 -0
  257. package/registry/examples/meter/native/credits.dark.png +0 -0
  258. package/registry/examples/meter/native/credits.js +15 -0
  259. package/registry/examples/meter/native/credits.light.png +0 -0
  260. package/registry/examples/meter/native/credits.tsx +12 -0
  261. package/registry/examples/meter/native/split-ring.d.ts +4 -0
  262. package/registry/examples/meter/native/split-ring.dark.png +0 -0
  263. package/registry/examples/meter/native/split-ring.js +24 -0
  264. package/registry/examples/meter/native/split-ring.light.png +0 -0
  265. package/registry/examples/meter/native/split-ring.tsx +19 -0
  266. package/registry/examples/number-ticker/native/balance.d.ts +4 -0
  267. package/registry/examples/number-ticker/native/balance.dark.png +0 -0
  268. package/registry/examples/number-ticker/native/balance.js +18 -0
  269. package/registry/examples/number-ticker/native/balance.light.png +0 -0
  270. package/registry/examples/number-ticker/native/balance.tsx +17 -0
  271. package/registry/examples/onboarding/native/first-launch.d.ts +4 -0
  272. package/registry/examples/onboarding/native/first-launch.dark.png +0 -0
  273. package/registry/examples/onboarding/native/first-launch.js +23 -0
  274. package/registry/examples/onboarding/native/first-launch.light.png +0 -0
  275. package/registry/examples/onboarding/native/first-launch.tsx +19 -0
  276. package/registry/examples/otp-input/native/invalid.d.ts +4 -0
  277. package/registry/examples/otp-input/native/invalid.dark.png +0 -0
  278. package/registry/examples/otp-input/native/invalid.js +15 -0
  279. package/registry/examples/otp-input/native/invalid.light.png +0 -0
  280. package/registry/examples/otp-input/native/invalid.tsx +14 -0
  281. package/registry/examples/otp-input/native/verify.d.ts +4 -0
  282. package/registry/examples/otp-input/native/verify.dark.png +0 -0
  283. package/registry/examples/otp-input/native/verify.js +17 -0
  284. package/registry/examples/otp-input/native/verify.light.png +0 -0
  285. package/registry/examples/otp-input/native/verify.tsx +14 -0
  286. package/registry/examples/permission-prompt/native/blocked.d.ts +4 -0
  287. package/registry/examples/permission-prompt/native/blocked.dark.png +0 -0
  288. package/registry/examples/permission-prompt/native/blocked.js +25 -0
  289. package/registry/examples/permission-prompt/native/blocked.light.png +0 -0
  290. package/registry/examples/permission-prompt/native/blocked.tsx +21 -0
  291. package/registry/examples/permission-prompt/native/camera.d.ts +4 -0
  292. package/registry/examples/permission-prompt/native/camera.dark.png +0 -0
  293. package/registry/examples/permission-prompt/native/camera.js +25 -0
  294. package/registry/examples/permission-prompt/native/camera.light.png +0 -0
  295. package/registry/examples/permission-prompt/native/camera.tsx +21 -0
  296. package/registry/examples/pull-to-refresh/native/feed.d.ts +4 -0
  297. package/registry/examples/pull-to-refresh/native/feed.dark.png +0 -0
  298. package/registry/examples/pull-to-refresh/native/feed.js +14 -0
  299. package/registry/examples/pull-to-refresh/native/feed.light.png +0 -0
  300. package/registry/examples/pull-to-refresh/native/feed.tsx +19 -0
  301. package/registry/examples/radio-group/buttons.d.ts +4 -0
  302. package/registry/examples/radio-group/buttons.js +17 -0
  303. package/registry/examples/radio-group/buttons.tsx +21 -0
  304. package/registry/examples/radio-group/cards.js +1 -1
  305. package/registry/examples/radio-group/cards.tsx +2 -2
  306. package/registry/examples/radio-group/native/buttons.d.ts +4 -0
  307. package/registry/examples/radio-group/native/buttons.dark.png +0 -0
  308. package/registry/examples/radio-group/native/buttons.js +25 -0
  309. package/registry/examples/radio-group/native/buttons.light.png +0 -0
  310. package/registry/examples/radio-group/native/buttons.tsx +21 -0
  311. package/registry/examples/radio-group/native/cards.d.ts +4 -0
  312. package/registry/examples/radio-group/native/cards.dark.png +0 -0
  313. package/registry/examples/radio-group/native/cards.js +23 -0
  314. package/registry/examples/radio-group/native/cards.light.png +0 -0
  315. package/registry/examples/radio-group/native/cards.tsx +19 -0
  316. package/registry/examples/radio-group/native/list.d.ts +4 -0
  317. package/registry/examples/radio-group/native/list.dark.png +0 -0
  318. package/registry/examples/radio-group/native/list.js +24 -0
  319. package/registry/examples/radio-group/native/list.light.png +0 -0
  320. package/registry/examples/radio-group/native/list.tsx +20 -0
  321. package/registry/examples/radio-group/native/segmented.d.ts +4 -0
  322. package/registry/examples/radio-group/native/segmented.dark.png +0 -0
  323. package/registry/examples/radio-group/native/segmented.js +24 -0
  324. package/registry/examples/radio-group/native/segmented.light.png +0 -0
  325. package/registry/examples/radio-group/native/segmented.tsx +20 -0
  326. package/registry/examples/radio-group/segmented.d.ts +4 -0
  327. package/registry/examples/radio-group/segmented.js +15 -0
  328. package/registry/examples/radio-group/segmented.tsx +12 -0
  329. package/registry/examples/search-field/native/cancel.d.ts +4 -0
  330. package/registry/examples/search-field/native/cancel.dark.png +0 -0
  331. package/registry/examples/search-field/native/cancel.js +14 -0
  332. package/registry/examples/search-field/native/cancel.light.png +0 -0
  333. package/registry/examples/search-field/native/cancel.tsx +13 -0
  334. package/registry/examples/slider/floating.d.ts +4 -0
  335. package/registry/examples/slider/floating.js +11 -0
  336. package/registry/examples/slider/floating.tsx +12 -0
  337. package/registry/examples/slider/native/default.d.ts +4 -0
  338. package/registry/examples/slider/native/default.dark.png +0 -0
  339. package/registry/examples/slider/native/default.js +14 -0
  340. package/registry/examples/slider/native/default.light.png +0 -0
  341. package/registry/examples/slider/native/default.tsx +13 -0
  342. package/registry/examples/slider/native/range.d.ts +4 -0
  343. package/registry/examples/slider/native/range.dark.png +0 -0
  344. package/registry/examples/slider/native/range.js +12 -0
  345. package/registry/examples/slider/native/range.light.png +0 -0
  346. package/registry/examples/slider/native/range.tsx +11 -0
  347. package/registry/examples/slider/native/stepped.d.ts +4 -0
  348. package/registry/examples/slider/native/stepped.dark.png +0 -0
  349. package/registry/examples/slider/native/stepped.js +28 -0
  350. package/registry/examples/slider/native/stepped.light.png +0 -0
  351. package/registry/examples/slider/native/stepped.tsx +24 -0
  352. package/registry/examples/slider/native/vertical.d.ts +4 -0
  353. package/registry/examples/slider/native/vertical.dark.png +0 -0
  354. package/registry/examples/slider/native/vertical.js +16 -0
  355. package/registry/examples/slider/native/vertical.light.png +0 -0
  356. package/registry/examples/slider/native/vertical.tsx +13 -0
  357. package/registry/examples/slider/price-range.d.ts +4 -0
  358. package/registry/examples/slider/price-range.js +29 -0
  359. package/registry/examples/slider/price-range.tsx +27 -0
  360. package/registry/examples/slider/stepped.d.ts +4 -0
  361. package/registry/examples/slider/stepped.js +28 -0
  362. package/registry/examples/slider/stepped.tsx +24 -0
  363. package/registry/examples/slider/vertical.d.ts +4 -0
  364. package/registry/examples/slider/vertical.js +15 -0
  365. package/registry/examples/slider/vertical.tsx +14 -0
  366. package/registry/examples/stat/grid.d.ts +4 -0
  367. package/registry/examples/stat/grid.js +17 -0
  368. package/registry/examples/stat/grid.tsx +14 -0
  369. package/registry/examples/stepper/native/run.d.ts +4 -0
  370. package/registry/examples/stepper/native/run.dark.png +0 -0
  371. package/registry/examples/stepper/native/run.js +24 -0
  372. package/registry/examples/stepper/native/run.light.png +0 -0
  373. package/registry/examples/stepper/native/run.tsx +20 -0
  374. package/registry/examples/swipeable-row/native/conversation.d.ts +4 -0
  375. package/registry/examples/swipeable-row/native/conversation.dark.png +0 -0
  376. package/registry/examples/swipeable-row/native/conversation.js +30 -0
  377. package/registry/examples/swipeable-row/native/conversation.light.png +0 -0
  378. package/registry/examples/swipeable-row/native/conversation.tsx +27 -0
  379. package/registry/examples/switch/native/default.d.ts +4 -0
  380. package/registry/examples/switch/native/default.dark.png +0 -0
  381. package/registry/examples/switch/native/default.js +16 -0
  382. package/registry/examples/switch/native/default.light.png +0 -0
  383. package/registry/examples/switch/native/default.tsx +13 -0
  384. package/registry/examples/switch/native/settings.d.ts +4 -0
  385. package/registry/examples/switch/native/settings.dark.png +0 -0
  386. package/registry/examples/switch/native/settings.js +20 -0
  387. package/registry/examples/switch/native/settings.light.png +0 -0
  388. package/registry/examples/switch/native/settings.tsx +17 -0
  389. package/registry/examples/tab-bar/native/main-sections.d.ts +4 -0
  390. package/registry/examples/tab-bar/native/main-sections.dark.png +0 -0
  391. package/registry/examples/tab-bar/native/main-sections.js +29 -0
  392. package/registry/examples/tab-bar/native/main-sections.light.png +0 -0
  393. package/registry/examples/tab-bar/native/main-sections.tsx +30 -0
  394. package/registry/examples/tabs/native/sections.d.ts +4 -0
  395. package/registry/examples/tabs/native/sections.dark.png +0 -0
  396. package/registry/examples/tabs/native/sections.js +23 -0
  397. package/registry/examples/tabs/native/sections.light.png +0 -0
  398. package/registry/examples/tabs/native/sections.tsx +19 -0
  399. package/registry/examples/tabs/native/segmented.d.ts +4 -0
  400. package/registry/examples/tabs/native/segmented.dark.png +0 -0
  401. package/registry/examples/tabs/native/segmented.js +22 -0
  402. package/registry/examples/tabs/native/segmented.light.png +0 -0
  403. package/registry/examples/tabs/native/segmented.tsx +18 -0
  404. package/registry/examples/toast/native/snackbar.d.ts +4 -0
  405. package/registry/examples/toast/native/snackbar.dark.png +0 -0
  406. package/registry/examples/toast/native/snackbar.js +23 -0
  407. package/registry/examples/toast/native/snackbar.light.png +0 -0
  408. package/registry/examples/toast/native/snackbar.tsx +21 -0
  409. package/registry/examples/tree-view/docs.d.ts +4 -0
  410. package/registry/examples/tree-view/docs.js +24 -0
  411. package/registry/examples/tree-view/docs.tsx +22 -0
  412. package/registry/examples/tree-view/lazy.d.ts +4 -0
  413. package/registry/examples/tree-view/lazy.js +21 -0
  414. package/registry/examples/tree-view/lazy.tsx +19 -0
  415. package/registry/fab.json +122 -0
  416. package/registry/field.json +16 -4
  417. package/registry/file-upload.json +2 -2
  418. package/registry/filter-bar.json +1 -1
  419. package/registry/form.json +252 -44
  420. package/registry/gallery-page.json +1 -1
  421. package/registry/glow-card.json +1 -1
  422. package/registry/goal-gauge.json +1 -1
  423. package/registry/header.json +137 -0
  424. package/registry/how-it-works-page.json +1 -1
  425. package/registry/image-cropper.json +1 -1
  426. package/registry/image-viewer.json +107 -0
  427. package/registry/index.json +322 -44
  428. package/registry/iso.json +1 -1
  429. package/registry/kanban.json +253 -0
  430. package/registry/kbd.json +1 -1
  431. package/registry/landing-page.json +1 -1
  432. package/registry/landscape.json +1 -1
  433. package/registry/legal-page.json +1 -1
  434. package/registry/link-card.json +1 -1
  435. package/registry/list.json +367 -30
  436. package/registry/loader.json +157 -4
  437. package/registry/longform-page.json +1 -1
  438. package/registry/map.json +1368 -0
  439. package/registry/marketing-layout.json +1 -1
  440. package/registry/marquee.json +1 -1
  441. package/registry/mascot-quote.json +1 -1
  442. package/registry/mascot-state.json +1 -1
  443. package/registry/mascots.json +1 -1
  444. package/registry/media-capture.json +1 -1
  445. package/registry/media-picker.json +129 -0
  446. package/registry/meter.json +136 -4
  447. package/registry/nav-bar.json +1 -1
  448. package/registry/number-ticker.json +96 -4
  449. package/registry/onboarding.json +95 -0
  450. package/registry/otp-input.json +150 -0
  451. package/registry/page-header.json +1 -1
  452. package/registry/page-hero.json +1 -1
  453. package/registry/page.json +1 -1
  454. package/registry/pagination.json +1 -1
  455. package/registry/permission-prompt.json +172 -0
  456. package/registry/pointer-light.json +1 -1
  457. package/registry/popover.json +1 -1
  458. package/registry/pricing-page.json +1 -1
  459. package/registry/product-page.json +1 -1
  460. package/registry/profile-card.json +1 -1
  461. package/registry/progress.json +2 -2
  462. package/registry/promise-card.json +1 -1
  463. package/registry/pull-to-refresh.json +74 -0
  464. package/registry/radio-group.json +228 -16
  465. package/registry/scroll-stage.json +1 -1
  466. package/registry/search-field.json +30 -3
  467. package/registry/section-backdrop.json +1 -1
  468. package/registry/separator.json +1 -1
  469. package/registry/settings-layout.json +1 -1
  470. package/registry/skeleton.json +1 -1
  471. package/registry/slider.json +315 -14
  472. package/registry/slot.json +1 -1
  473. package/registry/spinner.json +1 -1
  474. package/registry/split-view.json +1 -1
  475. package/registry/stage-banner.json +1 -1
  476. package/registry/stat.json +68 -5
  477. package/registry/status-page.json +1 -1
  478. package/registry/stepper.json +75 -4
  479. package/registry/swipeable-row.json +124 -0
  480. package/registry/switch.json +116 -4
  481. package/registry/tab-bar.json +115 -0
  482. package/registry/tabs.json +96 -6
  483. package/registry/tag-input.json +1 -1
  484. package/registry/terminal-replay.json +1 -1
  485. package/registry/theme.json +8 -1
  486. package/registry/toast.json +17 -3
  487. package/registry/toc.json +1 -1
  488. package/registry/tooltip.json +1 -1
  489. package/registry/tree-view.json +291 -0
  490. package/registry/video-player.json +1 -1
  491. package/registry/video-trimmer.json +1 -1
  492. package/registry/virtual.json +1 -1
  493. package/skills/choice-controls/SKILL.md +39 -0
  494. package/skills/form/SKILL.md +3 -0
  495. package/skills/map/SKILL.md +35 -0
  496. package/dist/chunk-I5RVM5CW.js.map +0 -1
  497. package/dist/chunk-RUPRYJ45.js +0 -82
  498. package/dist/chunk-RUPRYJ45.js.map +0 -1
package/dist/native.js CHANGED
@@ -151,10 +151,24 @@ function monthGrid(month, weekStartsOn) {
151
151
  return Array.from({ length: 6 }, (_, w) => days.slice(w * 7, w * 7 + 7)).filter((week, w) => w < 5 || week[0].slice(0, 7) === first.slice(0, 7));
152
152
  }
153
153
 
154
- // src/native/avatar.tsx
155
- import * as React2 from "react";
156
- import { Image, StyleSheet, Text, View } from "react-native";
157
- import { SvgUri } from "react-native-svg";
154
+ // src/native/action-sheet.tsx
155
+ import { Modal, Pressable, StyleSheet as StyleSheet2, View } from "react-native";
156
+
157
+ // src/native/overlay.tsx
158
+ import * as React from "react";
159
+ var modalName = (label) => ({ "aria-label": label });
160
+ function useOpen({ open, defaultOpen = false, onOpenChange }) {
161
+ const [own, setOwn] = React.useState(defaultOpen);
162
+ const value = open ?? own;
163
+ const set = React.useCallback(
164
+ (next) => {
165
+ if (open === void 0) setOwn(next);
166
+ onOpenChange?.(next);
167
+ },
168
+ [open, onOpenChange]
169
+ );
170
+ return [value, set];
171
+ }
158
172
 
159
173
  // ../tokens/dist/native.js
160
174
  var themes = /* @__PURE__ */ Object.freeze({ dark: /* @__PURE__ */ Object.freeze({
@@ -314,24 +328,25 @@ var marks = /* @__PURE__ */ Object.freeze({
314
328
  });
315
329
 
316
330
  // src/native/theme.tsx
317
- import * as React from "react";
331
+ import * as React2 from "react";
318
332
  import { AccessibilityInfo, useColorScheme } from "react-native";
319
333
  import { jsx } from "react/jsx-runtime";
320
334
  var themes2 = themes;
321
335
  var radius2 = radius;
322
336
  var motion2 = motion;
323
337
  var stillMotion = { ...motion2, duration: { instant: 0, fast: 0, base: 0 } };
324
- var ThemeContext = React.createContext(null);
338
+ var NO_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };
339
+ var ThemeContext = React2.createContext(null);
325
340
  var noop = () => void 0;
326
341
  function resolve(mode, system) {
327
342
  if (mode === "system") return system === "light" ? "light" : "dark";
328
343
  return mode;
329
344
  }
330
- function ThemeProvider({ children, mode: controlled, defaultMode = "system", onModeChange, overrides, fonts, haptics }) {
345
+ function ThemeProvider({ children, mode: controlled, defaultMode = "system", onModeChange, overrides, fonts, haptics, insets }) {
331
346
  const system = useColorScheme();
332
- const [own, setOwn] = React.useState(defaultMode);
347
+ const [own, setOwn] = React2.useState(defaultMode);
333
348
  const mode = controlled ?? own;
334
- const setMode = React.useCallback(
349
+ const setMode = React2.useCallback(
335
350
  (next) => {
336
351
  if (controlled === void 0) setOwn(next);
337
352
  onModeChange?.(next);
@@ -341,23 +356,23 @@ function ThemeProvider({ children, mode: controlled, defaultMode = "system", onM
341
356
  const scheme = resolve(mode, system);
342
357
  const override = overrides?.[scheme];
343
358
  const reduce = useReducedMotion();
344
- const theme = React.useMemo(() => override ? { ...themes2[scheme], ...override } : themes2[scheme], [scheme, override]);
345
- const value = React.useMemo(
346
- () => ({ mode, setMode, scheme, theme, radius: radius2, motion: reduce ? stillMotion : motion2, fonts: fonts ?? {}, haptic: haptics ?? noop }),
347
- [mode, setMode, scheme, theme, fonts, reduce, haptics]
359
+ const theme = React2.useMemo(() => override ? { ...themes2[scheme], ...override } : themes2[scheme], [scheme, override]);
360
+ const value = React2.useMemo(
361
+ () => ({ mode, setMode, scheme, theme, radius: radius2, motion: reduce ? stillMotion : motion2, fonts: fonts ?? {}, haptic: haptics ?? noop, insets: insets ?? NO_INSETS }),
362
+ [mode, setMode, scheme, theme, fonts, reduce, haptics, insets]
348
363
  );
349
364
  return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
350
365
  }
351
366
  function useTheme() {
352
- const context = React.useContext(ThemeContext);
367
+ const context = React2.useContext(ThemeContext);
353
368
  const system = useColorScheme();
354
369
  if (context) return context;
355
370
  const scheme = resolve("system", system);
356
- return { mode: "system", setMode: noop, scheme, theme: themes2[scheme], radius: radius2, motion: motion2, fonts: {}, haptic: noop };
371
+ return { mode: "system", setMode: noop, scheme, theme: themes2[scheme], radius: radius2, motion: motion2, fonts: {}, haptic: noop, insets: NO_INSETS };
357
372
  }
358
373
  function useReducedMotion() {
359
- const [reduce, setReduce] = React.useState(false);
360
- React.useEffect(() => {
374
+ const [reduce, setReduce] = React2.useState(false);
375
+ React2.useEffect(() => {
361
376
  let alive = true;
362
377
  void AccessibilityInfo.isReduceMotionEnabled().then((value) => {
363
378
  if (alive) setReduce(value);
@@ -377,77 +392,304 @@ function alpha(color, opacity) {
377
392
  return `rgba(${r},${g},${b},${opacity})`;
378
393
  }
379
394
  function useSvgId(prefix) {
380
- return `${prefix}${React.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
395
+ return `${prefix}${React2.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
396
+ }
397
+
398
+ // src/native/txt.tsx
399
+ import { StyleSheet, Text } from "react-native";
400
+ import { jsx as jsx2 } from "react/jsx-runtime";
401
+ var TONE = {
402
+ text: "textPrimary",
403
+ secondary: "textSecondary",
404
+ muted: "textMuted",
405
+ accent: "accentText",
406
+ success: "successText",
407
+ warning: "warningText",
408
+ danger: "dangerText",
409
+ onAccent: "onAccent",
410
+ onMedia: "textOnMedia"
411
+ };
412
+ function Txt({ variant = "body", tone: tone3 = "text", style, ...props }) {
413
+ const { theme, fonts } = useTheme();
414
+ const family = variant === "display" || variant === "title" ? fonts.display : variant === "mono" ? fonts.mono : fonts.sans;
415
+ return /* @__PURE__ */ jsx2(
416
+ Text,
417
+ {
418
+ role: variant === "display" || variant === "title" ? "heading" : void 0,
419
+ ...props,
420
+ style: [styles[variant], { color: theme[TONE[tone3]] }, family ? { fontFamily: family } : null, style]
421
+ }
422
+ );
423
+ }
424
+ var textStyles = StyleSheet.create({
425
+ display: { fontSize: 30, lineHeight: 36, fontWeight: "900", letterSpacing: -0.5 },
426
+ title: { fontSize: 18, lineHeight: 24, fontWeight: "800" },
427
+ body: { fontSize: 15, lineHeight: 21 },
428
+ caption: { fontSize: 12, lineHeight: 16 },
429
+ label: { fontSize: 14, lineHeight: 18, fontWeight: "700" },
430
+ mono: { fontSize: 14, lineHeight: 18, fontWeight: "700", fontVariant: ["tabular-nums"] }
431
+ });
432
+ var styles = textStyles;
433
+
434
+ // src/native/action-sheet.tsx
435
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
436
+ function ActionSheet({ title, description, actions, cancelLabel, ...controlled }) {
437
+ const [open, setOpen] = useOpen(controlled);
438
+ const { theme, radius: radius3, insets, haptic } = useTheme();
439
+ const reduce = useReducedMotion();
440
+ const card = { backgroundColor: theme.glassBg, borderColor: theme.glassBorder, borderTopColor: theme.edgeLight, borderRadius: radius3.xl };
441
+ return /* @__PURE__ */ jsxs(Modal, { ...modalName(title), visible: open, transparent: true, animationType: reduce ? "none" : "slide", onRequestClose: () => setOpen(false), statusBarTranslucent: true, children: [
442
+ /* @__PURE__ */ jsx3(Pressable, { "aria-hidden": true, accessible: false, style: [StyleSheet2.absoluteFill, { backgroundColor: theme.scrim }], onPress: () => setOpen(false) }),
443
+ /* @__PURE__ */ jsxs(View, { style: [styles2.bottom, styles2.actionWrap, { paddingBottom: 8 + insets.bottom }], pointerEvents: "box-none", children: [
444
+ /* @__PURE__ */ jsxs(View, { role: "menu", "aria-label": title, style: [styles2.actionCard, card], children: [
445
+ /* @__PURE__ */ jsxs(View, { style: styles2.actionHead, children: [
446
+ /* @__PURE__ */ jsx3(Txt, { variant: "caption", tone: "secondary", style: styles2.centred, children: title }),
447
+ description ? /* @__PURE__ */ jsx3(Txt, { variant: "caption", tone: "muted", style: styles2.centred, children: description }) : null
448
+ ] }),
449
+ actions.map((action, i) => /* @__PURE__ */ jsxs(
450
+ Pressable,
451
+ {
452
+ role: "menuitem",
453
+ "aria-disabled": action.disabled,
454
+ disabled: action.disabled,
455
+ onPress: () => {
456
+ haptic("selection");
457
+ setOpen(false);
458
+ action.onPress();
459
+ },
460
+ style: ({ pressed }) => [styles2.action, { borderTopColor: theme.borderSubtle, backgroundColor: pressed ? theme.surface2 : "transparent", opacity: action.disabled ? 0.4 : 1 }],
461
+ children: [
462
+ action.icon ? /* @__PURE__ */ jsx3(View, { "aria-hidden": true, children: action.icon }) : null,
463
+ /* @__PURE__ */ jsx3(Txt, { variant: "label", tone: action.destructive ? "danger" : "text", children: action.label })
464
+ ]
465
+ },
466
+ i
467
+ ))
468
+ ] }),
469
+ /* @__PURE__ */ jsx3(Pressable, { role: "button", onPress: () => setOpen(false), style: ({ pressed }) => [styles2.cancel, card, { backgroundColor: pressed ? theme.surface2 : theme.surface1 }], children: /* @__PURE__ */ jsx3(Txt, { variant: "label", children: cancelLabel }) })
470
+ ] })
471
+ ] });
472
+ }
473
+ var styles2 = StyleSheet2.create({
474
+ bottom: { flex: 1, justifyContent: "flex-end" },
475
+ actionWrap: { paddingHorizontal: 8, gap: 8 },
476
+ actionCard: { borderWidth: StyleSheet2.hairlineWidth, overflow: "hidden" },
477
+ actionHead: { paddingVertical: 12, paddingHorizontal: 16, gap: 2 },
478
+ centred: { textAlign: "center" },
479
+ action: { flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 10, minHeight: 52, paddingHorizontal: 16, borderTopWidth: StyleSheet2.hairlineWidth },
480
+ cancel: { minHeight: 52, alignItems: "center", justifyContent: "center", borderWidth: StyleSheet2.hairlineWidth }
481
+ });
482
+
483
+ // src/native/activity-feed.tsx
484
+ import * as React3 from "react";
485
+ import { AccessibilityInfo as AccessibilityInfo2, SectionList, StyleSheet as StyleSheet3, View as View2 } from "react-native";
486
+
487
+ // src/activity-feed/group.ts
488
+ var dayKey = (date) => `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
489
+ function groupActivity(events, { now = /* @__PURE__ */ new Date(), locale = "en-US", today = "Today", yesterday = "Yesterday", fold = true } = {}) {
490
+ const sorted = [...events].sort((a, b) => new Date(b.at).getTime() - new Date(a.at).getTime());
491
+ const day = new Intl.DateTimeFormat(locale, { weekday: "long", month: "short", day: "numeric" });
492
+ const todayKey = dayKey(now);
493
+ const yesterdayKey = dayKey(new Date(now.getTime() - 864e5));
494
+ const groups = [];
495
+ let current = null;
496
+ let currentKey = "";
497
+ for (const event of sorted) {
498
+ const date = new Date(event.at);
499
+ const key = dayKey(date);
500
+ if (!current || key !== currentKey) {
501
+ currentKey = key;
502
+ current = { label: key === todayKey ? today : key === yesterdayKey ? yesterday : day.format(date), events: [] };
503
+ groups.push(current);
504
+ }
505
+ const last = current.events[current.events.length - 1];
506
+ if (fold && last && event.actor && event.kind && last.event.actor === event.actor && last.event.kind === event.kind) last.count += 1;
507
+ else current.events.push({ event, count: 1 });
508
+ }
509
+ return groups;
510
+ }
511
+ var UNITS = [
512
+ ["second", 60],
513
+ ["minute", 60],
514
+ ["hour", 24],
515
+ ["day", 7],
516
+ ["week", 4.35],
517
+ ["month", 12],
518
+ ["year", Number.POSITIVE_INFINITY]
519
+ ];
520
+ function timeAgo(at, { now = /* @__PURE__ */ new Date(), locale = "en-US", style = "short" } = {}) {
521
+ let value = (new Date(at).getTime() - now.getTime()) / 1e3;
522
+ let unit = "second";
523
+ for (const [name, size] of UNITS) {
524
+ unit = name;
525
+ if (Math.abs(value) < size - 0.5) break;
526
+ value /= size;
527
+ }
528
+ return new Intl.RelativeTimeFormat(locale, { numeric: "auto", style }).format(Math.round(value) + 0, unit);
529
+ }
530
+
531
+ // src/native/activity-feed.tsx
532
+ import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
533
+ var LABELS = { today: "Today", yesterday: "Yesterday", times: (n) => `\xD7${n}`, newEvents: (n) => n === 1 ? "1 new event" : `${n} new events` };
534
+ var tone = (t, name) => ({ neutral: t.borderStrong, accent: t.accent, success: t.success, warning: t.warning, danger: t.danger, info: t.info })[name ?? "neutral"];
535
+ function ActivityFeed({ events, "aria-label": label, locale = "en-US", now: given, fold = true, live, leading, empty, labels: words, style }) {
536
+ const { theme } = useTheme();
537
+ const labels = { ...LABELS, ...words };
538
+ const [tick, setTick] = React3.useState(() => given ?? /* @__PURE__ */ new Date());
539
+ React3.useEffect(() => {
540
+ if (given) return;
541
+ const timer2 = setInterval(() => setTick(/* @__PURE__ */ new Date()), 6e4);
542
+ return () => clearInterval(timer2);
543
+ }, [given]);
544
+ const now = given ?? tick;
545
+ const seen = React3.useRef(events.length);
546
+ React3.useEffect(() => {
547
+ const added = events.length - seen.current;
548
+ seen.current = events.length;
549
+ if (live && added > 0) AccessibilityInfo2.announceForAccessibility(labels.newEvents(added));
550
+ }, [events.length, live]);
551
+ const sections = groupActivity(events, { now, locale, today: labels.today, yesterday: labels.yesterday, fold }).map((g) => ({ title: g.label, data: g.events }));
552
+ return /* @__PURE__ */ jsx4(
553
+ SectionList,
554
+ {
555
+ "aria-label": label,
556
+ style,
557
+ sections,
558
+ keyExtractor: (item) => item.event.id,
559
+ stickySectionHeadersEnabled: true,
560
+ ListEmptyComponent: empty ? /* @__PURE__ */ jsx4(Fragment, { children: empty }) : null,
561
+ renderSectionHeader: ({ section }) => /* @__PURE__ */ jsx4(View2, { style: [styles3.heading, { backgroundColor: theme.surface0 }], children: /* @__PURE__ */ jsx4(Txt, { variant: "caption", tone: "secondary", role: "heading", style: styles3.headingText, children: section.title }) }),
562
+ renderItem: ({ item: { event, count } }) => /* @__PURE__ */ jsxs2(View2, { style: styles3.row, accessible: true, children: [
563
+ leading ? leading(event) : /* @__PURE__ */ jsx4(View2, { "aria-hidden": true, style: [styles3.marker, { backgroundColor: tone(theme, event.tone) }] }),
564
+ /* @__PURE__ */ jsxs2(View2, { style: styles3.body, children: [
565
+ /* @__PURE__ */ jsxs2(Txt, { children: [
566
+ event.title,
567
+ count > 1 ? /* @__PURE__ */ jsx4(Txt, { variant: "caption", tone: "secondary", children: ` ${labels.times(count)}` }) : null
568
+ ] }),
569
+ event.description ? /* @__PURE__ */ jsx4(Txt, { variant: "caption", tone: "secondary", children: event.description }) : null
570
+ ] }),
571
+ /* @__PURE__ */ jsx4(Txt, { variant: "caption", tone: "secondary", children: timeAgo(event.at, { now, locale }) })
572
+ ] })
573
+ }
574
+ );
381
575
  }
576
+ var styles3 = StyleSheet3.create({
577
+ heading: { paddingVertical: 6 },
578
+ headingText: { fontWeight: "700", textTransform: "uppercase", letterSpacing: 0.6 },
579
+ row: { flexDirection: "row", alignItems: "flex-start", gap: 12, paddingVertical: 10 },
580
+ marker: { width: 10, height: 10, borderRadius: 5, marginTop: 5 },
581
+ body: { flex: 1, gap: 2 }
582
+ });
382
583
 
383
584
  // src/native/avatar.tsx
384
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
585
+ import * as React4 from "react";
586
+ import { Image, StyleSheet as StyleSheet4, Text as Text2, View as View3 } from "react-native";
587
+ import Svg, { Circle, Defs, LinearGradient, Stop, SvgUri } from "react-native-svg";
588
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
385
589
  var SIDE = { xs: 20, sm: 32, md: 40, lg: 56, xl: 80 };
386
590
  function isSvgUri(uri) {
387
591
  return /^data:image\/svg\+xml[;,]/i.test(uri) || /\.svg(?:[?#]|$)/i.test(uri);
388
592
  }
389
- function AvatarRoot({ src, svg, alt = "", fallback, size = "md", style, ...props }) {
593
+ function AvatarRoot({ src, svg, alt = "", fallback, size = "md", presence, presenceLabel, ring, style, ...props }) {
390
594
  const { theme } = useTheme();
391
- const [failedSrc, setFailedSrc] = React2.useState(null);
595
+ const gradient = useSvgId("kz-ring-");
596
+ const [failedSrc, setFailedSrc] = React4.useState(null);
392
597
  const failed = Boolean(src) && failedSrc === src;
393
598
  const side = typeof size === "number" ? size : SIDE[size];
394
599
  const initial = alt.trim().charAt(0).toUpperCase();
395
600
  const content = fallback ?? initial;
396
- return /* @__PURE__ */ jsx2(
397
- View,
601
+ const picture = /* @__PURE__ */ jsx5(
602
+ View3,
398
603
  {
399
- accessible: Boolean(alt),
400
- role: alt ? "img" : void 0,
401
- "aria-label": alt || void 0,
402
- ...props,
403
- style: [styles.root, { width: side, height: side, borderRadius: side / 2, backgroundColor: theme.surface3 }, style],
404
- children: src && !failed && (svg || isSvgUri(src)) ? /* @__PURE__ */ jsx2(View, { style: StyleSheet.absoluteFill, pointerEvents: "none", children: /* @__PURE__ */ jsx2(SvgUri, { testID: props.testID ? `${props.testID}.svg` : void 0, uri: src, width: "100%", height: "100%", preserveAspectRatio: "xMidYMid slice", onError: () => setFailedSrc(src) }) }) : src && !failed ? /* @__PURE__ */ jsx2(Image, { testID: props.testID ? `${props.testID}.image` : void 0, source: { uri: src }, onError: () => setFailedSrc(src), resizeMode: "cover", style: StyleSheet.absoluteFill }) : typeof content === "string" ? /* @__PURE__ */ jsx2(Text, { style: [styles.initial, { color: theme.textSecondary, fontSize: Math.max(9, Math.round(side * 0.4)) }], children: content }) : content
604
+ accessible: Boolean(alt) && !presence && !ring,
605
+ role: alt && !presence && !ring ? "img" : void 0,
606
+ "aria-label": alt && !presence && !ring ? alt : void 0,
607
+ ...presence || ring ? {} : props,
608
+ style: [styles4.root, { width: side, height: side, borderRadius: side / 2, backgroundColor: theme.surface3 }, presence || ring ? null : style],
609
+ children: src && !failed && (svg || isSvgUri(src)) ? /* @__PURE__ */ jsx5(View3, { style: StyleSheet4.absoluteFill, pointerEvents: "none", children: /* @__PURE__ */ jsx5(SvgUri, { testID: props.testID ? `${props.testID}.svg` : void 0, uri: src, width: "100%", height: "100%", preserveAspectRatio: "xMidYMid slice", onError: () => setFailedSrc(src) }) }) : src && !failed ? /* @__PURE__ */ jsx5(Image, { testID: props.testID ? `${props.testID}.image` : void 0, source: { uri: src }, onError: () => setFailedSrc(src), resizeMode: "cover", style: StyleSheet4.absoluteFill }) : typeof content === "string" ? /* @__PURE__ */ jsx5(Text2, { style: [styles4.initial, { color: theme.textSecondary, fontSize: Math.max(9, Math.round(side * 0.4)) }], children: content }) : content
405
610
  }
406
611
  );
612
+ if (!presence && !ring) return picture;
613
+ const gap = ring ? Math.max(2.5, Math.round(side * 0.07)) : 0;
614
+ const outer = side + gap * 4;
615
+ const dot = Math.max(8, Math.round(side * 0.28));
616
+ const dotColor = presence === "online" ? theme.success : presence === "away" ? theme.warning : presence === "busy" ? theme.danger : theme.surface0;
617
+ const name = [alt, presence ? presenceLabel : null].filter(Boolean).join(", ");
618
+ return /* @__PURE__ */ jsxs3(View3, { accessible: Boolean(name), role: name ? "img" : void 0, "aria-label": name || void 0, ...props, style: [{ width: outer, height: outer, alignItems: "center", justifyContent: "center" }, style], children: [
619
+ ring ? /* @__PURE__ */ jsxs3(Svg, { width: outer, height: outer, style: StyleSheet4.absoluteFill, "aria-hidden": true, children: [
620
+ /* @__PURE__ */ jsx5(Defs, { children: /* @__PURE__ */ jsxs3(LinearGradient, { id: gradient, x1: "0", y1: "1", x2: "1", y2: "0", children: [
621
+ /* @__PURE__ */ jsx5(Stop, { offset: "0", stopColor: theme.accent }),
622
+ /* @__PURE__ */ jsx5(Stop, { offset: "1", stopColor: theme.accent2 })
623
+ ] }) }),
624
+ /* @__PURE__ */ jsx5(
625
+ Circle,
626
+ {
627
+ cx: outer / 2,
628
+ cy: outer / 2,
629
+ r: outer / 2 - gap / 2 - 0.5,
630
+ fill: "none",
631
+ strokeWidth: gap,
632
+ stroke: ring === "story" ? `url(#${gradient})` : ring === "live" ? theme.danger : theme.borderStrong
633
+ }
634
+ )
635
+ ] }) : null,
636
+ picture,
637
+ presence ? /* @__PURE__ */ jsx5(
638
+ View3,
639
+ {
640
+ "aria-hidden": true,
641
+ style: [
642
+ styles4.dot,
643
+ { width: dot, height: dot, borderRadius: dot / 2, right: gap * 2, bottom: gap * 2, backgroundColor: dotColor, borderColor: presence === "offline" ? theme.textMuted : theme.surface0 }
644
+ ]
645
+ }
646
+ ) : null
647
+ ] });
407
648
  }
408
649
  function AvatarGroup({ max, size = "md", style, children, ...props }) {
409
650
  const { theme } = useTheme();
410
- const items2 = React2.Children.toArray(children);
651
+ const items2 = React4.Children.toArray(children);
411
652
  const shown = max === void 0 ? items2 : items2.slice(0, max);
412
653
  const rest = items2.length - shown.length;
413
654
  const side = typeof size === "number" ? size : SIDE[size];
414
655
  const ring = { borderWidth: 2, borderColor: theme.surface0, marginLeft: -side / 5 };
415
- return /* @__PURE__ */ jsxs(View, { ...props, style: [styles.group, { paddingLeft: side / 5 }, style], children: [
416
- shown.map((child, i) => /* @__PURE__ */ jsx2(View, { style: [ring, { borderRadius: side }], children: React2.isValidElement(child) ? React2.cloneElement(child, { size }) : child }, i)),
417
- rest > 0 ? /* @__PURE__ */ jsx2(View, { style: [ring, { borderRadius: side }], children: /* @__PURE__ */ jsx2(AvatarRoot, { size, fallback: `+${rest}` }) }) : null
656
+ return /* @__PURE__ */ jsxs3(View3, { ...props, style: [styles4.group, { paddingLeft: side / 5 }, style], children: [
657
+ shown.map((child, i) => /* @__PURE__ */ jsx5(View3, { style: [ring, { borderRadius: side }], children: React4.isValidElement(child) ? React4.cloneElement(child, { size }) : child }, i)),
658
+ rest > 0 ? /* @__PURE__ */ jsx5(View3, { style: [ring, { borderRadius: side }], children: /* @__PURE__ */ jsx5(AvatarRoot, { size, fallback: `+${rest}` }) }) : null
418
659
  ] });
419
660
  }
420
661
  var Avatar = Object.assign(AvatarRoot, { Group: AvatarGroup });
421
- var styles = StyleSheet.create({
662
+ var styles4 = StyleSheet4.create({
422
663
  root: { overflow: "hidden", alignItems: "center", justifyContent: "center" },
423
664
  initial: { fontWeight: "700" },
424
- group: { flexDirection: "row", alignItems: "center" }
665
+ group: { flexDirection: "row", alignItems: "center" },
666
+ dot: { position: "absolute", borderWidth: 2 }
425
667
  });
426
668
 
427
669
  // src/native/badge.tsx
428
- import * as React3 from "react";
429
- import { Animated, StyleSheet as StyleSheet2, Text as Text2 } from "react-native";
430
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
431
- function look(tone2, t) {
432
- switch (tone2) {
670
+ import * as React5 from "react";
671
+ import { Animated, StyleSheet as StyleSheet5, Text as Text3 } from "react-native";
672
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
673
+ function look(tone3, t) {
674
+ switch (tone3) {
433
675
  case "accent":
434
676
  return { bg: t.accentSoft, fg: t.textPrimary, border: alpha(t.accent, 0.4), dot: t.accent };
435
677
  case "success":
436
678
  case "warning":
437
679
  case "danger":
438
- return { bg: alpha(t[tone2], 0.15), fg: t.textPrimary, border: alpha(t[tone2], 0.4), dot: t[tone2] };
680
+ return { bg: alpha(t[tone3], 0.15), fg: t.textPrimary, border: alpha(t[tone3], 0.4), dot: t[tone3] };
439
681
  case "scrim":
440
682
  return { bg: t.scrim, fg: t.textOnMedia, border: "transparent", dot: t.textOnMedia };
441
683
  default:
442
684
  return { bg: t.surface3, fg: t.textSecondary, border: "transparent", dot: t.textSecondary };
443
685
  }
444
686
  }
445
- function Badge({ tone: tone2 = "neutral", size = "sm", dot, pulse, style, children, ...props }) {
687
+ function Badge({ tone: tone3 = "neutral", size = "sm", dot, pulse, style, children, ...props }) {
446
688
  const { theme } = useTheme();
447
- const colors = look(tone2, theme);
689
+ const colors = look(tone3, theme);
448
690
  const reduce = useReducedMotion();
449
- const [opacity] = React3.useState(() => new Animated.Value(1));
450
- React3.useEffect(() => {
691
+ const [opacity] = React5.useState(() => new Animated.Value(1));
692
+ React5.useEffect(() => {
451
693
  if (!dot || !pulse || reduce) return;
452
694
  const loop = Animated.loop(
453
695
  Animated.sequence([
@@ -461,19 +703,19 @@ function Badge({ tone: tone2 = "neutral", size = "sm", dot, pulse, style, childr
461
703
  opacity.setValue(1);
462
704
  };
463
705
  }, [dot, pulse, reduce, opacity]);
464
- return /* @__PURE__ */ jsxs2(
706
+ return /* @__PURE__ */ jsxs4(
465
707
  Animated.View,
466
708
  {
467
709
  ...props,
468
- style: [styles2.root, size === "md" ? styles2.md : styles2.sm, { backgroundColor: colors.bg, borderColor: colors.border }, style],
710
+ style: [styles5.root, size === "md" ? styles5.md : styles5.sm, { backgroundColor: colors.bg, borderColor: colors.border }, style],
469
711
  children: [
470
- dot ? /* @__PURE__ */ jsx3(Animated.View, { "aria-hidden": true, style: [styles2.dot, { backgroundColor: colors.dot, opacity }] }) : null,
471
- typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx3(Text2, { style: [styles2.text, { color: colors.fg, fontSize: size === "md" ? 11 : 10 }], children }) : children
712
+ dot ? /* @__PURE__ */ jsx6(Animated.View, { "aria-hidden": true, style: [styles5.dot, { backgroundColor: colors.dot, opacity }] }) : null,
713
+ typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx6(Text3, { style: [styles5.text, { color: colors.fg, fontSize: size === "md" ? 11 : 10 }], children }) : children
472
714
  ]
473
715
  }
474
716
  );
475
717
  }
476
- var styles2 = StyleSheet2.create({
718
+ var styles5 = StyleSheet5.create({
477
719
  root: { flexDirection: "row", alignItems: "center", alignSelf: "flex-start", gap: 4, borderRadius: 9999, borderWidth: 1 },
478
720
  sm: { paddingHorizontal: 8, paddingVertical: 2 },
479
721
  md: { paddingHorizontal: 10, paddingVertical: 4 },
@@ -482,48 +724,10 @@ var styles2 = StyleSheet2.create({
482
724
  });
483
725
 
484
726
  // src/native/button.tsx
485
- import * as React4 from "react";
486
- import { ActivityIndicator, Pressable, StyleSheet as StyleSheet4, View as View2 } from "react-native";
487
- import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg";
488
-
489
- // src/native/txt.tsx
490
- import { StyleSheet as StyleSheet3, Text as Text3 } from "react-native";
491
- import { jsx as jsx4 } from "react/jsx-runtime";
492
- var TONE = {
493
- text: "textPrimary",
494
- secondary: "textSecondary",
495
- muted: "textMuted",
496
- accent: "accentText",
497
- success: "successText",
498
- warning: "warningText",
499
- danger: "dangerText",
500
- onAccent: "onAccent",
501
- onMedia: "textOnMedia"
502
- };
503
- function Txt({ variant = "body", tone: tone2 = "text", style, ...props }) {
504
- const { theme, fonts } = useTheme();
505
- const family = variant === "display" || variant === "title" ? fonts.display : variant === "mono" ? fonts.mono : fonts.sans;
506
- return /* @__PURE__ */ jsx4(
507
- Text3,
508
- {
509
- role: variant === "display" || variant === "title" ? "heading" : void 0,
510
- ...props,
511
- style: [styles3[variant], { color: theme[TONE[tone2]] }, family ? { fontFamily: family } : null, style]
512
- }
513
- );
514
- }
515
- var textStyles = StyleSheet3.create({
516
- display: { fontSize: 30, lineHeight: 36, fontWeight: "900", letterSpacing: -0.5 },
517
- title: { fontSize: 18, lineHeight: 24, fontWeight: "800" },
518
- body: { fontSize: 15, lineHeight: 21 },
519
- caption: { fontSize: 12, lineHeight: 16 },
520
- label: { fontSize: 14, lineHeight: 18, fontWeight: "700" },
521
- mono: { fontSize: 14, lineHeight: 18, fontWeight: "700", fontVariant: ["tabular-nums"] }
522
- });
523
- var styles3 = textStyles;
524
-
525
- // src/native/button.tsx
526
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
727
+ import * as React6 from "react";
728
+ import { ActivityIndicator, Pressable as Pressable2, StyleSheet as StyleSheet6, View as View4 } from "react-native";
729
+ import Svg2, { Defs as Defs2, LinearGradient as LinearGradient2, Rect, Stop as Stop2 } from "react-native-svg";
730
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
527
731
  function look2(variant, t) {
528
732
  switch (variant) {
529
733
  case "primary":
@@ -558,19 +762,19 @@ function useButton({ variant = "secondary", size = "md", shape = "rounded", load
558
762
  }
559
763
  function Fill({ colors, id }) {
560
764
  if (!colors.gradient) return null;
561
- return /* @__PURE__ */ jsxs3(Svg, { "aria-hidden": true, pointerEvents: "none", style: StyleSheet4.absoluteFill, width: "100%", height: "100%", children: [
562
- /* @__PURE__ */ jsx5(Defs, { children: /* @__PURE__ */ jsxs3(LinearGradient, { id, x1: "0", y1: "0", x2: "1", y2: "0", children: [
563
- /* @__PURE__ */ jsx5(Stop, { offset: "0", stopColor: colors.gradient[0] }),
564
- /* @__PURE__ */ jsx5(Stop, { offset: "1", stopColor: colors.gradient[1] })
765
+ return /* @__PURE__ */ jsxs5(Svg2, { "aria-hidden": true, pointerEvents: "none", style: StyleSheet6.absoluteFill, width: "100%", height: "100%", children: [
766
+ /* @__PURE__ */ jsx7(Defs2, { children: /* @__PURE__ */ jsxs5(LinearGradient2, { id, x1: "0", y1: "0", x2: "1", y2: "0", children: [
767
+ /* @__PURE__ */ jsx7(Stop2, { offset: "0", stopColor: colors.gradient[0] }),
768
+ /* @__PURE__ */ jsx7(Stop2, { offset: "1", stopColor: colors.gradient[1] })
565
769
  ] }) }),
566
- /* @__PURE__ */ jsx5(Rect, { width: "100%", height: "100%", fill: `url(#${id})` })
770
+ /* @__PURE__ */ jsx7(Rect, { width: "100%", height: "100%", fill: `url(#${id})` })
567
771
  ] });
568
772
  }
569
773
  function Button({ label, icon, variant, size = "md", shape, loading = false, disabled, style, ...props }) {
570
774
  const { colors, inactive, frame } = useButton({ variant, size, shape, loading, disabled });
571
- const gradientId = `kz-button-${React4.useId().replace(/:/g, "")}`;
572
- return /* @__PURE__ */ jsxs3(
573
- Pressable,
775
+ const gradientId = `kz-button-${React6.useId().replace(/:/g, "")}`;
776
+ return /* @__PURE__ */ jsxs5(
777
+ Pressable2,
574
778
  {
575
779
  role: "button",
576
780
  "aria-label": label,
@@ -578,12 +782,12 @@ function Button({ label, icon, variant, size = "md", shape, loading = false, dis
578
782
  "aria-busy": loading,
579
783
  ...props,
580
784
  disabled: inactive,
581
- style: ({ pressed }) => [styles4.base, { paddingHorizontal: PADDING[size] }, frame(pressed), style],
785
+ style: ({ pressed }) => [styles6.base, { paddingHorizontal: PADDING[size] }, frame(pressed), style],
582
786
  children: [
583
- /* @__PURE__ */ jsx5(Fill, { colors, id: gradientId }),
584
- /* @__PURE__ */ jsxs3(View2, { style: styles4.row, children: [
585
- loading ? /* @__PURE__ */ jsx5(ActivityIndicator, { "aria-hidden": true, size: "small", color: colors.fg }) : icon,
586
- /* @__PURE__ */ jsx5(Txt, { variant: "label", numberOfLines: 1, style: { color: colors.fg, fontSize: size === "sm" ? 12 : 14 }, children: label })
787
+ /* @__PURE__ */ jsx7(Fill, { colors, id: gradientId }),
788
+ /* @__PURE__ */ jsxs5(View4, { style: styles6.row, children: [
789
+ loading ? /* @__PURE__ */ jsx7(ActivityIndicator, { "aria-hidden": true, size: "small", color: colors.fg }) : icon,
790
+ /* @__PURE__ */ jsx7(Txt, { variant: "label", numberOfLines: 1, style: { color: colors.fg, fontSize: size === "sm" ? 12 : 14 }, children: label })
587
791
  ] })
588
792
  ]
589
793
  }
@@ -591,10 +795,10 @@ function Button({ label, icon, variant, size = "md", shape, loading = false, dis
591
795
  }
592
796
  function IconButton({ label, icon, variant, size = "md", shape, loading = false, disabled, style, ...props }) {
593
797
  const { colors, inactive, frame } = useButton({ variant, size, shape, loading, disabled });
594
- const gradientId = `kz-button-${React4.useId().replace(/:/g, "")}`;
798
+ const gradientId = `kz-button-${React6.useId().replace(/:/g, "")}`;
595
799
  const side = HEIGHT[size];
596
- return /* @__PURE__ */ jsxs3(
597
- Pressable,
800
+ return /* @__PURE__ */ jsxs5(
801
+ Pressable2,
598
802
  {
599
803
  role: "button",
600
804
  "aria-label": label,
@@ -603,36 +807,36 @@ function IconButton({ label, icon, variant, size = "md", shape, loading = false,
603
807
  hitSlop: side < 44 ? (44 - side) / 2 : void 0,
604
808
  ...props,
605
809
  disabled: inactive,
606
- style: ({ pressed }) => [styles4.base, frame(pressed), { width: side }, style],
810
+ style: ({ pressed }) => [styles6.base, frame(pressed), { width: side }, style],
607
811
  children: [
608
- /* @__PURE__ */ jsx5(Fill, { colors, id: gradientId }),
609
- loading ? /* @__PURE__ */ jsx5(ActivityIndicator, { "aria-hidden": true, size: "small", color: colors.fg }) : icon
812
+ /* @__PURE__ */ jsx7(Fill, { colors, id: gradientId }),
813
+ loading ? /* @__PURE__ */ jsx7(ActivityIndicator, { "aria-hidden": true, size: "small", color: colors.fg }) : icon
610
814
  ]
611
815
  }
612
816
  );
613
817
  }
614
- var styles4 = StyleSheet4.create({
818
+ var styles6 = StyleSheet6.create({
615
819
  base: { alignItems: "center", justifyContent: "center", borderWidth: 1, overflow: "hidden" },
616
820
  row: { flexDirection: "row", alignItems: "center", gap: 8 }
617
821
  });
618
822
 
619
823
  // src/native/card.tsx
620
- import { Image as Image2, Pressable as Pressable2, StyleSheet as StyleSheet5, View as View3 } from "react-native";
621
- import { jsx as jsx6 } from "react/jsx-runtime";
622
- function CardRoot({ tone: tone2 = "default", radius: radius3 = "xl", onPress, style, ...props }) {
824
+ import { Image as Image2, Pressable as Pressable3, StyleSheet as StyleSheet7, View as View5 } from "react-native";
825
+ import { jsx as jsx8 } from "react/jsx-runtime";
826
+ function CardRoot({ tone: tone3 = "default", radius: radius3 = "xl", onPress, style, ...props }) {
623
827
  const { theme, radius: r } = useTheme();
624
828
  const frame = [
625
- styles5.root,
829
+ styles7.root,
626
830
  {
627
- backgroundColor: tone2 === "elevated" ? theme.surface2 : theme.surface1,
831
+ backgroundColor: tone3 === "elevated" ? theme.surface2 : theme.surface1,
628
832
  borderColor: theme.borderDefault,
629
833
  borderRadius: r[radius3]
630
834
  },
631
- tone2 === "elevated" ? [styles5.shadow, { shadowColor: theme.scrimStrong }] : null
835
+ tone3 === "elevated" ? [styles7.shadow, { shadowColor: theme.scrimStrong }] : null
632
836
  ];
633
- if (!onPress) return /* @__PURE__ */ jsx6(View3, { ...props, style: [frame, style] });
634
- return /* @__PURE__ */ jsx6(
635
- Pressable2,
837
+ if (!onPress) return /* @__PURE__ */ jsx8(View5, { ...props, style: [frame, style] });
838
+ return /* @__PURE__ */ jsx8(
839
+ Pressable3,
636
840
  {
637
841
  role: "button",
638
842
  onPress,
@@ -644,14 +848,14 @@ function CardRoot({ tone: tone2 = "default", radius: radius3 = "xl", onPress, st
644
848
  var ASPECT = { video: 16 / 9, square: 1, portrait: 3 / 4 };
645
849
  function CardMedia({ aspect = "video", style, ...props }) {
646
850
  const { theme } = useTheme();
647
- return /* @__PURE__ */ jsx6(View3, { ...props, style: [styles5.media, { backgroundColor: theme.media }, aspect === "auto" ? null : { aspectRatio: ASPECT[aspect] }, style] });
851
+ return /* @__PURE__ */ jsx8(View5, { ...props, style: [styles7.media, { backgroundColor: theme.media }, aspect === "auto" ? null : { aspectRatio: ASPECT[aspect] }, style] });
648
852
  }
649
853
  function CardImage({ src, fallback, alt, style, ...props }) {
650
854
  const { theme } = useTheme();
651
855
  if (!src) {
652
- return /* @__PURE__ */ jsx6(View3, { "aria-hidden": true, style: [StyleSheet5.absoluteFill, styles5.center, { backgroundColor: theme.accentSoft }], children: fallback });
856
+ return /* @__PURE__ */ jsx8(View5, { "aria-hidden": true, style: [StyleSheet7.absoluteFill, styles7.center, { backgroundColor: theme.accentSoft }], children: fallback });
653
857
  }
654
- return /* @__PURE__ */ jsx6(Image2, { accessible: Boolean(alt), alt, "aria-label": alt, resizeMode: "cover", ...props, source: { uri: src }, style: [StyleSheet5.absoluteFill, style] });
858
+ return /* @__PURE__ */ jsx8(Image2, { accessible: Boolean(alt), alt, "aria-label": alt, resizeMode: "cover", ...props, source: { uri: src }, style: [StyleSheet7.absoluteFill, style] });
655
859
  }
656
860
  var CORNER = {
657
861
  "top-left": { top: 10, left: 10 },
@@ -660,21 +864,21 @@ var CORNER = {
660
864
  "bottom-right": { bottom: 10, right: 10 }
661
865
  };
662
866
  function CardOverlay({ corner = "top-left", style, ...props }) {
663
- return /* @__PURE__ */ jsx6(View3, { ...props, style: [styles5.overlay, CORNER[corner], style] });
867
+ return /* @__PURE__ */ jsx8(View5, { ...props, style: [styles7.overlay, CORNER[corner], style] });
664
868
  }
665
869
  var PADDING2 = { none: 0, sm: 12, md: 16, lg: 24 };
666
870
  function CardBody({ padding = "md", style, ...props }) {
667
- return /* @__PURE__ */ jsx6(View3, { ...props, style: [styles5.body, { padding: PADDING2[padding] }, style] });
871
+ return /* @__PURE__ */ jsx8(View5, { ...props, style: [styles7.body, { padding: PADDING2[padding] }, style] });
668
872
  }
669
873
  function CardTitle({ numberOfLines = 1, ...props }) {
670
- return /* @__PURE__ */ jsx6(Txt, { variant: "label", role: "heading", numberOfLines, ...props });
874
+ return /* @__PURE__ */ jsx8(Txt, { variant: "label", role: "heading", numberOfLines, ...props });
671
875
  }
672
876
  function CardDescription({ numberOfLines = 2, ...props }) {
673
- return /* @__PURE__ */ jsx6(Txt, { variant: "caption", tone: "secondary", numberOfLines, ...props });
877
+ return /* @__PURE__ */ jsx8(Txt, { variant: "caption", tone: "secondary", numberOfLines, ...props });
674
878
  }
675
879
  function CardFooter({ style, ...props }) {
676
880
  const { theme } = useTheme();
677
- return /* @__PURE__ */ jsx6(View3, { ...props, style: [styles5.footer, { borderTopColor: theme.borderSubtle }, style] });
881
+ return /* @__PURE__ */ jsx8(View5, { ...props, style: [styles7.footer, { borderTopColor: theme.borderSubtle }, style] });
678
882
  }
679
883
  var Card = {
680
884
  Root: CardRoot,
@@ -686,37 +890,37 @@ var Card = {
686
890
  Description: CardDescription,
687
891
  Footer: CardFooter
688
892
  };
689
- var styles5 = StyleSheet5.create({
690
- root: { overflow: "hidden", borderWidth: StyleSheet5.hairlineWidth },
893
+ var styles7 = StyleSheet7.create({
894
+ root: { overflow: "hidden", borderWidth: StyleSheet7.hairlineWidth },
691
895
  shadow: { shadowOpacity: 0.25, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, elevation: 4 },
692
896
  media: { position: "relative", overflow: "hidden", width: "100%" },
693
897
  center: { alignItems: "center", justifyContent: "center" },
694
898
  overlay: { position: "absolute", zIndex: 1, flexDirection: "row", alignItems: "center", gap: 6 },
695
899
  body: { gap: 12 },
696
- footer: { flexDirection: "row", alignItems: "center", gap: 8, borderTopWidth: StyleSheet5.hairlineWidth, paddingTop: 12, marginTop: "auto" }
900
+ footer: { flexDirection: "row", alignItems: "center", gap: 8, borderTopWidth: StyleSheet7.hairlineWidth, paddingTop: 12, marginTop: "auto" }
697
901
  });
698
902
 
699
903
  // src/native/checkbox.tsx
700
- import * as React5 from "react";
701
- import { Pressable as Pressable3, StyleSheet as StyleSheet6, Text as Text4, View as View4 } from "react-native";
702
- import Svg2, { Path } from "react-native-svg";
703
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
904
+ import * as React7 from "react";
905
+ import { Pressable as Pressable4, StyleSheet as StyleSheet8, Text as Text4, View as View6 } from "react-native";
906
+ import Svg3, { Path } from "react-native-svg";
907
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
704
908
  function Checkbox({ children, label, checked, defaultChecked = false, onCheckedChange, error, disabled, style }) {
705
909
  const { theme, radius: radius3 } = useTheme();
706
- const [own, setOwn] = React5.useState(defaultChecked);
910
+ const [own, setOwn] = React7.useState(defaultChecked);
707
911
  const on = checked ?? own;
708
912
  const toggle = () => {
709
913
  if (checked === void 0) setOwn(!on);
710
914
  onCheckedChange?.(!on);
711
915
  };
712
- const box = /* @__PURE__ */ jsx7(
713
- View4,
916
+ const box = /* @__PURE__ */ jsx9(
917
+ View6,
714
918
  {
715
919
  style: [
716
- styles6.box,
920
+ styles8.box,
717
921
  { borderRadius: radius3.xs + 2, borderColor: error ? theme.danger : on ? theme.accent : theme.borderStrong, backgroundColor: on ? theme.accent : theme.surface1 }
718
922
  ],
719
- children: on ? /* @__PURE__ */ jsx7(Svg2, { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: theme.onAccent, strokeWidth: 3, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7(Path, { d: "M20 6 9 17l-5-5" }) }) : null
923
+ children: on ? /* @__PURE__ */ jsx9(Svg3, { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: theme.onAccent, strokeWidth: 3, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx9(Path, { d: "M20 6 9 17l-5-5" }) }) : null
720
924
  }
721
925
  );
722
926
  const plain = children === void 0 || typeof children === "string";
@@ -729,21 +933,21 @@ function Checkbox({ children, label, checked, defaultChecked = false, onCheckedC
729
933
  disabled,
730
934
  onPress: toggle
731
935
  };
732
- return /* @__PURE__ */ jsxs4(View4, { style: [styles6.root, style], children: [
733
- plain ? /* @__PURE__ */ jsxs4(Pressable3, { ...a11y, hitSlop: 4, style: [styles6.row, disabled ? styles6.disabled : null], children: [
936
+ return /* @__PURE__ */ jsxs6(View6, { style: [styles8.root, style], children: [
937
+ plain ? /* @__PURE__ */ jsxs6(Pressable4, { ...a11y, hitSlop: 4, style: [styles8.row, disabled ? styles8.disabled : null], children: [
734
938
  box,
735
- children !== void 0 ? /* @__PURE__ */ jsx7(View4, { style: styles6.text, children: /* @__PURE__ */ jsx7(Text4, { style: [styles6.label, { color: theme.textPrimary }], children }) }) : null
939
+ children !== void 0 ? /* @__PURE__ */ jsx9(View6, { style: styles8.text, children: /* @__PURE__ */ jsx9(Text4, { style: [styles8.label, { color: theme.textPrimary }], children }) }) : null
736
940
  ] }) : (
737
941
  // Words with links: the box alone is the control (a 44-pt target, named by `label`), the links stay links.
738
- /* @__PURE__ */ jsxs4(View4, { style: [styles6.row, disabled ? styles6.disabled : null], children: [
739
- /* @__PURE__ */ jsx7(Pressable3, { ...a11y, hitSlop: 11, style: styles6.target, children: box }),
740
- /* @__PURE__ */ jsx7(View4, { style: styles6.text, children })
942
+ /* @__PURE__ */ jsxs6(View6, { style: [styles8.row, disabled ? styles8.disabled : null], children: [
943
+ /* @__PURE__ */ jsx9(Pressable4, { ...a11y, hitSlop: 11, style: styles8.target, children: box }),
944
+ /* @__PURE__ */ jsx9(View6, { style: styles8.text, children })
741
945
  ] })
742
946
  ),
743
- error ? /* @__PURE__ */ jsx7(Text4, { role: "alert", "aria-live": "polite", style: [styles6.error, { color: theme.dangerText }], children: error }) : null
947
+ error ? /* @__PURE__ */ jsx9(Text4, { role: "alert", "aria-live": "polite", style: [styles8.error, { color: theme.dangerText }], children: error }) : null
744
948
  ] });
745
949
  }
746
- var styles6 = StyleSheet6.create({
950
+ var styles8 = StyleSheet8.create({
747
951
  root: { gap: 2, alignSelf: "stretch" },
748
952
  row: { flexDirection: "row", alignItems: "center", gap: 12, minHeight: 44 },
749
953
  target: { minHeight: 44, justifyContent: "center" },
@@ -755,18 +959,18 @@ var styles6 = StyleSheet6.create({
755
959
  });
756
960
 
757
961
  // src/native/chip.tsx
758
- import * as React6 from "react";
759
- import { Pressable as Pressable4, ScrollView, StyleSheet as StyleSheet7, Text as Text5, View as View5 } from "react-native";
760
- import { Fragment, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
761
- var ChipGroupContext = React6.createContext(null);
962
+ import * as React8 from "react";
963
+ import { Pressable as Pressable5, ScrollView, StyleSheet as StyleSheet9, Text as Text5, View as View7 } from "react-native";
964
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
965
+ var ChipGroupContext = React8.createContext(null);
762
966
  function Label({ children, color, size }) {
763
- if (typeof children !== "string" && typeof children !== "number") return /* @__PURE__ */ jsx8(Fragment, { children });
764
- return /* @__PURE__ */ jsx8(Text5, { style: [styles7.label, { color, fontSize: size === "sm" ? 12 : 13 }], children });
967
+ if (typeof children !== "string" && typeof children !== "number") return /* @__PURE__ */ jsx10(Fragment2, { children });
968
+ return /* @__PURE__ */ jsx10(Text5, { style: [styles9.label, { color, fontSize: size === "sm" ? 12 : 13 }], children });
765
969
  }
766
970
  function ChipBase(props) {
767
- const group = React6.useContext(ChipGroupContext);
971
+ const group = React8.useContext(ChipGroupContext);
768
972
  const { theme, radius: radius3 } = useTheme();
769
- const [own, setOwn] = React6.useState(props.removable ? false : props.defaultSelected ?? false);
973
+ const [own, setOwn] = React8.useState(props.removable ? false : props.defaultSelected ?? false);
770
974
  const size = props.size ?? group?.size ?? "md";
771
975
  const frame = (on2, pressed) => ({
772
976
  height: size === "sm" ? 28 : 36,
@@ -777,9 +981,9 @@ function ChipBase(props) {
777
981
  });
778
982
  if (props.removable) {
779
983
  const { removable: _r2, removeLabel, onRemove, disabled: disabled2, size: _s2, style: style2, children: children2, ...rest2 } = props;
780
- return /* @__PURE__ */ jsxs5(View5, { ...rest2, style: [styles7.base, frame(false, false), disabled2 ? styles7.disabled : null, style2], children: [
781
- /* @__PURE__ */ jsx8(Label, { color: theme.textSecondary, size, children: children2 }),
782
- /* @__PURE__ */ jsx8(Pressable4, { role: "button", "aria-label": removeLabel, disabled: disabled2 ?? void 0, hitSlop: 10, onPress: onRemove, style: styles7.remove, children: /* @__PURE__ */ jsx8(Text5, { style: [styles7.cross, { color: theme.textSecondary }], children: "\xD7" }) })
984
+ return /* @__PURE__ */ jsxs7(View7, { ...rest2, style: [styles9.base, frame(false, false), disabled2 ? styles9.disabled : null, style2], children: [
985
+ /* @__PURE__ */ jsx10(Label, { color: theme.textSecondary, size, children: children2 }),
986
+ /* @__PURE__ */ jsx10(Pressable5, { role: "button", "aria-label": removeLabel, disabled: disabled2 ?? void 0, hitSlop: 10, onPress: onRemove, style: styles9.remove, children: /* @__PURE__ */ jsx10(Text5, { style: [styles9.cross, { color: theme.textSecondary }], children: "\xD7" }) })
783
987
  ] });
784
988
  }
785
989
  const { removable: _r, value, selected, defaultSelected: _d, onSelectedChange, disabled: ownDisabled, size: _s, style, children, ...rest } = props;
@@ -792,8 +996,8 @@ function ChipBase(props) {
792
996
  onSelectedChange?.(!on);
793
997
  };
794
998
  const single = group?.type === "single";
795
- return /* @__PURE__ */ jsx8(
796
- Pressable4,
999
+ return /* @__PURE__ */ jsx10(
1000
+ Pressable5,
797
1001
  {
798
1002
  role: single ? "radio" : "checkbox",
799
1003
  "aria-checked": on,
@@ -801,17 +1005,17 @@ function ChipBase(props) {
801
1005
  ...rest,
802
1006
  disabled,
803
1007
  onPress: press,
804
- style: ({ pressed }) => [styles7.base, frame(on, pressed), disabled ? styles7.disabled : null, style],
805
- children: /* @__PURE__ */ jsx8(Label, { color: on ? theme.textPrimary : theme.textSecondary, size, children })
1008
+ style: ({ pressed }) => [styles9.base, frame(on, pressed), disabled ? styles9.disabled : null, style],
1009
+ children: /* @__PURE__ */ jsx10(Label, { color: on ? theme.textPrimary : theme.textSecondary, size, children })
806
1010
  }
807
1011
  );
808
1012
  }
809
1013
  function ChipGroup(props) {
810
1014
  const { size, disabled, scrollable, "aria-label": label, style, children } = props;
811
1015
  const initial = props.type === "single" ? props.defaultValue ?? "" : props.defaultValue ?? [];
812
- const [own, setOwn] = React6.useState(initial);
1016
+ const [own, setOwn] = React8.useState(initial);
813
1017
  const current = props.value ?? own;
814
- const context = React6.useMemo(() => {
1018
+ const context = React8.useMemo(() => {
815
1019
  const list = Array.isArray(current) ? current : [current];
816
1020
  return {
817
1021
  type: props.type,
@@ -826,10 +1030,10 @@ function ChipGroup(props) {
826
1030
  };
827
1031
  }, [current, props.type, props.value, props.onValueChange, size, disabled]);
828
1032
  const a11y = { role: props.type === "single" ? "radiogroup" : "group", "aria-label": label };
829
- return /* @__PURE__ */ jsx8(ChipGroupContext.Provider, { value: context, children: scrollable ? /* @__PURE__ */ jsx8(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, ...a11y, style, contentContainerStyle: styles7.row, children }) : /* @__PURE__ */ jsx8(View5, { ...a11y, style: [styles7.row, styles7.wrap, style], children }) });
1033
+ return /* @__PURE__ */ jsx10(ChipGroupContext.Provider, { value: context, children: scrollable ? /* @__PURE__ */ jsx10(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, ...a11y, style, contentContainerStyle: styles9.row, children }) : /* @__PURE__ */ jsx10(View7, { ...a11y, style: [styles9.row, styles9.wrap, style], children }) });
830
1034
  }
831
1035
  var Chip = Object.assign(ChipBase, { Group: ChipGroup });
832
- var styles7 = StyleSheet7.create({
1036
+ var styles9 = StyleSheet9.create({
833
1037
  base: { flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 6, paddingHorizontal: 14, borderWidth: 1, alignSelf: "flex-start" },
834
1038
  label: { fontWeight: "600" },
835
1039
  remove: { marginRight: -6, width: 24, height: 24, alignItems: "center", justifyContent: "center" },
@@ -839,10 +1043,239 @@ var styles7 = StyleSheet7.create({
839
1043
  wrap: { flexWrap: "wrap" }
840
1044
  });
841
1045
 
1046
+ // src/native/combobox.tsx
1047
+ import * as React10 from "react";
1048
+ import { Pressable as Pressable7, ScrollView as ScrollView2, StyleSheet as StyleSheet11, Text as Text7, TextInput, View as View9 } from "react-native";
1049
+ import Svg4, { Path as Path2 } from "react-native-svg";
1050
+
1051
+ // src/native/dialog.tsx
1052
+ import * as React9 from "react";
1053
+ import { Animated as Animated2, Modal as Modal2, Pressable as Pressable6, StyleSheet as StyleSheet10, Text as Text6, View as View8 } from "react-native";
1054
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1055
+ function Sheet({ open, onOpenChange, title, closeLabel = "Close", children, style }) {
1056
+ const { theme, radius: radius3, motion: motion3 } = useTheme();
1057
+ const [rise] = React9.useState(() => new Animated2.Value(0));
1058
+ React9.useEffect(() => {
1059
+ if (open) Animated2.timing(rise, { toValue: 1, duration: motion3.duration.base * 1.6, useNativeDriver: true }).start();
1060
+ else rise.setValue(0);
1061
+ }, [open, rise, motion3.duration.base]);
1062
+ return /* @__PURE__ */ jsx11(Modal2, { transparent: true, visible: open, animationType: "none", onRequestClose: () => onOpenChange(false), statusBarTranslucent: true, children: /* @__PURE__ */ jsxs8(View8, { style: styles10.backdrop, children: [
1063
+ /* @__PURE__ */ jsx11(Animated2.View, { style: [StyleSheet10.absoluteFill, { opacity: rise }], children: /* @__PURE__ */ jsx11(Pressable6, { role: "button", "aria-label": closeLabel, onPress: () => onOpenChange(false), style: [StyleSheet10.absoluteFill, { backgroundColor: theme.scrim }] }) }),
1064
+ /* @__PURE__ */ jsxs8(
1065
+ Animated2.View,
1066
+ {
1067
+ role: "dialog",
1068
+ "aria-label": title,
1069
+ style: [
1070
+ styles10.sheet,
1071
+ {
1072
+ backgroundColor: theme.surface1,
1073
+ borderColor: theme.borderDefault,
1074
+ borderTopLeftRadius: radius3["2xl"],
1075
+ borderTopRightRadius: radius3["2xl"],
1076
+ shadowColor: theme.scrimStrong,
1077
+ transform: [{ translateY: rise.interpolate({ inputRange: [0, 1], outputRange: [48, 0] }) }],
1078
+ opacity: rise.interpolate({ inputRange: [0, 1], outputRange: [0.6, 1] })
1079
+ },
1080
+ style
1081
+ ],
1082
+ children: [
1083
+ /* @__PURE__ */ jsx11(View8, { "aria-hidden": true, style: [styles10.grip, { backgroundColor: theme.borderStrong }] }),
1084
+ title ? /* @__PURE__ */ jsx11(Text6, { role: "heading", style: [styles10.title, { color: theme.textPrimary }], children: title }) : null,
1085
+ children
1086
+ ]
1087
+ }
1088
+ )
1089
+ ] }) });
1090
+ }
1091
+ var styles10 = StyleSheet10.create({
1092
+ backdrop: { flex: 1, justifyContent: "flex-end" },
1093
+ sheet: { maxHeight: "85%", paddingHorizontal: 16, paddingTop: 8, paddingBottom: 28, gap: 12, borderWidth: StyleSheet10.hairlineWidth, shadowOpacity: 0.3, shadowRadius: 16, shadowOffset: { width: 0, height: -4 }, elevation: 12 },
1094
+ grip: { alignSelf: "center", width: 40, height: 5, borderRadius: 3, marginBottom: 4 },
1095
+ title: { fontSize: 17, fontWeight: "700" }
1096
+ });
1097
+
1098
+ // src/native/combobox.tsx
1099
+ import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1100
+ function Chevron({ color }) {
1101
+ return /* @__PURE__ */ jsx12(Svg4, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx12(Path2, { d: "m6 9 6 6 6-6" }) });
1102
+ }
1103
+ function Tick({ color }) {
1104
+ return /* @__PURE__ */ jsx12(Svg4, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2.6, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx12(Path2, { d: "M20 6 9 17l-5-5" }) });
1105
+ }
1106
+ function Trigger({ shared, text, onPress, open }) {
1107
+ const { theme, radius: radius3 } = useTheme();
1108
+ const { label, placeholder, hint, error, disabled } = shared;
1109
+ const caption = error ?? hint;
1110
+ return /* @__PURE__ */ jsxs9(View9, { style: [styles11.field, shared.style], children: [
1111
+ /* @__PURE__ */ jsx12(Text7, { style: [styles11.label, { color: theme.textSecondary }], children: label }),
1112
+ /* @__PURE__ */ jsxs9(
1113
+ Pressable7,
1114
+ {
1115
+ role: "button",
1116
+ "aria-label": `${label}, ${text ?? placeholder ?? ""}`.replace(/, $/, ""),
1117
+ "aria-expanded": open,
1118
+ "aria-haspopup": "listbox",
1119
+ "aria-disabled": disabled || void 0,
1120
+ accessibilityHint: caption,
1121
+ disabled,
1122
+ onPress,
1123
+ style: [styles11.trigger, { borderRadius: radius3.md, backgroundColor: theme.surface2, borderColor: error ? theme.danger : open ? theme.accent : theme.borderDefault }, disabled ? styles11.disabled : null],
1124
+ children: [
1125
+ /* @__PURE__ */ jsx12(Text7, { numberOfLines: 1, style: [styles11.triggerText, { color: text ? theme.textPrimary : theme.textSecondary }], children: text ?? placeholder ?? "" }),
1126
+ /* @__PURE__ */ jsx12(Chevron, { color: theme.textSecondary })
1127
+ ]
1128
+ }
1129
+ ),
1130
+ caption ? /* @__PURE__ */ jsx12(Text7, { role: error ? "alert" : void 0, "aria-live": error ? "polite" : void 0, style: [styles11.caption, { color: error ? theme.dangerText : theme.textSecondary }], children: caption }) : null
1131
+ ] });
1132
+ }
1133
+ function Options({ options, isChosen, onPick, multiple }) {
1134
+ const { theme, radius: radius3, haptic } = useTheme();
1135
+ return /* @__PURE__ */ jsx12(ScrollView2, { role: multiple ? "list" : "radiogroup", keyboardShouldPersistTaps: "handled", style: styles11.options, children: options.map((o) => {
1136
+ const chosen = isChosen(o.value);
1137
+ return /* @__PURE__ */ jsxs9(
1138
+ Pressable7,
1139
+ {
1140
+ role: multiple ? "checkbox" : "radio",
1141
+ "aria-checked": chosen,
1142
+ "aria-label": o.description ? `${o.label}, ${o.description}` : o.label,
1143
+ "aria-disabled": o.disabled || void 0,
1144
+ disabled: o.disabled,
1145
+ onPress: () => {
1146
+ haptic("selection");
1147
+ onPick(o);
1148
+ },
1149
+ style: ({ pressed }) => [styles11.option, { borderRadius: radius3.md, backgroundColor: chosen ? theme.accentSoft : pressed ? theme.surface3 : "transparent" }, o.disabled ? styles11.disabled : null],
1150
+ children: [
1151
+ /* @__PURE__ */ jsxs9(View9, { style: styles11.optionText, children: [
1152
+ /* @__PURE__ */ jsx12(Text7, { style: [styles11.optionLabel, { color: theme.textPrimary, fontWeight: chosen ? "700" : "500" }], children: o.label }),
1153
+ o.description ? /* @__PURE__ */ jsx12(Text7, { style: [styles11.caption, { color: theme.textSecondary }], children: o.description }) : null
1154
+ ] }),
1155
+ chosen ? /* @__PURE__ */ jsx12(Tick, { color: theme.accentText }) : null
1156
+ ]
1157
+ },
1158
+ o.value
1159
+ );
1160
+ }) });
1161
+ }
1162
+ function Select({ options, value: valueProp, defaultValue = null, onValueChange, sheetTitle, ...shared }) {
1163
+ const [own, setOwn] = React10.useState(defaultValue);
1164
+ const value = valueProp !== void 0 ? valueProp : own;
1165
+ const [open, setOpen] = React10.useState(false);
1166
+ const close = () => {
1167
+ setOpen(false);
1168
+ shared.onBlur?.();
1169
+ };
1170
+ return /* @__PURE__ */ jsxs9(Fragment3, { children: [
1171
+ /* @__PURE__ */ jsx12(Trigger, { shared, text: options.find((o) => o.value === value)?.label ?? null, open, onPress: () => setOpen(true) }),
1172
+ /* @__PURE__ */ jsx12(Sheet, { open, onOpenChange: (o) => o ? setOpen(true) : close(), title: sheetTitle ?? shared.label, children: /* @__PURE__ */ jsx12(
1173
+ Options,
1174
+ {
1175
+ options,
1176
+ isChosen: (v) => v === value,
1177
+ onPick: (o) => {
1178
+ if (valueProp === void 0) setOwn(o.value);
1179
+ onValueChange?.(o.value);
1180
+ close();
1181
+ }
1182
+ }
1183
+ ) })
1184
+ ] });
1185
+ }
1186
+ var comboboxLabels = { search: "Search", loading: "Searching\u2026", empty: "No results", done: "Done" };
1187
+ function Combobox({ options = [], onSearch, multiple, value, onValueChange, labels: given, ...shared }) {
1188
+ const labels = { ...comboboxLabels, ...given };
1189
+ const { theme, radius: radius3 } = useTheme();
1190
+ const [open, setOpen] = React10.useState(false);
1191
+ const [query, setQuery] = React10.useState("");
1192
+ const [found, setFound] = React10.useState(null);
1193
+ const [loading, setLoading] = React10.useState(false);
1194
+ const [seen, setSeen] = React10.useState({});
1195
+ const chosen = value == null ? [] : typeof value === "string" ? value ? [value] : [] : [...value];
1196
+ React10.useEffect(() => {
1197
+ if (!onSearch || !open) return;
1198
+ const controller = new AbortController();
1199
+ const timer2 = setTimeout(() => {
1200
+ setLoading(true);
1201
+ onSearch(query, controller.signal).then((result) => {
1202
+ if (!controller.signal.aborted) setFound(result);
1203
+ }).catch(() => void 0).finally(() => {
1204
+ if (!controller.signal.aborted) setLoading(false);
1205
+ });
1206
+ }, 250);
1207
+ return () => {
1208
+ clearTimeout(timer2);
1209
+ controller.abort();
1210
+ };
1211
+ }, [query, onSearch, open]);
1212
+ const q = query.trim().toLowerCase();
1213
+ const list = onSearch ? found ?? [] : options.filter((o) => !q || o.label.toLowerCase().includes(q));
1214
+ const labelOf = (v) => options.find((o) => o.value === v)?.label ?? seen[v]?.label ?? v;
1215
+ const close = () => {
1216
+ setOpen(false);
1217
+ setQuery("");
1218
+ shared.onBlur?.();
1219
+ };
1220
+ return /* @__PURE__ */ jsxs9(Fragment3, { children: [
1221
+ /* @__PURE__ */ jsx12(Trigger, { shared, text: chosen.length ? chosen.map(labelOf).join(", ") : null, open, onPress: () => setOpen(true) }),
1222
+ /* @__PURE__ */ jsxs9(Sheet, { open, onOpenChange: (o) => o ? setOpen(true) : close(), title: shared.label, children: [
1223
+ /* @__PURE__ */ jsx12(
1224
+ TextInput,
1225
+ {
1226
+ "aria-label": labels.search,
1227
+ placeholder: labels.search,
1228
+ placeholderTextColor: theme.textMuted,
1229
+ value: query,
1230
+ onChangeText: setQuery,
1231
+ autoFocus: true,
1232
+ autoCorrect: false,
1233
+ returnKeyType: "search",
1234
+ style: [styles11.search, { borderRadius: radius3.md, backgroundColor: theme.surface2, borderColor: theme.borderDefault, color: theme.textPrimary }]
1235
+ }
1236
+ ),
1237
+ loading ? /* @__PURE__ */ jsx12(Text7, { style: [styles11.caption, { color: theme.textSecondary }], children: labels.loading }) : null,
1238
+ !loading && list.length === 0 ? /* @__PURE__ */ jsx12(Text7, { style: [styles11.caption, { color: theme.textSecondary }], children: labels.empty }) : null,
1239
+ /* @__PURE__ */ jsx12(
1240
+ Options,
1241
+ {
1242
+ options: list,
1243
+ multiple,
1244
+ isChosen: (v) => chosen.includes(v),
1245
+ onPick: (o) => {
1246
+ setSeen((known) => ({ ...known, [o.value]: o }));
1247
+ if (multiple) onValueChange?.(chosen.includes(o.value) ? chosen.filter((v) => v !== o.value) : [...chosen, o.value]);
1248
+ else {
1249
+ onValueChange?.(o.value);
1250
+ close();
1251
+ }
1252
+ }
1253
+ }
1254
+ ),
1255
+ multiple ? /* @__PURE__ */ jsx12(Pressable7, { role: "button", onPress: close, style: [styles11.done, { borderRadius: radius3.md, backgroundColor: theme.accent }], children: /* @__PURE__ */ jsx12(Text7, { style: [styles11.doneText, { color: theme.onAccent }], children: labels.done }) }) : null
1256
+ ] })
1257
+ ] });
1258
+ }
1259
+ var styles11 = StyleSheet11.create({
1260
+ field: { gap: 6, alignSelf: "stretch" },
1261
+ label: { fontSize: 12, lineHeight: 16, fontWeight: "600" },
1262
+ trigger: { minHeight: 48, flexDirection: "row", alignItems: "center", gap: 8, paddingHorizontal: 14, borderWidth: 1 },
1263
+ triggerText: { flex: 1, fontSize: 16 },
1264
+ caption: { fontSize: 12, lineHeight: 16 },
1265
+ options: { flexGrow: 0 },
1266
+ option: { minHeight: 48, flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 12, paddingVertical: 8 },
1267
+ optionText: { flex: 1, gap: 2 },
1268
+ optionLabel: { fontSize: 16 },
1269
+ search: { height: 44, paddingHorizontal: 12, borderWidth: 1, fontSize: 16 },
1270
+ done: { height: 48, alignItems: "center", justifyContent: "center" },
1271
+ doneText: { fontSize: 15, fontWeight: "700" },
1272
+ disabled: { opacity: 0.4 }
1273
+ });
1274
+
842
1275
  // src/native/countdown.tsx
843
- import * as React7 from "react";
844
- import { Animated as Animated2, StyleSheet as StyleSheet8, Text as Text6 } from "react-native";
845
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1276
+ import * as React11 from "react";
1277
+ import { Animated as Animated3, StyleSheet as StyleSheet12, Text as Text8 } from "react-native";
1278
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
846
1279
  var FONT = { sm: 14, md: 20, lg: 32 };
847
1280
  function Countdown({ target, skewMs = 0, units, urgentBelowMs = 6e4, size = "md", label, showLabel = false, style }) {
848
1281
  const { theme, fonts } = useTheme();
@@ -850,13 +1283,13 @@ function Countdown({ target, skewMs = 0, units, urgentBelowMs = 6e4, size = "md"
850
1283
  const ms = useCountdown(target, skewMs);
851
1284
  const urgent = ms > 0 && ms < urgentBelowMs;
852
1285
  const parts = countdownParts(ms, units);
853
- const [opacity] = React7.useState(() => new Animated2.Value(1));
854
- React7.useEffect(() => {
1286
+ const [opacity] = React11.useState(() => new Animated3.Value(1));
1287
+ React11.useEffect(() => {
855
1288
  if (!urgent || reduce) return;
856
- const loop = Animated2.loop(
857
- Animated2.sequence([
858
- Animated2.timing(opacity, { toValue: 0.4, duration: 500, useNativeDriver: true }),
859
- Animated2.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true })
1289
+ const loop = Animated3.loop(
1290
+ Animated3.sequence([
1291
+ Animated3.timing(opacity, { toValue: 0.4, duration: 500, useNativeDriver: true }),
1292
+ Animated3.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true })
860
1293
  ])
861
1294
  );
862
1295
  loop.start();
@@ -867,24 +1300,24 @@ function Countdown({ target, skewMs = 0, units, urgentBelowMs = 6e4, size = "md"
867
1300
  }, [urgent, reduce, opacity]);
868
1301
  const color = urgent ? theme.dangerText : theme.textPrimary;
869
1302
  const text = parts.map(([value, unit]) => `${String(value).padStart(2, "0")}${unit}`).join(" ");
870
- return /* @__PURE__ */ jsxs6(
871
- Animated2.View,
1303
+ return /* @__PURE__ */ jsxs10(
1304
+ Animated3.View,
872
1305
  {
873
1306
  accessible: true,
874
1307
  role: "timer",
875
1308
  "aria-label": `${label} ${text}`,
876
- style: [styles8.root, style],
1309
+ style: [styles12.root, style],
877
1310
  children: [
878
- showLabel ? /* @__PURE__ */ jsx9(Text6, { style: [styles8.label, { color: theme.textSecondary, fontSize: Math.max(11, Math.round(FONT[size] * 0.6)) }], children: label }) : null,
879
- parts.map(([value, unit], i) => /* @__PURE__ */ jsxs6(Animated2.View, { style: [styles8.segment, urgent && i === parts.length - 1 ? { opacity } : null], children: [
880
- /* @__PURE__ */ jsx9(Text6, { style: [styles8.value, { color, fontSize: FONT[size] }, fonts.display ? { fontFamily: fonts.display } : null], children: String(value).padStart(2, "0") }),
881
- /* @__PURE__ */ jsx9(Text6, { style: [styles8.unit, { color: theme.textSecondary, fontSize: Math.round(FONT[size] / 2) }], children: unit })
1311
+ showLabel ? /* @__PURE__ */ jsx13(Text8, { style: [styles12.label, { color: theme.textSecondary, fontSize: Math.max(11, Math.round(FONT[size] * 0.6)) }], children: label }) : null,
1312
+ parts.map(([value, unit], i) => /* @__PURE__ */ jsxs10(Animated3.View, { style: [styles12.segment, urgent && i === parts.length - 1 ? { opacity } : null], children: [
1313
+ /* @__PURE__ */ jsx13(Text8, { style: [styles12.value, { color, fontSize: FONT[size] }, fonts.display ? { fontFamily: fonts.display } : null], children: String(value).padStart(2, "0") }),
1314
+ /* @__PURE__ */ jsx13(Text8, { style: [styles12.unit, { color: theme.textSecondary, fontSize: Math.round(FONT[size] / 2) }], children: unit })
882
1315
  ] }, unit))
883
1316
  ]
884
1317
  }
885
1318
  );
886
1319
  }
887
- var styles8 = StyleSheet8.create({
1320
+ var styles12 = StyleSheet12.create({
888
1321
  root: { flexDirection: "row", alignItems: "baseline", gap: 6 },
889
1322
  segment: { flexDirection: "row", alignItems: "baseline" },
890
1323
  value: { fontWeight: "900", fontVariant: ["tabular-nums"], letterSpacing: -0.3 },
@@ -893,18 +1326,18 @@ var styles8 = StyleSheet8.create({
893
1326
  });
894
1327
 
895
1328
  // src/native/date-picker.tsx
896
- import * as React8 from "react";
897
- import { Platform, StyleSheet as StyleSheet9, Text as Text7, TextInput, View as View6 } from "react-native";
898
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1329
+ import * as React12 from "react";
1330
+ import { Platform, StyleSheet as StyleSheet13, Text as Text9, TextInput as TextInput2, View as View10 } from "react-native";
1331
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
899
1332
  var LENGTH = DATE_PART_LENGTH;
900
1333
  var dateFieldLabels = { day: "Day", month: "Month", year: "Year" };
901
1334
  function DateField({ label, hint, error, value, defaultValue, onValueChange, onBlur, locale = "en-US", labels: given, autoComplete, disabled, inputRef, onSubmitEditing, returnKeyType = "done", style }) {
902
1335
  const { theme, radius: radius3 } = useTheme();
903
1336
  const labels = { ...dateFieldLabels, ...given };
904
- const order = React8.useMemo(() => datePartsOrder(locale), [locale]);
905
- const [parts, setParts] = React8.useState(() => splitDate(value ?? defaultValue));
906
- const [focused, setFocused] = React8.useState(null);
907
- const refs = { day: React8.useRef(null), month: React8.useRef(null), year: React8.useRef(null) };
1337
+ const order = React12.useMemo(() => datePartsOrder(locale), [locale]);
1338
+ const [parts, setParts] = React12.useState(() => splitDate(value ?? defaultValue));
1339
+ const [focused, setFocused] = React12.useState(null);
1340
+ const refs = { day: React12.useRef(null), month: React12.useRef(null), year: React12.useRef(null) };
908
1341
  if (value !== void 0 && value !== composeDate(parts) && composeDate(splitDate(value)) === value) setParts(splitDate(value));
909
1342
  const caption = error ?? hint;
910
1343
  const change = (part, text) => {
@@ -915,12 +1348,12 @@ function DateField({ label, hint, error, value, defaultValue, onValueChange, onB
915
1348
  const following = order[order.indexOf(part) + 1];
916
1349
  if (digits.length === LENGTH[part] && following) refs[following].current?.focus();
917
1350
  };
918
- return /* @__PURE__ */ jsxs7(View6, { role: "group", "aria-label": label, style: [styles9.root, disabled ? styles9.disabled : null, style], children: [
919
- /* @__PURE__ */ jsx10(Text7, { style: [styles9.label, { color: theme.textSecondary }], children: label }),
920
- /* @__PURE__ */ jsx10(View6, { style: styles9.row, children: order.map((part, i) => /* @__PURE__ */ jsxs7(View6, { style: part === "year" ? styles9.yearBox : styles9.box, children: [
921
- /* @__PURE__ */ jsx10(Text7, { style: [styles9.part, { color: theme.textSecondary }], children: labels[part] }),
922
- /* @__PURE__ */ jsx10(
923
- TextInput,
1351
+ return /* @__PURE__ */ jsxs11(View10, { role: "group", "aria-label": label, style: [styles13.root, disabled ? styles13.disabled : null, style], children: [
1352
+ /* @__PURE__ */ jsx14(Text9, { style: [styles13.label, { color: theme.textSecondary }], children: label }),
1353
+ /* @__PURE__ */ jsx14(View10, { style: styles13.row, children: order.map((part, i) => /* @__PURE__ */ jsxs11(View10, { style: part === "year" ? styles13.yearBox : styles13.box, children: [
1354
+ /* @__PURE__ */ jsx14(Text9, { style: [styles13.part, { color: theme.textSecondary }], children: labels[part] }),
1355
+ /* @__PURE__ */ jsx14(
1356
+ TextInput2,
924
1357
  {
925
1358
  ref: (node) => {
926
1359
  refs[part].current = node;
@@ -951,16 +1384,16 @@ function DateField({ label, hint, error, value, defaultValue, onValueChange, onB
951
1384
  if (i === order.length - 1) onBlur?.();
952
1385
  },
953
1386
  style: [
954
- styles9.input,
1387
+ styles13.input,
955
1388
  { color: theme.textPrimary, backgroundColor: theme.surface2, borderRadius: radius3.md, borderColor: error ? theme.danger : focused === part ? theme.accent : theme.borderDefault }
956
1389
  ]
957
1390
  }
958
1391
  )
959
1392
  ] }, part)) }),
960
- caption ? /* @__PURE__ */ jsx10(Text7, { role: error ? "alert" : void 0, "aria-live": error ? "polite" : void 0, style: [styles9.caption, { color: error ? theme.dangerText : theme.textSecondary }], children: caption }) : null
1393
+ caption ? /* @__PURE__ */ jsx14(Text9, { role: error ? "alert" : void 0, "aria-live": error ? "polite" : void 0, style: [styles13.caption, { color: error ? theme.dangerText : theme.textSecondary }], children: caption }) : null
961
1394
  ] });
962
1395
  }
963
- var styles9 = StyleSheet9.create({
1396
+ var styles13 = StyleSheet13.create({
964
1397
  root: { gap: 6, alignSelf: "stretch" },
965
1398
  label: { fontSize: 12, lineHeight: 16, fontWeight: "600" },
966
1399
  row: { flexDirection: "row", gap: 10 },
@@ -973,26 +1406,26 @@ var styles9 = StyleSheet9.create({
973
1406
  });
974
1407
 
975
1408
  // src/native/date-time.tsx
976
- import * as React10 from "react";
977
- import { Pressable as Pressable6, ScrollView as ScrollView3, StyleSheet as StyleSheet11, Text as Text9, View as View8 } from "react-native";
978
- import Svg3, { Path as Path2 } from "react-native-svg";
1409
+ import * as React14 from "react";
1410
+ import { Pressable as Pressable9, ScrollView as ScrollView4, StyleSheet as StyleSheet15, Text as Text11, View as View12 } from "react-native";
1411
+ import Svg5, { Path as Path3 } from "react-native-svg";
979
1412
 
980
1413
  // src/native/wheel.tsx
981
- import * as React9 from "react";
982
- import { Pressable as Pressable5, ScrollView as ScrollView2, StyleSheet as StyleSheet10, Text as Text8, View as View7 } from "react-native";
983
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1414
+ import * as React13 from "react";
1415
+ import { Pressable as Pressable8, ScrollView as ScrollView3, StyleSheet as StyleSheet14, Text as Text10, View as View11 } from "react-native";
1416
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
984
1417
  var ITEM = 44;
985
- var VisibleContext = React9.createContext(5);
986
- function WheelPicker({ label, children, visible = 5, invalid, style }) {
1418
+ var FrameContext = React13.createContext({ visible: 5, unset: false });
1419
+ function WheelPicker({ label, children, visible = 5, invalid, unset = false, style }) {
987
1420
  const { theme, radius: radius3 } = useTheme();
988
- return /* @__PURE__ */ jsx11(VisibleContext.Provider, { value: visible, children: /* @__PURE__ */ jsxs8(
989
- View7,
1421
+ return /* @__PURE__ */ jsx15(FrameContext.Provider, { value: React13.useMemo(() => ({ visible, unset }), [visible, unset]), children: /* @__PURE__ */ jsxs12(
1422
+ View11,
990
1423
  {
991
1424
  role: "group",
992
1425
  "aria-label": label,
993
- style: [styles10.root, { height: ITEM * visible, borderRadius: radius3.xl, backgroundColor: theme.surface1, borderColor: invalid ? theme.danger : theme.borderDefault }, style],
1426
+ style: [styles14.root, { height: ITEM * visible, borderRadius: radius3.xl, backgroundColor: theme.surface1, borderColor: invalid ? theme.danger : theme.borderDefault }, style],
994
1427
  children: [
995
- /* @__PURE__ */ jsx11(View7, { pointerEvents: "none", style: [styles10.band, { top: ITEM * (visible - 1) / 2, height: ITEM, borderRadius: radius3.lg, backgroundColor: theme.surface3, borderColor: theme.borderSubtle }] }),
1428
+ /* @__PURE__ */ jsx15(View11, { pointerEvents: "none", style: [styles14.band, { top: ITEM * (visible - 1) / 2, height: ITEM, borderRadius: radius3.lg, backgroundColor: theme.surface3, borderColor: theme.borderSubtle }] }),
996
1429
  children
997
1430
  ]
998
1431
  }
@@ -1000,7 +1433,7 @@ function WheelPicker({ label, children, visible = 5, invalid, style }) {
1000
1433
  }
1001
1434
  function WheelDivider({ children }) {
1002
1435
  const { theme } = useTheme();
1003
- return /* @__PURE__ */ jsx11(Text8, { "aria-hidden": true, style: [styles10.divider, { color: theme.textSecondary }], children });
1436
+ return /* @__PURE__ */ jsx15(Text10, { "aria-hidden": true, style: [styles14.divider, { color: theme.textSecondary }], children });
1004
1437
  }
1005
1438
  var nearestEnabled = (options, index) => {
1006
1439
  for (let d = 0; d < options.length; d++) {
@@ -1011,14 +1444,14 @@ var nearestEnabled = (options, index) => {
1011
1444
  };
1012
1445
  function Wheel({ label, options, value: valueProp, defaultValue, onValueChange, disabled, style }) {
1013
1446
  const { theme, haptic } = useTheme();
1014
- const visible = React9.useContext(VisibleContext);
1015
- const [own, setOwn] = React9.useState(defaultValue ?? options[0]?.value ?? "");
1447
+ const { visible, unset } = React13.useContext(FrameContext);
1448
+ const [own, setOwn] = React13.useState(defaultValue ?? options[0]?.value ?? "");
1016
1449
  const value = valueProp ?? own;
1017
1450
  const index = Math.max(0, options.findIndex((o) => o.value === value));
1018
- const scroller = React9.useRef(null);
1019
- const passing = React9.useRef(index);
1020
- const [shown, setShown] = React9.useState(index);
1021
- const [seen, setSeen] = React9.useState(index);
1451
+ const scroller = React13.useRef(null);
1452
+ const passing = React13.useRef(index);
1453
+ const [shown, setShown] = React13.useState(index);
1454
+ const [seen, setSeen] = React13.useState(index);
1022
1455
  if (seen !== index) {
1023
1456
  setSeen(index);
1024
1457
  setShown(index);
@@ -1031,7 +1464,7 @@ function Wheel({ label, options, value: valueProp, defaultValue, onValueChange,
1031
1464
  if (valueProp === void 0) setOwn(option.value);
1032
1465
  if (option.value !== value) onValueChange?.(option.value);
1033
1466
  };
1034
- React9.useEffect(() => {
1467
+ React13.useEffect(() => {
1035
1468
  passing.current = index;
1036
1469
  scroller.current?.scrollTo({ y: index * ITEM, animated: false });
1037
1470
  }, [index]);
@@ -1050,8 +1483,8 @@ function Wheel({ label, options, value: valueProp, defaultValue, onValueChange,
1050
1483
  if (options[i]) commit(i);
1051
1484
  };
1052
1485
  const pad = (visible - 1) / 2 * ITEM;
1053
- return /* @__PURE__ */ jsx11(
1054
- View7,
1486
+ return /* @__PURE__ */ jsx15(
1487
+ View11,
1055
1488
  {
1056
1489
  accessible: true,
1057
1490
  role: "spinbutton",
@@ -1063,9 +1496,9 @@ function Wheel({ label, options, value: valueProp, defaultValue, onValueChange,
1063
1496
  "aria-disabled": disabled || void 0,
1064
1497
  accessibilityActions: [{ name: "increment" }, { name: "decrement" }],
1065
1498
  onAccessibilityAction: (e) => step(e.nativeEvent.actionName === "increment" ? 1 : -1),
1066
- style: [styles10.column, disabled ? styles10.disabled : null, style],
1067
- children: /* @__PURE__ */ jsx11(
1068
- ScrollView2,
1499
+ style: [styles14.column, disabled ? styles14.disabled : null, style],
1500
+ children: /* @__PURE__ */ jsx15(
1501
+ ScrollView3,
1069
1502
  {
1070
1503
  ref: scroller,
1071
1504
  "aria-hidden": true,
@@ -1084,15 +1517,15 @@ function Wheel({ label, options, value: valueProp, defaultValue, onValueChange,
1084
1517
  },
1085
1518
  children: options.map((o, i) => {
1086
1519
  const distance = Math.abs(i - shown);
1087
- return /* @__PURE__ */ jsx11(Pressable5, { focusable: false, tabIndex: -1, disabled: disabled || o.disabled, onPress: () => commit(i), style: [styles10.item, { height: ITEM }], children: /* @__PURE__ */ jsx11(
1088
- Text8,
1520
+ return /* @__PURE__ */ jsx15(Pressable8, { focusable: false, tabIndex: -1, disabled: disabled || o.disabled, onPress: () => commit(i), style: [styles14.item, { height: ITEM }], children: /* @__PURE__ */ jsx15(
1521
+ Text10,
1089
1522
  {
1090
1523
  numberOfLines: 1,
1091
1524
  style: [
1092
- styles10.itemText,
1525
+ styles14.itemText,
1093
1526
  {
1094
- color: o.disabled ? theme.textMuted : i === shown ? theme.textPrimary : theme.textSecondary,
1095
- fontWeight: i === shown ? "600" : "400",
1527
+ color: o.disabled ? theme.textMuted : i === shown && !unset ? theme.textPrimary : theme.textSecondary,
1528
+ fontWeight: i === shown && !unset ? "600" : "400",
1096
1529
  opacity: distance === 0 ? 1 : distance === 1 ? 0.7 : 0.4,
1097
1530
  transform: [{ scale: distance === 0 ? 1 : 0.92 }],
1098
1531
  textDecorationLine: o.disabled ? "line-through" : "none"
@@ -1107,9 +1540,9 @@ function Wheel({ label, options, value: valueProp, defaultValue, onValueChange,
1107
1540
  }
1108
1541
  );
1109
1542
  }
1110
- var styles10 = StyleSheet10.create({
1111
- root: { flexDirection: "row", alignItems: "stretch", borderWidth: StyleSheet10.hairlineWidth, paddingHorizontal: 6, gap: 4, overflow: "hidden", alignSelf: "flex-start" },
1112
- band: { position: "absolute", left: 6, right: 6, borderWidth: StyleSheet10.hairlineWidth },
1543
+ var styles14 = StyleSheet14.create({
1544
+ root: { flexDirection: "row", alignItems: "stretch", borderWidth: StyleSheet14.hairlineWidth, paddingHorizontal: 6, gap: 4, overflow: "hidden", alignSelf: "flex-start" },
1545
+ band: { position: "absolute", left: 6, right: 6, borderWidth: StyleSheet14.hairlineWidth },
1113
1546
  column: { minWidth: 56, flexGrow: 1 },
1114
1547
  item: { alignItems: "center", justifyContent: "center", paddingHorizontal: 8 },
1115
1548
  itemText: { fontSize: 18, fontVariant: ["tabular-nums"] },
@@ -1118,19 +1551,19 @@ var styles10 = StyleSheet10.create({
1118
1551
  });
1119
1552
 
1120
1553
  // src/native/date-time.tsx
1121
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1554
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1122
1555
  var longDate = (locale, iso) => new Intl.DateTimeFormat(locale, { dateStyle: "long" }).format(toLocalDate(iso));
1123
1556
  var useOwn = (value, initial) => {
1124
- const [own, setOwn] = React10.useState(initial);
1557
+ const [own, setOwn] = React14.useState(initial);
1125
1558
  return [value !== void 0 ? value : own, (next) => value === void 0 && setOwn(next)];
1126
1559
  };
1127
- function Chevron({ direction, color }) {
1128
- return /* @__PURE__ */ jsx12(Svg3, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx12(Path2, { d: direction === "left" ? "m15 18-6-6 6-6" : "m9 18 6-6-6-6" }) });
1560
+ function Chevron2({ direction, color }) {
1561
+ return /* @__PURE__ */ jsx16(Svg5, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx16(Path3, { d: direction === "left" ? "m15 18-6-6 6-6" : "m9 18 6-6-6-6" }) });
1129
1562
  }
1130
1563
  function NavButton({ label, direction, disabled, onPress }) {
1131
1564
  const { theme, radius: radius3 } = useTheme();
1132
- return /* @__PURE__ */ jsx12(
1133
- Pressable6,
1565
+ return /* @__PURE__ */ jsx16(
1566
+ Pressable9,
1134
1567
  {
1135
1568
  role: "button",
1136
1569
  "aria-label": label,
@@ -1138,49 +1571,49 @@ function NavButton({ label, direction, disabled, onPress }) {
1138
1571
  disabled,
1139
1572
  hitSlop: 6,
1140
1573
  onPress,
1141
- style: ({ pressed }) => [styles11.nav, { borderRadius: radius3.md, backgroundColor: pressed ? theme.surface3 : theme.surface2, borderColor: theme.borderSubtle }, disabled ? styles11.disabled : null],
1142
- children: /* @__PURE__ */ jsx12(Chevron, { direction, color: theme.textSecondary })
1574
+ style: ({ pressed }) => [styles15.nav, { borderRadius: radius3.md, backgroundColor: pressed ? theme.surface3 : theme.surface2, borderColor: theme.borderSubtle }, disabled ? styles15.disabled : null],
1575
+ children: /* @__PURE__ */ jsx16(Chevron2, { direction, color: theme.textSecondary })
1143
1576
  }
1144
1577
  );
1145
1578
  }
1146
1579
  function Node({ color, style }) {
1147
- return /* @__PURE__ */ jsx12(View8, { "aria-hidden": true, style: [styles11.node, { backgroundColor: color }, style] });
1580
+ return /* @__PURE__ */ jsx16(View12, { "aria-hidden": true, style: [styles15.node, { backgroundColor: color }, style] });
1148
1581
  }
1149
1582
  var calendarLabels = { previousMonth: "Previous month", nextMonth: "Next month" };
1150
1583
  function Calendar({ locale, value, range, onSelect, defaultMonth, min, max, isDateDisabled, weekStartsOn, today: todayProp, labels: given, style }) {
1151
1584
  const labels = { ...calendarLabels, ...given };
1152
1585
  const { theme, radius: radius3, haptic } = useTheme();
1153
1586
  const today = todayProp ?? todayIso();
1154
- const [month, setMonth] = React10.useState(`${(defaultMonth ?? value ?? range?.start ?? today).slice(0, 7)}-01`);
1587
+ const [month, setMonth] = React14.useState(`${(defaultMonth ?? value ?? range?.start ?? today).slice(0, 7)}-01`);
1155
1588
  const start = weekStartsOn ?? weekStartOf(locale);
1156
1589
  const weeks = monthGrid(month, start);
1157
1590
  const weekday = new Intl.DateTimeFormat(locale, { weekday: "narrow" });
1158
1591
  const title = new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(toLocalDate(month));
1159
1592
  const [lo, hi] = range?.end ? range.start <= range.end ? [range.start, range.end] : [range.end, range.start] : [null, null];
1160
1593
  const off = (iso) => Boolean(min && iso < min || max && iso > max || isDateDisabled?.(iso));
1161
- return /* @__PURE__ */ jsxs9(View8, { style: [styles11.calendar, { backgroundColor: theme.surface1, borderColor: theme.borderDefault, borderRadius: radius3.xl }, style], children: [
1162
- /* @__PURE__ */ jsxs9(View8, { style: styles11.header, children: [
1163
- /* @__PURE__ */ jsx12(NavButton, { label: labels.previousMonth, direction: "left", disabled: Boolean(min && addDays(month, -1) < min), onPress: () => setMonth(addMonths(month, -1)) }),
1164
- /* @__PURE__ */ jsx12(Text9, { role: "heading", "aria-live": "polite", style: [styles11.title, { color: theme.textPrimary }], children: title }),
1165
- /* @__PURE__ */ jsx12(NavButton, { label: labels.nextMonth, direction: "right", disabled: Boolean(max && addMonths(month, 1) > max), onPress: () => setMonth(addMonths(month, 1)) })
1594
+ return /* @__PURE__ */ jsxs13(View12, { style: [styles15.calendar, { backgroundColor: theme.surface1, borderColor: theme.borderDefault, borderRadius: radius3.xl }, style], children: [
1595
+ /* @__PURE__ */ jsxs13(View12, { style: styles15.header, children: [
1596
+ /* @__PURE__ */ jsx16(NavButton, { label: labels.previousMonth, direction: "left", disabled: Boolean(min && addDays(month, -1) < min), onPress: () => setMonth(addMonths(month, -1)) }),
1597
+ /* @__PURE__ */ jsx16(Text11, { role: "heading", "aria-live": "polite", style: [styles15.title, { color: theme.textPrimary }], children: title }),
1598
+ /* @__PURE__ */ jsx16(NavButton, { label: labels.nextMonth, direction: "right", disabled: Boolean(max && addMonths(month, 1) > max), onPress: () => setMonth(addMonths(month, 1)) })
1166
1599
  ] }),
1167
- /* @__PURE__ */ jsx12(View8, { style: styles11.week, "aria-hidden": true, children: weeks[0].map((iso) => /* @__PURE__ */ jsx12(Text9, { style: [styles11.weekday, { color: theme.textSecondary }], children: weekday.format(toLocalDate(iso)) }, iso)) }),
1168
- /* @__PURE__ */ jsx12(View8, { role: "radiogroup", "aria-label": title, children: weeks.map((week) => /* @__PURE__ */ jsx12(View8, { style: styles11.week, children: week.map((iso) => {
1600
+ /* @__PURE__ */ jsx16(View12, { style: styles15.week, "aria-hidden": true, children: weeks[0].map((iso) => /* @__PURE__ */ jsx16(Text11, { style: [styles15.weekday, { color: theme.textSecondary }], children: weekday.format(toLocalDate(iso)) }, iso)) }),
1601
+ /* @__PURE__ */ jsx16(View12, { role: "radiogroup", "aria-label": title, children: weeks.map((week) => /* @__PURE__ */ jsx16(View12, { style: styles15.week, children: week.map((iso) => {
1169
1602
  const outside = iso.slice(0, 7) !== month.slice(0, 7);
1170
1603
  const selected = iso === value || Boolean(range && (iso === range.start || iso === range.end));
1171
1604
  const disabled = off(iso);
1172
1605
  const band = lo && hi && lo !== hi && iso >= lo && iso <= hi;
1173
- return /* @__PURE__ */ jsx12(
1174
- View8,
1606
+ return /* @__PURE__ */ jsx16(
1607
+ View12,
1175
1608
  {
1176
1609
  style: [
1177
- styles11.cell,
1610
+ styles15.cell,
1178
1611
  band ? { backgroundColor: theme.accentSoft } : null,
1179
1612
  band && iso === lo ? { borderTopLeftRadius: radius3.lg, borderBottomLeftRadius: radius3.lg } : null,
1180
1613
  band && iso === hi ? { borderTopRightRadius: radius3.lg, borderBottomRightRadius: radius3.lg } : null
1181
1614
  ],
1182
- children: /* @__PURE__ */ jsxs9(
1183
- Pressable6,
1615
+ children: /* @__PURE__ */ jsxs13(
1616
+ Pressable9,
1184
1617
  {
1185
1618
  role: "radio",
1186
1619
  "aria-label": longDate(locale, iso),
@@ -1193,16 +1626,16 @@ function Calendar({ locale, value, range, onSelect, defaultMonth, min, max, isDa
1193
1626
  onSelect?.(iso);
1194
1627
  },
1195
1628
  style: ({ pressed }) => [
1196
- styles11.day,
1629
+ styles15.day,
1197
1630
  { borderRadius: radius3.lg },
1198
1631
  selected ? { backgroundColor: theme.accent } : pressed ? { backgroundColor: theme.surface3 } : null
1199
1632
  ],
1200
1633
  children: [
1201
- /* @__PURE__ */ jsx12(
1202
- Text9,
1634
+ /* @__PURE__ */ jsx16(
1635
+ Text11,
1203
1636
  {
1204
1637
  style: [
1205
- styles11.dayText,
1638
+ styles15.dayText,
1206
1639
  {
1207
1640
  color: selected ? theme.onAccent : disabled ? theme.textMuted : iso === today ? theme.accentText : outside ? theme.textSecondary : theme.textPrimary,
1208
1641
  fontWeight: selected || iso === today ? "700" : "400",
@@ -1212,7 +1645,7 @@ function Calendar({ locale, value, range, onSelect, defaultMonth, min, max, isDa
1212
1645
  children: Number(iso.slice(8))
1213
1646
  }
1214
1647
  ),
1215
- iso === today ? /* @__PURE__ */ jsx12(Node, { color: selected ? theme.onAccent : theme.accent, style: styles11.todayNode }) : null
1648
+ iso === today ? /* @__PURE__ */ jsx16(Node, { color: selected ? theme.onAccent : theme.accent, style: styles15.todayNode }) : null
1216
1649
  ]
1217
1650
  }
1218
1651
  )
@@ -1224,21 +1657,21 @@ function Calendar({ locale, value, range, onSelect, defaultMonth, min, max, isDa
1224
1657
  }
1225
1658
  function MonthPicker({ locale, value, onValueChange, min, max, labels, style }) {
1226
1659
  const { theme, radius: radius3, haptic } = useTheme();
1227
- const [year, setYear] = React10.useState(Number((value ?? todayIso()).slice(0, 4)));
1660
+ const [year, setYear] = React14.useState(Number((value ?? todayIso()).slice(0, 4)));
1228
1661
  const names = monthNames(locale, "short").map((n) => n.replace(/\.$/, ""));
1229
1662
  const long = monthNames(locale, "long");
1230
- return /* @__PURE__ */ jsxs9(View8, { style: [styles11.calendar, { backgroundColor: theme.surface1, borderColor: theme.borderDefault, borderRadius: radius3.xl }, style], children: [
1231
- /* @__PURE__ */ jsxs9(View8, { style: styles11.header, children: [
1232
- /* @__PURE__ */ jsx12(NavButton, { label: labels?.previousYear ?? "Previous year", direction: "left", disabled: Boolean(min && year - 1 < Number(min.slice(0, 4))), onPress: () => setYear(year - 1) }),
1233
- /* @__PURE__ */ jsx12(Text9, { role: "heading", "aria-live": "polite", style: [styles11.title, { color: theme.textPrimary }], children: year }),
1234
- /* @__PURE__ */ jsx12(NavButton, { label: labels?.nextYear ?? "Next year", direction: "right", disabled: Boolean(max && year + 1 > Number(max.slice(0, 4))), onPress: () => setYear(year + 1) })
1663
+ return /* @__PURE__ */ jsxs13(View12, { style: [styles15.calendar, { backgroundColor: theme.surface1, borderColor: theme.borderDefault, borderRadius: radius3.xl }, style], children: [
1664
+ /* @__PURE__ */ jsxs13(View12, { style: styles15.header, children: [
1665
+ /* @__PURE__ */ jsx16(NavButton, { label: labels?.previousYear ?? "Previous year", direction: "left", disabled: Boolean(min && year - 1 < Number(min.slice(0, 4))), onPress: () => setYear(year - 1) }),
1666
+ /* @__PURE__ */ jsx16(Text11, { role: "heading", "aria-live": "polite", style: [styles15.title, { color: theme.textPrimary }], children: year }),
1667
+ /* @__PURE__ */ jsx16(NavButton, { label: labels?.nextYear ?? "Next year", direction: "right", disabled: Boolean(max && year + 1 > Number(max.slice(0, 4))), onPress: () => setYear(year + 1) })
1235
1668
  ] }),
1236
- /* @__PURE__ */ jsx12(View8, { role: "radiogroup", "aria-label": String(year), style: styles11.months, children: names.map((name, i) => {
1669
+ /* @__PURE__ */ jsx16(View12, { role: "radiogroup", "aria-label": String(year), style: styles15.months, children: names.map((name, i) => {
1237
1670
  const id = `${year}-${String(i + 1).padStart(2, "0")}`;
1238
1671
  const selected = id === value;
1239
1672
  const disabled = Boolean(min && id < min || max && id > max);
1240
- return /* @__PURE__ */ jsx12(
1241
- Pressable6,
1673
+ return /* @__PURE__ */ jsx16(
1674
+ Pressable9,
1242
1675
  {
1243
1676
  role: "radio",
1244
1677
  "aria-checked": selected,
@@ -1249,8 +1682,8 @@ function MonthPicker({ locale, value, onValueChange, min, max, labels, style })
1249
1682
  haptic("selection");
1250
1683
  onValueChange?.(id);
1251
1684
  },
1252
- style: ({ pressed }) => [styles11.month, { borderRadius: radius3.lg, backgroundColor: selected ? theme.accent : pressed ? theme.surface3 : "transparent" }, disabled ? styles11.disabled : null],
1253
- children: /* @__PURE__ */ jsx12(Text9, { style: [styles11.monthText, { color: selected ? theme.onAccent : theme.textPrimary, fontWeight: selected ? "700" : "500" }], children: name })
1685
+ style: ({ pressed }) => [styles15.month, { borderRadius: radius3.lg, backgroundColor: selected ? theme.accent : pressed ? theme.surface3 : "transparent" }, disabled ? styles15.disabled : null],
1686
+ children: /* @__PURE__ */ jsx16(Text11, { style: [styles15.monthText, { color: selected ? theme.onAccent : theme.textPrimary, fontWeight: selected ? "700" : "500" }], children: name })
1254
1687
  },
1255
1688
  id
1256
1689
  );
@@ -1264,13 +1697,13 @@ function DayStrip({ label, locale, value: valueProp, defaultValue = null, onValu
1264
1697
  const [value, setValue] = useOwn(valueProp, defaultValue);
1265
1698
  const weekday = new Intl.DateTimeFormat(locale, { weekday: "short" });
1266
1699
  const list = Array.from({ length: days }, (_, i) => addDays(first, i));
1267
- return /* @__PURE__ */ jsx12(ScrollView3, { horizontal: true, showsHorizontalScrollIndicator: false, role: "radiogroup", "aria-label": label, contentContainerStyle: styles11.strip, style, children: list.map((iso) => {
1700
+ return /* @__PURE__ */ jsx16(ScrollView4, { horizontal: true, showsHorizontalScrollIndicator: false, role: "radiogroup", "aria-label": label, contentContainerStyle: styles15.strip, style, children: list.map((iso) => {
1268
1701
  const selected = iso === value;
1269
1702
  const disabled = Boolean(isDateDisabled?.(iso));
1270
1703
  const marked = Boolean(isDateMarked?.(iso));
1271
1704
  const name = longDate(locale, iso);
1272
- return /* @__PURE__ */ jsxs9(
1273
- Pressable6,
1705
+ return /* @__PURE__ */ jsxs13(
1706
+ Pressable9,
1274
1707
  {
1275
1708
  role: "radio",
1276
1709
  "aria-checked": selected,
@@ -1284,7 +1717,7 @@ function DayStrip({ label, locale, value: valueProp, defaultValue = null, onValu
1284
1717
  onValueChange?.(iso);
1285
1718
  },
1286
1719
  style: ({ pressed }) => [
1287
- styles11.stripDay,
1720
+ styles15.stripDay,
1288
1721
  {
1289
1722
  borderRadius: radius3.xl,
1290
1723
  backgroundColor: selected ? theme.accent : disabled ? "transparent" : theme.surface2,
@@ -1294,10 +1727,10 @@ function DayStrip({ label, locale, value: valueProp, defaultValue = null, onValu
1294
1727
  }
1295
1728
  ],
1296
1729
  children: [
1297
- iso === today ? /* @__PURE__ */ jsx12(Node, { color: selected ? theme.onAccent : theme.accent, style: styles11.stripNode }) : null,
1298
- /* @__PURE__ */ jsx12(Text9, { style: [styles11.stripWeekday, { color: selected ? theme.onAccent : disabled ? theme.textMuted : theme.textSecondary }], children: weekday.format(toLocalDate(iso)).replace(/\.$/, "").toUpperCase() }),
1299
- /* @__PURE__ */ jsx12(Text9, { style: [styles11.stripNumber, { color: selected ? theme.onAccent : disabled ? theme.textMuted : theme.textPrimary }], children: Number(iso.slice(8)) }),
1300
- /* @__PURE__ */ jsx12(View8, { style: [styles11.dot, marked ? { backgroundColor: selected ? theme.onAccent : theme.textSecondary } : null] })
1730
+ iso === today ? /* @__PURE__ */ jsx16(Node, { color: selected ? theme.onAccent : theme.accent, style: styles15.stripNode }) : null,
1731
+ /* @__PURE__ */ jsx16(Text11, { style: [styles15.stripWeekday, { color: selected ? theme.onAccent : disabled ? theme.textMuted : theme.textSecondary }], children: weekday.format(toLocalDate(iso)).replace(/\.$/, "").toUpperCase() }),
1732
+ /* @__PURE__ */ jsx16(Text11, { style: [styles15.stripNumber, { color: selected ? theme.onAccent : disabled ? theme.textMuted : theme.textPrimary }], children: Number(iso.slice(8)) }),
1733
+ /* @__PURE__ */ jsx16(View12, { style: [styles15.dot, marked ? { backgroundColor: selected ? theme.onAccent : theme.textSecondary } : null] })
1301
1734
  ]
1302
1735
  },
1303
1736
  iso
@@ -1312,11 +1745,11 @@ function TimePicker({ label, locale, value: valueProp, defaultValue = null, onVa
1312
1745
  onValueChange?.(next);
1313
1746
  };
1314
1747
  if (variant === "slots")
1315
- return /* @__PURE__ */ jsx12(View8, { role: "radiogroup", "aria-label": label, style: [styles11.slots, style], children: slots.map((t) => {
1748
+ return /* @__PURE__ */ jsx16(View12, { role: "radiogroup", "aria-label": label, style: [styles15.slots, style], children: slots.map((t) => {
1316
1749
  const selected = t === value;
1317
1750
  const off = disabled || Boolean(isTimeDisabled?.(t));
1318
- return /* @__PURE__ */ jsx12(
1319
- Pressable6,
1751
+ return /* @__PURE__ */ jsx16(
1752
+ Pressable9,
1320
1753
  {
1321
1754
  role: "radio",
1322
1755
  "aria-checked": selected,
@@ -1328,7 +1761,7 @@ function TimePicker({ label, locale, value: valueProp, defaultValue = null, onVa
1328
1761
  set(t);
1329
1762
  },
1330
1763
  style: ({ pressed }) => [
1331
- styles11.slot,
1764
+ styles15.slot,
1332
1765
  {
1333
1766
  borderRadius: radius3.lg,
1334
1767
  backgroundColor: selected ? theme.accent : off ? "transparent" : theme.surface2,
@@ -1337,7 +1770,7 @@ function TimePicker({ label, locale, value: valueProp, defaultValue = null, onVa
1337
1770
  transform: [{ scale: pressed ? 0.97 : 1 }]
1338
1771
  }
1339
1772
  ],
1340
- children: /* @__PURE__ */ jsx12(Text9, { style: [styles11.slotText, { color: selected ? theme.onAccent : off ? theme.textMuted : theme.textPrimary, textDecorationLine: off ? "line-through" : "none" }], children: formatTime(locale, t) })
1773
+ children: /* @__PURE__ */ jsx16(Text11, { style: [styles15.slotText, { color: selected ? theme.onAccent : off ? theme.textMuted : theme.textPrimary, textDecorationLine: off ? "line-through" : "none" }], children: formatTime(locale, t) })
1341
1774
  },
1342
1775
  t
1343
1776
  );
@@ -1353,11 +1786,11 @@ function TimePicker({ label, locale, value: valueProp, defaultValue = null, onVa
1353
1786
  const hours = twelve ? [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map((h) => ({ value: String(h), label: String(h) })) : Array.from({ length: 24 }, (_, h) => ({ value: String(h), label: two(h) }));
1354
1787
  const minutes = Array.from({ length: Math.ceil(60 / minuteStep) }, (_, i) => ({ value: String(i * minuteStep), label: two(i * minuteStep) }));
1355
1788
  const [am, pmLabel] = dayPeriods(locale);
1356
- return /* @__PURE__ */ jsxs9(WheelPicker, { label: value ? `${label}, ${formatTime(locale, value)}` : label, style, children: [
1357
- /* @__PURE__ */ jsx12(Wheel, { label: labels.hours, options: hours, disabled, value: twelve ? String(h24 % 12 === 0 ? 12 : h24 % 12) : String(h24), onValueChange: (v) => put(twelve ? Number(v) % 12 + (pm ? 12 : 0) : Number(v), minute) }),
1358
- /* @__PURE__ */ jsx12(WheelDivider, { children: ":" }),
1359
- /* @__PURE__ */ jsx12(Wheel, { label: labels.minutes, options: minutes, disabled, value: String(Math.min(60 - minuteStep, Math.round(minute / minuteStep) * minuteStep)), onValueChange: (v) => put(h24, Number(v)) }),
1360
- twelve ? /* @__PURE__ */ jsx12(
1789
+ return /* @__PURE__ */ jsxs13(WheelPicker, { label: value ? `${label}, ${formatTime(locale, value)}` : label, style, children: [
1790
+ /* @__PURE__ */ jsx16(Wheel, { label: labels.hours, options: hours, disabled, value: twelve ? String(h24 % 12 === 0 ? 12 : h24 % 12) : String(h24), onValueChange: (v) => put(twelve ? Number(v) % 12 + (pm ? 12 : 0) : Number(v), minute) }),
1791
+ /* @__PURE__ */ jsx16(WheelDivider, { children: ":" }),
1792
+ /* @__PURE__ */ jsx16(Wheel, { label: labels.minutes, options: minutes, disabled, value: String(Math.min(60 - minuteStep, Math.round(minute / minuteStep) * minuteStep)), onValueChange: (v) => put(h24, Number(v)) }),
1793
+ twelve ? /* @__PURE__ */ jsx16(
1361
1794
  Wheel,
1362
1795
  {
1363
1796
  label: labels.period,
@@ -1390,22 +1823,22 @@ function DateWheel({ label, locale, value: valueProp, defaultValue = null, onVal
1390
1823
  };
1391
1824
  const last = daysInMonth(year, month);
1392
1825
  const columns = {
1393
- day: /* @__PURE__ */ jsx12(Wheel, { label: names.day, disabled, options: Array.from({ length: last }, (_, i) => ({ value: String(i + 1), label: String(i + 1), disabled: isoOf(year, month, i + 1) > hi || isoOf(year, month, i + 1) < lo })), value: String(Math.min(day, last)), onValueChange: (v) => set(year, month, Number(v)), style: styles11.dayWheel }, "day"),
1394
- month: /* @__PURE__ */ jsx12(Wheel, { label: names.month, disabled, options: months.map((n, i) => ({ value: String(i + 1), label: n, disabled: isoOf(year, i + 1, 1) > hi || isoOf(year, i + 1, daysInMonth(year, i + 1)) < lo })), value: String(month), onValueChange: (v) => set(year, Number(v), day), style: styles11.monthWheel }, "month"),
1395
- year: /* @__PURE__ */ jsx12(Wheel, { label: names.year, disabled, options: yearRange(Number(hi.slice(0, 4)), Number(lo.slice(0, 4))).map((y) => ({ value: String(y), label: String(y) })), value: String(year), onValueChange: (v) => set(Number(v), month, day), style: styles11.yearWheel }, "year")
1826
+ day: /* @__PURE__ */ jsx16(Wheel, { label: names.day, disabled, options: Array.from({ length: last }, (_, i) => ({ value: String(i + 1), label: String(i + 1), disabled: isoOf(year, month, i + 1) > hi || isoOf(year, month, i + 1) < lo })), value: String(Math.min(day, last)), onValueChange: (v) => set(year, month, Number(v)), style: styles15.dayWheel }, "day"),
1827
+ month: /* @__PURE__ */ jsx16(Wheel, { label: names.month, disabled, options: months.map((n, i) => ({ value: String(i + 1), label: n, disabled: isoOf(year, i + 1, 1) > hi || isoOf(year, i + 1, daysInMonth(year, i + 1)) < lo })), value: String(month), onValueChange: (v) => set(year, Number(v), day), style: styles15.monthWheel }, "month"),
1828
+ year: /* @__PURE__ */ jsx16(Wheel, { label: names.year, disabled, options: yearRange(Number(hi.slice(0, 4)), Number(lo.slice(0, 4))).map((y) => ({ value: String(y), label: String(y) })), value: String(year), onValueChange: (v) => set(Number(v), month, day), style: styles15.yearWheel }, "year")
1396
1829
  };
1397
1830
  const caption = error ?? hint;
1398
- return /* @__PURE__ */ jsxs9(View8, { style: [styles11.field, style], children: [
1399
- /* @__PURE__ */ jsx12(Text9, { "aria-hidden": true, style: [styles11.fieldLabel, { color: theme.textSecondary }], children: label }),
1400
- /* @__PURE__ */ jsx12(WheelPicker, { label, invalid: Boolean(error), children: datePartsOrder(locale).map((part) => columns[part]) }),
1401
- caption ? /* @__PURE__ */ jsx12(Text9, { role: error ? "alert" : void 0, "aria-live": error ? "polite" : void 0, style: [styles11.caption, { color: error ? theme.dangerText : theme.textSecondary }], children: caption }) : null
1831
+ return /* @__PURE__ */ jsxs13(View12, { style: [styles15.field, style], children: [
1832
+ /* @__PURE__ */ jsx16(Text11, { "aria-hidden": true, style: [styles15.fieldLabel, { color: theme.textSecondary }], children: label }),
1833
+ /* @__PURE__ */ jsx16(WheelPicker, { label, invalid: Boolean(error), unset: !value, children: datePartsOrder(locale).map((part) => columns[part]) }),
1834
+ caption ? /* @__PURE__ */ jsx16(Text11, { role: error ? "alert" : void 0, "aria-live": error ? "polite" : void 0, style: [styles15.caption, { color: error ? theme.dangerText : theme.textSecondary }], children: caption }) : null
1402
1835
  ] });
1403
1836
  }
1404
- var styles11 = StyleSheet11.create({
1405
- calendar: { padding: 12, gap: 4, borderWidth: StyleSheet11.hairlineWidth, alignSelf: "flex-start" },
1837
+ var styles15 = StyleSheet15.create({
1838
+ calendar: { padding: 12, gap: 4, borderWidth: StyleSheet15.hairlineWidth, alignSelf: "flex-start" },
1406
1839
  header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 6, gap: 8 },
1407
1840
  title: { fontSize: 15, fontWeight: "700", textTransform: "capitalize" },
1408
- nav: { width: 36, height: 36, alignItems: "center", justifyContent: "center", borderWidth: StyleSheet11.hairlineWidth },
1841
+ nav: { width: 36, height: 36, alignItems: "center", justifyContent: "center", borderWidth: StyleSheet15.hairlineWidth },
1409
1842
  week: { flexDirection: "row" },
1410
1843
  weekday: { width: 44, textAlign: "center", fontSize: 11, fontWeight: "700", paddingBottom: 4 },
1411
1844
  cell: { width: 44, height: 44, marginVertical: 1 },
@@ -1434,39 +1867,115 @@ var styles11 = StyleSheet11.create({
1434
1867
  disabled: { opacity: 0.4 }
1435
1868
  });
1436
1869
 
1437
- // src/native/empty-state.tsx
1438
- import { StyleSheet as StyleSheet12, View as View9 } from "react-native";
1439
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1440
- function EmptyState({ icon, title, description, action, style, ...props }) {
1441
- const { theme } = useTheme();
1442
- return /* @__PURE__ */ jsxs10(View9, { ...props, style: [styles12.root, style], children: [
1443
- icon ? /* @__PURE__ */ jsx13(View9, { "aria-hidden": true, style: [styles12.icon, { backgroundColor: theme.surface2 }], children: icon }) : null,
1444
- /* @__PURE__ */ jsx13(Txt, { variant: "label", role: "heading", style: styles12.center, children: title }),
1445
- description ? /* @__PURE__ */ jsx13(Txt, { tone: "secondary", style: styles12.center, children: description }) : null,
1446
- action ? /* @__PURE__ */ jsx13(View9, { style: styles12.action, children: action }) : null
1447
- ] });
1448
- }
1449
- var styles12 = StyleSheet12.create({
1450
- root: { alignItems: "center", justifyContent: "center", gap: 8, paddingVertical: 40, paddingHorizontal: 24 },
1451
- icon: { width: 48, height: 48, borderRadius: 24, alignItems: "center", justifyContent: "center", marginBottom: 4 },
1452
- center: { textAlign: "center", maxWidth: 360 },
1870
+ // src/native/description-list.tsx
1871
+ import { StyleSheet as StyleSheet16, View as View13 } from "react-native";
1872
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1873
+ function DescriptionList({ items: items2, layout = "stacked", style }) {
1874
+ const { theme, radius: radius3 } = useTheme();
1875
+ return /* @__PURE__ */ jsx17(View13, { role: "list", style: [layout === "grid" ? styles16.grid : layout === "inline" ? null : styles16.stacked, style], children: items2.map((item, i) => {
1876
+ const value = typeof item.details === "string" || typeof item.details === "number" ? /* @__PURE__ */ jsx17(Txt, { variant: layout === "grid" ? "title" : "body", style: layout === "inline" ? styles16.right : null, children: item.details }) : item.details;
1877
+ return /* @__PURE__ */ jsxs14(
1878
+ View13,
1879
+ {
1880
+ role: "listitem",
1881
+ accessible: true,
1882
+ style: [
1883
+ layout === "inline" ? [styles16.inline, i > 0 ? { borderTopWidth: StyleSheet16.hairlineWidth, borderTopColor: theme.borderSubtle } : null] : null,
1884
+ layout === "grid" ? [styles16.card, { backgroundColor: theme.surface1, borderColor: theme.borderDefault, borderRadius: radius3.lg }] : null
1885
+ ],
1886
+ children: [
1887
+ /* @__PURE__ */ jsx17(Txt, { variant: "caption", tone: "secondary", style: layout === "grid" ? styles16.upper : null, children: item.term }),
1888
+ /* @__PURE__ */ jsxs14(View13, { style: layout === "inline" ? styles16.valueInline : styles16.value, children: [
1889
+ value,
1890
+ item.hint ? /* @__PURE__ */ jsx17(Txt, { variant: "caption", tone: "secondary", style: layout === "inline" ? styles16.right : null, children: item.hint }) : null
1891
+ ] })
1892
+ ]
1893
+ },
1894
+ item.id ?? item.term
1895
+ );
1896
+ }) });
1897
+ }
1898
+ var styles16 = StyleSheet16.create({
1899
+ stacked: { gap: 14 },
1900
+ inline: { flexDirection: "row", alignItems: "baseline", justifyContent: "space-between", gap: 16, paddingVertical: 10 },
1901
+ grid: { flexDirection: "row", flexWrap: "wrap", gap: 10 },
1902
+ card: { flexBasis: "47%", flexGrow: 1, padding: 12, gap: 4, borderWidth: StyleSheet16.hairlineWidth },
1903
+ upper: { textTransform: "uppercase", letterSpacing: 0.6, fontWeight: "700" },
1904
+ value: { gap: 2, marginTop: 2 },
1905
+ valueInline: { flexShrink: 1, alignItems: "flex-end", gap: 2 },
1906
+ right: { textAlign: "right" }
1907
+ });
1908
+
1909
+ // src/native/empty-state.tsx
1910
+ import { StyleSheet as StyleSheet17, View as View14 } from "react-native";
1911
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1912
+ function EmptyState({ icon, title, description, action, style, ...props }) {
1913
+ const { theme } = useTheme();
1914
+ return /* @__PURE__ */ jsxs15(View14, { ...props, style: [styles17.root, style], children: [
1915
+ icon ? /* @__PURE__ */ jsx18(View14, { "aria-hidden": true, style: [styles17.icon, { backgroundColor: theme.surface2 }], children: icon }) : null,
1916
+ /* @__PURE__ */ jsx18(Txt, { variant: "label", role: "heading", style: styles17.center, children: title }),
1917
+ description ? /* @__PURE__ */ jsx18(Txt, { tone: "secondary", style: styles17.center, children: description }) : null,
1918
+ action ? /* @__PURE__ */ jsx18(View14, { style: styles17.action, children: action }) : null
1919
+ ] });
1920
+ }
1921
+ var styles17 = StyleSheet17.create({
1922
+ root: { alignItems: "center", justifyContent: "center", gap: 8, paddingVertical: 40, paddingHorizontal: 24 },
1923
+ icon: { width: 48, height: 48, borderRadius: 24, alignItems: "center", justifyContent: "center", marginBottom: 4 },
1924
+ center: { textAlign: "center", maxWidth: 360 },
1453
1925
  action: { marginTop: 8, flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: 8 }
1454
1926
  });
1455
1927
 
1928
+ // src/native/fab.tsx
1929
+ import { Pressable as Pressable10, StyleSheet as StyleSheet18, View as View15 } from "react-native";
1930
+ import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
1931
+ function Fab({ label, icon, onPress, extended, placement = "end", offset = 0, style }) {
1932
+ const { theme, insets, haptic } = useTheme();
1933
+ const position = placement === "center" ? { alignSelf: "center" } : placement === "start" ? { left: 16 + insets.left } : { right: 16 + insets.right };
1934
+ return /* @__PURE__ */ jsx19(View15, { pointerEvents: "box-none", style: [styles18.layer, placement === "center" ? styles18.centre : null], children: /* @__PURE__ */ jsxs16(
1935
+ Pressable10,
1936
+ {
1937
+ role: "button",
1938
+ "aria-label": label,
1939
+ onPress: () => {
1940
+ haptic("impact");
1941
+ onPress();
1942
+ },
1943
+ style: ({ pressed }) => [
1944
+ styles18.fab,
1945
+ extended ? styles18.extended : null,
1946
+ position,
1947
+ { bottom: 16 + insets.bottom + offset, backgroundColor: pressed ? theme.accentHover : theme.accent, borderTopColor: theme.edgeOnFill, shadowColor: theme.scrimStrong },
1948
+ style
1949
+ ],
1950
+ children: [
1951
+ /* @__PURE__ */ jsx19(View15, { "aria-hidden": true, children: icon }),
1952
+ extended ? /* @__PURE__ */ jsx19(Txt, { variant: "label", tone: "onAccent", "aria-hidden": true, numberOfLines: 1, style: styles18.label, children: label }) : null
1953
+ ]
1954
+ }
1955
+ ) });
1956
+ }
1957
+ var styles18 = StyleSheet18.create({
1958
+ layer: { position: "absolute", top: 0, right: 0, bottom: 0, left: 0 },
1959
+ centre: { alignItems: "center" },
1960
+ fab: { borderTopWidth: 1, borderColor: "transparent", position: "absolute", minWidth: 56, height: 56, borderRadius: 28, alignItems: "center", justifyContent: "center", flexDirection: "row", gap: 8, shadowOpacity: 0.3, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, elevation: 6 },
1961
+ extended: { paddingHorizontal: 20 },
1962
+ label: { flexShrink: 0 }
1963
+ });
1964
+
1456
1965
  // src/native/field.tsx
1457
- import * as React11 from "react";
1458
- import { StyleSheet as StyleSheet13, Text as Text10, TextInput as TextInput2, View as View10 } from "react-native";
1459
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1966
+ import * as React15 from "react";
1967
+ import { StyleSheet as StyleSheet19, Text as Text12, TextInput as TextInput3, View as View16 } from "react-native";
1968
+ import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
1460
1969
  function TextField({ label, hint, error, value, defaultValue, onValueChange, disabled, end, inputRef, style, multiline, onFocus, onBlur, ...props }) {
1461
1970
  const { theme, radius: radius3 } = useTheme();
1462
- const [focused, setFocused] = React11.useState(false);
1971
+ const [focused, setFocused] = React15.useState(false);
1463
1972
  const caption = error ?? hint;
1464
1973
  const border = error ? theme.danger : focused ? theme.accent : theme.borderDefault;
1465
- return /* @__PURE__ */ jsxs11(View10, { style: [styles13.root, disabled ? styles13.disabled : null, style], children: [
1466
- /* @__PURE__ */ jsx14(Text10, { style: [styles13.label, { color: theme.textSecondary }], children: label }),
1467
- /* @__PURE__ */ jsxs11(View10, { style: [styles13.frame, multiline ? styles13.multiline : null, { borderRadius: radius3.md, borderColor: border, backgroundColor: theme.surface2 }], children: [
1468
- /* @__PURE__ */ jsx14(
1469
- TextInput2,
1974
+ return /* @__PURE__ */ jsxs17(View16, { style: [styles19.root, disabled ? styles19.disabled : null, style], children: [
1975
+ /* @__PURE__ */ jsx20(Text12, { style: [styles19.label, { color: theme.textSecondary }], children: label }),
1976
+ /* @__PURE__ */ jsxs17(View16, { style: [styles19.frame, multiline ? styles19.multiline : null, { borderRadius: radius3.md, borderColor: border, backgroundColor: theme.surface2 }], children: [
1977
+ /* @__PURE__ */ jsx20(
1978
+ TextInput3,
1470
1979
  {
1471
1980
  ref: inputRef,
1472
1981
  "aria-label": label,
@@ -1487,16 +1996,16 @@ function TextField({ label, hint, error, value, defaultValue, onValueChange, dis
1487
1996
  setFocused(false);
1488
1997
  onBlur?.(event);
1489
1998
  },
1490
- style: [styles13.input, multiline ? styles13.inputMultiline : null, { color: theme.textPrimary }],
1999
+ style: [styles19.input, multiline ? styles19.inputMultiline : null, { color: theme.textPrimary }],
1491
2000
  ...props
1492
2001
  }
1493
2002
  ),
1494
- end ? /* @__PURE__ */ jsx14(View10, { style: styles13.end, children: end }) : null
2003
+ end ? /* @__PURE__ */ jsx20(View16, { style: styles19.end, children: end }) : null
1495
2004
  ] }),
1496
- caption ? /* @__PURE__ */ jsx14(Text10, { role: error ? "alert" : void 0, "aria-live": error ? "polite" : void 0, style: [styles13.caption, { color: error ? theme.dangerText : theme.textSecondary }], children: caption }) : null
2005
+ caption ? /* @__PURE__ */ jsx20(Text12, { role: error ? "alert" : void 0, "aria-live": error ? "polite" : void 0, style: [styles19.caption, { color: error ? theme.dangerText : theme.textSecondary }], children: caption }) : null
1497
2006
  ] });
1498
2007
  }
1499
- var styles13 = StyleSheet13.create({
2008
+ var styles19 = StyleSheet19.create({
1500
2009
  root: { gap: 6, alignSelf: "stretch" },
1501
2010
  label: { fontSize: 12, lineHeight: 16, fontWeight: "600" },
1502
2011
  frame: { flexDirection: "row", alignItems: "center", minHeight: 44, paddingHorizontal: 12, borderWidth: 1 },
@@ -1509,20 +2018,20 @@ var styles13 = StyleSheet13.create({
1509
2018
  });
1510
2019
 
1511
2020
  // src/native/goal-gauge.tsx
1512
- import { Animated as Animated4, StyleSheet as StyleSheet14, View as View11 } from "react-native";
2021
+ import { Animated as Animated5, StyleSheet as StyleSheet20, View as View17 } from "react-native";
1513
2022
 
1514
2023
  // src/native/story-motion.ts
1515
- import * as React12 from "react";
1516
- import { AccessibilityInfo as AccessibilityInfo2, Animated as Animated3, Easing } from "react-native";
2024
+ import * as React16 from "react";
2025
+ import { AccessibilityInfo as AccessibilityInfo3, Animated as Animated4, Easing } from "react-native";
1517
2026
  function useEntrance(animated, delay = 0, duration = 700) {
1518
- const [value] = React12.useState(() => new Animated3.Value(animated ? 0 : 1));
1519
- React12.useEffect(() => {
2027
+ const [value] = React16.useState(() => new Animated4.Value(animated ? 0 : 1));
2028
+ React16.useEffect(() => {
1520
2029
  if (!animated) return;
1521
2030
  let cancelled = false;
1522
- void AccessibilityInfo2.isReduceMotionEnabled().then((reduce) => {
2031
+ void AccessibilityInfo3.isReduceMotionEnabled().then((reduce) => {
1523
2032
  if (cancelled) return;
1524
2033
  if (reduce) value.setValue(1);
1525
- else Animated3.timing(value, { toValue: 1, duration, delay, easing: Easing.out(Easing.cubic), useNativeDriver: true }).start();
2034
+ else Animated4.timing(value, { toValue: 1, duration, delay, easing: Easing.out(Easing.cubic), useNativeDriver: true }).start();
1526
2035
  });
1527
2036
  return () => {
1528
2037
  cancelled = true;
@@ -1532,17 +2041,17 @@ function useEntrance(animated, delay = 0, duration = 700) {
1532
2041
  }
1533
2042
 
1534
2043
  // src/native/goal-gauge.tsx
1535
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
2044
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
1536
2045
  function Cell({ lit, animate, order, animated, arcade }) {
1537
2046
  const { theme } = useTheme();
1538
2047
  const t = useEntrance(animated && animate, 300 + order * 100, 350);
1539
2048
  const spentOpacity = arcade ? 0.14 : 1;
1540
2049
  const opacity = !animate ? 1 : lit ? t.interpolate({ inputRange: [0, 1], outputRange: [0.25, 1] }) : t.interpolate({ inputRange: [0, 1], outputRange: [1, arcade ? 0.14 : 1] });
1541
2050
  const color = lit || arcade ? theme.accent : theme.surface3;
1542
- return /* @__PURE__ */ jsx15(
1543
- Animated4.View,
2051
+ return /* @__PURE__ */ jsx21(
2052
+ Animated5.View,
1544
2053
  {
1545
- style: [styles14.cell, arcade ? styles14.cellArcade : null, { backgroundColor: color, opacity: lit || animate ? opacity : spentOpacity }]
2054
+ style: [styles20.cell, arcade ? styles20.cellArcade : null, { backgroundColor: color, opacity: lit || animate ? opacity : spentOpacity }]
1546
2055
  }
1547
2056
  );
1548
2057
  }
@@ -1552,8 +2061,8 @@ function GoalGauge({ label, segments, value, valueText, mode = "fill", showLabel
1552
2061
  const lit = Math.min(total, Math.max(0, Math.round(value ?? total)));
1553
2062
  const words = valueText ?? `${lit} / ${total}`;
1554
2063
  const arcade = variant === "arcade";
1555
- return /* @__PURE__ */ jsxs12(
1556
- View11,
2064
+ return /* @__PURE__ */ jsxs18(
2065
+ View17,
1557
2066
  {
1558
2067
  accessible: true,
1559
2068
  role: "meter",
@@ -1563,22 +2072,22 @@ function GoalGauge({ label, segments, value, valueText, mode = "fill", showLabel
1563
2072
  "aria-valuenow": lit,
1564
2073
  "aria-valuetext": words,
1565
2074
  ...props,
1566
- style: [styles14.root, style],
2075
+ style: [styles20.root, style],
1567
2076
  children: [
1568
- showLabel ? /* @__PURE__ */ jsxs12(View11, { "aria-hidden": true, style: [styles14.head, arcade ? styles14.headArcade : null], children: [
1569
- /* @__PURE__ */ jsx15(Txt, { variant: arcade ? "mono" : "caption", tone: "secondary", children: arcade ? label.toUpperCase() : label }),
1570
- arcade ? null : /* @__PURE__ */ jsx15(Txt, { variant: "caption", children: words })
2077
+ showLabel ? /* @__PURE__ */ jsxs18(View17, { "aria-hidden": true, style: [styles20.head, arcade ? styles20.headArcade : null], children: [
2078
+ /* @__PURE__ */ jsx21(Txt, { variant: arcade ? "mono" : "caption", tone: "secondary", children: arcade ? label.toUpperCase() : label }),
2079
+ arcade ? null : /* @__PURE__ */ jsx21(Txt, { variant: "caption", children: words })
1571
2080
  ] }) : null,
1572
- /* @__PURE__ */ jsx15(View11, { "aria-hidden": true, style: [styles14.cells, arcade ? [styles14.cellsArcade, { borderColor: theme.borderSubtle, backgroundColor: theme.surface1 }] : null], children: Array.from({ length: total }, (_, i) => {
2081
+ /* @__PURE__ */ jsx21(View17, { "aria-hidden": true, style: [styles20.cells, arcade ? [styles20.cellsArcade, { borderColor: theme.borderSubtle, backgroundColor: theme.surface1 }] : null], children: Array.from({ length: total }, (_, i) => {
1573
2082
  const on = i < lit;
1574
2083
  const animate = mode === "fill" ? on : !on;
1575
- return /* @__PURE__ */ jsx15(Cell, { lit: on, animate, order: mode === "fill" ? i : i - lit, animated, arcade }, i);
2084
+ return /* @__PURE__ */ jsx21(Cell, { lit: on, animate, order: mode === "fill" ? i : i - lit, animated, arcade }, i);
1576
2085
  }) })
1577
2086
  ]
1578
2087
  }
1579
2088
  );
1580
2089
  }
1581
- var styles14 = StyleSheet14.create({
2090
+ var styles20 = StyleSheet20.create({
1582
2091
  root: { alignSelf: "stretch", gap: 8 },
1583
2092
  head: { flexDirection: "row", justifyContent: "space-between", alignItems: "baseline", gap: 12 },
1584
2093
  headArcade: { justifyContent: "center" },
@@ -1588,9 +2097,190 @@ var styles14 = StyleSheet14.create({
1588
2097
  cellArcade: { height: 10, borderRadius: 1 }
1589
2098
  });
1590
2099
 
2100
+ // src/native/header.tsx
2101
+ import * as React17 from "react";
2102
+ import { Animated as Animated6, Pressable as Pressable11, StyleSheet as StyleSheet21, View as View18 } from "react-native";
2103
+ import Svg6, { Path as Path4 } from "react-native-svg";
2104
+ import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
2105
+ var BAR = 44;
2106
+ var LARGE = 52;
2107
+ function Header({ title, subtitle, scrollY, size = "large", backLabel, onBack, actions, children, style }) {
2108
+ const { theme, insets } = useTheme();
2109
+ const reduce = useReducedMotion();
2110
+ const large = size === "large";
2111
+ const fixed = React17.useMemo(() => new Animated6.Value(large ? 0 : 1), [large]);
2112
+ const progress = scrollY && large ? scrollY.interpolate({ inputRange: [0, LARGE], outputRange: [0, 1], extrapolate: "clamp" }) : fixed;
2113
+ const smallOpacity = progress.interpolate({ inputRange: [0.6, 1], outputRange: [0, 1], extrapolate: "clamp" });
2114
+ const largeOpacity = progress.interpolate({ inputRange: [0, 0.7], outputRange: [1, 0], extrapolate: "clamp" });
2115
+ const largeShift = reduce ? 0 : progress.interpolate({ inputRange: [0, 1], outputRange: [0, -10] });
2116
+ const largeHeight = progress.interpolate({ inputRange: [0, 1], outputRange: [LARGE + (subtitle ? 18 : 0), 0] });
2117
+ return /* @__PURE__ */ jsxs19(View18, { style: [{ paddingTop: insets.top, backgroundColor: theme.surface0 }, style], children: [
2118
+ /* @__PURE__ */ jsxs19(View18, { style: styles21.bar, children: [
2119
+ /* @__PURE__ */ jsx22(View18, { style: styles21.side, children: onBack && backLabel ? /* @__PURE__ */ jsxs19(Pressable11, { role: "button", "aria-label": backLabel, onPress: onBack, hitSlop: 8, style: styles21.back, children: [
2120
+ /* @__PURE__ */ jsx22(Svg6, { width: 22, height: 22, viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx22(Path4, { d: "M15 5l-7 7 7 7", stroke: theme.accentText, strokeWidth: 2.4, fill: "none", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2121
+ /* @__PURE__ */ jsx22(Txt, { variant: "label", tone: "accent", numberOfLines: 1, children: backLabel })
2122
+ ] }) : null }),
2123
+ /* @__PURE__ */ jsx22(Animated6.View, { style: [styles21.middle, { opacity: smallOpacity }], "aria-hidden": large, children: /* @__PURE__ */ jsx22(Txt, { variant: "label", numberOfLines: 1, role: large ? void 0 : "heading", children: title }) }),
2124
+ /* @__PURE__ */ jsx22(View18, { style: [styles21.side, styles21.right], children: actions })
2125
+ ] }),
2126
+ large ? /* @__PURE__ */ jsx22(Animated6.View, { style: { height: largeHeight, overflow: "hidden" }, children: /* @__PURE__ */ jsxs19(Animated6.View, { style: [styles21.large, { opacity: largeOpacity, transform: [{ translateY: largeShift }] }], children: [
2127
+ /* @__PURE__ */ jsx22(Txt, { variant: "display", numberOfLines: 1, role: "heading", style: styles21.largeTitle, children: title }),
2128
+ subtitle ? /* @__PURE__ */ jsx22(Txt, { variant: "caption", tone: "secondary", children: subtitle }) : null
2129
+ ] }) }) : null,
2130
+ children ? /* @__PURE__ */ jsx22(View18, { style: styles21.children, children }) : null,
2131
+ /* @__PURE__ */ jsx22(Animated6.View, { "aria-hidden": true, style: [styles21.rule, { backgroundColor: theme.borderSubtle, opacity: smallOpacity }] })
2132
+ ] });
2133
+ }
2134
+ function useCollapsingHeader() {
2135
+ const [scrollY] = React17.useState(() => new Animated6.Value(0));
2136
+ const onScroll = React17.useMemo(() => Animated6.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: false }), [scrollY]);
2137
+ return { scrollY, onScroll };
2138
+ }
2139
+ var styles21 = StyleSheet21.create({
2140
+ bar: { height: BAR, flexDirection: "row", alignItems: "center", paddingHorizontal: 8 },
2141
+ side: { flex: 1, flexDirection: "row", alignItems: "center" },
2142
+ right: { justifyContent: "flex-end", gap: 4 },
2143
+ middle: { flex: 2, alignItems: "center" },
2144
+ back: { flexDirection: "row", alignItems: "center", gap: 2, minHeight: 44, paddingRight: 8 },
2145
+ large: { paddingHorizontal: 16, paddingBottom: 6 },
2146
+ largeTitle: { fontSize: 32, lineHeight: 40 },
2147
+ children: { paddingHorizontal: 16, paddingBottom: 8 },
2148
+ rule: { height: StyleSheet21.hairlineWidth }
2149
+ });
2150
+
2151
+ // src/native/image-viewer.tsx
2152
+ import * as React18 from "react";
2153
+ import { AccessibilityInfo as AccessibilityInfo4, Animated as Animated7, Image as Image3, Modal as Modal3, PanResponder, Pressable as Pressable12, StyleSheet as StyleSheet22, useWindowDimensions, View as View19 } from "react-native";
2154
+ import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
2155
+ var MAX_SCALE = 4;
2156
+ function ImageViewer({ images, index, onIndexChange, closeLabel, positionLabel = (n, total) => `${n} / ${total}` }) {
2157
+ const { theme, insets, haptic } = useTheme();
2158
+ const reduce = useReducedMotion();
2159
+ const { width, height } = useWindowDimensions();
2160
+ const open = index !== null && images[index] !== void 0;
2161
+ const [scale] = React18.useState(() => new Animated7.Value(1));
2162
+ const [pan] = React18.useState(() => new Animated7.ValueXY({ x: 0, y: 0 }));
2163
+ const [dismiss2] = React18.useState(() => new Animated7.Value(0));
2164
+ const state = React18.useRef({ scale: 1, x: 0, y: 0, pinch: 0, base: 1, lastTap: 0 });
2165
+ const reset = React18.useCallback(() => {
2166
+ state.current = { ...state.current, scale: 1, x: 0, y: 0 };
2167
+ scale.setValue(1);
2168
+ pan.setValue({ x: 0, y: 0 });
2169
+ dismiss2.setValue(0);
2170
+ }, [scale, pan, dismiss2]);
2171
+ React18.useEffect(() => {
2172
+ reset();
2173
+ if (open) AccessibilityInfo4.announceForAccessibility(`${images[index].alt}, ${positionLabel(index + 1, images.length)}`);
2174
+ }, [index]);
2175
+ const go = (to) => {
2176
+ if (to < 0 || to >= images.length) return;
2177
+ haptic("selection");
2178
+ onIndexChange(to);
2179
+ };
2180
+ const animateTo = (value, to) => reduce ? value.setValue(to) : Animated7.spring(value, { toValue: to, useNativeDriver: true, damping: 20 }).start();
2181
+ const distance = (touches) => Math.hypot(touches[0].pageX - touches[1].pageX, touches[0].pageY - touches[1].pageY);
2182
+ const responder = React18.useMemo(
2183
+ () => PanResponder.create({
2184
+ onStartShouldSetPanResponder: () => true,
2185
+ onMoveShouldSetPanResponder: (_, g) => Math.abs(g.dx) > 4 || Math.abs(g.dy) > 4,
2186
+ onPanResponderGrant: (e) => {
2187
+ const now = Date.now();
2188
+ const s = state.current;
2189
+ if (e.nativeEvent.touches.length === 1 && now - s.lastTap < 280) {
2190
+ const next = s.scale > 1 ? 1 : 2.5;
2191
+ s.scale = next;
2192
+ s.x = 0;
2193
+ s.y = 0;
2194
+ animateTo(scale, next);
2195
+ pan.setValue({ x: 0, y: 0 });
2196
+ }
2197
+ s.lastTap = now;
2198
+ s.pinch = 0;
2199
+ },
2200
+ onPanResponderMove: (e, g) => {
2201
+ const s = state.current;
2202
+ const touches = e.nativeEvent.touches;
2203
+ if (touches.length === 2) {
2204
+ const d = distance(touches);
2205
+ if (!s.pinch) {
2206
+ s.pinch = d;
2207
+ s.base = s.scale;
2208
+ }
2209
+ s.scale = Math.min(MAX_SCALE, Math.max(1, s.base * (d / s.pinch)));
2210
+ scale.setValue(s.scale);
2211
+ return;
2212
+ }
2213
+ if (s.scale > 1) pan.setValue({ x: s.x + g.dx, y: s.y + g.dy });
2214
+ else if (Math.abs(g.dy) > Math.abs(g.dx)) dismiss2.setValue(Math.max(0, g.dy));
2215
+ else pan.setValue({ x: g.dx, y: 0 });
2216
+ },
2217
+ onPanResponderRelease: (_, g) => {
2218
+ const s = state.current;
2219
+ if (s.pinch) {
2220
+ s.pinch = 0;
2221
+ if (s.scale <= 1.02) reset();
2222
+ return;
2223
+ }
2224
+ if (s.scale > 1) {
2225
+ s.x += g.dx;
2226
+ s.y += g.dy;
2227
+ return;
2228
+ }
2229
+ if (g.dy > 120 || g.vy > 1.2) return onIndexChange(null);
2230
+ if (g.dx < -width / 4 || g.vx < -0.8) go((index ?? 0) + 1);
2231
+ else if (g.dx > width / 4 || g.vx > 0.8) go((index ?? 0) - 1);
2232
+ animateTo(dismiss2, 0);
2233
+ Animated7.spring(pan, { toValue: { x: 0, y: 0 }, useNativeDriver: true }).start();
2234
+ }
2235
+ }),
2236
+ [index, width, images.length]
2237
+ // eslint-disable-line react-hooks/exhaustive-deps -- the gesture reads refs
2238
+ );
2239
+ if (!open) return null;
2240
+ const image = images[index];
2241
+ const backdrop = dismiss2.interpolate({ inputRange: [0, height / 2], outputRange: [1, 0.3], extrapolate: "clamp" });
2242
+ return /* @__PURE__ */ jsxs20(Modal3, { ...modalName(image.alt), visible: true, transparent: true, animationType: reduce ? "none" : "fade", onRequestClose: () => onIndexChange(null), statusBarTranslucent: true, children: [
2243
+ /* @__PURE__ */ jsx23(Animated7.View, { style: [StyleSheet22.absoluteFill, { backgroundColor: theme.media, opacity: backdrop }] }),
2244
+ /* @__PURE__ */ jsx23(
2245
+ View19,
2246
+ {
2247
+ style: StyleSheet22.absoluteFill,
2248
+ accessible: true,
2249
+ role: "img",
2250
+ "aria-label": `${image.alt}, ${positionLabel(index + 1, images.length)}`,
2251
+ accessibilityActions: [{ name: "increment" }, { name: "decrement" }, { name: "escape" }],
2252
+ onAccessibilityAction: (e) => {
2253
+ const name = e.nativeEvent.actionName;
2254
+ if (name === "increment") go(index + 1);
2255
+ if (name === "decrement") go(index - 1);
2256
+ if (name === "escape") onIndexChange(null);
2257
+ },
2258
+ ...responder.panHandlers,
2259
+ children: /* @__PURE__ */ jsx23(Animated7.View, { style: { width, height, transform: [{ translateX: pan.x }, { translateY: Animated7.add(pan.y, dismiss2) }, { scale }] }, children: /* @__PURE__ */ jsx23(Image3, { source: { uri: image.uri }, resizeMode: "contain", style: { width, height }, accessibilityIgnoresInvertColors: true }) })
2260
+ }
2261
+ ),
2262
+ /* @__PURE__ */ jsxs20(View19, { pointerEvents: "box-none", style: [styles22.top, { paddingTop: insets.top + 8 }], children: [
2263
+ /* @__PURE__ */ jsx23(View19, { "aria-hidden": true, style: [styles22.counter, { backgroundColor: theme.scrimStrong }], children: /* @__PURE__ */ jsx23(Txt, { variant: "label", tone: "onMedia", children: positionLabel(index + 1, images.length) }) }),
2264
+ /* @__PURE__ */ jsx23(Pressable12, { role: "button", "aria-label": closeLabel, hitSlop: 12, onPress: () => onIndexChange(null), style: [styles22.close, { backgroundColor: theme.scrimStrong }], children: /* @__PURE__ */ jsx23(Txt, { tone: "onMedia", style: styles22.cross, "aria-hidden": true, children: "\xD7" }) })
2265
+ ] }),
2266
+ image.caption ? /* @__PURE__ */ jsx23(View19, { pointerEvents: "none", style: [styles22.caption, { paddingBottom: insets.bottom + 16, backgroundColor: theme.scrimStrong }], children: /* @__PURE__ */ jsx23(Txt, { tone: "onMedia", children: image.caption }) }) : null
2267
+ ] });
2268
+ }
2269
+ function prefetchNeighbours(images, index) {
2270
+ if (index === null) return;
2271
+ for (const i of [index - 1, index + 1]) if (images[i]) void Image3.prefetch(images[i].uri).catch(() => void 0);
2272
+ }
2273
+ var styles22 = StyleSheet22.create({
2274
+ top: { position: "absolute", top: 0, left: 0, right: 0, flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingHorizontal: 16 },
2275
+ counter: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 999 },
2276
+ close: { width: 40, height: 40, borderRadius: 20, alignItems: "center", justifyContent: "center" },
2277
+ cross: { fontSize: 24, lineHeight: 26 },
2278
+ caption: { position: "absolute", left: 0, right: 0, bottom: 0, paddingTop: 12, paddingHorizontal: 16 }
2279
+ });
2280
+
1591
2281
  // src/native/KrizakaMark.tsx
1592
- import { View as View12 } from "react-native";
1593
- import Svg4, { Circle, Defs as Defs2, G as Group, LinearGradient as LinearGradient2, Path as Path3, RadialGradient, Stop as Stop2 } from "react-native-svg";
2282
+ import { View as View20 } from "react-native";
2283
+ import Svg7, { Circle as Circle2, Defs as Defs3, G as Group, LinearGradient as LinearGradient3, Path as Path5, RadialGradient, Stop as Stop3 } from "react-native-svg";
1594
2284
 
1595
2285
  // src/marks/krizaka-geometry.ts
1596
2286
  var KRIZAKA = {
@@ -1612,24 +2302,24 @@ var KRIZAKA = {
1612
2302
  };
1613
2303
 
1614
2304
  // src/native/mark-motion.ts
1615
- import { useEffect as useEffect6, useState as useState12 } from "react";
1616
- import { AccessibilityInfo as AccessibilityInfo3, Animated as Animated5, Easing as Easing2 } from "react-native";
2305
+ import { useEffect as useEffect10, useState as useState18 } from "react";
2306
+ import { AccessibilityInfo as AccessibilityInfo5, Animated as Animated8, Easing as Easing2 } from "react-native";
1617
2307
  var markA11y = (title) => title ? { accessible: true, accessibilityRole: "image", accessibilityLabel: title } : { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants" };
1618
2308
  function useMarkMotion(size, animated, spinMs = 3e4) {
1619
- const [spin] = useState12(() => new Animated5.Value(0));
1620
- const [pulse] = useState12(() => new Animated5.Value(0));
1621
- useEffect6(() => {
2309
+ const [spin] = useState18(() => new Animated8.Value(0));
2310
+ const [pulse] = useState18(() => new Animated8.Value(0));
2311
+ useEffect10(() => {
1622
2312
  if (!animated) return;
1623
2313
  let loops = [];
1624
2314
  let cancelled = false;
1625
- void AccessibilityInfo3.isReduceMotionEnabled().then((reduce) => {
2315
+ void AccessibilityInfo5.isReduceMotionEnabled().then((reduce) => {
1626
2316
  if (reduce || cancelled) return;
1627
2317
  loops = [
1628
- Animated5.loop(Animated5.timing(spin, { toValue: 1, duration: spinMs, easing: Easing2.linear, useNativeDriver: true })),
1629
- Animated5.loop(
1630
- Animated5.sequence([
1631
- Animated5.timing(pulse, { toValue: 1, duration: 1600, easing: Easing2.inOut(Easing2.ease), useNativeDriver: true }),
1632
- Animated5.timing(pulse, { toValue: 0, duration: 1600, easing: Easing2.inOut(Easing2.ease), useNativeDriver: true })
2318
+ Animated8.loop(Animated8.timing(spin, { toValue: 1, duration: spinMs, easing: Easing2.linear, useNativeDriver: true })),
2319
+ Animated8.loop(
2320
+ Animated8.sequence([
2321
+ Animated8.timing(pulse, { toValue: 1, duration: 1600, easing: Easing2.inOut(Easing2.ease), useNativeDriver: true }),
2322
+ Animated8.timing(pulse, { toValue: 0, duration: 1600, easing: Easing2.inOut(Easing2.ease), useNativeDriver: true })
1633
2323
  ])
1634
2324
  )
1635
2325
  ];
@@ -1641,7 +2331,7 @@ function useMarkMotion(size, animated, spinMs = 3e4) {
1641
2331
  };
1642
2332
  }, [animated, spin, pulse, spinMs]);
1643
2333
  return {
1644
- Animated: Animated5,
2334
+ Animated: Animated8,
1645
2335
  layer: { position: "absolute", width: size, height: size },
1646
2336
  spinStyle: { transform: [{ rotate: spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] }) }] },
1647
2337
  pulseStyle: { opacity: pulse.interpolate({ inputRange: [0, 1], outputRange: [0.85, 1] }) }
@@ -1649,39 +2339,39 @@ function useMarkMotion(size, animated, spinMs = 3e4) {
1649
2339
  }
1650
2340
 
1651
2341
  // src/native/KrizakaMark.tsx
1652
- import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
2342
+ import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
1653
2343
  function KrizakaMark({ size = 48, animated = true, title, neutral }) {
1654
2344
  const { theme } = useTheme();
1655
- const { Animated: Animated14, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated);
2345
+ const { Animated: Animated22, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated);
1656
2346
  const id = useSvgId("kzm");
1657
2347
  const viewBox = size < 48 ? KRIZAKA.croppedViewBox : KRIZAKA.viewBox;
1658
2348
  const stroke = neutral ?? theme.textMuted;
1659
- const blue = /* @__PURE__ */ jsx16(LinearGradient2, { id: `${id}b`, gradientUnits: "userSpaceOnUse", x1: KRIZAKA.blue.x1 + KRIZAKA.offset, y1: KRIZAKA.blue.y1 + KRIZAKA.offset, x2: KRIZAKA.blue.x2 + KRIZAKA.offset, y2: KRIZAKA.blue.y2 + KRIZAKA.offset, children: KRIZAKA.blue.stops.map(([offset, color]) => /* @__PURE__ */ jsx16(Stop2, { offset, stopColor: color }, offset)) });
1660
- const dot = (c) => /* @__PURE__ */ jsxs13(Fragment2, { children: [
1661
- /* @__PURE__ */ jsx16(Circle, { cx: c.cx, cy: c.cy, r: c.r, fill: `url(#${id}b)` }),
1662
- /* @__PURE__ */ jsx16(Circle, { cx: c.cx, cy: c.cy, r: c.inner, fill: KRIZAKA.highlight })
2349
+ const blue = /* @__PURE__ */ jsx24(LinearGradient3, { id: `${id}b`, gradientUnits: "userSpaceOnUse", x1: KRIZAKA.blue.x1 + KRIZAKA.offset, y1: KRIZAKA.blue.y1 + KRIZAKA.offset, x2: KRIZAKA.blue.x2 + KRIZAKA.offset, y2: KRIZAKA.blue.y2 + KRIZAKA.offset, children: KRIZAKA.blue.stops.map(([offset, color]) => /* @__PURE__ */ jsx24(Stop3, { offset, stopColor: color }, offset)) });
2350
+ const dot = (c) => /* @__PURE__ */ jsxs21(Fragment4, { children: [
2351
+ /* @__PURE__ */ jsx24(Circle2, { cx: c.cx, cy: c.cy, r: c.r, fill: `url(#${id}b)` }),
2352
+ /* @__PURE__ */ jsx24(Circle2, { cx: c.cx, cy: c.cy, r: c.inner, fill: KRIZAKA.highlight })
1663
2353
  ] });
1664
- return /* @__PURE__ */ jsxs13(View12, { style: { width: size, height: size }, ...markA11y(title), children: [
1665
- /* @__PURE__ */ jsxs13(Svg4, { viewBox, style: layer, children: [
1666
- /* @__PURE__ */ jsxs13(Defs2, { children: [
1667
- /* @__PURE__ */ jsxs13(RadialGradient, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
1668
- /* @__PURE__ */ jsx16(Stop2, { offset: "0%", stopColor: KRIZAKA.glow.color, stopOpacity: KRIZAKA.glow.opacity }),
1669
- /* @__PURE__ */ jsx16(Stop2, { offset: "100%", stopColor: KRIZAKA.glow.color, stopOpacity: 0 })
2354
+ return /* @__PURE__ */ jsxs21(View20, { style: { width: size, height: size }, ...markA11y(title), children: [
2355
+ /* @__PURE__ */ jsxs21(Svg7, { viewBox, style: layer, children: [
2356
+ /* @__PURE__ */ jsxs21(Defs3, { children: [
2357
+ /* @__PURE__ */ jsxs21(RadialGradient, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
2358
+ /* @__PURE__ */ jsx24(Stop3, { offset: "0%", stopColor: KRIZAKA.glow.color, stopOpacity: KRIZAKA.glow.opacity }),
2359
+ /* @__PURE__ */ jsx24(Stop3, { offset: "100%", stopColor: KRIZAKA.glow.color, stopOpacity: 0 })
1670
2360
  ] }),
1671
- /* @__PURE__ */ jsxs13(LinearGradient2, { id: `${id}i`, gradientUnits: "userSpaceOnUse", x1: KRIZAKA.ink.x1 + KRIZAKA.offset, y1: KRIZAKA.ink.y1 + KRIZAKA.offset, x2: KRIZAKA.ink.x2 + KRIZAKA.offset, y2: KRIZAKA.ink.y2 + KRIZAKA.offset, children: [
1672
- /* @__PURE__ */ jsx16(Stop2, { offset: "0%", stopColor: theme.textSecondary }),
1673
- /* @__PURE__ */ jsx16(Stop2, { offset: "100%", stopColor: theme.textPrimary })
2361
+ /* @__PURE__ */ jsxs21(LinearGradient3, { id: `${id}i`, gradientUnits: "userSpaceOnUse", x1: KRIZAKA.ink.x1 + KRIZAKA.offset, y1: KRIZAKA.ink.y1 + KRIZAKA.offset, x2: KRIZAKA.ink.x2 + KRIZAKA.offset, y2: KRIZAKA.ink.y2 + KRIZAKA.offset, children: [
2362
+ /* @__PURE__ */ jsx24(Stop3, { offset: "0%", stopColor: theme.textSecondary }),
2363
+ /* @__PURE__ */ jsx24(Stop3, { offset: "100%", stopColor: theme.textPrimary })
1674
2364
  ] }),
1675
2365
  blue
1676
2366
  ] }),
1677
- size >= 48 ? /* @__PURE__ */ jsx16(Circle, { cx: 200, cy: 200, r: 190, fill: `url(#${id}g)` }) : null,
1678
- /* @__PURE__ */ jsx16(Circle, { cx: 200, cy: 200, r: KRIZAKA.ring.r, stroke, strokeWidth: KRIZAKA.ring.width, opacity: 0.35, fill: "none" }),
1679
- /* @__PURE__ */ jsx16(Group, { transform: `translate(${KRIZAKA.offset} ${KRIZAKA.offset})`, children: /* @__PURE__ */ jsx16(Path3, { d: KRIZAKA.shield, stroke: `url(#${id}i)`, strokeWidth: KRIZAKA.stroke, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }) })
2367
+ size >= 48 ? /* @__PURE__ */ jsx24(Circle2, { cx: 200, cy: 200, r: 190, fill: `url(#${id}g)` }) : null,
2368
+ /* @__PURE__ */ jsx24(Circle2, { cx: 200, cy: 200, r: KRIZAKA.ring.r, stroke, strokeWidth: KRIZAKA.ring.width, opacity: 0.35, fill: "none" }),
2369
+ /* @__PURE__ */ jsx24(Group, { transform: `translate(${KRIZAKA.offset} ${KRIZAKA.offset})`, children: /* @__PURE__ */ jsx24(Path5, { d: KRIZAKA.shield, stroke: `url(#${id}i)`, strokeWidth: KRIZAKA.stroke, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }) })
1680
2370
  ] }),
1681
- /* @__PURE__ */ jsx16(Animated14.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsx16(Svg4, { viewBox, style: layer, children: /* @__PURE__ */ jsx16(Circle, { cx: 200, cy: 200, r: KRIZAKA.orbit.r, stroke, strokeWidth: KRIZAKA.orbit.width, strokeDasharray: KRIZAKA.orbit.dash, opacity: 0.6, fill: "none" }) }) }),
1682
- /* @__PURE__ */ jsx16(Animated14.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs13(Svg4, { viewBox, style: layer, children: [
1683
- /* @__PURE__ */ jsx16(Defs2, { children: blue }),
1684
- /* @__PURE__ */ jsxs13(Group, { transform: `translate(${KRIZAKA.offset} ${KRIZAKA.offset})`, children: [
2371
+ /* @__PURE__ */ jsx24(Animated22.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsx24(Svg7, { viewBox, style: layer, children: /* @__PURE__ */ jsx24(Circle2, { cx: 200, cy: 200, r: KRIZAKA.orbit.r, stroke, strokeWidth: KRIZAKA.orbit.width, strokeDasharray: KRIZAKA.orbit.dash, opacity: 0.6, fill: "none" }) }) }),
2372
+ /* @__PURE__ */ jsx24(Animated22.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs21(Svg7, { viewBox, style: layer, children: [
2373
+ /* @__PURE__ */ jsx24(Defs3, { children: blue }),
2374
+ /* @__PURE__ */ jsxs21(Group, { transform: `translate(${KRIZAKA.offset} ${KRIZAKA.offset})`, children: [
1685
2375
  dot(KRIZAKA.node),
1686
2376
  dot(KRIZAKA.core)
1687
2377
  ] })
@@ -1689,14 +2379,115 @@ function KrizakaMark({ size = 48, animated = true, title, neutral }) {
1689
2379
  ] });
1690
2380
  }
1691
2381
 
2382
+ // src/native/loader.tsx
2383
+ import * as React19 from "react";
2384
+ import { AccessibilityInfo as AccessibilityInfo6, Animated as Animated9, Easing as Easing3, StyleSheet as StyleSheet23, View as View21 } from "react-native";
2385
+ import Svg8, { Circle as Circle3, Path as Path6 } from "react-native-svg";
2386
+ import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
2387
+ var HEX = "M12 3 19.79 7.5 19.79 16.5 12 21 4.21 16.5 4.21 7.5Z";
2388
+ var PERIMETER = 54;
2389
+ function LoaderGlyph({ state = "loading", value, size = 20, color }) {
2390
+ const { theme } = useTheme();
2391
+ const reduce = useReducedMotion();
2392
+ const [spin] = React19.useState(() => new Animated9.Value(0));
2393
+ const known = typeof value === "number" && Number.isFinite(value);
2394
+ React19.useEffect(() => {
2395
+ if (state !== "loading" || known || reduce) return;
2396
+ const loop = Animated9.loop(Animated9.timing(spin, { toValue: 1, duration: 1400, easing: Easing3.linear, useNativeDriver: true }));
2397
+ loop.start();
2398
+ return () => loop.stop();
2399
+ }, [state, known, reduce, spin]);
2400
+ const stroke = color ?? (state === "success" ? theme.success : state === "error" ? theme.danger : theme.accent);
2401
+ const fill = state !== "loading" ? 1 : known ? Math.min(1, Math.max(0, value)) : 0.3;
2402
+ const rotate = spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] });
2403
+ return /* @__PURE__ */ jsx25(Animated9.View, { "aria-hidden": true, style: { width: size, height: size, transform: state === "loading" && !known ? [{ rotate }] : [] }, children: /* @__PURE__ */ jsxs22(Svg8, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: [
2404
+ /* @__PURE__ */ jsx25(Path6, { d: HEX, stroke, strokeOpacity: 0.22, strokeWidth: 2.2, strokeLinejoin: "round" }),
2405
+ /* @__PURE__ */ jsx25(Path6, { d: HEX, stroke, strokeWidth: 2.2, strokeLinejoin: "round", strokeLinecap: "round", strokeDasharray: `${fill * PERIMETER} ${PERIMETER}` }),
2406
+ state === "loading" ? /* @__PURE__ */ jsx25(Circle3, { cx: 12, cy: 12, r: 2.6, fill: stroke }) : null,
2407
+ state === "success" ? /* @__PURE__ */ jsx25(Path6, { d: "M8.3 12.3l2.6 2.6 4.9-5.3", stroke, strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round" }) : null,
2408
+ state === "error" ? /* @__PURE__ */ jsx25(Path6, { d: "M9.4 9.4l5.2 5.2M14.6 9.4l-5.2 5.2", stroke, strokeWidth: 2.2, strokeLinecap: "round" }) : null
2409
+ ] }) });
2410
+ }
2411
+ function useDelayedWait(active, delay = 250, minDuration = 600) {
2412
+ const [shown, setShown] = React19.useState(false);
2413
+ const since = React19.useRef(0);
2414
+ React19.useEffect(() => {
2415
+ if (active && !shown) {
2416
+ const timer2 = setTimeout(() => {
2417
+ since.current = Date.now();
2418
+ setShown(true);
2419
+ }, delay);
2420
+ return () => clearTimeout(timer2);
2421
+ }
2422
+ if (!active && shown) {
2423
+ const timer2 = setTimeout(() => setShown(false), Math.max(0, minDuration - (Date.now() - since.current)));
2424
+ return () => clearTimeout(timer2);
2425
+ }
2426
+ return void 0;
2427
+ }, [active, shown, delay, minDuration]);
2428
+ return shown;
2429
+ }
2430
+ var GLYPH = { inline: 20, block: 36, overlay: 36, page: 56 };
2431
+ function Loader({ label, status = "loading", successLabel, errorLabel, value, eta, delay = 250, minDuration = 600, endDuration = 1600, variant = "inline", style }) {
2432
+ const { theme, radius: radius3 } = useTheme();
2433
+ const waiting = useDelayedWait(status === "loading", delay, minDuration);
2434
+ const [ending, setEnding] = React19.useState(null);
2435
+ const seen = React19.useRef(false);
2436
+ React19.useEffect(() => {
2437
+ if (waiting) {
2438
+ seen.current = true;
2439
+ return;
2440
+ }
2441
+ if (!seen.current || status === "loading") return;
2442
+ seen.current = false;
2443
+ if (endDuration <= 0) return;
2444
+ const show2 = setTimeout(() => setEnding(status), 0);
2445
+ const hide = Number.isFinite(endDuration) ? setTimeout(() => setEnding(null), endDuration) : void 0;
2446
+ return () => {
2447
+ clearTimeout(show2);
2448
+ clearTimeout(hide);
2449
+ };
2450
+ }, [waiting, status, endDuration]);
2451
+ const phase = waiting ? "loading" : ending;
2452
+ const words = phase === "success" ? successLabel ?? label : phase === "error" ? errorLabel ?? label : label;
2453
+ React19.useEffect(() => {
2454
+ if (phase) AccessibilityInfo6.announceForAccessibility(words);
2455
+ }, [phase, words]);
2456
+ if (!phase) return null;
2457
+ const known = phase === "loading" && typeof value === "number" && Number.isFinite(value);
2458
+ const detail = phase === "loading" ? [known ? `${Math.round(Math.min(1, Math.max(0, value)) * 100)} %` : null, eta].filter(Boolean).join(" \xB7 ") : "";
2459
+ const stacked = variant !== "inline";
2460
+ const box = /* @__PURE__ */ jsxs22(View21, { style: [stacked ? styles23.stacked : styles23.inline, variant === "overlay" ? { backgroundColor: alpha(theme.surface1, 0.92), borderColor: theme.borderDefault, borderRadius: radius3.lg, ...styles23.card } : null], children: [
2461
+ /* @__PURE__ */ jsx25(LoaderGlyph, { state: phase, value: known ? value : null, size: GLYPH[variant] }),
2462
+ /* @__PURE__ */ jsxs22(View21, { style: stacked ? styles23.center : styles23.text, children: [
2463
+ /* @__PURE__ */ jsx25(Txt, { variant: variant === "page" ? "title" : "label", style: stacked ? styles23.centered : null, children: words }),
2464
+ detail ? /* @__PURE__ */ jsx25(Txt, { variant: "caption", tone: "secondary", style: stacked ? styles23.centered : null, children: detail }) : null
2465
+ ] })
2466
+ ] });
2467
+ const a11y = { accessible: true, role: "progressbar", "aria-label": words, "aria-busy": phase === "loading", accessibilityLiveRegion: "polite" };
2468
+ if (variant === "overlay" || variant === "page")
2469
+ return /* @__PURE__ */ jsx25(View21, { ...a11y, style: [StyleSheet23.absoluteFill, styles23.cover, variant === "page" ? { backgroundColor: alpha(theme.surface0, 0.86) } : null, style], children: box });
2470
+ return /* @__PURE__ */ jsx25(View21, { ...a11y, style: [variant === "block" ? styles23.block : null, style], children: box });
2471
+ }
2472
+ var styles23 = StyleSheet23.create({
2473
+ inline: { flexDirection: "row", alignItems: "center", gap: 10 },
2474
+ stacked: { alignItems: "center", gap: 10 },
2475
+ card: { paddingHorizontal: 24, paddingVertical: 20, borderWidth: StyleSheet23.hairlineWidth },
2476
+ text: { flexShrink: 1, gap: 2 },
2477
+ center: { alignItems: "center", gap: 2 },
2478
+ centered: { textAlign: "center" },
2479
+ block: { paddingVertical: 40, alignItems: "center" },
2480
+ cover: { alignItems: "center", justifyContent: "center", zIndex: 10 }
2481
+ });
2482
+
1692
2483
  // src/native/mascot-state.tsx
1693
- import * as React14 from "react";
1694
- import { AccessibilityInfo as AccessibilityInfo5, Animated as Animated7, Easing as Easing4, StyleSheet as StyleSheet15, View as View14 } from "react-native";
2484
+ import * as React21 from "react";
2485
+ import { AccessibilityInfo as AccessibilityInfo8, Animated as Animated11, Easing as Easing5, StyleSheet as StyleSheet24, View as View23 } from "react-native";
1695
2486
 
1696
2487
  // src/native/mascots.tsx
1697
- import { useEffect as useEffect7, useState as useState13 } from "react";
1698
- import { AccessibilityInfo as AccessibilityInfo4, Animated as Animated6, Easing as Easing3, View as View13 } from "react-native";
1699
- import Svg5, { Circle as Circle2, Defs as Defs3, Ellipse, G, LinearGradient as LinearGradient3, Path as Path4, Rect as Rect2, Stop as Stop3 } from "react-native-svg";
2488
+ import { useEffect as useEffect12, useState as useState20 } from "react";
2489
+ import { AccessibilityInfo as AccessibilityInfo7, Animated as Animated10, Easing as Easing4, View as View22 } from "react-native";
2490
+ import Svg9, { Circle as Circle4, Defs as Defs4, Ellipse, G, LinearGradient as LinearGradient4, Path as Path7, Rect as Rect2, Stop as Stop4 } from "react-native-svg";
1700
2491
 
1701
2492
  // src/mascots/geometry.ts
1702
2493
  var mirror = (d) => d.replace(/(-?\d+(?:\.\d+)?) (-?\d+(?:\.\d+)?)/g, (_, x, y) => `${120 - Number(x)} ${y}`);
@@ -1854,17 +2645,17 @@ var SHADE = "#000000";
1854
2645
  var PARCEL = ["#f59e0b", "#d97706", "#b45309"];
1855
2646
 
1856
2647
  // src/native/mascots.tsx
1857
- import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
2648
+ import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
1858
2649
  function useBob(animated) {
1859
- const [y] = useState13(() => new Animated6.Value(0));
1860
- useEffect7(() => {
2650
+ const [y] = useState20(() => new Animated10.Value(0));
2651
+ useEffect12(() => {
1861
2652
  if (!animated) return;
1862
2653
  let loop;
1863
2654
  let cancelled = false;
1864
- void AccessibilityInfo4.isReduceMotionEnabled().then((reduce) => {
2655
+ void AccessibilityInfo7.isReduceMotionEnabled().then((reduce) => {
1865
2656
  if (reduce || cancelled) return;
1866
- const step = (toValue) => Animated6.timing(y, { toValue, duration: 1800, easing: Easing3.inOut(Easing3.ease), useNativeDriver: true });
1867
- loop = Animated6.loop(Animated6.sequence([step(-2.5), step(0)]));
2657
+ const step = (toValue) => Animated10.timing(y, { toValue, duration: 1800, easing: Easing4.inOut(Easing4.ease), useNativeDriver: true });
2658
+ loop = Animated10.loop(Animated10.sequence([step(-2.5), step(0)]));
1868
2659
  loop.start();
1869
2660
  });
1870
2661
  return () => {
@@ -1874,13 +2665,13 @@ function useBob(animated) {
1874
2665
  }, [animated, y]);
1875
2666
  return y;
1876
2667
  }
1877
- function Mascot({ bird = "owl", mood = "welcome", tone: tone2 = "brand", size = 96, animated = true, title, style }) {
2668
+ function Mascot({ bird = "owl", mood = "welcome", tone: tone3 = "brand", size = 96, animated = true, title, style }) {
1878
2669
  const { theme } = useTheme();
1879
2670
  const id = useSvgId("kzb");
1880
2671
  const bob = useBob(animated);
1881
2672
  const g = BIRDS[bird];
1882
2673
  const brand = { from: theme.accent2, to: theme.accent, wing: theme.accent, detail: theme.accent2, beak: theme.warning, eye: theme.textPrimary };
1883
- const p = tone2 === "own" ? OWN_PALETTES[bird] : brand;
2674
+ const p = tone3 === "own" ? OWN_PALETTES[bird] : brand;
1884
2675
  const outline = theme.borderStrong;
1885
2676
  const body = `url(#${id})`;
1886
2677
  const line = { stroke: outline, strokeWidth: 1.4, strokeLinejoin: "round" };
@@ -1888,62 +2679,62 @@ function Mascot({ bird = "owl", mood = "welcome", tone: tone2 = "brand", size =
1888
2679
  const look3 = mood === "thinking" ? 1.4 : 0;
1889
2680
  const rot = (deg, [x, y]) => `rotate(${deg} ${x} ${y})`;
1890
2681
  const [wl, wr] = g.wings;
1891
- return /* @__PURE__ */ jsx17(View13, { style: [{ width: size, height: size }, style], ...markA11y(title), children: /* @__PURE__ */ jsx17(Animated6.View, { style: { transform: [{ translateY: bob }] }, children: /* @__PURE__ */ jsxs14(Svg5, { width: size, height: size, viewBox: "0 0 120 120", children: [
1892
- /* @__PURE__ */ jsx17(Defs3, { children: /* @__PURE__ */ jsxs14(LinearGradient3, { id, x1: "0", y1: "0", x2: "0", y2: "1", children: [
1893
- /* @__PURE__ */ jsx17(Stop3, { offset: "0%", stopColor: p.from }),
1894
- /* @__PURE__ */ jsx17(Stop3, { offset: "100%", stopColor: p.to })
2682
+ return /* @__PURE__ */ jsx26(View22, { style: [{ width: size, height: size }, style], ...markA11y(title), children: /* @__PURE__ */ jsx26(Animated10.View, { style: { transform: [{ translateY: bob }] }, children: /* @__PURE__ */ jsxs23(Svg9, { width: size, height: size, viewBox: "0 0 120 120", children: [
2683
+ /* @__PURE__ */ jsx26(Defs4, { children: /* @__PURE__ */ jsxs23(LinearGradient4, { id, x1: "0", y1: "0", x2: "0", y2: "1", children: [
2684
+ /* @__PURE__ */ jsx26(Stop4, { offset: "0%", stopColor: p.from }),
2685
+ /* @__PURE__ */ jsx26(Stop4, { offset: "100%", stopColor: p.to })
1895
2686
  ] }) }),
1896
- /* @__PURE__ */ jsx17(Ellipse, { cx: g.shadow[0], cy: g.shadow[1], rx: g.shadow[2], ry: g.shadow[3], fill: SHADE, opacity: 0.14 }),
1897
- mood === "empty" && /* @__PURE__ */ jsx17(Path4, { d: MOOD_PARTS.tray, stroke: outline, strokeWidth: 1.6, strokeDasharray: "3 3", fill: "none" }),
1898
- g.legs.map((d) => /* @__PURE__ */ jsx17(Path4, { d, stroke: p.beak, strokeWidth: 2.6, strokeLinecap: "round", fill: "none" }, d)),
1899
- g.back?.map((d) => d.endsWith("Z") ? /* @__PURE__ */ jsx17(Path4, { d, fill: p.detail, ...line }, d) : /* @__PURE__ */ jsx17(Path4, { d, stroke: outline, strokeWidth: 1.4, fill: "none" }, d)),
1900
- g.parcel?.map((d, i) => /* @__PURE__ */ jsx17(Path4, { d, fill: PARCEL[i], ...line }, d)),
1901
- /* @__PURE__ */ jsx17(Path4, { d: g.body, fill: body, ...line }),
1902
- /* @__PURE__ */ jsx17(Path4, { d: g.belly, fill: LIGHT, opacity: 0.28 }),
2687
+ /* @__PURE__ */ jsx26(Ellipse, { cx: g.shadow[0], cy: g.shadow[1], rx: g.shadow[2], ry: g.shadow[3], fill: SHADE, opacity: 0.14 }),
2688
+ mood === "empty" && /* @__PURE__ */ jsx26(Path7, { d: MOOD_PARTS.tray, stroke: outline, strokeWidth: 1.6, strokeDasharray: "3 3", fill: "none" }),
2689
+ g.legs.map((d) => /* @__PURE__ */ jsx26(Path7, { d, stroke: p.beak, strokeWidth: 2.6, strokeLinecap: "round", fill: "none" }, d)),
2690
+ g.back?.map((d) => d.endsWith("Z") ? /* @__PURE__ */ jsx26(Path7, { d, fill: p.detail, ...line }, d) : /* @__PURE__ */ jsx26(Path7, { d, stroke: outline, strokeWidth: 1.4, fill: "none" }, d)),
2691
+ g.parcel?.map((d, i) => /* @__PURE__ */ jsx26(Path7, { d, fill: PARCEL[i], ...line }, d)),
2692
+ /* @__PURE__ */ jsx26(Path7, { d: g.body, fill: body, ...line }),
2693
+ /* @__PURE__ */ jsx26(Path7, { d: g.belly, fill: LIGHT, opacity: 0.28 }),
1903
2694
  [wl, wr].map((w, i) => {
1904
2695
  const turn = mood === "success" ? i === 0 ? 28 : -28 : mood === "welcome" && i === 1 ? -20 : 0;
1905
- return /* @__PURE__ */ jsxs14(G, { transform: turn ? rot(turn, w.pivot) : void 0, children: [
1906
- /* @__PURE__ */ jsx17(Path4, { d: w.d, fill: p.wing, ...line }),
1907
- /* @__PURE__ */ jsx17(Path4, { d: w.d, fill: SHADE, opacity: 0.16 })
2696
+ return /* @__PURE__ */ jsxs23(G, { transform: turn ? rot(turn, w.pivot) : void 0, children: [
2697
+ /* @__PURE__ */ jsx26(Path7, { d: w.d, fill: p.wing, ...line }),
2698
+ /* @__PURE__ */ jsx26(Path7, { d: w.d, fill: SHADE, opacity: 0.16 })
1908
2699
  ] }, i);
1909
2700
  }),
1910
- g.neck && /* @__PURE__ */ jsx17(Path4, { d: g.neck.d, stroke: body, strokeWidth: g.neck.width, strokeLinecap: "round", fill: "none" }),
1911
- g.head.r > 0 && /* @__PURE__ */ jsx17(Circle2, { cx: g.head.cx, cy: g.head.cy, r: g.head.r, fill: body, ...line }),
1912
- g.details.map((d) => /* @__PURE__ */ jsx17(Path4, { d, fill: p.detail, ...line }, d)),
1913
- g.visor && /* @__PURE__ */ jsx17(Rect2, { x: g.visor.x, y: g.visor.y, width: g.visor.w, height: g.visor.h, rx: 4, fill: theme.surface0, ...line }),
2701
+ g.neck && /* @__PURE__ */ jsx26(Path7, { d: g.neck.d, stroke: body, strokeWidth: g.neck.width, strokeLinecap: "round", fill: "none" }),
2702
+ g.head.r > 0 && /* @__PURE__ */ jsx26(Circle4, { cx: g.head.cx, cy: g.head.cy, r: g.head.r, fill: body, ...line }),
2703
+ g.details.map((d) => /* @__PURE__ */ jsx26(Path7, { d, fill: p.detail, ...line }, d)),
2704
+ g.visor && /* @__PURE__ */ jsx26(Rect2, { x: g.visor.x, y: g.visor.y, width: g.visor.w, height: g.visor.h, rx: 4, fill: theme.surface0, ...line }),
1914
2705
  g.eyes.at.map(
1915
- (at, i) => mood === "empty" && g.eyes.white > 0 ? /* @__PURE__ */ jsxs14(G, { children: [
1916
- /* @__PURE__ */ jsx17(Circle2, { cx: at[0], cy: at[1], r: g.eyes.white, fill: LIGHT, ...line }),
1917
- /* @__PURE__ */ jsx17(Circle2, { cx: at[0], cy: at[1] + g.eyes.pupil * 0.7, r: g.eyes.pupil, fill: SHADE }),
1918
- /* @__PURE__ */ jsx17(Path4, { d: upperLid(at, g.eyes.white), fill: p.detail, ...line })
1919
- ] }, i) : mood === "success" || mood === "empty" ? /* @__PURE__ */ jsx17(Path4, { d: mood === "success" ? archEye(at, eyeR * 0.85) : lidEye(at, eyeR * 0.8), stroke: g.visor ? p.eye : outline, strokeWidth: 2.2, strokeLinecap: "round", fill: "none" }, i) : /* @__PURE__ */ jsxs14(G, { children: [
1920
- g.eyes.white > 0 && /* @__PURE__ */ jsx17(Circle2, { cx: at[0], cy: at[1], r: g.eyes.white, fill: LIGHT, ...line }),
1921
- /* @__PURE__ */ jsx17(Circle2, { cx: at[0] + look3, cy: at[1] - look3, r: g.eyes.pupil, fill: g.visor ? p.eye : SHADE })
2706
+ (at, i) => mood === "empty" && g.eyes.white > 0 ? /* @__PURE__ */ jsxs23(G, { children: [
2707
+ /* @__PURE__ */ jsx26(Circle4, { cx: at[0], cy: at[1], r: g.eyes.white, fill: LIGHT, ...line }),
2708
+ /* @__PURE__ */ jsx26(Circle4, { cx: at[0], cy: at[1] + g.eyes.pupil * 0.7, r: g.eyes.pupil, fill: SHADE }),
2709
+ /* @__PURE__ */ jsx26(Path7, { d: upperLid(at, g.eyes.white), fill: p.detail, ...line })
2710
+ ] }, i) : mood === "success" || mood === "empty" ? /* @__PURE__ */ jsx26(Path7, { d: mood === "success" ? archEye(at, eyeR * 0.85) : lidEye(at, eyeR * 0.8), stroke: g.visor ? p.eye : outline, strokeWidth: 2.2, strokeLinecap: "round", fill: "none" }, i) : /* @__PURE__ */ jsxs23(G, { children: [
2711
+ g.eyes.white > 0 && /* @__PURE__ */ jsx26(Circle4, { cx: at[0], cy: at[1], r: g.eyes.white, fill: LIGHT, ...line }),
2712
+ /* @__PURE__ */ jsx26(Circle4, { cx: at[0] + look3, cy: at[1] - look3, r: g.eyes.pupil, fill: g.visor ? p.eye : SHADE })
1922
2713
  ] }, i)
1923
2714
  ),
1924
- g.glasses && g.eyes.at.map(([x, y]) => /* @__PURE__ */ jsx17(Circle2, { cx: x, cy: y, r: 6.5, fill: "none", stroke: outline, strokeWidth: 1.3 }, x)),
1925
- mood === "error" && g.eyes.at.map((at, i) => /* @__PURE__ */ jsx17(Path4, { d: brow(at, eyeR, g.eyes.at.length === 1 ? 1 : i === 0 ? -1 : 1), stroke: outline, strokeWidth: 2, strokeLinecap: "round" }, i)),
1926
- /* @__PURE__ */ jsx17(Path4, { d: g.beak, fill: p.beak, ...line }),
1927
- mood === "thinking" && MOOD_PARTS.dots.map(([cx, cy, r], i) => /* @__PURE__ */ jsx17(Circle2, { cx, cy, r, fill: theme.textSecondary, opacity: 0.5 + i * 0.25 }, cx)),
1928
- (mood === "success" || mood === "error") && /* @__PURE__ */ jsx17(Circle2, { cx: MOOD_PARTS.badge.cx, cy: MOOD_PARTS.badge.cy, r: MOOD_PARTS.badge.r, fill: mood === "success" ? theme.success : theme.danger }),
1929
- mood === "success" && /* @__PURE__ */ jsx17(Path4, { d: MOOD_PARTS.check, stroke: theme.surface0, strokeWidth: 2.6, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }),
1930
- mood === "error" && /* @__PURE__ */ jsx17(Path4, { d: MOOD_PARTS.bang.line, stroke: theme.surface0, strokeWidth: 2.8, strokeLinecap: "round" }),
1931
- mood === "error" && /* @__PURE__ */ jsx17(Circle2, { cx: MOOD_PARTS.bang.dot[0], cy: MOOD_PARTS.bang.dot[1], r: 1.6, fill: theme.surface0 })
2715
+ g.glasses && g.eyes.at.map(([x, y]) => /* @__PURE__ */ jsx26(Circle4, { cx: x, cy: y, r: 6.5, fill: "none", stroke: outline, strokeWidth: 1.3 }, x)),
2716
+ mood === "error" && g.eyes.at.map((at, i) => /* @__PURE__ */ jsx26(Path7, { d: brow(at, eyeR, g.eyes.at.length === 1 ? 1 : i === 0 ? -1 : 1), stroke: outline, strokeWidth: 2, strokeLinecap: "round" }, i)),
2717
+ /* @__PURE__ */ jsx26(Path7, { d: g.beak, fill: p.beak, ...line }),
2718
+ mood === "thinking" && MOOD_PARTS.dots.map(([cx, cy, r], i) => /* @__PURE__ */ jsx26(Circle4, { cx, cy, r, fill: theme.textSecondary, opacity: 0.5 + i * 0.25 }, cx)),
2719
+ (mood === "success" || mood === "error") && /* @__PURE__ */ jsx26(Circle4, { cx: MOOD_PARTS.badge.cx, cy: MOOD_PARTS.badge.cy, r: MOOD_PARTS.badge.r, fill: mood === "success" ? theme.success : theme.danger }),
2720
+ mood === "success" && /* @__PURE__ */ jsx26(Path7, { d: MOOD_PARTS.check, stroke: theme.surface0, strokeWidth: 2.6, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }),
2721
+ mood === "error" && /* @__PURE__ */ jsx26(Path7, { d: MOOD_PARTS.bang.line, stroke: theme.surface0, strokeWidth: 2.8, strokeLinecap: "round" }),
2722
+ mood === "error" && /* @__PURE__ */ jsx26(Circle4, { cx: MOOD_PARTS.bang.dot[0], cy: MOOD_PARTS.bang.dot[1], r: 1.6, fill: theme.surface0 })
1932
2723
  ] }) }) });
1933
2724
  }
1934
2725
 
1935
2726
  // src/native/mascot-state.tsx
1936
- import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2727
+ import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
1937
2728
  var SIZE = { sm: 64, md: 96, lg: 128 };
1938
2729
  function useArrival(animated) {
1939
- const [value] = React14.useState(() => new Animated7.Value(animated ? 0 : 1));
1940
- React14.useEffect(() => {
2730
+ const [value] = React21.useState(() => new Animated11.Value(animated ? 0 : 1));
2731
+ React21.useEffect(() => {
1941
2732
  if (!animated) return;
1942
2733
  let cancelled = false;
1943
- void AccessibilityInfo5.isReduceMotionEnabled().then((reduce) => {
2734
+ void AccessibilityInfo8.isReduceMotionEnabled().then((reduce) => {
1944
2735
  if (cancelled) return;
1945
2736
  if (reduce) value.setValue(1);
1946
- else Animated7.timing(value, { toValue: 1, duration: 420, easing: Easing4.out(Easing4.cubic), useNativeDriver: true }).start();
2737
+ else Animated11.timing(value, { toValue: 1, duration: 420, easing: Easing5.out(Easing5.cubic), useNativeDriver: true }).start();
1947
2738
  });
1948
2739
  return () => {
1949
2740
  cancelled = true;
@@ -1951,33 +2742,33 @@ function useArrival(animated) {
1951
2742
  }, [animated, value]);
1952
2743
  return value;
1953
2744
  }
1954
- function MascotState({ bird = "owl", mood = "empty", title, description, action, size = "md", layout = "stacked", tone: tone2, animated = true, style, ...props }) {
2745
+ function MascotState({ bird = "owl", mood = "empty", title, description, action, size = "md", layout = "stacked", tone: tone3, animated = true, style, ...props }) {
1955
2746
  const opacity = useArrival(animated);
1956
2747
  const inline = layout === "inline";
1957
- return /* @__PURE__ */ jsxs15(
1958
- Animated7.View,
2748
+ return /* @__PURE__ */ jsxs24(
2749
+ Animated11.View,
1959
2750
  {
1960
2751
  role: mood === "error" ? "alert" : "status",
1961
2752
  accessibilityLiveRegion: mood === "error" ? "assertive" : "polite",
1962
2753
  "aria-busy": mood === "thinking" ? true : void 0,
1963
2754
  ...props,
1964
- style: [inline ? styles15.inline : styles15.stacked, { opacity, transform: [{ translateY: opacity.interpolate({ inputRange: [0, 1], outputRange: [6, 0] }) }] }, style],
2755
+ style: [inline ? styles24.inline : styles24.stacked, { opacity, transform: [{ translateY: opacity.interpolate({ inputRange: [0, 1], outputRange: [6, 0] }) }] }, style],
1965
2756
  children: [
1966
- /* @__PURE__ */ jsx18(Mascot, { bird, mood, tone: tone2, size: SIZE[size], animated }),
1967
- /* @__PURE__ */ jsxs15(View14, { style: inline ? styles15.wordsInline : styles15.words, children: [
1968
- /* @__PURE__ */ jsx18(Txt, { variant: "label", role: "heading", style: inline ? null : styles15.center, children: title }),
1969
- description ? /* @__PURE__ */ jsx18(Txt, { tone: "secondary", style: inline ? null : styles15.center, children: description }) : null,
1970
- action ? /* @__PURE__ */ jsx18(View14, { style: [styles15.action, inline ? null : styles15.actionCentred], children: action }) : null
2757
+ /* @__PURE__ */ jsx27(Mascot, { bird, mood, tone: tone3, size: SIZE[size], animated }),
2758
+ /* @__PURE__ */ jsxs24(View23, { style: inline ? styles24.wordsInline : styles24.words, children: [
2759
+ /* @__PURE__ */ jsx27(Txt, { variant: "label", role: "heading", style: inline ? null : styles24.center, children: title }),
2760
+ description ? /* @__PURE__ */ jsx27(Txt, { tone: "secondary", style: inline ? null : styles24.center, children: description }) : null,
2761
+ action ? /* @__PURE__ */ jsx27(View23, { style: [styles24.action, inline ? null : styles24.actionCentred], children: action }) : null
1971
2762
  ] })
1972
2763
  ]
1973
2764
  }
1974
2765
  );
1975
2766
  }
1976
- var ErrorState = (props) => /* @__PURE__ */ jsx18(MascotState, { mood: "error", ...props });
1977
- var SuccessState = (props) => /* @__PURE__ */ jsx18(MascotState, { mood: "success", ...props });
1978
- var LoadingState = (props) => /* @__PURE__ */ jsx18(MascotState, { mood: "thinking", ...props });
1979
- var WelcomeState = (props) => /* @__PURE__ */ jsx18(MascotState, { mood: "welcome", ...props });
1980
- var styles15 = StyleSheet15.create({
2767
+ var ErrorState = (props) => /* @__PURE__ */ jsx27(MascotState, { mood: "error", ...props });
2768
+ var SuccessState = (props) => /* @__PURE__ */ jsx27(MascotState, { mood: "success", ...props });
2769
+ var LoadingState = (props) => /* @__PURE__ */ jsx27(MascotState, { mood: "thinking", ...props });
2770
+ var WelcomeState = (props) => /* @__PURE__ */ jsx27(MascotState, { mood: "welcome", ...props });
2771
+ var styles24 = StyleSheet24.create({
1981
2772
  stacked: { alignItems: "center", justifyContent: "center", gap: 12, paddingVertical: 40, paddingHorizontal: 24 },
1982
2773
  inline: { flexDirection: "row", alignItems: "center", gap: 16 },
1983
2774
  words: { alignItems: "center", gap: 6 },
@@ -1987,9 +2778,150 @@ var styles15 = StyleSheet15.create({
1987
2778
  actionCentred: { justifyContent: "center" }
1988
2779
  });
1989
2780
 
2781
+ // src/native/meter.tsx
2782
+ import { StyleSheet as StyleSheet25, View as View24 } from "react-native";
2783
+ import Svg10, { Circle as Circle5 } from "react-native-svg";
2784
+ import { jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
2785
+ var THICK = { sm: 6, md: 8, lg: 12 };
2786
+ var RING = { sm: 56, md: 96, lg: 144 };
2787
+ var partColor = (t, i) => [t.accent, t.warning, t.success, t.textSecondary, t.danger][i % 5];
2788
+ function Meter({ label, value = 0, min = 0, max = 100, valueText, thresholds, optimum = "low", parts, variant = "bar", size = "md", showLabel, children, style }) {
2789
+ const { theme } = useTheme();
2790
+ const span = max - min || 1;
2791
+ const ratio = Math.min(1, Math.max(0, (value - min) / span));
2792
+ const level = !thresholds ? "ok" : ratio >= thresholds.high ? optimum === "low" ? "danger" : "success" : ratio >= thresholds.low ? "warning" : optimum === "low" ? "success" : "danger";
2793
+ const tone3 = { ok: theme.accent, success: theme.success, warning: theme.warning, danger: theme.danger }[level];
2794
+ const words = valueText ?? `${Math.round(ratio * 100)} %`;
2795
+ const shares = (parts ?? []).map((p, i) => ({ ...p, color: partColor(theme, i), ratio: Math.min(1, Math.max(0, p.value / span)), words: p.valueText ?? `${Math.round(p.value / span * 100)} %` }));
2796
+ const a11y = parts ? { role: "group", "aria-label": `${label}: ${shares.map((p) => `${p.label} ${p.words}`).join(", ")}` } : { role: "meter", "aria-label": label, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": Math.min(max, Math.max(min, value)), "aria-valuetext": words };
2797
+ const legend = parts ? /* @__PURE__ */ jsx28(View24, { style: styles25.legend, "aria-hidden": true, children: shares.map((p, i) => /* @__PURE__ */ jsxs25(View24, { style: styles25.legendItem, children: [
2798
+ /* @__PURE__ */ jsx28(View24, { style: [styles25.swatch, { backgroundColor: p.color }] }),
2799
+ /* @__PURE__ */ jsx28(Txt, { variant: "caption", children: p.label }),
2800
+ /* @__PURE__ */ jsx28(Txt, { variant: "caption", tone: "secondary", children: p.words })
2801
+ ] }, i)) }) : null;
2802
+ if (variant === "ring") {
2803
+ const side = RING[size];
2804
+ const r = 44;
2805
+ const c = 2 * Math.PI * r;
2806
+ let offset = 0;
2807
+ const arcs = parts ? shares.map((p) => {
2808
+ const arc = { color: p.color, len: p.ratio, start: offset };
2809
+ offset += p.ratio;
2810
+ return arc;
2811
+ }) : [{ color: tone3, len: ratio, start: 0 }];
2812
+ return /* @__PURE__ */ jsxs25(View24, { accessible: true, ...a11y, style: [styles25.ringRoot, style], children: [
2813
+ /* @__PURE__ */ jsxs25(View24, { style: { width: side, height: side }, children: [
2814
+ /* @__PURE__ */ jsxs25(Svg10, { width: side, height: side, viewBox: "0 0 100 100", style: { transform: [{ rotate: "-90deg" }] }, children: [
2815
+ /* @__PURE__ */ jsx28(Circle5, { cx: 50, cy: 50, r, fill: "none", stroke: theme.borderDefault, strokeWidth: 9 }),
2816
+ arcs.map((a, i) => /* @__PURE__ */ jsx28(Circle5, { cx: 50, cy: 50, r, fill: "none", stroke: a.color, strokeWidth: 9, strokeDasharray: `${Math.max(0, a.len * c - (parts ? 2 : 0))} ${c}`, strokeDashoffset: -a.start * c, strokeLinecap: parts ? "butt" : "round" }, i))
2817
+ ] }),
2818
+ children !== void 0 ? /* @__PURE__ */ jsx28(View24, { style: [StyleSheet25.absoluteFill, styles25.center], children }) : null
2819
+ ] }),
2820
+ legend
2821
+ ] });
2822
+ }
2823
+ return /* @__PURE__ */ jsxs25(View24, { accessible: true, ...a11y, style: [styles25.root, style], children: [
2824
+ showLabel ? /* @__PURE__ */ jsxs25(View24, { style: styles25.header, "aria-hidden": true, children: [
2825
+ /* @__PURE__ */ jsx28(Txt, { variant: "caption", numberOfLines: 1, style: styles25.caption, children: label }),
2826
+ !parts ? /* @__PURE__ */ jsx28(Txt, { variant: "caption", tone: "secondary", children: words }) : null
2827
+ ] }) : null,
2828
+ /* @__PURE__ */ jsx28(View24, { style: [styles25.track, { height: THICK[size], backgroundColor: theme.surface3 }], children: parts ? shares.map((p, i) => /* @__PURE__ */ jsx28(View24, { style: { width: `${p.ratio * 100}%`, backgroundColor: p.color } }, i)) : /* @__PURE__ */ jsx28(View24, { style: [styles25.fill, { width: `${ratio * 100}%`, backgroundColor: tone3 }] }) }),
2829
+ legend
2830
+ ] });
2831
+ }
2832
+ var styles25 = StyleSheet25.create({
2833
+ root: { width: "100%", gap: 6 },
2834
+ header: { flexDirection: "row", alignItems: "baseline", gap: 8 },
2835
+ caption: { flex: 1, fontWeight: "600" },
2836
+ track: { flexDirection: "row", gap: 2, borderRadius: 999, overflow: "hidden", width: "100%" },
2837
+ fill: { height: "100%", borderRadius: 999 },
2838
+ legend: { flexDirection: "row", flexWrap: "wrap", columnGap: 14, rowGap: 4, marginTop: 4 },
2839
+ legendItem: { flexDirection: "row", alignItems: "center", gap: 6 },
2840
+ swatch: { width: 8, height: 8, borderRadius: 4 },
2841
+ ringRoot: { alignItems: "center", gap: 8 },
2842
+ center: { alignItems: "center", justifyContent: "center" }
2843
+ });
2844
+
2845
+ // src/native/number-ticker.tsx
2846
+ import * as React22 from "react";
2847
+ import { AccessibilityInfo as AccessibilityInfo9, Animated as Animated12, Easing as Easing6, Text as Text13 } from "react-native";
2848
+ import { jsx as jsx29 } from "react/jsx-runtime";
2849
+ function NumberTicker({ value, locale, format, trigger = "mount", duration = 1100, announce, variant = "display", tone: tone3 = "text", style }) {
2850
+ const reduce = useReducedMotion();
2851
+ const writer = React22.useMemo(() => new Intl.NumberFormat(locale, format), [locale, format]);
2852
+ const [shown, setShown] = React22.useState(() => reduce ? value : trigger === "mount" ? 0 : value);
2853
+ const [anim] = React22.useState(() => new Animated12.Value(trigger === "mount" ? 0 : value));
2854
+ const first = React22.useRef(true);
2855
+ React22.useEffect(() => {
2856
+ const isFirst = first.current;
2857
+ first.current = false;
2858
+ if (reduce || !isFirst && trigger === "mount" || isFirst && trigger === "change") {
2859
+ anim.setValue(value);
2860
+ setShown(value);
2861
+ if (!isFirst && announce) AccessibilityInfo9.announceForAccessibility(writer.format(value));
2862
+ return;
2863
+ }
2864
+ const id = anim.addListener(({ value: v }) => setShown(v));
2865
+ const run = Animated12.timing(anim, { toValue: value, duration, easing: Easing6.out(Easing6.cubic), useNativeDriver: false });
2866
+ run.start(({ finished }) => {
2867
+ if (finished) setShown(value);
2868
+ });
2869
+ if (!isFirst && announce) AccessibilityInfo9.announceForAccessibility(writer.format(value));
2870
+ return () => {
2871
+ run.stop();
2872
+ anim.removeListener(id);
2873
+ };
2874
+ }, [value, reduce, trigger, duration, announce, anim, writer]);
2875
+ const digits = Number.isInteger(value) ? Math.round(shown) : shown;
2876
+ return /* @__PURE__ */ jsx29(Txt, { variant, tone: tone3, "aria-label": writer.format(value), style: [{ fontVariant: ["tabular-nums"] }, style], children: /* @__PURE__ */ jsx29(Text13, { "aria-hidden": true, children: writer.format(digits) }) });
2877
+ }
2878
+
2879
+ // src/native/onboarding.tsx
2880
+ import * as React23 from "react";
2881
+ import { ScrollView as ScrollView5, StyleSheet as StyleSheet26, View as View25 } from "react-native";
2882
+ import { jsx as jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
2883
+ function Onboarding({ slides, labels, onDone, style }) {
2884
+ const { theme, insets, haptic } = useTheme();
2885
+ const [width, setWidth] = React23.useState(0);
2886
+ const [page, setPage] = React23.useState(0);
2887
+ const scroller = React23.useRef(null);
2888
+ const last = page === slides.length - 1;
2889
+ const go = (to) => {
2890
+ scroller.current?.scrollTo({ x: to * width, animated: true });
2891
+ setPage(to);
2892
+ haptic("selection");
2893
+ };
2894
+ const onScroll = (e) => {
2895
+ if (width > 0) setPage(Math.round(e.nativeEvent.contentOffset.x / width));
2896
+ };
2897
+ return /* @__PURE__ */ jsxs26(View25, { style: [styles26.root, { backgroundColor: theme.surface0, paddingTop: insets.top + 8, paddingBottom: insets.bottom + 16 }, style], onLayout: (e) => setWidth(e.nativeEvent.layout.width), children: [
2898
+ /* @__PURE__ */ jsx30(View25, { style: styles26.top, children: !last ? /* @__PURE__ */ jsx30(Button, { label: labels.skip, variant: "ghost", size: "sm", onPress: onDone }) : /* @__PURE__ */ jsx30(View25, { style: styles26.spacer }) }),
2899
+ /* @__PURE__ */ jsx30(ScrollView5, { ref: scroller, tabIndex: 0, horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, onMomentumScrollEnd: onScroll, style: styles26.flex, children: slides.map((slide, i) => /* @__PURE__ */ jsxs26(View25, { style: [styles26.slide, { width: width || void 0 }], accessible: true, "aria-label": `${labels.position(i + 1, slides.length)}. ${slide.title}. ${slide.description}`, "aria-hidden": i !== page, children: [
2900
+ slide.visual ? /* @__PURE__ */ jsx30(View25, { style: styles26.visual, children: slide.visual }) : null,
2901
+ /* @__PURE__ */ jsx30(Txt, { variant: "display", style: styles26.centred, children: slide.title }),
2902
+ /* @__PURE__ */ jsx30(Txt, { tone: "secondary", style: [styles26.centred, styles26.description], children: slide.description })
2903
+ ] }, i)) }),
2904
+ /* @__PURE__ */ jsx30(View25, { style: styles26.dots, "aria-hidden": true, children: slides.map((_, i) => /* @__PURE__ */ jsx30(View25, { style: [styles26.dot, { width: i === page ? 22 : 8, backgroundColor: i === page ? theme.accent : theme.borderStrong }] }, i)) }),
2905
+ /* @__PURE__ */ jsx30(View25, { style: styles26.bottom, children: /* @__PURE__ */ jsx30(Button, { label: last ? labels.done : labels.next, variant: last ? "gradient" : "primary", size: "lg", onPress: () => last ? onDone() : go(page + 1) }) })
2906
+ ] });
2907
+ }
2908
+ var styles26 = StyleSheet26.create({
2909
+ root: { flex: 1 },
2910
+ top: { flexDirection: "row", justifyContent: "flex-end", paddingHorizontal: 16, minHeight: 32 },
2911
+ spacer: { height: 32 },
2912
+ flex: { flex: 1 },
2913
+ slide: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 32, gap: 12 },
2914
+ visual: { marginBottom: 12 },
2915
+ centred: { textAlign: "center" },
2916
+ description: { maxWidth: 340 },
2917
+ dots: { flexDirection: "row", justifyContent: "center", gap: 6, marginVertical: 16 },
2918
+ dot: { height: 8, borderRadius: 4 },
2919
+ bottom: { paddingHorizontal: 24 }
2920
+ });
2921
+
1990
2922
  // src/native/OrazakaMark.tsx
1991
- import { View as View15 } from "react-native";
1992
- import Svg6, { Circle as Circle3, Defs as Defs4, LinearGradient as LinearGradient4, Path as Path5, RadialGradient as RadialGradient2, Stop as Stop4 } from "react-native-svg";
2923
+ import { View as View26 } from "react-native";
2924
+ import Svg11, { Circle as Circle6, Defs as Defs5, LinearGradient as LinearGradient5, Path as Path8, RadialGradient as RadialGradient2, Stop as Stop5 } from "react-native-svg";
1993
2925
 
1994
2926
  // src/marks/orazaka-geometry.ts
1995
2927
  var orange = marks.orazaka[marks.orazaka.length - 1][1];
@@ -2018,41 +2950,41 @@ var ORAZAKA = {
2018
2950
  };
2019
2951
 
2020
2952
  // src/native/OrazakaMark.tsx
2021
- import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2953
+ import { jsx as jsx31, jsxs as jsxs27 } from "react/jsx-runtime";
2022
2954
  function OrazakaMark({ size = 48, animated = true, title, neutral }) {
2023
2955
  const { theme } = useTheme();
2024
- const { Animated: Animated14, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated);
2956
+ const { Animated: Animated22, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated);
2025
2957
  const id = useSvgId("ozm");
2026
2958
  const viewBox = size < 48 ? ORAZAKA.croppedViewBox : ORAZAKA.viewBox;
2027
2959
  const stroke = neutral ?? theme.textMuted;
2028
- const gradient = /* @__PURE__ */ jsx19(LinearGradient4, { id: `${id}a`, gradientUnits: "userSpaceOnUse", x1: ORAZAKA.gradient.x1, y1: ORAZAKA.gradient.y1, x2: ORAZAKA.gradient.x2, y2: ORAZAKA.gradient.y2, children: ORAZAKA.gradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx19(Stop4, { offset, stopColor: color }, offset)) });
2960
+ const gradient = /* @__PURE__ */ jsx31(LinearGradient5, { id: `${id}a`, gradientUnits: "userSpaceOnUse", x1: ORAZAKA.gradient.x1, y1: ORAZAKA.gradient.y1, x2: ORAZAKA.gradient.x2, y2: ORAZAKA.gradient.y2, children: ORAZAKA.gradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx31(Stop5, { offset, stopColor: color }, offset)) });
2029
2961
  const fill = `url(#${id}a)`;
2030
- return /* @__PURE__ */ jsxs16(View15, { style: { width: size, height: size }, ...markA11y(title), children: [
2031
- /* @__PURE__ */ jsxs16(Svg6, { viewBox, style: layer, children: [
2032
- /* @__PURE__ */ jsx19(Defs4, { children: /* @__PURE__ */ jsxs16(RadialGradient2, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
2033
- /* @__PURE__ */ jsx19(Stop4, { offset: "0%", stopColor: ORAZAKA.glow.color, stopOpacity: ORAZAKA.glow.opacity }),
2034
- /* @__PURE__ */ jsx19(Stop4, { offset: "100%", stopColor: ORAZAKA.glow.color, stopOpacity: 0 })
2962
+ return /* @__PURE__ */ jsxs27(View26, { style: { width: size, height: size }, ...markA11y(title), children: [
2963
+ /* @__PURE__ */ jsxs27(Svg11, { viewBox, style: layer, children: [
2964
+ /* @__PURE__ */ jsx31(Defs5, { children: /* @__PURE__ */ jsxs27(RadialGradient2, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
2965
+ /* @__PURE__ */ jsx31(Stop5, { offset: "0%", stopColor: ORAZAKA.glow.color, stopOpacity: ORAZAKA.glow.opacity }),
2966
+ /* @__PURE__ */ jsx31(Stop5, { offset: "100%", stopColor: ORAZAKA.glow.color, stopOpacity: 0 })
2035
2967
  ] }) }),
2036
- size >= 48 ? /* @__PURE__ */ jsx19(Circle3, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: 190, fill: `url(#${id}g)` }) : null,
2037
- /* @__PURE__ */ jsx19(Circle3, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.orbit.r, stroke, strokeWidth: ORAZAKA.orbit.width, strokeDasharray: ORAZAKA.orbit.dash, opacity: 0.6, fill: "none" }),
2038
- /* @__PURE__ */ jsx19(Circle3, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.ring.r, stroke, strokeWidth: ORAZAKA.ring.width, opacity: 0.35, fill: "none" })
2968
+ size >= 48 ? /* @__PURE__ */ jsx31(Circle6, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: 190, fill: `url(#${id}g)` }) : null,
2969
+ /* @__PURE__ */ jsx31(Circle6, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.orbit.r, stroke, strokeWidth: ORAZAKA.orbit.width, strokeDasharray: ORAZAKA.orbit.dash, opacity: 0.6, fill: "none" }),
2970
+ /* @__PURE__ */ jsx31(Circle6, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.ring.r, stroke, strokeWidth: ORAZAKA.ring.width, opacity: 0.35, fill: "none" })
2039
2971
  ] }),
2040
- /* @__PURE__ */ jsx19(Animated14.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsxs16(Svg6, { viewBox, style: layer, children: [
2041
- /* @__PURE__ */ jsx19(Defs4, { children: gradient }),
2042
- ORAZAKA.shards.map((d) => /* @__PURE__ */ jsx19(Path5, { d, fill, stroke: fill, strokeWidth: ORAZAKA.shardStroke, strokeLinejoin: "round" }, d))
2972
+ /* @__PURE__ */ jsx31(Animated22.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsxs27(Svg11, { viewBox, style: layer, children: [
2973
+ /* @__PURE__ */ jsx31(Defs5, { children: gradient }),
2974
+ ORAZAKA.shards.map((d) => /* @__PURE__ */ jsx31(Path8, { d, fill, stroke: fill, strokeWidth: ORAZAKA.shardStroke, strokeLinejoin: "round" }, d))
2043
2975
  ] }) }),
2044
- /* @__PURE__ */ jsx19(Animated14.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs16(Svg6, { viewBox, style: layer, children: [
2045
- /* @__PURE__ */ jsx19(Defs4, { children: gradient }),
2046
- /* @__PURE__ */ jsx19(Circle3, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.core.r, fill }),
2047
- /* @__PURE__ */ jsx19(Circle3, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.core.inner, fill: ORAZAKA.highlight })
2976
+ /* @__PURE__ */ jsx31(Animated22.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs27(Svg11, { viewBox, style: layer, children: [
2977
+ /* @__PURE__ */ jsx31(Defs5, { children: gradient }),
2978
+ /* @__PURE__ */ jsx31(Circle6, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.core.r, fill }),
2979
+ /* @__PURE__ */ jsx31(Circle6, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.core.inner, fill: ORAZAKA.highlight })
2048
2980
  ] }) })
2049
2981
  ] });
2050
2982
  }
2051
2983
 
2052
2984
  // src/native/OrochiaMark.tsx
2053
- import { useEffect as useEffect9, useState as useState15 } from "react";
2054
- import { AccessibilityInfo as AccessibilityInfo6, Animated as Animated8, Easing as Easing5, View as View16 } from "react-native";
2055
- import Svg7, { Circle as Circle4, Defs as Defs5, Ellipse as Ellipse2, G as Group2, LinearGradient as LinearGradient5, Path as Path6, RadialGradient as RadialGradient3, Stop as Stop5 } from "react-native-svg";
2985
+ import { useEffect as useEffect15, useState as useState24 } from "react";
2986
+ import { AccessibilityInfo as AccessibilityInfo10, Animated as Animated13, Easing as Easing7, View as View27 } from "react-native";
2987
+ import Svg12, { Circle as Circle7, Defs as Defs6, Ellipse as Ellipse2, G as Group2, LinearGradient as LinearGradient6, Path as Path9, RadialGradient as RadialGradient3, Stop as Stop6 } from "react-native-svg";
2056
2988
 
2057
2989
  // src/marks/orochia-geometry.ts
2058
2990
  var OROCHIA = {
@@ -2079,25 +3011,25 @@ var OROCHIA = {
2079
3011
  };
2080
3012
 
2081
3013
  // src/native/OrochiaMark.tsx
2082
- import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
3014
+ import { jsx as jsx32, jsxs as jsxs28 } from "react/jsx-runtime";
2083
3015
  var CENTER = OROCHIA.offset + 180;
2084
3016
  function OrochiaMark({ size = 48, animated = true, title, neutral: neutralProp }) {
2085
3017
  const { theme } = useTheme();
2086
3018
  const neutral = neutralProp ?? theme.textMuted;
2087
- const [spin] = useState15(() => new Animated8.Value(0));
2088
- const [pulse] = useState15(() => new Animated8.Value(0));
2089
- useEffect9(() => {
3019
+ const [spin] = useState24(() => new Animated13.Value(0));
3020
+ const [pulse] = useState24(() => new Animated13.Value(0));
3021
+ useEffect15(() => {
2090
3022
  if (!animated) return;
2091
3023
  let loops = [];
2092
3024
  let cancelled = false;
2093
- void AccessibilityInfo6.isReduceMotionEnabled().then((reduce) => {
3025
+ void AccessibilityInfo10.isReduceMotionEnabled().then((reduce) => {
2094
3026
  if (reduce || cancelled) return;
2095
3027
  loops = [
2096
- Animated8.loop(Animated8.timing(spin, { toValue: 1, duration: 3e4, easing: Easing5.linear, useNativeDriver: true })),
2097
- Animated8.loop(
2098
- Animated8.sequence([
2099
- Animated8.timing(pulse, { toValue: 1, duration: 1600, easing: Easing5.inOut(Easing5.ease), useNativeDriver: true }),
2100
- Animated8.timing(pulse, { toValue: 0, duration: 1600, easing: Easing5.inOut(Easing5.ease), useNativeDriver: true })
3028
+ Animated13.loop(Animated13.timing(spin, { toValue: 1, duration: 3e4, easing: Easing7.linear, useNativeDriver: true })),
3029
+ Animated13.loop(
3030
+ Animated13.sequence([
3031
+ Animated13.timing(pulse, { toValue: 1, duration: 1600, easing: Easing7.inOut(Easing7.ease), useNativeDriver: true }),
3032
+ Animated13.timing(pulse, { toValue: 0, duration: 1600, easing: Easing7.inOut(Easing7.ease), useNativeDriver: true })
2101
3033
  ])
2102
3034
  )
2103
3035
  ];
@@ -2111,44 +3043,117 @@ function OrochiaMark({ size = 48, animated = true, title, neutral: neutralProp }
2111
3043
  const viewBox = size < 48 ? OROCHIA.croppedViewBox : OROCHIA.viewBox;
2112
3044
  const layer = { position: "absolute", width: size, height: size };
2113
3045
  const a11y = title ? { accessible: true, accessibilityRole: "image", accessibilityLabel: title } : { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants" };
2114
- const bodyGradient = /* @__PURE__ */ jsx20(LinearGradient5, { id: "body", gradientUnits: "userSpaceOnUse", x1: OROCHIA.body.x1 + OROCHIA.offset, y1: OROCHIA.body.y1 + OROCHIA.offset, x2: OROCHIA.body.x2 + OROCHIA.offset, y2: OROCHIA.body.y2 + OROCHIA.offset, children: OROCHIA.body.stops.map(([offset, color]) => /* @__PURE__ */ jsx20(Stop5, { offset, stopColor: color }, offset)) });
2115
- return /* @__PURE__ */ jsxs17(View16, { style: { width: size, height: size }, ...a11y, children: [
2116
- /* @__PURE__ */ jsxs17(Svg7, { viewBox, style: layer, children: [
2117
- /* @__PURE__ */ jsx20(Defs5, { children: /* @__PURE__ */ jsxs17(RadialGradient3, { id: "glow", cx: "50%", cy: "50%", r: "50%", children: [
2118
- /* @__PURE__ */ jsx20(Stop5, { offset: "0%", stopColor: OROCHIA.glow.color, stopOpacity: OROCHIA.glow.opacity }),
2119
- /* @__PURE__ */ jsx20(Stop5, { offset: "100%", stopColor: OROCHIA.glow.color, stopOpacity: 0 })
3046
+ const bodyGradient = /* @__PURE__ */ jsx32(LinearGradient6, { id: "body", gradientUnits: "userSpaceOnUse", x1: OROCHIA.body.x1 + OROCHIA.offset, y1: OROCHIA.body.y1 + OROCHIA.offset, x2: OROCHIA.body.x2 + OROCHIA.offset, y2: OROCHIA.body.y2 + OROCHIA.offset, children: OROCHIA.body.stops.map(([offset, color]) => /* @__PURE__ */ jsx32(Stop6, { offset, stopColor: color }, offset)) });
3047
+ return /* @__PURE__ */ jsxs28(View27, { style: { width: size, height: size }, ...a11y, children: [
3048
+ /* @__PURE__ */ jsxs28(Svg12, { viewBox, style: layer, children: [
3049
+ /* @__PURE__ */ jsx32(Defs6, { children: /* @__PURE__ */ jsxs28(RadialGradient3, { id: "glow", cx: "50%", cy: "50%", r: "50%", children: [
3050
+ /* @__PURE__ */ jsx32(Stop6, { offset: "0%", stopColor: OROCHIA.glow.color, stopOpacity: OROCHIA.glow.opacity }),
3051
+ /* @__PURE__ */ jsx32(Stop6, { offset: "100%", stopColor: OROCHIA.glow.color, stopOpacity: 0 })
2120
3052
  ] }) }),
2121
- /* @__PURE__ */ jsx20(Circle4, { cx: CENTER, cy: CENTER, r: 170, fill: "url(#glow)" }),
2122
- /* @__PURE__ */ jsx20(Circle4, { cx: CENTER, cy: CENTER, r: OROCHIA.ring.r, stroke: neutral, strokeWidth: OROCHIA.ring.width, opacity: 0.35, fill: "none" })
3053
+ /* @__PURE__ */ jsx32(Circle7, { cx: CENTER, cy: CENTER, r: 170, fill: "url(#glow)" }),
3054
+ /* @__PURE__ */ jsx32(Circle7, { cx: CENTER, cy: CENTER, r: OROCHIA.ring.r, stroke: neutral, strokeWidth: OROCHIA.ring.width, opacity: 0.35, fill: "none" })
2123
3055
  ] }),
2124
- /* @__PURE__ */ jsx20(Animated8.View, { style: [layer, { transform: [{ rotate: spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] }) }] }], children: /* @__PURE__ */ jsx20(Svg7, { viewBox, style: layer, children: /* @__PURE__ */ jsx20(Circle4, { cx: CENTER, cy: CENTER, r: OROCHIA.orbit.r, stroke: neutral, strokeWidth: OROCHIA.orbit.width, strokeDasharray: OROCHIA.orbit.dash, opacity: 0.6, fill: "none" }) }) }),
2125
- /* @__PURE__ */ jsxs17(Svg7, { viewBox, style: layer, children: [
2126
- /* @__PURE__ */ jsx20(Defs5, { children: bodyGradient }),
2127
- /* @__PURE__ */ jsxs17(Group2, { transform: `translate(${OROCHIA.offset} ${OROCHIA.offset})`, children: [
2128
- /* @__PURE__ */ jsx20(Path6, { d: OROCHIA.arc, stroke: "url(#body)", strokeWidth: 22, strokeLinecap: "round", fill: "none" }),
2129
- /* @__PURE__ */ jsx20(Path6, { d: OROCHIA.arc, stroke: OROCHIA.scales.color, strokeOpacity: OROCHIA.scales.opacity, strokeWidth: OROCHIA.scales.width, strokeLinecap: "round", strokeDasharray: OROCHIA.scales.dash, fill: "none" }),
2130
- /* @__PURE__ */ jsx20(Path6, { d: OROCHIA.neck, stroke: "url(#body)", strokeWidth: 14, strokeLinecap: "round", fill: "none" }),
2131
- /* @__PURE__ */ jsx20(Path6, { d: OROCHIA.tail, stroke: "url(#body)", strokeWidth: 6, strokeLinecap: "round", fill: "none" }),
2132
- /* @__PURE__ */ jsx20(Ellipse2, { cx: OROCHIA.head.cx, cy: OROCHIA.head.cy, rx: OROCHIA.head.rx, ry: OROCHIA.head.ry, rotation: OROCHIA.head.rotate, origin: `${OROCHIA.head.cx}, ${OROCHIA.head.cy}`, fill: "url(#body)" }),
2133
- /* @__PURE__ */ jsx20(Path6, { d: OROCHIA.tongue.d, stroke: OROCHIA.tongue.color, strokeWidth: 3, strokeLinecap: "round", fill: "none" })
3056
+ /* @__PURE__ */ jsx32(Animated13.View, { style: [layer, { transform: [{ rotate: spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] }) }] }], children: /* @__PURE__ */ jsx32(Svg12, { viewBox, style: layer, children: /* @__PURE__ */ jsx32(Circle7, { cx: CENTER, cy: CENTER, r: OROCHIA.orbit.r, stroke: neutral, strokeWidth: OROCHIA.orbit.width, strokeDasharray: OROCHIA.orbit.dash, opacity: 0.6, fill: "none" }) }) }),
3057
+ /* @__PURE__ */ jsxs28(Svg12, { viewBox, style: layer, children: [
3058
+ /* @__PURE__ */ jsx32(Defs6, { children: bodyGradient }),
3059
+ /* @__PURE__ */ jsxs28(Group2, { transform: `translate(${OROCHIA.offset} ${OROCHIA.offset})`, children: [
3060
+ /* @__PURE__ */ jsx32(Path9, { d: OROCHIA.arc, stroke: "url(#body)", strokeWidth: 22, strokeLinecap: "round", fill: "none" }),
3061
+ /* @__PURE__ */ jsx32(Path9, { d: OROCHIA.arc, stroke: OROCHIA.scales.color, strokeOpacity: OROCHIA.scales.opacity, strokeWidth: OROCHIA.scales.width, strokeLinecap: "round", strokeDasharray: OROCHIA.scales.dash, fill: "none" }),
3062
+ /* @__PURE__ */ jsx32(Path9, { d: OROCHIA.neck, stroke: "url(#body)", strokeWidth: 14, strokeLinecap: "round", fill: "none" }),
3063
+ /* @__PURE__ */ jsx32(Path9, { d: OROCHIA.tail, stroke: "url(#body)", strokeWidth: 6, strokeLinecap: "round", fill: "none" }),
3064
+ /* @__PURE__ */ jsx32(Ellipse2, { cx: OROCHIA.head.cx, cy: OROCHIA.head.cy, rx: OROCHIA.head.rx, ry: OROCHIA.head.ry, rotation: OROCHIA.head.rotate, origin: `${OROCHIA.head.cx}, ${OROCHIA.head.cy}`, fill: "url(#body)" }),
3065
+ /* @__PURE__ */ jsx32(Path9, { d: OROCHIA.tongue.d, stroke: OROCHIA.tongue.color, strokeWidth: 3, strokeLinecap: "round", fill: "none" })
2134
3066
  ] })
2135
3067
  ] }),
2136
- /* @__PURE__ */ jsx20(Animated8.View, { style: [layer, { opacity: pulse.interpolate({ inputRange: [0, 1], outputRange: [0.85, 1] }) }], children: /* @__PURE__ */ jsxs17(Svg7, { viewBox, style: layer, children: [
2137
- /* @__PURE__ */ jsx20(Defs5, { children: /* @__PURE__ */ jsx20(LinearGradient5, { id: "flame", x1: "50%", y1: "100%", x2: "50%", y2: "0%", children: OROCHIA.flameGradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx20(Stop5, { offset, stopColor: color }, offset)) }) }),
2138
- /* @__PURE__ */ jsxs17(Group2, { transform: `translate(${OROCHIA.offset} ${OROCHIA.offset})`, children: [
2139
- /* @__PURE__ */ jsx20(Circle4, { cx: OROCHIA.eye.cx, cy: OROCHIA.eye.cy, r: OROCHIA.eye.r, fill: OROCHIA.eye.color }),
2140
- /* @__PURE__ */ jsx20(Path6, { d: OROCHIA.flame.d, transform: `translate(${OROCHIA.flame.translate[0]} ${OROCHIA.flame.translate[1]}) scale(${OROCHIA.flame.scale})`, fill: "url(#flame)" })
3068
+ /* @__PURE__ */ jsx32(Animated13.View, { style: [layer, { opacity: pulse.interpolate({ inputRange: [0, 1], outputRange: [0.85, 1] }) }], children: /* @__PURE__ */ jsxs28(Svg12, { viewBox, style: layer, children: [
3069
+ /* @__PURE__ */ jsx32(Defs6, { children: /* @__PURE__ */ jsx32(LinearGradient6, { id: "flame", x1: "50%", y1: "100%", x2: "50%", y2: "0%", children: OROCHIA.flameGradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx32(Stop6, { offset, stopColor: color }, offset)) }) }),
3070
+ /* @__PURE__ */ jsxs28(Group2, { transform: `translate(${OROCHIA.offset} ${OROCHIA.offset})`, children: [
3071
+ /* @__PURE__ */ jsx32(Circle7, { cx: OROCHIA.eye.cx, cy: OROCHIA.eye.cy, r: OROCHIA.eye.r, fill: OROCHIA.eye.color }),
3072
+ /* @__PURE__ */ jsx32(Path9, { d: OROCHIA.flame.d, transform: `translate(${OROCHIA.flame.translate[0]} ${OROCHIA.flame.translate[1]}) scale(${OROCHIA.flame.scale})`, fill: "url(#flame)" })
2141
3073
  ] })
2142
3074
  ] }) })
2143
3075
  ] });
2144
3076
  }
2145
3077
 
3078
+ // src/native/otp-input.tsx
3079
+ import * as React25 from "react";
3080
+ import { Platform as Platform2, Pressable as Pressable13, StyleSheet as StyleSheet27, TextInput as TextInput4, View as View28 } from "react-native";
3081
+ import { jsx as jsx33, jsxs as jsxs29 } from "react/jsx-runtime";
3082
+ function OtpInput({ label, length = 6, value, onValueChange, onComplete, mode = "numeric", invalid, disabled, autoFocus, style }) {
3083
+ const { theme, radius: radius3, haptic } = useTheme();
3084
+ const [own, setOwn] = React25.useState("");
3085
+ const code = value ?? own;
3086
+ const [focused, setFocused] = React25.useState(false);
3087
+ const input = React25.useRef(null);
3088
+ React25.useEffect(() => {
3089
+ if (invalid) haptic("warning");
3090
+ }, [invalid, haptic]);
3091
+ const change = (raw) => {
3092
+ const next = (mode === "numeric" ? raw.replace(/\D/g, "") : raw.replace(/\s/g, "").toUpperCase()).slice(0, length);
3093
+ if (value === void 0) setOwn(next);
3094
+ onValueChange?.(next);
3095
+ if (next.length === length && code.length !== length) {
3096
+ haptic("success");
3097
+ onComplete?.(next);
3098
+ }
3099
+ };
3100
+ return /* @__PURE__ */ jsxs29(Pressable13, { onPress: () => input.current?.focus(), disabled, accessible: false, style: [styles27.root, style], children: [
3101
+ /* @__PURE__ */ jsx33(View28, { style: styles27.boxes, "aria-hidden": true, children: Array.from({ length }, (_, i) => {
3102
+ const active = focused && i === Math.min(code.length, length - 1);
3103
+ return /* @__PURE__ */ jsx33(
3104
+ View28,
3105
+ {
3106
+ style: [
3107
+ styles27.box,
3108
+ {
3109
+ borderRadius: radius3.md,
3110
+ backgroundColor: theme.surface2,
3111
+ borderColor: invalid ? theme.danger : active ? theme.ring : theme.borderDefault,
3112
+ borderWidth: invalid || active ? 2 : 1
3113
+ }
3114
+ ],
3115
+ children: /* @__PURE__ */ jsx33(Txt, { variant: "title", children: code[i] ?? "" })
3116
+ },
3117
+ i
3118
+ );
3119
+ }) }),
3120
+ /* @__PURE__ */ jsx33(
3121
+ TextInput4,
3122
+ {
3123
+ ref: input,
3124
+ "aria-label": label,
3125
+ "aria-invalid": invalid || void 0,
3126
+ value: code,
3127
+ onChangeText: change,
3128
+ maxLength: length,
3129
+ editable: !disabled,
3130
+ autoFocus,
3131
+ keyboardType: mode === "numeric" ? "number-pad" : "default",
3132
+ textContentType: "oneTimeCode",
3133
+ autoComplete: Platform2.OS === "android" && mode === "numeric" ? "sms-otp" : "one-time-code",
3134
+ autoCapitalize: "characters",
3135
+ autoCorrect: false,
3136
+ caretHidden: true,
3137
+ onFocus: () => setFocused(true),
3138
+ onBlur: () => setFocused(false),
3139
+ style: styles27.hidden
3140
+ }
3141
+ )
3142
+ ] });
3143
+ }
3144
+ var styles27 = StyleSheet27.create({
3145
+ root: { alignSelf: "flex-start" },
3146
+ boxes: { flexDirection: "row", gap: 8 },
3147
+ box: { width: 46, height: 56, alignItems: "center", justifyContent: "center" },
3148
+ hidden: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, opacity: 0.011, color: "transparent" }
3149
+ });
3150
+
2146
3151
  // src/native/pagination.tsx
2147
- import { Pressable as Pressable7, StyleSheet as StyleSheet16, Text as Text11, View as View17 } from "react-native";
2148
- import Svg8, { Path as Path7 } from "react-native-svg";
2149
- import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
2150
- function Chevron2({ direction, color }) {
2151
- return /* @__PURE__ */ jsx21(Svg8, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx21(Path7, { d: direction === "left" ? "m15 6-6 6 6 6" : "m9 6 6 6-6 6" }) });
3152
+ import { Pressable as Pressable14, StyleSheet as StyleSheet28, Text as Text14, View as View29 } from "react-native";
3153
+ import Svg13, { Path as Path10 } from "react-native-svg";
3154
+ import { jsx as jsx34, jsxs as jsxs30 } from "react/jsx-runtime";
3155
+ function Chevron3({ direction, color }) {
3156
+ return /* @__PURE__ */ jsx34(Svg13, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx34(Path10, { d: direction === "left" ? "m15 6-6 6 6 6" : "m9 6 6 6-6 6" }) });
2152
3157
  }
2153
3158
  function Pagination({ page = 1, pageCount, onPageChange, hasPrevious, hasNext, onPrevious, onNext, status, disabled, labels, style }) {
2154
3159
  const { theme, radius: radius3 } = useTheme();
@@ -2157,8 +3162,8 @@ function Pagination({ page = 1, pageCount, onPageChange, hasPrevious, hasNext, o
2157
3162
  const current = Math.min(Math.max(1, page), count);
2158
3163
  const canPrevious = !disabled && (paged ? current > 1 : Boolean(hasPrevious));
2159
3164
  const canNext = !disabled && (paged ? current < count : Boolean(hasNext));
2160
- const button = (direction, enabled, onPress, label) => /* @__PURE__ */ jsx21(
2161
- Pressable7,
3165
+ const button = (direction, enabled, onPress, label) => /* @__PURE__ */ jsx34(
3166
+ Pressable14,
2162
3167
  {
2163
3168
  role: "button",
2164
3169
  "aria-label": label,
@@ -2167,29 +3172,66 @@ function Pagination({ page = 1, pageCount, onPageChange, hasPrevious, hasNext, o
2167
3172
  hitSlop: 6,
2168
3173
  onPress,
2169
3174
  style: ({ pressed }) => [
2170
- styles16.button,
3175
+ styles28.button,
2171
3176
  { borderRadius: radius3.sm, borderColor: theme.borderDefault, backgroundColor: theme.surface1, opacity: enabled ? pressed ? 0.8 : 1 : 0.4 }
2172
3177
  ],
2173
- children: /* @__PURE__ */ jsx21(Chevron2, { direction, color: theme.textPrimary })
3178
+ children: /* @__PURE__ */ jsx34(Chevron3, { direction, color: theme.textPrimary })
2174
3179
  }
2175
3180
  );
2176
3181
  const text = status ?? (paged ? labels.compact(current, count) : null);
2177
- return /* @__PURE__ */ jsxs18(View17, { role: "navigation", style: [styles16.row, style], children: [
3182
+ return /* @__PURE__ */ jsxs30(View29, { role: "navigation", style: [styles28.row, style], children: [
2178
3183
  button("left", canPrevious, paged ? () => onPageChange?.(current - 1) : onPrevious, labels.previous),
2179
- text ? /* @__PURE__ */ jsx21(Text11, { "aria-live": "polite", style: [styles16.status, { color: theme.textSecondary }], children: text }) : null,
3184
+ text ? /* @__PURE__ */ jsx34(Text14, { "aria-live": "polite", style: [styles28.status, { color: theme.textSecondary }], children: text }) : null,
2180
3185
  button("right", canNext, paged ? () => onPageChange?.(current + 1) : onNext, labels.next)
2181
3186
  ] });
2182
3187
  }
2183
- var styles16 = StyleSheet16.create({
3188
+ var styles28 = StyleSheet28.create({
2184
3189
  row: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: 12 },
2185
- button: { width: 44, height: 44, alignItems: "center", justifyContent: "center", borderWidth: StyleSheet16.hairlineWidth },
3190
+ button: { width: 44, height: 44, alignItems: "center", justifyContent: "center", borderWidth: StyleSheet28.hairlineWidth },
2186
3191
  status: { fontSize: 13, fontWeight: "600", fontVariant: ["tabular-nums"] }
2187
3192
  });
2188
3193
 
3194
+ // src/native/permission-prompt.tsx
3195
+ import { StyleSheet as StyleSheet29, View as View30 } from "react-native";
3196
+ import { Fragment as Fragment5, jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
3197
+ function PermissionPrompt({
3198
+ status,
3199
+ title,
3200
+ description,
3201
+ allowLabel,
3202
+ onAllow,
3203
+ settingsLabel,
3204
+ onOpenSettings,
3205
+ blockedDescription,
3206
+ dismissLabel,
3207
+ onDismiss,
3208
+ mascot = "falcon",
3209
+ children,
3210
+ style
3211
+ }) {
3212
+ const { theme, radius: radius3 } = useTheme();
3213
+ if (status === "granted") return /* @__PURE__ */ jsx35(Fragment5, { children: children ?? null });
3214
+ const blocked = status === "blocked" || status === "denied" && Boolean(onOpenSettings);
3215
+ return /* @__PURE__ */ jsxs31(View30, { style: [styles29.root, { backgroundColor: theme.surface1, borderColor: theme.borderSubtle, borderRadius: radius3.xl }, style], children: [
3216
+ /* @__PURE__ */ jsx35(Mascot, { bird: mascot, mood: blocked ? "error" : "welcome", size: 104 }),
3217
+ /* @__PURE__ */ jsx35(Txt, { variant: "title", style: styles29.centred, children: title }),
3218
+ /* @__PURE__ */ jsx35(Txt, { tone: "secondary", style: styles29.centred, children: blocked && blockedDescription ? blockedDescription : description }),
3219
+ /* @__PURE__ */ jsxs31(View30, { style: styles29.actions, children: [
3220
+ blocked && settingsLabel && onOpenSettings ? /* @__PURE__ */ jsx35(Button, { label: settingsLabel, variant: "primary", onPress: onOpenSettings }) : /* @__PURE__ */ jsx35(Button, { label: allowLabel, variant: "primary", onPress: onAllow }),
3221
+ dismissLabel && onDismiss ? /* @__PURE__ */ jsx35(Button, { label: dismissLabel, variant: "ghost", onPress: onDismiss }) : null
3222
+ ] })
3223
+ ] });
3224
+ }
3225
+ var styles29 = StyleSheet29.create({
3226
+ root: { alignItems: "center", gap: 10, padding: 24, borderWidth: StyleSheet29.hairlineWidth },
3227
+ centred: { textAlign: "center", maxWidth: 340 },
3228
+ actions: { marginTop: 8, gap: 8, alignSelf: "stretch" }
3229
+ });
3230
+
2189
3231
  // src/native/phoenix.tsx
2190
- import { useEffect as useEffect10, useState as useState16 } from "react";
2191
- import { AccessibilityInfo as AccessibilityInfo7, Animated as Animated9, Easing as Easing6, View as View18 } from "react-native";
2192
- import Svg9, { Circle as Circle5, Defs as Defs6, LinearGradient as LinearGradient6, Path as Path8, RadialGradient as RadialGradient4, Stop as Stop6 } from "react-native-svg";
3232
+ import { useEffect as useEffect17, useState as useState26 } from "react";
3233
+ import { AccessibilityInfo as AccessibilityInfo11, Animated as Animated14, Easing as Easing8, View as View31 } from "react-native";
3234
+ import Svg14, { Circle as Circle8, Defs as Defs7, LinearGradient as LinearGradient7, Path as Path11, RadialGradient as RadialGradient4, Stop as Stop7 } from "react-native-svg";
2193
3235
 
2194
3236
  // src/mascots/phoenix-geometry.ts
2195
3237
  var PHOENIX = {
@@ -2212,17 +3254,17 @@ var PHOENIX_PALETTES = {
2212
3254
  };
2213
3255
 
2214
3256
  // src/native/phoenix.tsx
2215
- import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
3257
+ import { jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
2216
3258
  function useFloat(animated) {
2217
- const [y] = useState16(() => new Animated9.Value(0));
2218
- useEffect10(() => {
3259
+ const [y] = useState26(() => new Animated14.Value(0));
3260
+ useEffect17(() => {
2219
3261
  if (!animated) return;
2220
3262
  let loop;
2221
3263
  let cancelled = false;
2222
- void AccessibilityInfo7.isReduceMotionEnabled().then((reduce) => {
3264
+ void AccessibilityInfo11.isReduceMotionEnabled().then((reduce) => {
2223
3265
  if (reduce || cancelled) return;
2224
- const step = (toValue) => Animated9.timing(y, { toValue, duration: 2500, easing: Easing6.inOut(Easing6.ease), useNativeDriver: true });
2225
- loop = Animated9.loop(Animated9.sequence([step(-6), step(0)]));
3266
+ const step = (toValue) => Animated14.timing(y, { toValue, duration: 2500, easing: Easing8.inOut(Easing8.ease), useNativeDriver: true });
3267
+ loop = Animated14.loop(Animated14.sequence([step(-6), step(0)]));
2226
3268
  loop.start();
2227
3269
  });
2228
3270
  return () => {
@@ -2232,41 +3274,41 @@ function useFloat(animated) {
2232
3274
  }, [animated, y]);
2233
3275
  return y;
2234
3276
  }
2235
- function Phoenix({ tone: tone2 = "own", size = 120, animated = true, title, style }) {
3277
+ function Phoenix({ tone: tone3 = "own", size = 120, animated = true, title, style }) {
2236
3278
  const { theme } = useTheme();
2237
3279
  const id = useSvgId("kzp");
2238
3280
  const y = useFloat(animated);
2239
- const p = tone2 === "brand" ? { left: [theme.accent2, theme.accent], right: [theme.accent, theme.accent2], core: ["#ffffff", theme.accent], body: theme.surface3, edge: theme.borderStrong, crest: theme.accent } : PHOENIX_PALETTES.own;
2240
- return /* @__PURE__ */ jsx22(View18, { style: [{ width: size, height: size }, style], ...markA11y(title), children: /* @__PURE__ */ jsx22(Animated9.View, { style: { transform: [{ translateY: y }] }, children: /* @__PURE__ */ jsxs19(Svg9, { width: size, height: size, viewBox: "0 0 120 120", children: [
2241
- /* @__PURE__ */ jsxs19(Defs6, { children: [
2242
- /* @__PURE__ */ jsxs19(LinearGradient6, { id: `${id}l`, x1: "1", y1: "0", x2: "0", y2: "1", children: [
2243
- /* @__PURE__ */ jsx22(Stop6, { offset: "0%", stopColor: p.left[0] }),
2244
- /* @__PURE__ */ jsx22(Stop6, { offset: "100%", stopColor: p.left[1] })
3281
+ const p = tone3 === "brand" ? { left: [theme.accent2, theme.accent], right: [theme.accent, theme.accent2], core: ["#ffffff", theme.accent], body: theme.surface3, edge: theme.borderStrong, crest: theme.accent } : PHOENIX_PALETTES.own;
3282
+ return /* @__PURE__ */ jsx36(View31, { style: [{ width: size, height: size }, style], ...markA11y(title), children: /* @__PURE__ */ jsx36(Animated14.View, { style: { transform: [{ translateY: y }] }, children: /* @__PURE__ */ jsxs32(Svg14, { width: size, height: size, viewBox: "0 0 120 120", children: [
3283
+ /* @__PURE__ */ jsxs32(Defs7, { children: [
3284
+ /* @__PURE__ */ jsxs32(LinearGradient7, { id: `${id}l`, x1: "1", y1: "0", x2: "0", y2: "1", children: [
3285
+ /* @__PURE__ */ jsx36(Stop7, { offset: "0%", stopColor: p.left[0] }),
3286
+ /* @__PURE__ */ jsx36(Stop7, { offset: "100%", stopColor: p.left[1] })
2245
3287
  ] }),
2246
- /* @__PURE__ */ jsxs19(LinearGradient6, { id: `${id}r`, x1: "0", y1: "0", x2: "1", y2: "1", children: [
2247
- /* @__PURE__ */ jsx22(Stop6, { offset: "0%", stopColor: p.right[0] }),
2248
- /* @__PURE__ */ jsx22(Stop6, { offset: "100%", stopColor: p.right[1] })
3288
+ /* @__PURE__ */ jsxs32(LinearGradient7, { id: `${id}r`, x1: "0", y1: "0", x2: "1", y2: "1", children: [
3289
+ /* @__PURE__ */ jsx36(Stop7, { offset: "0%", stopColor: p.right[0] }),
3290
+ /* @__PURE__ */ jsx36(Stop7, { offset: "100%", stopColor: p.right[1] })
2249
3291
  ] }),
2250
- /* @__PURE__ */ jsxs19(RadialGradient4, { id: `${id}c`, children: [
2251
- /* @__PURE__ */ jsx22(Stop6, { offset: "0%", stopColor: p.core[0] }),
2252
- /* @__PURE__ */ jsx22(Stop6, { offset: "100%", stopColor: p.core[1], stopOpacity: 0 })
3292
+ /* @__PURE__ */ jsxs32(RadialGradient4, { id: `${id}c`, children: [
3293
+ /* @__PURE__ */ jsx36(Stop7, { offset: "0%", stopColor: p.core[0] }),
3294
+ /* @__PURE__ */ jsx36(Stop7, { offset: "100%", stopColor: p.core[1], stopOpacity: 0 })
2253
3295
  ] })
2254
3296
  ] }),
2255
- /* @__PURE__ */ jsx22(Path8, { d: PHOENIX.wingL, fill: `url(#${id}l)` }),
2256
- /* @__PURE__ */ jsx22(Path8, { d: PHOENIX.wingR, fill: `url(#${id}r)` }),
2257
- /* @__PURE__ */ jsx22(Path8, { d: PHOENIX.tailL, fill: `url(#${id}l)`, opacity: 0.7 }),
2258
- /* @__PURE__ */ jsx22(Path8, { d: PHOENIX.tailR, fill: `url(#${id}r)`, opacity: 0.7 }),
2259
- /* @__PURE__ */ jsx22(Path8, { d: PHOENIX.body, fill: p.body, stroke: p.edge, strokeOpacity: 0.5 }),
2260
- /* @__PURE__ */ jsx22(Circle5, { cx: 60, cy: 58, r: 12, fill: `url(#${id}c)` }),
2261
- /* @__PURE__ */ jsx22(Circle5, { cx: 60, cy: 58, r: 3.5, fill: "#ffffff" }),
2262
- /* @__PURE__ */ jsx22(Path8, { d: PHOENIX.crest, stroke: p.crest, strokeWidth: 2, strokeLinecap: "round" })
3297
+ /* @__PURE__ */ jsx36(Path11, { d: PHOENIX.wingL, fill: `url(#${id}l)` }),
3298
+ /* @__PURE__ */ jsx36(Path11, { d: PHOENIX.wingR, fill: `url(#${id}r)` }),
3299
+ /* @__PURE__ */ jsx36(Path11, { d: PHOENIX.tailL, fill: `url(#${id}l)`, opacity: 0.7 }),
3300
+ /* @__PURE__ */ jsx36(Path11, { d: PHOENIX.tailR, fill: `url(#${id}r)`, opacity: 0.7 }),
3301
+ /* @__PURE__ */ jsx36(Path11, { d: PHOENIX.body, fill: p.body, stroke: p.edge, strokeOpacity: 0.5 }),
3302
+ /* @__PURE__ */ jsx36(Circle8, { cx: 60, cy: 58, r: 12, fill: `url(#${id}c)` }),
3303
+ /* @__PURE__ */ jsx36(Circle8, { cx: 60, cy: 58, r: 3.5, fill: "#ffffff" }),
3304
+ /* @__PURE__ */ jsx36(Path11, { d: PHOENIX.crest, stroke: p.crest, strokeWidth: 2, strokeLinecap: "round" })
2263
3305
  ] }) }) });
2264
3306
  }
2265
3307
 
2266
3308
  // src/native/YazakiaMark.tsx
2267
- import React17 from "react";
2268
- import { View as View19 } from "react-native";
2269
- import Svg10, { Circle as Circle6, Defs as Defs7, LinearGradient as LinearGradient7, Path as Path9, RadialGradient as RadialGradient5, Stop as Stop7 } from "react-native-svg";
3309
+ import React27 from "react";
3310
+ import { View as View32 } from "react-native";
3311
+ import Svg15, { Circle as Circle9, Defs as Defs8, LinearGradient as LinearGradient8, Path as Path12, RadialGradient as RadialGradient5, Stop as Stop8 } from "react-native-svg";
2270
3312
 
2271
3313
  // src/marks/yazakia-geometry.ts
2272
3314
  var turquoise = marks.yazakia[marks.yazakia.length - 1][1];
@@ -2296,54 +3338,54 @@ var YAZAKIA = {
2296
3338
  };
2297
3339
 
2298
3340
  // src/native/YazakiaMark.tsx
2299
- import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
3341
+ import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
2300
3342
  function YazakiaMark({ size = 48, animated = true, title, neutral }) {
2301
3343
  const { theme } = useTheme();
2302
- const { Animated: Animated14, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated);
3344
+ const { Animated: Animated22, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated);
2303
3345
  const id = useSvgId("yzm");
2304
3346
  const viewBox = size < 48 ? YAZAKIA.croppedViewBox : YAZAKIA.viewBox;
2305
3347
  const stroke = neutral ?? theme.textMuted;
2306
- const gradient = /* @__PURE__ */ jsx23(LinearGradient7, { id: `${id}a`, gradientUnits: "userSpaceOnUse", x1: YAZAKIA.gradient.x1, y1: YAZAKIA.gradient.y1, x2: YAZAKIA.gradient.x2, y2: YAZAKIA.gradient.y2, children: YAZAKIA.gradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx23(Stop7, { offset, stopColor: color }, offset)) });
3348
+ const gradient = /* @__PURE__ */ jsx37(LinearGradient8, { id: `${id}a`, gradientUnits: "userSpaceOnUse", x1: YAZAKIA.gradient.x1, y1: YAZAKIA.gradient.y1, x2: YAZAKIA.gradient.x2, y2: YAZAKIA.gradient.y2, children: YAZAKIA.gradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx37(Stop8, { offset, stopColor: color }, offset)) });
2307
3349
  const fill = `url(#${id}a)`;
2308
- return /* @__PURE__ */ jsxs20(View19, { style: { width: size, height: size }, ...markA11y(title), children: [
2309
- /* @__PURE__ */ jsxs20(Svg10, { viewBox, style: layer, children: [
2310
- /* @__PURE__ */ jsxs20(Defs7, { children: [
2311
- /* @__PURE__ */ jsxs20(RadialGradient5, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
2312
- /* @__PURE__ */ jsx23(Stop7, { offset: "0%", stopColor: YAZAKIA.glow.color, stopOpacity: YAZAKIA.glow.opacity }),
2313
- /* @__PURE__ */ jsx23(Stop7, { offset: "100%", stopColor: YAZAKIA.glow.color, stopOpacity: 0 })
3350
+ return /* @__PURE__ */ jsxs33(View32, { style: { width: size, height: size }, ...markA11y(title), children: [
3351
+ /* @__PURE__ */ jsxs33(Svg15, { viewBox, style: layer, children: [
3352
+ /* @__PURE__ */ jsxs33(Defs8, { children: [
3353
+ /* @__PURE__ */ jsxs33(RadialGradient5, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
3354
+ /* @__PURE__ */ jsx37(Stop8, { offset: "0%", stopColor: YAZAKIA.glow.color, stopOpacity: YAZAKIA.glow.opacity }),
3355
+ /* @__PURE__ */ jsx37(Stop8, { offset: "100%", stopColor: YAZAKIA.glow.color, stopOpacity: 0 })
2314
3356
  ] }),
2315
3357
  gradient
2316
3358
  ] }),
2317
- size >= 48 ? /* @__PURE__ */ jsx23(Circle6, { cx: YAZAKIA.center, cy: YAZAKIA.center, r: 190, fill: `url(#${id}g)` }) : null,
2318
- /* @__PURE__ */ jsx23(Circle6, { cx: YAZAKIA.center, cy: YAZAKIA.center, r: YAZAKIA.ring.r, stroke, strokeWidth: YAZAKIA.ring.width, opacity: 0.35, fill: "none" }),
2319
- YAZAKIA.voices.map((v, i) => /* @__PURE__ */ jsxs20(React17.Fragment, { children: [
2320
- /* @__PURE__ */ jsx23(Path9, { d: v.body, fill }),
2321
- /* @__PURE__ */ jsx23(Path9, { d: v.tail, fill }),
2322
- i === 0 ? /* @__PURE__ */ jsx23(Path9, { d: `${v.body} ${v.tail}`, fill: YAZAKIA.shade.color, opacity: YAZAKIA.shade.opacity }) : null
3359
+ size >= 48 ? /* @__PURE__ */ jsx37(Circle9, { cx: YAZAKIA.center, cy: YAZAKIA.center, r: 190, fill: `url(#${id}g)` }) : null,
3360
+ /* @__PURE__ */ jsx37(Circle9, { cx: YAZAKIA.center, cy: YAZAKIA.center, r: YAZAKIA.ring.r, stroke, strokeWidth: YAZAKIA.ring.width, opacity: 0.35, fill: "none" }),
3361
+ YAZAKIA.voices.map((v, i) => /* @__PURE__ */ jsxs33(React27.Fragment, { children: [
3362
+ /* @__PURE__ */ jsx37(Path12, { d: v.body, fill }),
3363
+ /* @__PURE__ */ jsx37(Path12, { d: v.tail, fill }),
3364
+ i === 0 ? /* @__PURE__ */ jsx37(Path12, { d: `${v.body} ${v.tail}`, fill: YAZAKIA.shade.color, opacity: YAZAKIA.shade.opacity }) : null
2323
3365
  ] }, v.body))
2324
3366
  ] }),
2325
- /* @__PURE__ */ jsx23(Animated14.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsxs20(Svg10, { viewBox, style: layer, children: [
2326
- /* @__PURE__ */ jsx23(Defs7, { children: gradient }),
2327
- /* @__PURE__ */ jsx23(Circle6, { cx: YAZAKIA.center, cy: YAZAKIA.center, r: YAZAKIA.orbit.r, stroke, strokeWidth: YAZAKIA.orbit.width, strokeDasharray: YAZAKIA.orbit.dash, opacity: 0.6, fill: "none" }),
2328
- YAZAKIA.pair.at.map(([cx, cy]) => /* @__PURE__ */ jsx23(Circle6, { cx, cy, r: YAZAKIA.pair.r, fill }, cx))
3367
+ /* @__PURE__ */ jsx37(Animated22.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsxs33(Svg15, { viewBox, style: layer, children: [
3368
+ /* @__PURE__ */ jsx37(Defs8, { children: gradient }),
3369
+ /* @__PURE__ */ jsx37(Circle9, { cx: YAZAKIA.center, cy: YAZAKIA.center, r: YAZAKIA.orbit.r, stroke, strokeWidth: YAZAKIA.orbit.width, strokeDasharray: YAZAKIA.orbit.dash, opacity: 0.6, fill: "none" }),
3370
+ YAZAKIA.pair.at.map(([cx, cy]) => /* @__PURE__ */ jsx37(Circle9, { cx, cy, r: YAZAKIA.pair.r, fill }, cx))
2329
3371
  ] }) }),
2330
- /* @__PURE__ */ jsx23(Animated14.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs20(Svg10, { viewBox, style: layer, children: [
2331
- /* @__PURE__ */ jsxs20(Defs7, { children: [
3372
+ /* @__PURE__ */ jsx37(Animated22.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs33(Svg15, { viewBox, style: layer, children: [
3373
+ /* @__PURE__ */ jsxs33(Defs8, { children: [
2332
3374
  gradient,
2333
- /* @__PURE__ */ jsxs20(LinearGradient7, { id: `${id}l`, gradientUnits: "userSpaceOnUse", x1: 0, y1: YAZAKIA.lens.y1, x2: 0, y2: YAZAKIA.lens.y2, children: [
2334
- /* @__PURE__ */ jsx23(Stop7, { offset: "0%", stopColor: YAZAKIA.highlight.color, stopOpacity: YAZAKIA.highlight.from }),
2335
- /* @__PURE__ */ jsx23(Stop7, { offset: "100%", stopColor: YAZAKIA.highlight.color, stopOpacity: YAZAKIA.highlight.to })
3375
+ /* @__PURE__ */ jsxs33(LinearGradient8, { id: `${id}l`, gradientUnits: "userSpaceOnUse", x1: 0, y1: YAZAKIA.lens.y1, x2: 0, y2: YAZAKIA.lens.y2, children: [
3376
+ /* @__PURE__ */ jsx37(Stop8, { offset: "0%", stopColor: YAZAKIA.highlight.color, stopOpacity: YAZAKIA.highlight.from }),
3377
+ /* @__PURE__ */ jsx37(Stop8, { offset: "100%", stopColor: YAZAKIA.highlight.color, stopOpacity: YAZAKIA.highlight.to })
2336
3378
  ] })
2337
3379
  ] }),
2338
- /* @__PURE__ */ jsx23(Path9, { d: YAZAKIA.lens.d, fill }),
2339
- /* @__PURE__ */ jsx23(Path9, { d: YAZAKIA.lens.d, fill: `url(#${id}l)` })
3380
+ /* @__PURE__ */ jsx37(Path12, { d: YAZAKIA.lens.d, fill }),
3381
+ /* @__PURE__ */ jsx37(Path12, { d: YAZAKIA.lens.d, fill: `url(#${id}l)` })
2340
3382
  ] }) })
2341
3383
  ] });
2342
3384
  }
2343
3385
 
2344
3386
  // src/native/YororisMark.tsx
2345
- import { View as View20 } from "react-native";
2346
- import Svg11, { Circle as Circle7, Defs as Defs8, LinearGradient as LinearGradient8, Path as Path10, RadialGradient as RadialGradient6, Stop as Stop8 } from "react-native-svg";
3387
+ import { View as View33 } from "react-native";
3388
+ import Svg16, { Circle as Circle10, Defs as Defs9, LinearGradient as LinearGradient9, Path as Path13, RadialGradient as RadialGradient6, Stop as Stop9 } from "react-native-svg";
2347
3389
 
2348
3390
  // src/marks/yororis-geometry.ts
2349
3391
  var sand = marks.yororis[0][1];
@@ -2379,65 +3421,65 @@ var YORORIS = {
2379
3421
  };
2380
3422
 
2381
3423
  // src/native/YororisMark.tsx
2382
- import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
3424
+ import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
2383
3425
  function YororisMark({ size = 48, animated = true, title, neutral }) {
2384
3426
  const { theme } = useTheme();
2385
- const { Animated: Animated14, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated, 36e3);
3427
+ const { Animated: Animated22, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated, 36e3);
2386
3428
  const id = useSvgId("yrm");
2387
3429
  const viewBox = size < 48 ? YORORIS.croppedViewBox : YORORIS.viewBox;
2388
3430
  const stroke = neutral ?? theme.textMuted;
2389
- const gradient = /* @__PURE__ */ jsx24(LinearGradient8, { id: `${id}a`, gradientUnits: "userSpaceOnUse", x1: YORORIS.gradient.x1, y1: YORORIS.gradient.y1, x2: YORORIS.gradient.x2, y2: YORORIS.gradient.y2, children: YORORIS.gradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx24(Stop8, { offset, stopColor: color }, offset)) });
3431
+ const gradient = /* @__PURE__ */ jsx38(LinearGradient9, { id: `${id}a`, gradientUnits: "userSpaceOnUse", x1: YORORIS.gradient.x1, y1: YORORIS.gradient.y1, x2: YORORIS.gradient.x2, y2: YORORIS.gradient.y2, children: YORORIS.gradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx38(Stop9, { offset, stopColor: color }, offset)) });
2390
3432
  const fill = `url(#${id}a)`;
2391
- return /* @__PURE__ */ jsxs21(View20, { style: { width: size, height: size }, ...markA11y(title), children: [
2392
- /* @__PURE__ */ jsxs21(Svg11, { viewBox, style: layer, children: [
2393
- /* @__PURE__ */ jsxs21(Defs8, { children: [
2394
- /* @__PURE__ */ jsxs21(RadialGradient6, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
2395
- /* @__PURE__ */ jsx24(Stop8, { offset: "0%", stopColor: YORORIS.glow.color, stopOpacity: YORORIS.glow.opacity }),
2396
- /* @__PURE__ */ jsx24(Stop8, { offset: "100%", stopColor: YORORIS.glow.color, stopOpacity: 0 })
3433
+ return /* @__PURE__ */ jsxs34(View33, { style: { width: size, height: size }, ...markA11y(title), children: [
3434
+ /* @__PURE__ */ jsxs34(Svg16, { viewBox, style: layer, children: [
3435
+ /* @__PURE__ */ jsxs34(Defs9, { children: [
3436
+ /* @__PURE__ */ jsxs34(RadialGradient6, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
3437
+ /* @__PURE__ */ jsx38(Stop9, { offset: "0%", stopColor: YORORIS.glow.color, stopOpacity: YORORIS.glow.opacity }),
3438
+ /* @__PURE__ */ jsx38(Stop9, { offset: "100%", stopColor: YORORIS.glow.color, stopOpacity: 0 })
2397
3439
  ] }),
2398
3440
  gradient
2399
3441
  ] }),
2400
- size >= 48 ? /* @__PURE__ */ jsx24(Circle7, { cx: YORORIS.center, cy: YORORIS.center, r: 190, fill: `url(#${id}g)` }) : null,
2401
- /* @__PURE__ */ jsx24(Circle7, { cx: YORORIS.center, cy: YORORIS.center, r: YORORIS.ring.r, stroke, strokeWidth: YORORIS.ring.width, opacity: 0.35, fill: "none" }),
2402
- /* @__PURE__ */ jsx24(Path10, { d: YORORIS.stem, stroke: fill, strokeWidth: YORORIS.stroke, strokeLinecap: "round", fill: "none" }),
2403
- YORORIS.leaves.map((d) => /* @__PURE__ */ jsx24(Path10, { d, fill }, d)),
2404
- /* @__PURE__ */ jsx24(Path10, { d: YORORIS.veins, stroke: YORORIS.vein.color, strokeOpacity: YORORIS.vein.opacity, strokeWidth: YORORIS.vein.width, strokeLinecap: "round", strokeDasharray: YORORIS.vein.dash, fill: "none" })
3442
+ size >= 48 ? /* @__PURE__ */ jsx38(Circle10, { cx: YORORIS.center, cy: YORORIS.center, r: 190, fill: `url(#${id}g)` }) : null,
3443
+ /* @__PURE__ */ jsx38(Circle10, { cx: YORORIS.center, cy: YORORIS.center, r: YORORIS.ring.r, stroke, strokeWidth: YORORIS.ring.width, opacity: 0.35, fill: "none" }),
3444
+ /* @__PURE__ */ jsx38(Path13, { d: YORORIS.stem, stroke: fill, strokeWidth: YORORIS.stroke, strokeLinecap: "round", fill: "none" }),
3445
+ YORORIS.leaves.map((d) => /* @__PURE__ */ jsx38(Path13, { d, fill }, d)),
3446
+ /* @__PURE__ */ jsx38(Path13, { d: YORORIS.veins, stroke: YORORIS.vein.color, strokeOpacity: YORORIS.vein.opacity, strokeWidth: YORORIS.vein.width, strokeLinecap: "round", strokeDasharray: YORORIS.vein.dash, fill: "none" })
2405
3447
  ] }),
2406
- /* @__PURE__ */ jsx24(Animated14.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsxs21(Svg11, { viewBox, style: layer, children: [
2407
- /* @__PURE__ */ jsx24(Defs8, { children: gradient }),
2408
- /* @__PURE__ */ jsx24(Circle7, { cx: YORORIS.center, cy: YORORIS.center, r: YORORIS.orbit.r, stroke, strokeWidth: YORORIS.orbit.width, strokeDasharray: YORORIS.orbit.dash, opacity: 0.6, fill: "none" }),
2409
- /* @__PURE__ */ jsx24(Circle7, { cx: YORORIS.moment.at[0], cy: YORORIS.moment.at[1], r: YORORIS.moment.r, fill })
3448
+ /* @__PURE__ */ jsx38(Animated22.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsxs34(Svg16, { viewBox, style: layer, children: [
3449
+ /* @__PURE__ */ jsx38(Defs9, { children: gradient }),
3450
+ /* @__PURE__ */ jsx38(Circle10, { cx: YORORIS.center, cy: YORORIS.center, r: YORORIS.orbit.r, stroke, strokeWidth: YORORIS.orbit.width, strokeDasharray: YORORIS.orbit.dash, opacity: 0.6, fill: "none" }),
3451
+ /* @__PURE__ */ jsx38(Circle10, { cx: YORORIS.moment.at[0], cy: YORORIS.moment.at[1], r: YORORIS.moment.r, fill })
2410
3452
  ] }) }),
2411
- /* @__PURE__ */ jsx24(Animated14.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs21(Svg11, { viewBox, style: layer, children: [
2412
- /* @__PURE__ */ jsx24(Defs8, { children: /* @__PURE__ */ jsx24(LinearGradient8, { id: `${id}c`, x1: "50%", y1: "100%", x2: "50%", y2: "0%", children: YORORIS.coreGradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx24(Stop8, { offset, stopColor: color }, offset)) }) }),
2413
- /* @__PURE__ */ jsx24(Circle7, { cx: YORORIS.core.cx, cy: YORORIS.core.cy, r: YORORIS.core.r, fill: `url(#${id}c)` }),
2414
- /* @__PURE__ */ jsx24(Circle7, { cx: YORORIS.core.cx, cy: YORORIS.core.cy, r: YORORIS.core.inner, fill: YORORIS.highlight })
3453
+ /* @__PURE__ */ jsx38(Animated22.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs34(Svg16, { viewBox, style: layer, children: [
3454
+ /* @__PURE__ */ jsx38(Defs9, { children: /* @__PURE__ */ jsx38(LinearGradient9, { id: `${id}c`, x1: "50%", y1: "100%", x2: "50%", y2: "0%", children: YORORIS.coreGradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx38(Stop9, { offset, stopColor: color }, offset)) }) }),
3455
+ /* @__PURE__ */ jsx38(Circle10, { cx: YORORIS.core.cx, cy: YORORIS.core.cy, r: YORORIS.core.r, fill: `url(#${id}c)` }),
3456
+ /* @__PURE__ */ jsx38(Circle10, { cx: YORORIS.core.cx, cy: YORORIS.core.cy, r: YORORIS.core.inner, fill: YORORIS.highlight })
2415
3457
  ] }) })
2416
3458
  ] });
2417
3459
  }
2418
3460
 
2419
3461
  // src/native/ProductMark.tsx
2420
- import { jsx as jsx25 } from "react/jsx-runtime";
3462
+ import { jsx as jsx39 } from "react/jsx-runtime";
2421
3463
  function ProductMark({ id, ...props }) {
2422
- if (id === "krizaka") return /* @__PURE__ */ jsx25(KrizakaMark, { ...props });
2423
- if (id === "orazaka") return /* @__PURE__ */ jsx25(OrazakaMark, { ...props });
2424
- if (id === "yazakia") return /* @__PURE__ */ jsx25(YazakiaMark, { ...props });
2425
- if (id === "yororis") return /* @__PURE__ */ jsx25(YororisMark, { ...props });
2426
- return /* @__PURE__ */ jsx25(OrochiaMark, { ...props });
3464
+ if (id === "krizaka") return /* @__PURE__ */ jsx39(KrizakaMark, { ...props });
3465
+ if (id === "orazaka") return /* @__PURE__ */ jsx39(OrazakaMark, { ...props });
3466
+ if (id === "yazakia") return /* @__PURE__ */ jsx39(YazakiaMark, { ...props });
3467
+ if (id === "yororis") return /* @__PURE__ */ jsx39(YororisMark, { ...props });
3468
+ return /* @__PURE__ */ jsx39(OrochiaMark, { ...props });
2427
3469
  }
2428
3470
 
2429
3471
  // src/native/profile-card.tsx
2430
- import * as React18 from "react";
2431
- import { Animated as Animated10, StyleSheet as StyleSheet17, View as View21 } from "react-native";
2432
- import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
3472
+ import * as React28 from "react";
3473
+ import { Animated as Animated15, StyleSheet as StyleSheet30, View as View34 } from "react-native";
3474
+ import { jsx as jsx40, jsxs as jsxs35 } from "react/jsx-runtime";
2433
3475
  var ratioOf = (value, max = 100) => Math.min(1, Math.max(0, value / (max || 1)));
2434
3476
  function Bar({ label, ratio, words, animated, delay }) {
2435
3477
  const { theme } = useTheme();
2436
3478
  const t = useEntrance(animated, delay, 900);
2437
- const [width, setWidth] = React18.useState(0);
3479
+ const [width, setWidth] = React28.useState(0);
2438
3480
  const translateX = t.interpolate({ inputRange: [0, 1], outputRange: [-width * ratio, 0] });
2439
- return /* @__PURE__ */ jsx26(
2440
- View21,
3481
+ return /* @__PURE__ */ jsx40(
3482
+ View34,
2441
3483
  {
2442
3484
  accessible: true,
2443
3485
  role: "meter",
@@ -2447,42 +3489,42 @@ function Bar({ label, ratio, words, animated, delay }) {
2447
3489
  "aria-valuenow": Math.round(ratio * 100),
2448
3490
  "aria-valuetext": words,
2449
3491
  onLayout: (e) => setWidth(e.nativeEvent.layout.width),
2450
- style: [styles17.track, { backgroundColor: theme.surface3 }],
2451
- children: /* @__PURE__ */ jsx26(Animated10.View, { style: [styles17.fill, { width: `${ratio * 100}%`, backgroundColor: theme.accent, transform: [{ translateX }] }] })
3492
+ style: [styles30.track, { backgroundColor: theme.surface3 }],
3493
+ children: /* @__PURE__ */ jsx40(Animated15.View, { style: [styles30.fill, { width: `${ratio * 100}%`, backgroundColor: theme.accent, transform: [{ translateX }] }] })
2452
3494
  }
2453
3495
  );
2454
3496
  }
2455
3497
  function ProfileCard({ visual, name, statLabel, value = 100, valueText, stats, caption, children, animated = true, style, ...props }) {
2456
3498
  const { theme, radius: radius3 } = useTheme();
2457
3499
  const ratio = ratioOf(value);
2458
- return /* @__PURE__ */ jsxs22(View21, { ...props, style: [styles17.root, { backgroundColor: theme.surface1, borderColor: theme.borderSubtle, borderRadius: radius3.xl }, style], children: [
2459
- /* @__PURE__ */ jsx26(View21, { "aria-hidden": true, style: [styles17.disc, { backgroundColor: theme.surface2, borderColor: theme.accentSoft }], children: visual }),
2460
- /* @__PURE__ */ jsxs22(View21, { style: styles17.head, children: [
2461
- /* @__PURE__ */ jsx26(Txt, { variant: "title", style: styles17.name, children: name }),
2462
- statLabel ? /* @__PURE__ */ jsxs22(Txt, { variant: "caption", tone: "secondary", children: [
3500
+ return /* @__PURE__ */ jsxs35(View34, { ...props, style: [styles30.root, { backgroundColor: theme.surface1, borderColor: theme.borderSubtle, borderRadius: radius3.xl }, style], children: [
3501
+ /* @__PURE__ */ jsx40(View34, { "aria-hidden": true, style: [styles30.disc, { backgroundColor: theme.surface2, borderColor: theme.accentSoft }], children: visual }),
3502
+ /* @__PURE__ */ jsxs35(View34, { style: styles30.head, children: [
3503
+ /* @__PURE__ */ jsx40(Txt, { variant: "title", style: styles30.name, children: name }),
3504
+ statLabel ? /* @__PURE__ */ jsxs35(Txt, { variant: "caption", tone: "secondary", children: [
2463
3505
  statLabel,
2464
3506
  " ",
2465
- /* @__PURE__ */ jsx26(Txt, { variant: "caption", children: valueText ?? `${Math.round(ratio * 100)} %` })
3507
+ /* @__PURE__ */ jsx40(Txt, { variant: "caption", children: valueText ?? `${Math.round(ratio * 100)} %` })
2466
3508
  ] }) : null
2467
3509
  ] }),
2468
- statLabel ? /* @__PURE__ */ jsx26(Bar, { label: statLabel, ratio, words: valueText ?? `${Math.round(ratio * 100)} %`, animated, delay: 200 }) : null,
3510
+ statLabel ? /* @__PURE__ */ jsx40(Bar, { label: statLabel, ratio, words: valueText ?? `${Math.round(ratio * 100)} %`, animated, delay: 200 }) : null,
2469
3511
  stats?.map((s, i) => {
2470
3512
  const r = ratioOf(s.value, s.max);
2471
3513
  const words = s.valueText ?? `${Math.round(r * 100)} %`;
2472
- return /* @__PURE__ */ jsxs22(View21, { style: styles17.stat, children: [
2473
- /* @__PURE__ */ jsxs22(View21, { "aria-hidden": true, style: styles17.statHead, children: [
2474
- /* @__PURE__ */ jsx26(Txt, { variant: "caption", tone: "secondary", children: s.label }),
2475
- /* @__PURE__ */ jsx26(Txt, { variant: "caption", children: words })
3514
+ return /* @__PURE__ */ jsxs35(View34, { style: styles30.stat, children: [
3515
+ /* @__PURE__ */ jsxs35(View34, { "aria-hidden": true, style: styles30.statHead, children: [
3516
+ /* @__PURE__ */ jsx40(Txt, { variant: "caption", tone: "secondary", children: s.label }),
3517
+ /* @__PURE__ */ jsx40(Txt, { variant: "caption", children: words })
2476
3518
  ] }),
2477
- /* @__PURE__ */ jsx26(Bar, { label: s.label, ratio: r, words, animated, delay: 320 + i * 120 })
3519
+ /* @__PURE__ */ jsx40(Bar, { label: s.label, ratio: r, words, animated, delay: 320 + i * 120 })
2478
3520
  ] }, s.label);
2479
3521
  }),
2480
- caption ? /* @__PURE__ */ jsx26(Txt, { variant: "caption", tone: "secondary", style: styles17.caption, children: caption }) : null,
2481
- children ? /* @__PURE__ */ jsx26(View21, { style: styles17.extra, children }) : null
3522
+ caption ? /* @__PURE__ */ jsx40(Txt, { variant: "caption", tone: "secondary", style: styles30.caption, children: caption }) : null,
3523
+ children ? /* @__PURE__ */ jsx40(View34, { style: styles30.extra, children }) : null
2482
3524
  ] });
2483
3525
  }
2484
- var styles17 = StyleSheet17.create({
2485
- root: { alignItems: "center", gap: 12, padding: 20, borderWidth: StyleSheet17.hairlineWidth },
3526
+ var styles30 = StyleSheet30.create({
3527
+ root: { alignItems: "center", gap: 12, padding: 20, borderWidth: StyleSheet30.hairlineWidth },
2486
3528
  disc: { width: 104, height: 104, borderRadius: 52, borderWidth: 1, alignItems: "center", justifyContent: "center", overflow: "hidden" },
2487
3529
  head: { flexDirection: "row", alignSelf: "stretch", alignItems: "center", justifyContent: "space-between", gap: 8 },
2488
3530
  name: { flexShrink: 1, fontSize: 17 },
@@ -2495,13 +3537,13 @@ var styles17 = StyleSheet17.create({
2495
3537
  });
2496
3538
 
2497
3539
  // src/native/progress.tsx
2498
- import * as React19 from "react";
2499
- import { Animated as Animated11, Easing as Easing7, StyleSheet as StyleSheet18, View as View22 } from "react-native";
2500
- import Svg12, { Circle as Circle8, Defs as Defs9, LinearGradient as LinearGradient9, Rect as Rect3, Stop as Stop9 } from "react-native-svg";
2501
- import { jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
2502
- var AnimatedCircle = Animated11.createAnimatedComponent(Circle8);
2503
- var BAR = { sm: 4, md: 8, lg: 12 };
2504
- var RING = { sm: 40, md: 80, lg: 144 };
3540
+ import * as React29 from "react";
3541
+ import { Animated as Animated16, Easing as Easing9, StyleSheet as StyleSheet31, View as View35 } from "react-native";
3542
+ import Svg17, { Circle as Circle11, Defs as Defs10, LinearGradient as LinearGradient10, Rect as Rect3, Stop as Stop10 } from "react-native-svg";
3543
+ import { jsx as jsx41, jsxs as jsxs36 } from "react/jsx-runtime";
3544
+ var AnimatedCircle = Animated16.createAnimatedComponent(Circle11);
3545
+ var BAR2 = { sm: 4, md: 8, lg: 12 };
3546
+ var RING2 = { sm: 40, md: 80, lg: 144 };
2505
3547
  var STROKE = { sm: 12, md: 9, lg: 7 };
2506
3548
  function Progress({ variant = "bar", size = "md", value, max = 100, label, valueText, children, style }) {
2507
3549
  const { theme } = useTheme();
@@ -2510,21 +3552,21 @@ function Progress({ variant = "bar", size = "md", value, max = 100, label, value
2510
3552
  const known = typeof value === "number" && Number.isFinite(value);
2511
3553
  const ratio = known ? Math.min(1, Math.max(0, value / (max || 1))) : 0;
2512
3554
  const percent = Math.round(ratio * 100);
2513
- const [progress] = React19.useState(() => new Animated11.Value(ratio));
2514
- const [spin] = React19.useState(() => new Animated11.Value(0));
2515
- const [track, setTrack] = React19.useState(0);
2516
- React19.useEffect(() => {
3555
+ const [progress] = React29.useState(() => new Animated16.Value(ratio));
3556
+ const [spin] = React29.useState(() => new Animated16.Value(0));
3557
+ const [track, setTrack] = React29.useState(0);
3558
+ React29.useEffect(() => {
2517
3559
  if (reduce) {
2518
3560
  progress.setValue(ratio);
2519
3561
  return;
2520
3562
  }
2521
- const animation = Animated11.timing(progress, { toValue: ratio, duration: 700, easing: Easing7.out(Easing7.cubic), useNativeDriver: false });
3563
+ const animation = Animated16.timing(progress, { toValue: ratio, duration: 700, easing: Easing9.out(Easing9.cubic), useNativeDriver: false });
2522
3564
  animation.start();
2523
3565
  return () => animation.stop();
2524
3566
  }, [ratio, reduce, progress]);
2525
- React19.useEffect(() => {
3567
+ React29.useEffect(() => {
2526
3568
  if (known || reduce) return;
2527
- const loop = Animated11.loop(Animated11.timing(spin, { toValue: 1, duration: 1200, easing: Easing7.linear, useNativeDriver: true }));
3569
+ const loop = Animated16.loop(Animated16.timing(spin, { toValue: 1, duration: 1200, easing: Easing9.linear, useNativeDriver: true }));
2528
3570
  loop.start();
2529
3571
  return () => {
2530
3572
  loop.stop();
@@ -2540,22 +3582,22 @@ function Progress({ variant = "bar", size = "md", value, max = 100, label, value
2540
3582
  "aria-valuenow": known ? Math.min(max, Math.max(0, value)) : void 0,
2541
3583
  "aria-valuetext": known ? valueText ?? `${percent}%` : valueText
2542
3584
  };
2543
- const gradient = /* @__PURE__ */ jsx27(Defs9, { children: /* @__PURE__ */ jsxs23(LinearGradient9, { id, x1: "0", y1: "0", x2: "1", y2: variant === "ring" ? "1" : "0", children: [
2544
- /* @__PURE__ */ jsx27(Stop9, { offset: "0", stopColor: theme.accent }),
2545
- /* @__PURE__ */ jsx27(Stop9, { offset: "1", stopColor: theme.accent2 })
3585
+ const gradient = /* @__PURE__ */ jsx41(Defs10, { children: /* @__PURE__ */ jsxs36(LinearGradient10, { id, x1: "0", y1: "0", x2: "1", y2: variant === "ring" ? "1" : "0", children: [
3586
+ /* @__PURE__ */ jsx41(Stop10, { offset: "0", stopColor: theme.accent }),
3587
+ /* @__PURE__ */ jsx41(Stop10, { offset: "1", stopColor: theme.accent2 })
2546
3588
  ] }) });
2547
3589
  if (variant === "ring") {
2548
- const side = RING[size];
3590
+ const side = RING2[size];
2549
3591
  const stroke = STROKE[size];
2550
3592
  const r = 50 - stroke / 2;
2551
3593
  const circumference = 2 * Math.PI * r;
2552
3594
  const offset = known ? progress.interpolate({ inputRange: [0, 1], outputRange: [circumference, 0] }) : circumference * 0.75;
2553
3595
  const rotate = spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] });
2554
- return /* @__PURE__ */ jsxs23(View22, { ...a11y, style: [styles18.ring, { width: side, height: side }, style], children: [
2555
- /* @__PURE__ */ jsx27(Animated11.View, { style: [StyleSheet18.absoluteFill, { transform: [{ rotate: known ? "-90deg" : rotate }] }], children: /* @__PURE__ */ jsxs23(Svg12, { width: side, height: side, viewBox: "0 0 100 100", children: [
3596
+ return /* @__PURE__ */ jsxs36(View35, { ...a11y, style: [styles31.ring, { width: side, height: side }, style], children: [
3597
+ /* @__PURE__ */ jsx41(Animated16.View, { style: [StyleSheet31.absoluteFill, { transform: [{ rotate: known ? "-90deg" : rotate }] }], children: /* @__PURE__ */ jsxs36(Svg17, { width: side, height: side, viewBox: "0 0 100 100", children: [
2556
3598
  gradient,
2557
- /* @__PURE__ */ jsx27(Circle8, { cx: 50, cy: 50, r, fill: "none", stroke: theme.borderDefault, strokeWidth: stroke }),
2558
- /* @__PURE__ */ jsx27(
3599
+ /* @__PURE__ */ jsx41(Circle11, { cx: 50, cy: 50, r, fill: "none", stroke: theme.borderDefault, strokeWidth: stroke }),
3600
+ /* @__PURE__ */ jsx41(
2559
3601
  AnimatedCircle,
2560
3602
  {
2561
3603
  cx: 50,
@@ -2575,50 +3617,212 @@ function Progress({ variant = "bar", size = "md", value, max = 100, label, value
2575
3617
  }
2576
3618
  const width = known ? progress.interpolate({ inputRange: [0, 1], outputRange: ["0%", "100%"] }) : "40%";
2577
3619
  const translate = spin.interpolate({ inputRange: [0, 1], outputRange: [-0.4 * track, track] });
2578
- return /* @__PURE__ */ jsx27(
2579
- View22,
3620
+ return /* @__PURE__ */ jsx41(
3621
+ View35,
2580
3622
  {
2581
3623
  ...a11y,
2582
3624
  onLayout: known ? void 0 : (event) => setTrack(event.nativeEvent.layout.width),
2583
- style: [styles18.bar, { height: BAR[size], backgroundColor: theme.surface3 }, style],
2584
- children: /* @__PURE__ */ jsx27(Animated11.View, { style: [styles18.fill, { width }, known || reduce ? null : { transform: [{ translateX: translate }] }], children: /* @__PURE__ */ jsxs23(Svg12, { width: "100%", height: "100%", preserveAspectRatio: "none", children: [
3625
+ style: [styles31.bar, { height: BAR2[size], backgroundColor: theme.surface3 }, style],
3626
+ children: /* @__PURE__ */ jsx41(Animated16.View, { style: [styles31.fill, { width }, known || reduce ? null : { transform: [{ translateX: translate }] }], children: /* @__PURE__ */ jsxs36(Svg17, { width: "100%", height: "100%", preserveAspectRatio: "none", children: [
2585
3627
  gradient,
2586
- /* @__PURE__ */ jsx27(Rect3, { x: 0, y: 0, width: "100%", height: "100%", fill: `url(#${id})` })
3628
+ /* @__PURE__ */ jsx41(Rect3, { x: 0, y: 0, width: "100%", height: "100%", fill: `url(#${id})` })
2587
3629
  ] }) })
2588
3630
  }
2589
3631
  );
2590
3632
  }
2591
- var styles18 = StyleSheet18.create({
3633
+ var styles31 = StyleSheet31.create({
2592
3634
  ring: { alignItems: "center", justifyContent: "center" },
2593
3635
  bar: { width: "100%", overflow: "hidden", borderRadius: 9999 },
2594
3636
  fill: { height: "100%", overflow: "hidden", borderRadius: 9999 }
2595
3637
  });
2596
3638
 
3639
+ // src/native/pull-to-refresh.tsx
3640
+ import { RefreshControl } from "react-native";
3641
+ import { jsx as jsx42 } from "react/jsx-runtime";
3642
+ function PullToRefresh({ label, ...props }) {
3643
+ const { theme } = useTheme();
3644
+ return /* @__PURE__ */ jsx42(RefreshControl, { ...props, tintColor: theme.accent, colors: [theme.accent], progressBackgroundColor: theme.surface2, title: label, titleColor: theme.textSecondary });
3645
+ }
3646
+
3647
+ // src/native/radio-group.tsx
3648
+ import * as React30 from "react";
3649
+ import { Animated as Animated17, Pressable as Pressable15, StyleSheet as StyleSheet32, Text as Text15, View as View36 } from "react-native";
3650
+ import Svg18, { Path as Path14 } from "react-native-svg";
3651
+ import { jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
3652
+ function Check({ color }) {
3653
+ return /* @__PURE__ */ jsx43(Svg18, { width: 12, height: 12, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 3.2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx43(Path14, { d: "M20 6 9 17l-5-5" }) });
3654
+ }
3655
+ function Key({ option, checked, disabled, onPress }) {
3656
+ const { theme, radius: radius3, motion: motion3 } = useTheme();
3657
+ const [held, setHeld] = React30.useState(false);
3658
+ const [sink] = React30.useState(() => new Animated17.Value(checked ? 1 : 0));
3659
+ const down = checked || held;
3660
+ React30.useEffect(() => {
3661
+ Animated17.timing(sink, { toValue: down ? 1 : 0, duration: motion3.duration.fast, useNativeDriver: true }).start();
3662
+ }, [down, sink, motion3.duration.fast]);
3663
+ return /* @__PURE__ */ jsxs37(
3664
+ Pressable15,
3665
+ {
3666
+ role: "radio",
3667
+ "aria-checked": checked,
3668
+ "aria-label": option.hint ? `${option.label}, ${option.hint}` : option.label,
3669
+ "aria-disabled": disabled || void 0,
3670
+ disabled,
3671
+ onPress,
3672
+ onPressIn: () => setHeld(true),
3673
+ onPressOut: () => setHeld(false),
3674
+ style: [styles32.keySlot, disabled ? styles32.disabled : null],
3675
+ children: [
3676
+ /* @__PURE__ */ jsx43(View36, { style: [styles32.ledge, { borderRadius: radius3.lg, backgroundColor: checked ? theme.accentHover : theme.borderStrong }] }),
3677
+ /* @__PURE__ */ jsxs37(
3678
+ Animated17.View,
3679
+ {
3680
+ style: [
3681
+ styles32.key,
3682
+ {
3683
+ borderRadius: radius3.lg,
3684
+ backgroundColor: checked ? theme.accent : theme.surface2,
3685
+ borderColor: checked ? theme.accent : theme.borderDefault,
3686
+ transform: [{ translateY: sink.interpolate({ inputRange: [0, 1], outputRange: [0, 3] }) }]
3687
+ }
3688
+ ],
3689
+ children: [
3690
+ /* @__PURE__ */ jsx43(Text15, { style: [styles32.keyLabel, { color: checked ? theme.onAccent : theme.textPrimary }], children: option.label }),
3691
+ option.hint ? /* @__PURE__ */ jsx43(Text15, { style: [styles32.keyHint, { color: checked ? theme.onAccent : theme.textSecondary }], children: option.hint }) : null
3692
+ ]
3693
+ }
3694
+ )
3695
+ ]
3696
+ }
3697
+ );
3698
+ }
3699
+ function RadioGroup({ label, options, value: valueProp, defaultValue = null, onValueChange, variant = "list", error, disabled, style }) {
3700
+ const { theme, radius: radius3, haptic } = useTheme();
3701
+ const [own, setOwn] = React30.useState(defaultValue);
3702
+ const value = valueProp !== void 0 ? valueProp : own;
3703
+ const pick = (v) => {
3704
+ haptic(variant === "buttons" ? "impact" : "selection");
3705
+ if (valueProp === void 0) setOwn(v);
3706
+ if (v !== value) onValueChange?.(v);
3707
+ };
3708
+ const body = options.map((o) => {
3709
+ const checked = o.value === value;
3710
+ const off = Boolean(disabled || o.disabled);
3711
+ const name = o.description ? `${o.label}, ${o.description}` : o.label;
3712
+ if (variant === "buttons") return /* @__PURE__ */ jsx43(Key, { option: o, checked, disabled: off, onPress: () => pick(o.value) }, o.value);
3713
+ if (variant === "segmented")
3714
+ return /* @__PURE__ */ jsx43(
3715
+ Pressable15,
3716
+ {
3717
+ role: "radio",
3718
+ "aria-checked": checked,
3719
+ "aria-label": o.label,
3720
+ "aria-disabled": off || void 0,
3721
+ disabled: off,
3722
+ onPress: () => pick(o.value),
3723
+ style: [styles32.segment, { borderRadius: radius3.md }, checked ? { backgroundColor: theme.surface0, borderColor: theme.borderDefault } : null, off ? styles32.disabled : null],
3724
+ children: /* @__PURE__ */ jsx43(Text15, { numberOfLines: 1, style: [styles32.segmentLabel, { color: checked ? theme.textPrimary : theme.textSecondary }], children: o.label })
3725
+ },
3726
+ o.value
3727
+ );
3728
+ if (variant === "cards")
3729
+ return /* @__PURE__ */ jsxs37(
3730
+ Pressable15,
3731
+ {
3732
+ role: "radio",
3733
+ "aria-checked": checked,
3734
+ "aria-label": name,
3735
+ "aria-disabled": off || void 0,
3736
+ disabled: off,
3737
+ onPress: () => pick(o.value),
3738
+ style: ({ pressed }) => [
3739
+ styles32.card,
3740
+ { borderRadius: radius3.xl, backgroundColor: checked ? theme.accentSoft : theme.surface1, borderColor: checked ? theme.accent : theme.borderDefault, transform: [{ scale: pressed ? 0.98 : 1 }] },
3741
+ off ? styles32.disabled : null
3742
+ ],
3743
+ children: [
3744
+ /* @__PURE__ */ jsx43(View36, { style: [styles32.cardCheck, { borderColor: checked ? theme.accent : theme.borderStrong, backgroundColor: checked ? theme.accent : theme.surface1 }], children: checked ? /* @__PURE__ */ jsx43(Check, { color: theme.onAccent }) : null }),
3745
+ /* @__PURE__ */ jsx43(Text15, { style: [styles32.cardLabel, { color: theme.textPrimary }], children: o.label }),
3746
+ o.description ? /* @__PURE__ */ jsx43(Text15, { style: [styles32.cardDescription, { color: theme.textSecondary }], children: o.description }) : null
3747
+ ]
3748
+ },
3749
+ o.value
3750
+ );
3751
+ return /* @__PURE__ */ jsxs37(Pressable15, { role: "radio", "aria-checked": checked, "aria-label": name, "aria-disabled": off || void 0, disabled: off, onPress: () => pick(o.value), style: [styles32.row, off ? styles32.disabled : null], children: [
3752
+ /* @__PURE__ */ jsx43(View36, { style: [styles32.dot, { borderColor: checked ? theme.accent : theme.borderStrong, backgroundColor: checked ? theme.accent : theme.surface1 }], children: checked ? /* @__PURE__ */ jsx43(View36, { style: [styles32.dotIn, { backgroundColor: theme.onAccent }] }) : null }),
3753
+ /* @__PURE__ */ jsxs37(View36, { style: styles32.rowText, children: [
3754
+ /* @__PURE__ */ jsx43(Text15, { style: [styles32.rowLabel, { color: theme.textPrimary }], children: o.label }),
3755
+ o.description ? /* @__PURE__ */ jsx43(Text15, { style: [styles32.cardDescription, { color: theme.textSecondary }], children: o.description }) : null
3756
+ ] })
3757
+ ] }, o.value);
3758
+ });
3759
+ return /* @__PURE__ */ jsxs37(View36, { style: [styles32.root, style], children: [
3760
+ /* @__PURE__ */ jsx43(
3761
+ View36,
3762
+ {
3763
+ role: "radiogroup",
3764
+ "aria-label": label,
3765
+ style: variant === "segmented" ? [styles32.track, { borderRadius: radius3.lg, backgroundColor: theme.surface2, borderColor: error ? theme.danger : theme.borderDefault }] : variant === "buttons" ? styles32.keys : variant === "cards" ? styles32.cards : styles32.list,
3766
+ children: body
3767
+ }
3768
+ ),
3769
+ error ? /* @__PURE__ */ jsx43(Text15, { role: "alert", "aria-live": "polite", style: [styles32.error, { color: theme.dangerText }], children: error }) : null
3770
+ ] });
3771
+ }
3772
+ var styles32 = StyleSheet32.create({
3773
+ root: { gap: 6, alignSelf: "stretch" },
3774
+ list: { gap: 2 },
3775
+ row: { flexDirection: "row", alignItems: "center", gap: 12, minHeight: 44 },
3776
+ rowText: { flex: 1, gap: 1 },
3777
+ rowLabel: { fontSize: 15, lineHeight: 20 },
3778
+ dot: { width: 22, height: 22, borderRadius: 11, borderWidth: 1.5, alignItems: "center", justifyContent: "center" },
3779
+ dotIn: { width: 8, height: 8, borderRadius: 4 },
3780
+ cards: { flexDirection: "row", flexWrap: "wrap", gap: 10 },
3781
+ card: { flexGrow: 1, flexBasis: 140, minHeight: 72, padding: 14, paddingRight: 40, gap: 2, borderWidth: 1 },
3782
+ cardCheck: { position: "absolute", right: 12, top: 12, width: 20, height: 20, borderRadius: 10, borderWidth: 1.5, alignItems: "center", justifyContent: "center" },
3783
+ cardLabel: { fontSize: 16, fontWeight: "700" },
3784
+ cardDescription: { fontSize: 12, lineHeight: 16 },
3785
+ keys: { flexDirection: "row", flexWrap: "wrap", gap: 10, paddingBottom: 4 },
3786
+ keySlot: { minWidth: 64, minHeight: 52 },
3787
+ ledge: { position: "absolute", left: 0, right: 0, top: 4, bottom: -4 },
3788
+ key: { minHeight: 48, paddingHorizontal: 16, paddingVertical: 8, alignItems: "center", justifyContent: "center", gap: 1, borderWidth: 1 },
3789
+ keyLabel: { fontSize: 15, fontWeight: "700" },
3790
+ keyHint: { fontSize: 11, fontWeight: "500" },
3791
+ track: { flexDirection: "row", padding: 3, gap: 3, borderWidth: StyleSheet32.hairlineWidth, height: 42 },
3792
+ segment: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 8, borderWidth: StyleSheet32.hairlineWidth, borderColor: "transparent" },
3793
+ segmentLabel: { fontSize: 13, fontWeight: "600" },
3794
+ error: { fontSize: 12, lineHeight: 16 },
3795
+ disabled: { opacity: 0.4 }
3796
+ });
3797
+
2597
3798
  // src/native/search-field.tsx
2598
- import * as React20 from "react";
2599
- import { Pressable as Pressable8, StyleSheet as StyleSheet19, TextInput as TextInput3, View as View23 } from "react-native";
2600
- import Svg13, { Circle as Circle9, Path as Path11 } from "react-native-svg";
2601
- import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
2602
- function SearchField({ label, value, defaultValue = "", onValueChange, onSearch, debounce = 300, onSubmit, clearLabel, style, placeholder, ...props }) {
3799
+ import * as React31 from "react";
3800
+ import { Pressable as Pressable16, StyleSheet as StyleSheet33, TextInput as TextInput5, View as View37 } from "react-native";
3801
+ import Svg19, { Circle as Circle12, Path as Path15 } from "react-native-svg";
3802
+ import { jsx as jsx44, jsxs as jsxs38 } from "react/jsx-runtime";
3803
+ function SearchField({ label, value, defaultValue = "", onValueChange, onSearch, debounce = 300, onSubmit, clearLabel, cancelLabel, onCancel, style, placeholder, onFocus, onBlur, ...props }) {
3804
+ const [focused, setFocused] = React31.useState(false);
3805
+ const input = React31.useRef(null);
2603
3806
  const { theme, radius: radius3 } = useTheme();
2604
- const [own, setOwn] = React20.useState(defaultValue);
3807
+ const [own, setOwn] = React31.useState(defaultValue);
2605
3808
  const query = value ?? own;
2606
- const timer2 = React20.useRef(void 0);
2607
- React20.useEffect(() => () => clearTimeout(timer2.current), []);
3809
+ const timer2 = React31.useRef(void 0);
3810
+ React31.useEffect(() => () => clearTimeout(timer2.current), []);
2608
3811
  const change = (next) => {
2609
3812
  if (value === void 0) setOwn(next);
2610
3813
  onValueChange?.(next);
2611
3814
  clearTimeout(timer2.current);
2612
3815
  if (onSearch) timer2.current = setTimeout(() => onSearch(next), debounce);
2613
3816
  };
2614
- return /* @__PURE__ */ jsxs24(View23, { style: [styles19.frame, { borderRadius: radius3.md, borderColor: theme.borderDefault, backgroundColor: theme.surface2 }, style], children: [
2615
- /* @__PURE__ */ jsxs24(Svg13, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: theme.textSecondary, strokeWidth: 2, strokeLinecap: "round", "aria-hidden": true, children: [
2616
- /* @__PURE__ */ jsx28(Circle9, { cx: 11, cy: 11, r: 7 }),
2617
- /* @__PURE__ */ jsx28(Path11, { d: "m20 20-3.5-3.5" })
3817
+ const field = /* @__PURE__ */ jsxs38(View37, { style: [styles33.frame, { borderRadius: radius3.md, borderColor: theme.borderDefault, backgroundColor: theme.surface2 }, style], children: [
3818
+ /* @__PURE__ */ jsxs38(Svg19, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: theme.textSecondary, strokeWidth: 2, strokeLinecap: "round", "aria-hidden": true, children: [
3819
+ /* @__PURE__ */ jsx44(Circle12, { cx: 11, cy: 11, r: 7 }),
3820
+ /* @__PURE__ */ jsx44(Path15, { d: "m20 20-3.5-3.5" })
2618
3821
  ] }),
2619
- /* @__PURE__ */ jsx28(
2620
- TextInput3,
3822
+ /* @__PURE__ */ jsx44(
3823
+ TextInput5,
2621
3824
  {
3825
+ ref: input,
2622
3826
  role: "searchbox",
2623
3827
  "aria-label": label,
2624
3828
  value: query,
@@ -2634,34 +3838,63 @@ function SearchField({ label, value, defaultValue = "", onValueChange, onSearch,
2634
3838
  onSearch?.(query);
2635
3839
  onSubmit?.(query);
2636
3840
  },
2637
- style: [styles19.input, { color: theme.textPrimary }],
3841
+ style: [styles33.input, { color: theme.textPrimary }],
3842
+ onFocus: (e) => {
3843
+ setFocused(true);
3844
+ onFocus?.(e);
3845
+ },
3846
+ onBlur: (e) => {
3847
+ setFocused(false);
3848
+ onBlur?.(e);
3849
+ },
2638
3850
  ...props
2639
3851
  }
2640
3852
  ),
2641
- query ? /* @__PURE__ */ jsx28(Pressable8, { role: "button", "aria-label": clearLabel, hitSlop: 10, onPress: () => change(""), style: styles19.clear, children: /* @__PURE__ */ jsx28(Svg13, { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: theme.textSecondary, strokeWidth: 2.4, strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx28(Path11, { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
3853
+ query ? /* @__PURE__ */ jsx44(Pressable16, { role: "button", "aria-label": clearLabel, hitSlop: 10, onPress: () => change(""), style: styles33.clear, children: /* @__PURE__ */ jsx44(Svg19, { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: theme.textSecondary, strokeWidth: 2.4, strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx44(Path15, { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
3854
+ ] });
3855
+ if (!cancelLabel || !onCancel) return field;
3856
+ return /* @__PURE__ */ jsxs38(View37, { style: styles33.bar, children: [
3857
+ /* @__PURE__ */ jsx44(View37, { style: styles33.grow, children: field }),
3858
+ focused || query ? /* @__PURE__ */ jsx44(
3859
+ Pressable16,
3860
+ {
3861
+ role: "button",
3862
+ onPress: () => {
3863
+ change("");
3864
+ input.current?.blur();
3865
+ onCancel();
3866
+ },
3867
+ hitSlop: 8,
3868
+ style: styles33.cancel,
3869
+ children: /* @__PURE__ */ jsx44(Txt, { variant: "label", tone: "accent", children: cancelLabel })
3870
+ }
3871
+ ) : null
2642
3872
  ] });
2643
3873
  }
2644
- var styles19 = StyleSheet19.create({
2645
- frame: { flexDirection: "row", alignItems: "center", gap: 8, height: 44, paddingLeft: 12, paddingRight: 6, borderWidth: StyleSheet19.hairlineWidth },
3874
+ var styles33 = StyleSheet33.create({
3875
+ frame: { flexDirection: "row", alignItems: "center", gap: 8, height: 44, paddingLeft: 12, paddingRight: 6, borderWidth: StyleSheet33.hairlineWidth },
2646
3876
  input: { flex: 1, height: "100%", fontSize: 15, paddingVertical: 0 },
3877
+ bar: { flexDirection: "row", alignItems: "center", gap: 10 },
3878
+ grow: { flex: 1 },
3879
+ cancel: { minHeight: 44, justifyContent: "center" },
2647
3880
  clear: { width: 32, height: 32, alignItems: "center", justifyContent: "center" }
2648
3881
  });
2649
3882
 
2650
3883
  // src/native/segmented.tsx
2651
- import { Pressable as Pressable9, StyleSheet as StyleSheet20, Text as Text12, View as View24 } from "react-native";
2652
- import { jsx as jsx29 } from "react/jsx-runtime";
3884
+ import { Pressable as Pressable17, StyleSheet as StyleSheet34, Text as Text16, View as View38 } from "react-native";
3885
+ import { jsx as jsx45 } from "react/jsx-runtime";
2653
3886
  function Segmented({ options, value, onValueChange, size = "md", "aria-label": label, style }) {
2654
3887
  const { theme, radius: radius3 } = useTheme();
2655
- return /* @__PURE__ */ jsx29(
2656
- View24,
3888
+ return /* @__PURE__ */ jsx45(
3889
+ View38,
2657
3890
  {
2658
3891
  role: "tablist",
2659
3892
  "aria-label": label,
2660
- style: [styles20.track, { backgroundColor: theme.surface2, borderColor: theme.borderSubtle, borderRadius: radius3.md, height: size === "sm" ? 32 : 40 }, style],
3893
+ style: [styles34.track, { backgroundColor: theme.surface2, borderColor: theme.borderSubtle, borderRadius: radius3.md, height: size === "sm" ? 32 : 40 }, style],
2661
3894
  children: options.map((option) => {
2662
3895
  const selected = option.value === value;
2663
- return /* @__PURE__ */ jsx29(
2664
- Pressable9,
3896
+ return /* @__PURE__ */ jsx45(
3897
+ Pressable17,
2665
3898
  {
2666
3899
  role: "tab",
2667
3900
  "aria-selected": selected,
@@ -2671,12 +3904,12 @@ function Segmented({ options, value, onValueChange, size = "md", "aria-label": l
2671
3904
  if (!selected) onValueChange(option.value);
2672
3905
  },
2673
3906
  style: [
2674
- styles20.segment,
3907
+ styles34.segment,
2675
3908
  { borderRadius: radius3.sm },
2676
3909
  selected ? { backgroundColor: theme.surface0, borderColor: theme.borderDefault } : null,
2677
- option.disabled ? styles20.disabled : null
3910
+ option.disabled ? styles34.disabled : null
2678
3911
  ],
2679
- children: /* @__PURE__ */ jsx29(Text12, { numberOfLines: 1, style: [styles20.label, { color: selected ? theme.textPrimary : theme.textSecondary, fontSize: size === "sm" ? 12 : 13 }], children: option.label })
3912
+ children: /* @__PURE__ */ jsx45(Text16, { numberOfLines: 1, style: [styles34.label, { color: selected ? theme.textPrimary : theme.textSecondary, fontSize: size === "sm" ? 12 : 13 }], children: option.label })
2680
3913
  },
2681
3914
  option.value
2682
3915
  );
@@ -2684,17 +3917,17 @@ function Segmented({ options, value, onValueChange, size = "md", "aria-label": l
2684
3917
  }
2685
3918
  );
2686
3919
  }
2687
- var styles20 = StyleSheet20.create({
2688
- track: { flexDirection: "row", padding: 3, gap: 3, borderWidth: StyleSheet20.hairlineWidth },
2689
- segment: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 8, borderWidth: StyleSheet20.hairlineWidth, borderColor: "transparent" },
3920
+ var styles34 = StyleSheet34.create({
3921
+ track: { flexDirection: "row", padding: 3, gap: 3, borderWidth: StyleSheet34.hairlineWidth },
3922
+ segment: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 8, borderWidth: StyleSheet34.hairlineWidth, borderColor: "transparent" },
2690
3923
  label: { fontWeight: "600" },
2691
3924
  disabled: { opacity: 0.4 }
2692
3925
  });
2693
3926
 
2694
3927
  // src/native/skeleton.tsx
2695
- import * as React21 from "react";
2696
- import { Animated as Animated12 } from "react-native";
2697
- import { jsx as jsx30 } from "react/jsx-runtime";
3928
+ import * as React32 from "react";
3929
+ import { Animated as Animated18 } from "react-native";
3930
+ import { jsx as jsx46 } from "react/jsx-runtime";
2698
3931
  var SHAPE = {
2699
3932
  text: { width: "100%", height: 12, radius: 4 },
2700
3933
  circle: { width: 40, height: 40, radius: 9999 },
@@ -2703,13 +3936,13 @@ var SHAPE = {
2703
3936
  function Skeleton({ shape = "text", width, height, style, testID }) {
2704
3937
  const { theme } = useTheme();
2705
3938
  const reduce = useReducedMotion();
2706
- const [opacity] = React21.useState(() => new Animated12.Value(1));
2707
- React21.useEffect(() => {
3939
+ const [opacity] = React32.useState(() => new Animated18.Value(1));
3940
+ React32.useEffect(() => {
2708
3941
  if (reduce) return;
2709
- const loop = Animated12.loop(
2710
- Animated12.sequence([
2711
- Animated12.timing(opacity, { toValue: 0.5, duration: 900, useNativeDriver: true }),
2712
- Animated12.timing(opacity, { toValue: 1, duration: 900, useNativeDriver: true })
3942
+ const loop = Animated18.loop(
3943
+ Animated18.sequence([
3944
+ Animated18.timing(opacity, { toValue: 0.5, duration: 900, useNativeDriver: true }),
3945
+ Animated18.timing(opacity, { toValue: 1, duration: 900, useNativeDriver: true })
2713
3946
  ])
2714
3947
  );
2715
3948
  loop.start();
@@ -2720,8 +3953,8 @@ function Skeleton({ shape = "text", width, height, style, testID }) {
2720
3953
  }, [reduce, opacity]);
2721
3954
  const s = SHAPE[shape];
2722
3955
  const side = shape === "circle" ? width ?? height ?? s.width : void 0;
2723
- return /* @__PURE__ */ jsx30(
2724
- Animated12.View,
3956
+ return /* @__PURE__ */ jsx46(
3957
+ Animated18.View,
2725
3958
  {
2726
3959
  testID,
2727
3960
  "aria-hidden": true,
@@ -2733,12 +3966,187 @@ function Skeleton({ shape = "text", width, height, style, testID }) {
2733
3966
  );
2734
3967
  }
2735
3968
 
3969
+ // src/native/slider.tsx
3970
+ import * as React33 from "react";
3971
+ import { PanResponder as PanResponder2, StyleSheet as StyleSheet35, Text as Text17, View as View39 } from "react-native";
3972
+ import Svg20, { Defs as Defs11, LinearGradient as LinearGradient11, Rect as Rect4, Stop as Stop11 } from "react-native-svg";
3973
+ import { jsx as jsx47, jsxs as jsxs39 } from "react/jsx-runtime";
3974
+ var THUMB = 26;
3975
+ var toArray = (v) => v === void 0 ? void 0 : typeof v === "number" ? [v] : [...v];
3976
+ function Slider({
3977
+ label,
3978
+ thumbLabels,
3979
+ value,
3980
+ defaultValue,
3981
+ onValueChange,
3982
+ onValueCommit,
3983
+ min = 0,
3984
+ max = 100,
3985
+ step = 1,
3986
+ formatValue = String,
3987
+ showLabel,
3988
+ floatingValue,
3989
+ ticks,
3990
+ marks: marks2,
3991
+ tone: tone3 = "gradient",
3992
+ orientation = "horizontal",
3993
+ disabled,
3994
+ style
3995
+ }) {
3996
+ const { theme, radius: radius3, haptic } = useTheme();
3997
+ const range = Array.isArray(value ?? defaultValue);
3998
+ const vertical = orientation === "vertical";
3999
+ const [inner, setInner] = React33.useState(() => toArray(defaultValue) ?? [min]);
4000
+ const current = toArray(value) ?? inner;
4001
+ const [length, setLength] = React33.useState(0);
4002
+ const [dragging, setDragging] = React33.useState(null);
4003
+ const gradientId = useSvgId("kzs");
4004
+ const out = (next) => range ? [next[0], next[1]] : next[0];
4005
+ const snap = (v) => Math.min(max, Math.max(min, Math.round((v - min) / step) * step + min));
4006
+ const pct = (v) => (v - min) / (max - min || 1);
4007
+ const live = React33.useRef({ current, length, vertical, disabled });
4008
+ React33.useLayoutEffect(() => {
4009
+ live.current = { current, length, vertical, disabled };
4010
+ });
4011
+ const active = React33.useRef(0);
4012
+ const start = React33.useRef(0);
4013
+ const set = (next) => {
4014
+ if (value === void 0) setInner(next);
4015
+ onValueChange?.(out(next));
4016
+ };
4017
+ const move = (thumb, to) => {
4018
+ const now = live.current.current;
4019
+ let v = snap(to);
4020
+ if (now.length === 2) v = thumb === 0 ? Math.min(v, now[1]) : Math.max(v, now[0]);
4021
+ if (v === now[thumb]) return;
4022
+ haptic("selection");
4023
+ const next = [...now];
4024
+ next[thumb] = v;
4025
+ set(next);
4026
+ };
4027
+ const at = (position) => {
4028
+ const { length: l, vertical: vert } = live.current;
4029
+ const p = Math.min(1, Math.max(0, (vert ? l + THUMB / 2 - position : position - THUMB / 2) / (l || 1)));
4030
+ return min + p * (max - min);
4031
+ };
4032
+ const commit = () => onValueCommit?.(out(live.current.current));
4033
+ const handlers = React33.useRef({ move, at, commit });
4034
+ React33.useLayoutEffect(() => {
4035
+ handlers.current = { move, at, commit };
4036
+ });
4037
+ const [responder] = React33.useState(
4038
+ () => PanResponder2.create({
4039
+ onStartShouldSetPanResponder: () => !live.current.disabled,
4040
+ onMoveShouldSetPanResponder: () => !live.current.disabled,
4041
+ onPanResponderTerminationRequest: () => false,
4042
+ onPanResponderGrant: (e) => {
4043
+ const pos = live.current.vertical ? e.nativeEvent.locationY : e.nativeEvent.locationX;
4044
+ start.current = pos;
4045
+ const target = handlers.current.at(pos);
4046
+ const now = live.current.current;
4047
+ active.current = now.length === 2 && Math.abs(target - now[1]) < Math.abs(target - now[0]) ? 1 : 0;
4048
+ setDragging(active.current);
4049
+ handlers.current.move(active.current, target);
4050
+ },
4051
+ onPanResponderMove: (_, g) => handlers.current.move(active.current, handlers.current.at(start.current + (live.current.vertical ? g.dy : g.dx))),
4052
+ onPanResponderRelease: () => {
4053
+ setDragging(null);
4054
+ handlers.current.commit();
4055
+ },
4056
+ onPanResponderTerminate: () => setDragging(null)
4057
+ })
4058
+ );
4059
+ const lo = range ? Math.min(...current) : min;
4060
+ const hi = range ? Math.max(...current) : current[0];
4061
+ const tickValues = ticks === true ? (max - min) / step <= 40 ? Array.from({ length: Math.round((max - min) / step) + 1 }, (_, i) => min + i * step) : [] : ticks ? [...ticks] : [];
4062
+ const along = (p) => vertical ? { bottom: p * length } : { left: p * length };
4063
+ const onLayout = (e) => setLength(vertical ? e.nativeEvent.layout.height : e.nativeEvent.layout.width);
4064
+ const fill = vertical ? { bottom: pct(lo) * length, height: (pct(hi) - pct(lo)) * length, left: 0, right: 0 } : { left: pct(lo) * length, width: (pct(hi) - pct(lo)) * length, top: 0, bottom: 0 };
4065
+ return /* @__PURE__ */ jsxs39(View39, { style: [styles35.root, vertical ? styles35.rootVertical : null, disabled ? styles35.disabled : null, style], children: [
4066
+ showLabel ? /* @__PURE__ */ jsxs39(View39, { style: styles35.header, children: [
4067
+ /* @__PURE__ */ jsx47(Text17, { style: [styles35.label, { color: theme.textSecondary }], children: label }),
4068
+ /* @__PURE__ */ jsx47(Text17, { "aria-hidden": true, style: [styles35.value, { color: theme.textSecondary }], children: current.map(formatValue).join(" \u2013 ") })
4069
+ ] }) : null,
4070
+ /* @__PURE__ */ jsxs39(View39, { ...responder.panHandlers, style: vertical ? styles35.controlVertical : styles35.control, children: [
4071
+ /* @__PURE__ */ jsxs39(View39, { onLayout, pointerEvents: "none", style: [vertical ? styles35.trackVertical : styles35.track, { borderRadius: radius3.full, backgroundColor: theme.surface3 }], children: [
4072
+ /* @__PURE__ */ jsx47(View39, { style: [styles35.fill, fill, { borderRadius: radius3.full, overflow: "hidden", backgroundColor: theme.accent }], children: tone3 === "gradient" ? /* @__PURE__ */ jsxs39(Svg20, { width: "100%", height: "100%", "aria-hidden": true, children: [
4073
+ /* @__PURE__ */ jsx47(Defs11, { children: /* @__PURE__ */ jsxs39(LinearGradient11, { id: gradientId, x1: "0", y1: vertical ? "1" : "0", x2: vertical ? "0" : "1", y2: "0", children: [
4074
+ /* @__PURE__ */ jsx47(Stop11, { offset: "0", stopColor: theme.accent }),
4075
+ /* @__PURE__ */ jsx47(Stop11, { offset: "1", stopColor: theme.accent2 })
4076
+ ] }) }),
4077
+ /* @__PURE__ */ jsx47(Rect4, { width: "100%", height: "100%", fill: `url(#${gradientId})` })
4078
+ ] }) : null }),
4079
+ tickValues.map((t) => /* @__PURE__ */ jsx47(View39, { style: [vertical ? styles35.tickVertical : styles35.tick, along(pct(t)), { backgroundColor: t > lo && t < hi ? theme.onAccent : theme.borderStrong }] }, t))
4080
+ ] }),
4081
+ current.map((v, i) => /* @__PURE__ */ jsx47(
4082
+ View39,
4083
+ {
4084
+ accessible: true,
4085
+ role: "slider",
4086
+ "aria-label": range ? thumbLabels?.[i] ?? label : label,
4087
+ "aria-valuenow": v,
4088
+ "aria-valuemin": min,
4089
+ "aria-valuemax": max,
4090
+ "aria-valuetext": formatValue(v),
4091
+ "aria-disabled": disabled || void 0,
4092
+ accessibilityActions: [{ name: "increment" }, { name: "decrement" }],
4093
+ onAccessibilityAction: (e) => {
4094
+ const next = snap(v + (e.nativeEvent.actionName === "increment" ? step : -step));
4095
+ move(i, next);
4096
+ const values = [...current];
4097
+ values[i] = next;
4098
+ onValueCommit?.(out(values));
4099
+ },
4100
+ pointerEvents: "none",
4101
+ style: [styles35.thumb, vertical ? { bottom: pct(v) * length, left: (44 - THUMB) / 2, marginLeft: 0, marginTop: 0 } : { left: pct(v) * length - THUMB / 2, top: 0 }, { borderColor: theme.accent, backgroundColor: theme.textOnMedia, shadowColor: theme.scrimStrong }],
4102
+ children: floatingValue === "always" || floatingValue && dragging === i ? /* @__PURE__ */ jsx47(View39, { "aria-hidden": true, style: [vertical ? styles35.bubbleVertical : styles35.bubble, { backgroundColor: theme.textPrimary, borderRadius: radius3.md }], children: /* @__PURE__ */ jsx47(Text17, { style: [styles35.bubbleText, { color: theme.surface0 }], children: formatValue(v) }) }) : null
4103
+ },
4104
+ i
4105
+ ))
4106
+ ] }),
4107
+ marks2?.length && !vertical ? /* @__PURE__ */ jsx47(View39, { "aria-hidden": true, style: styles35.marks, children: marks2.map((m) => /* @__PURE__ */ jsx47(Text17, { style: [styles35.mark, { left: pct(m.value) * length, color: theme.textSecondary, transform: [{ translateX: m.value === min ? 0 : m.value === max ? -40 : -20 }], textAlign: m.value === min ? "left" : m.value === max ? "right" : "center" }], children: m.label }, m.value)) }) : null
4108
+ ] });
4109
+ }
4110
+ var styles35 = StyleSheet35.create({
4111
+ root: { gap: 8, alignSelf: "stretch" },
4112
+ rootVertical: { alignSelf: "flex-start", alignItems: "center" },
4113
+ header: { flexDirection: "row", justifyContent: "space-between", alignItems: "baseline", gap: 12 },
4114
+ label: { fontSize: 12, fontWeight: "600" },
4115
+ value: { fontSize: 12, fontVariant: ["tabular-nums"] },
4116
+ control: { height: 44, justifyContent: "center", paddingHorizontal: THUMB / 2 },
4117
+ controlVertical: { flex: 1, minHeight: 160, width: 44, alignItems: "center", paddingVertical: THUMB / 2 },
4118
+ track: { height: 6 },
4119
+ trackVertical: { width: 6, flex: 1 },
4120
+ fill: { position: "absolute" },
4121
+ tick: { position: "absolute", top: 1, width: 1, height: 4, marginLeft: -0.5 },
4122
+ tickVertical: { position: "absolute", left: 1, height: 1, width: 4, marginBottom: -0.5 },
4123
+ thumb: {
4124
+ position: "absolute",
4125
+ width: THUMB,
4126
+ height: THUMB,
4127
+ borderRadius: THUMB / 2,
4128
+ borderWidth: 2.5,
4129
+ marginLeft: THUMB / 2,
4130
+ marginTop: (44 - THUMB) / 2,
4131
+ shadowOpacity: 0.3,
4132
+ shadowRadius: 4,
4133
+ shadowOffset: { width: 0, height: 2 },
4134
+ elevation: 3
4135
+ },
4136
+ bubble: { position: "absolute", bottom: THUMB + 6, left: -17, minWidth: 56, paddingHorizontal: 8, paddingVertical: 4, alignItems: "center" },
4137
+ bubbleVertical: { position: "absolute", left: THUMB + 8, top: -2, minWidth: 48, paddingHorizontal: 8, paddingVertical: 4, alignItems: "center" },
4138
+ bubbleText: { fontSize: 12, fontWeight: "700", fontVariant: ["tabular-nums"] },
4139
+ marks: { height: 16, marginHorizontal: THUMB / 2 },
4140
+ mark: { position: "absolute", width: 40, fontSize: 11, fontWeight: "500" },
4141
+ disabled: { opacity: 0.4 }
4142
+ });
4143
+
2736
4144
  // src/native/spinner.tsx
2737
4145
  import { ActivityIndicator as ActivityIndicator2 } from "react-native";
2738
- import { jsx as jsx31 } from "react/jsx-runtime";
4146
+ import { jsx as jsx48 } from "react/jsx-runtime";
2739
4147
  function Spinner({ label, size = "md", ...props }) {
2740
4148
  const { theme } = useTheme();
2741
- return /* @__PURE__ */ jsx31(
4149
+ return /* @__PURE__ */ jsx48(
2742
4150
  ActivityIndicator2,
2743
4151
  {
2744
4152
  accessible: true,
@@ -2752,10 +4160,309 @@ function Spinner({ label, size = "md", ...props }) {
2752
4160
  );
2753
4161
  }
2754
4162
 
4163
+ // src/native/stepper.tsx
4164
+ import { StyleSheet as StyleSheet36, View as View40 } from "react-native";
4165
+ import Svg21, { Circle as Circle13, Path as Path16 } from "react-native-svg";
4166
+ import { jsx as jsx49, jsxs as jsxs40 } from "react/jsx-runtime";
4167
+ var WORDS = { done: "done", current: "in progress", upcoming: "to come", error: "failed" };
4168
+ function Stepper({ steps, current = 0, orientation = "vertical", statusLabels, "aria-label": label, style }) {
4169
+ const { theme } = useTheme();
4170
+ const words = { ...WORDS, ...statusLabels };
4171
+ const vertical = orientation === "vertical";
4172
+ return /* @__PURE__ */ jsx49(View40, { role: "list", "aria-label": label, style: [vertical ? styles36.column : styles36.row, style], children: steps.map((step, i) => {
4173
+ const status = step.status ?? (i < current ? "done" : i === current ? "current" : "upcoming");
4174
+ const last = i === steps.length - 1;
4175
+ const node = status === "current" ? /* @__PURE__ */ jsx49(LoaderGlyph, { value: step.value ?? null, size: 24 }) : status === "error" ? /* @__PURE__ */ jsx49(LoaderGlyph, { state: "error", size: 24 }) : /* @__PURE__ */ jsxs40(Svg21, { width: 24, height: 24, viewBox: "0 0 24 24", "aria-hidden": true, children: [
4176
+ /* @__PURE__ */ jsx49(Circle13, { cx: 12, cy: 12, r: 10, fill: status === "done" ? theme.accent : "none", stroke: status === "done" ? theme.accent : theme.borderStrong, strokeWidth: 2 }),
4177
+ status === "done" ? /* @__PURE__ */ jsx49(Path16, { d: "M7.5 12.3l3 3 6-6.3", stroke: theme.onAccent, strokeWidth: 2.2, fill: "none", strokeLinecap: "round", strokeLinejoin: "round" }) : null
4178
+ ] });
4179
+ const connector = !last ? /* @__PURE__ */ jsx49(View40, { "aria-hidden": true, style: [vertical ? styles36.vLine : styles36.hLine, { backgroundColor: status === "done" ? theme.accent : theme.borderDefault }] }) : null;
4180
+ return /* @__PURE__ */ jsxs40(View40, { role: "listitem", accessible: true, "aria-label": `${step.title}, ${words[status]}`, style: vertical ? styles36.vStep : styles36.hStep, children: [
4181
+ /* @__PURE__ */ jsxs40(View40, { style: vertical ? styles36.vRail : styles36.hRail, children: [
4182
+ node,
4183
+ connector
4184
+ ] }),
4185
+ /* @__PURE__ */ jsxs40(View40, { style: [styles36.body, vertical && !last ? { paddingBottom: 20 } : null], children: [
4186
+ /* @__PURE__ */ jsx49(Txt, { variant: "label", tone: status === "upcoming" ? "secondary" : "text", numberOfLines: vertical ? void 0 : 2, children: step.title }),
4187
+ step.description ? /* @__PURE__ */ jsx49(Txt, { variant: "caption", tone: "secondary", children: step.description }) : null,
4188
+ step.content && (status === "current" || status === "error") ? /* @__PURE__ */ jsx49(View40, { style: styles36.content, children: step.content }) : null
4189
+ ] })
4190
+ ] }, i);
4191
+ }) });
4192
+ }
4193
+ var styles36 = StyleSheet36.create({
4194
+ column: { gap: 0 },
4195
+ row: { flexDirection: "row" },
4196
+ vStep: { flexDirection: "row", gap: 12 },
4197
+ hStep: { flex: 1, gap: 8 },
4198
+ vRail: { alignItems: "center", width: 24 },
4199
+ hRail: { flexDirection: "row", alignItems: "center" },
4200
+ vLine: { width: 2, flex: 1, marginVertical: 4, borderRadius: 1 },
4201
+ hLine: { height: 2, flex: 1, marginHorizontal: 6, borderRadius: 1 },
4202
+ body: { flex: 1, gap: 2, paddingTop: 2 },
4203
+ content: { marginTop: 8 }
4204
+ });
4205
+
4206
+ // src/native/swipeable-row.tsx
4207
+ import * as React34 from "react";
4208
+ import { Animated as Animated19, PanResponder as PanResponder3, Pressable as Pressable18, StyleSheet as StyleSheet37, View as View41 } from "react-native";
4209
+ import { jsx as jsx50, jsxs as jsxs41 } from "react/jsx-runtime";
4210
+ var toneColor = (t, tone3) => ({ neutral: t.surface3, accent: t.accent, success: t.success, warning: t.warning, danger: t.danger })[tone3 ?? "neutral"];
4211
+ var toneText = (tone3) => tone3 === "neutral" || tone3 === void 0 ? "text" : "onAccent";
4212
+ function SwipeableRow({ children, trailing = [], leading = [], fullSwipe = 0.6, actionWidth = 80, onActivate, testID, style }) {
4213
+ const { theme, haptic } = useTheme();
4214
+ const reduce = useReducedMotion();
4215
+ const [x] = React34.useState(() => new Animated19.Value(0));
4216
+ const [width, setWidth] = React34.useState(0);
4217
+ const rest = React34.useRef(0);
4218
+ const armed = React34.useRef(false);
4219
+ const settle = (to) => {
4220
+ rest.current = to;
4221
+ if (reduce) x.setValue(to);
4222
+ else Animated19.spring(x, { toValue: to, useNativeDriver: true, damping: 22, stiffness: 240 }).start();
4223
+ };
4224
+ const run = (action) => {
4225
+ settle(0);
4226
+ action.onPress();
4227
+ };
4228
+ const pan = React34.useMemo(
4229
+ () => PanResponder3.create({
4230
+ onMoveShouldSetPanResponder: (_, g) => Math.abs(g.dx) > 8 && Math.abs(g.dx) > Math.abs(g.dy) * 1.5,
4231
+ onPanResponderMove: (_, g) => {
4232
+ let next = rest.current + g.dx;
4233
+ if (next < 0 && trailing.length === 0) next = 0;
4234
+ if (next > 0 && leading.length === 0) next = 0;
4235
+ x.setValue(next);
4236
+ const past = fullSwipe !== false && width > 0 && Math.abs(next) > width * fullSwipe;
4237
+ if (past !== armed.current) {
4238
+ armed.current = past;
4239
+ if (past) haptic("impact");
4240
+ }
4241
+ },
4242
+ onPanResponderRelease: (_, g) => {
4243
+ const at = rest.current + g.dx;
4244
+ if (armed.current) {
4245
+ armed.current = false;
4246
+ const action = at < 0 ? trailing[0] : leading[0];
4247
+ if (action) return run(action);
4248
+ }
4249
+ const open = at < 0 ? -trailing.length * actionWidth : leading.length * actionWidth;
4250
+ settle(Math.abs(at) > actionWidth / 2 ? open : 0);
4251
+ },
4252
+ onPanResponderTerminate: () => settle(0)
4253
+ }),
4254
+ [trailing, leading, fullSwipe, width, actionWidth]
4255
+ // eslint-disable-line react-hooks/exhaustive-deps -- run/settle are stable in effect
4256
+ );
4257
+ const side = (actions, edge) => /* @__PURE__ */ jsx50(View41, { "aria-hidden": true, style: [styles37.side, edge === "left" ? { left: 0 } : { right: 0, flexDirection: "row-reverse" }], children: actions.map((action, i) => (
4258
+ // eslint-disable-next-line react-hooks/refs -- runs on a press, never during render
4259
+ /* @__PURE__ */ jsxs41(Pressable18, { focusable: false, tabIndex: -1, onPress: () => run(action), style: [styles37.action, { width: actionWidth, backgroundColor: toneColor(theme, action.tone) }], children: [
4260
+ action.icon,
4261
+ /* @__PURE__ */ jsx50(Txt, { variant: "caption", tone: toneText(action.tone), style: styles37.actionText, numberOfLines: 1, children: action.label })
4262
+ ] }, i)
4263
+ )) });
4264
+ const all = [...leading, ...trailing];
4265
+ return /* @__PURE__ */ jsxs41(View41, { style: [styles37.root, style], onLayout: (e) => setWidth(e.nativeEvent.layout.width), children: [
4266
+ leading.length > 0 ? side(leading, "left") : null,
4267
+ trailing.length > 0 ? side(trailing, "right") : null,
4268
+ /* @__PURE__ */ jsx50(
4269
+ Animated19.View,
4270
+ {
4271
+ ...pan.panHandlers,
4272
+ accessible: true,
4273
+ testID,
4274
+ accessibilityActions: [...onActivate ? [{ name: "activate" }] : [], ...all.map((a) => ({ name: a.label, label: a.label }))],
4275
+ onAccessibilityAction: (e) => {
4276
+ if (e.nativeEvent.actionName === "activate") return onActivate?.();
4277
+ const action = all.find((a) => a.label === e.nativeEvent.actionName);
4278
+ if (action) action.onPress();
4279
+ },
4280
+ style: [styles37.front, { backgroundColor: theme.surface0, transform: [{ translateX: x }] }],
4281
+ children
4282
+ }
4283
+ )
4284
+ ] });
4285
+ }
4286
+ var styles37 = StyleSheet37.create({
4287
+ root: { overflow: "hidden" },
4288
+ side: { position: "absolute", top: 0, bottom: 0, flexDirection: "row" },
4289
+ action: { alignItems: "center", justifyContent: "center", gap: 4, paddingHorizontal: 6 },
4290
+ actionText: { fontWeight: "700" },
4291
+ front: {}
4292
+ });
4293
+
4294
+ // src/native/switch.tsx
4295
+ import * as React35 from "react";
4296
+ import { Animated as Animated20, Pressable as Pressable19, StyleSheet as StyleSheet38, Text as Text18, View as View42 } from "react-native";
4297
+ import { jsx as jsx51, jsxs as jsxs42 } from "react/jsx-runtime";
4298
+ var SIZES = { sm: { w: 40, h: 24, knob: 18 }, md: { w: 52, h: 32, knob: 26 } };
4299
+ function Switch({ label, checked, defaultChecked = false, onCheckedChange, description, showLabel, size = "md", error, disabled, style }) {
4300
+ const { theme, motion: motion3, haptic } = useTheme();
4301
+ const [own, setOwn] = React35.useState(defaultChecked);
4302
+ const on = checked ?? own;
4303
+ const d = SIZES[size];
4304
+ const travel = d.w - d.knob - (d.h - d.knob);
4305
+ const [x] = React35.useState(() => new Animated20.Value(on ? 1 : 0));
4306
+ React35.useEffect(() => {
4307
+ Animated20.timing(x, { toValue: on ? 1 : 0, duration: motion3.duration.base, useNativeDriver: true }).start();
4308
+ }, [on, x, motion3.duration.base]);
4309
+ const toggle = () => {
4310
+ haptic("selection");
4311
+ if (checked === void 0) setOwn(!on);
4312
+ onCheckedChange?.(!on);
4313
+ };
4314
+ const track = /* @__PURE__ */ jsx51(View42, { style: [styles38.track, { width: d.w, height: d.h, borderRadius: d.h / 2, backgroundColor: on ? theme.accent : theme.surface3, borderColor: error ? theme.danger : on ? theme.accent : theme.borderDefault }], children: /* @__PURE__ */ jsx51(
4315
+ Animated20.View,
4316
+ {
4317
+ style: [
4318
+ styles38.knob,
4319
+ {
4320
+ width: d.knob,
4321
+ height: d.knob,
4322
+ borderRadius: d.knob / 2,
4323
+ backgroundColor: theme.textOnMedia,
4324
+ shadowColor: theme.scrimStrong,
4325
+ transform: [{ translateX: x.interpolate({ inputRange: [0, 1], outputRange: [0, travel] }) }]
4326
+ }
4327
+ ]
4328
+ }
4329
+ ) });
4330
+ const a11y = {
4331
+ role: "switch",
4332
+ "aria-checked": on,
4333
+ "aria-label": label,
4334
+ "aria-disabled": disabled || void 0,
4335
+ accessibilityHint: error ?? description,
4336
+ disabled,
4337
+ onPress: toggle
4338
+ };
4339
+ if (!showLabel)
4340
+ return /* @__PURE__ */ jsx51(Pressable19, { ...a11y, hitSlop: { top: (44 - d.h) / 2, bottom: (44 - d.h) / 2, left: Math.max(0, (44 - d.w) / 2), right: Math.max(0, (44 - d.w) / 2) }, style: [disabled ? styles38.disabled : null, style], children: track });
4341
+ return /* @__PURE__ */ jsxs42(View42, { style: [styles38.root, style], children: [
4342
+ /* @__PURE__ */ jsxs42(Pressable19, { ...a11y, style: [styles38.row, disabled ? styles38.disabled : null], children: [
4343
+ /* @__PURE__ */ jsxs42(View42, { style: styles38.text, children: [
4344
+ /* @__PURE__ */ jsx51(Text18, { style: [styles38.label, { color: theme.textPrimary }], children: label }),
4345
+ description ? /* @__PURE__ */ jsx51(Text18, { style: [styles38.description, { color: theme.textSecondary }], children: description }) : null
4346
+ ] }),
4347
+ track
4348
+ ] }),
4349
+ error ? /* @__PURE__ */ jsx51(Text18, { role: "alert", "aria-live": "polite", style: [styles38.description, { color: theme.dangerText }], children: error }) : null
4350
+ ] });
4351
+ }
4352
+ var styles38 = StyleSheet38.create({
4353
+ root: { gap: 2, alignSelf: "stretch" },
4354
+ row: { flexDirection: "row", alignItems: "center", gap: 16, minHeight: 48 },
4355
+ text: { flex: 1, gap: 2 },
4356
+ label: { fontSize: 15, lineHeight: 20, fontWeight: "500" },
4357
+ description: { fontSize: 12, lineHeight: 16 },
4358
+ track: { justifyContent: "center", paddingHorizontal: 2, borderWidth: 1 },
4359
+ knob: { shadowOpacity: 0.25, shadowRadius: 3, shadowOffset: { width: 0, height: 1 }, elevation: 2 },
4360
+ disabled: { opacity: 0.4 }
4361
+ });
4362
+
4363
+ // src/native/tab-bar.tsx
4364
+ import { Pressable as Pressable20, StyleSheet as StyleSheet39, Text as Text19, View as View43 } from "react-native";
4365
+ import { jsx as jsx52, jsxs as jsxs43 } from "react/jsx-runtime";
4366
+ function TabBar({ items: items2, value, onValueChange, onReselect, "aria-label": label, style }) {
4367
+ const { theme, insets, haptic } = useTheme();
4368
+ return /* @__PURE__ */ jsx52(View43, { role: "tablist", "aria-label": label, style: [styles39.bar, { backgroundColor: theme.glassBg, borderTopColor: theme.glassBorder, paddingBottom: Math.max(6, insets.bottom) }, style], children: items2.map((item) => {
4369
+ const selected = item.value === value;
4370
+ const color = selected ? theme.accentText : theme.textSecondary;
4371
+ const badge = item.badge === true ? "" : typeof item.badge === "number" && item.badge > 0 ? item.badge > 99 ? "99+" : String(item.badge) : null;
4372
+ return /* @__PURE__ */ jsxs43(
4373
+ Pressable20,
4374
+ {
4375
+ role: "tab",
4376
+ "aria-selected": selected,
4377
+ onPress: () => {
4378
+ haptic("selection");
4379
+ if (selected) onReselect?.(item.value);
4380
+ else onValueChange(item.value);
4381
+ },
4382
+ style: ({ pressed }) => [styles39.item, { opacity: pressed ? 0.7 : 1 }],
4383
+ children: [
4384
+ /* @__PURE__ */ jsxs43(View43, { "aria-hidden": true, style: styles39.icon, children: [
4385
+ item.icon(selected, color),
4386
+ badge !== null ? /* @__PURE__ */ jsx52(View43, { style: [badge ? styles39.count : styles39.dot, { backgroundColor: theme.danger, borderColor: theme.surface1 }], children: badge ? /* @__PURE__ */ jsx52(Text19, { style: [styles39.countText, { color: theme.onAccent }], children: badge }) : null }) : null
4387
+ ] }),
4388
+ /* @__PURE__ */ jsx52(Text19, { numberOfLines: 1, style: [styles39.label, { color, fontWeight: selected ? "700" : "500" }], children: item.label }),
4389
+ badge !== null && item.badgeLabel ? /* @__PURE__ */ jsx52(Text19, { style: styles39.unseen, children: `, ${item.badgeLabel}` }) : null
4390
+ ]
4391
+ },
4392
+ item.value
4393
+ );
4394
+ }) });
4395
+ }
4396
+ var styles39 = StyleSheet39.create({
4397
+ bar: { flexDirection: "row", borderTopWidth: StyleSheet39.hairlineWidth, paddingTop: 6 },
4398
+ item: { flex: 1, alignItems: "center", gap: 2, minHeight: 48, justifyContent: "center" },
4399
+ icon: { width: 28, height: 26, alignItems: "center", justifyContent: "center" },
4400
+ label: { fontSize: 11, lineHeight: 14 },
4401
+ unseen: { position: "absolute", width: 1, height: 1, overflow: "hidden", opacity: 0 },
4402
+ count: { position: "absolute", top: -4, left: 16, minWidth: 18, height: 18, borderRadius: 9, paddingHorizontal: 4, alignItems: "center", justifyContent: "center", borderWidth: 2 },
4403
+ countText: { fontSize: 10, fontWeight: "800", lineHeight: 12 },
4404
+ dot: { position: "absolute", top: 0, right: 0, width: 10, height: 10, borderRadius: 5, borderWidth: 2 }
4405
+ });
4406
+
4407
+ // src/native/tabs.tsx
4408
+ import * as React36 from "react";
4409
+ import { Pressable as Pressable21, ScrollView as ScrollView6, StyleSheet as StyleSheet40, View as View44 } from "react-native";
4410
+ import { jsx as jsx53, jsxs as jsxs44 } from "react/jsx-runtime";
4411
+ function Tabs({ items: items2, value, defaultValue, onValueChange, "aria-label": label, variant = "underline", style }) {
4412
+ const { theme, radius: radius3, haptic } = useTheme();
4413
+ const [own, setOwn] = React36.useState(defaultValue ?? items2[0]?.value);
4414
+ const current = value ?? own;
4415
+ const select = (next) => {
4416
+ if (next === current) return;
4417
+ haptic("selection");
4418
+ if (value === void 0) setOwn(next);
4419
+ onValueChange?.(next);
4420
+ };
4421
+ const segmented = variant === "segmented";
4422
+ const tabs = items2.map((item) => {
4423
+ const selected = item.value === current;
4424
+ return /* @__PURE__ */ jsx53(
4425
+ Pressable21,
4426
+ {
4427
+ role: "tab",
4428
+ "aria-selected": selected,
4429
+ "aria-disabled": item.disabled,
4430
+ disabled: item.disabled,
4431
+ onPress: () => select(item.value),
4432
+ style: [
4433
+ segmented ? styles40.segment : styles40.tab,
4434
+ segmented && selected ? { backgroundColor: theme.surface0, borderColor: theme.borderDefault, borderRadius: radius3.sm } : null,
4435
+ !segmented ? { borderBottomColor: selected ? theme.accent : "transparent" } : null,
4436
+ item.disabled ? styles40.disabled : null
4437
+ ],
4438
+ children: /* @__PURE__ */ jsxs44(Txt, { variant: "label", tone: selected ? "text" : "secondary", numberOfLines: 1, children: [
4439
+ item.label,
4440
+ item.count !== void 0 ? /* @__PURE__ */ jsx53(Txt, { variant: "caption", tone: "secondary", children: ` ${item.count}` }) : null
4441
+ ] })
4442
+ },
4443
+ item.value
4444
+ );
4445
+ });
4446
+ const panel = items2.find((i) => i.value === current)?.content;
4447
+ return /* @__PURE__ */ jsxs44(View44, { style: [styles40.root, style], children: [
4448
+ segmented ? /* @__PURE__ */ jsx53(View44, { role: "tablist", "aria-label": label, style: [styles40.track, { backgroundColor: theme.surface2, borderColor: theme.borderSubtle, borderRadius: radius3.md }], children: tabs }) : /* @__PURE__ */ jsx53(View44, { style: [styles40.underline, { borderBottomColor: theme.borderSubtle }], children: /* @__PURE__ */ jsx53(ScrollView6, { horizontal: true, showsHorizontalScrollIndicator: false, role: "tablist", "aria-label": label, contentContainerStyle: styles40.scroll, children: tabs }) }),
4449
+ panel !== void 0 ? /* @__PURE__ */ jsx53(View44, { role: "tabpanel", children: panel }) : null
4450
+ ] });
4451
+ }
4452
+ var styles40 = StyleSheet40.create({
4453
+ root: { gap: 12 },
4454
+ underline: { borderBottomWidth: StyleSheet40.hairlineWidth },
4455
+ scroll: { gap: 4, paddingHorizontal: 4 },
4456
+ tab: { minHeight: 44, justifyContent: "center", paddingHorizontal: 12, borderBottomWidth: 2 },
4457
+ track: { flexDirection: "row", padding: 3, gap: 3, borderWidth: StyleSheet40.hairlineWidth, height: 40 },
4458
+ segment: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 8, borderWidth: StyleSheet40.hairlineWidth, borderColor: "transparent" },
4459
+ disabled: { opacity: 0.4 }
4460
+ });
4461
+
2755
4462
  // src/native/toast.tsx
2756
- import * as React22 from "react";
2757
- import { AccessibilityInfo as AccessibilityInfo8, Animated as Animated13, Pressable as Pressable10, StyleSheet as StyleSheet21, Text as Text13, View as View25 } from "react-native";
2758
- import { Fragment as Fragment3, jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
4463
+ import * as React37 from "react";
4464
+ import { AccessibilityInfo as AccessibilityInfo12, Animated as Animated21, PanResponder as PanResponder4, Pressable as Pressable22, StyleSheet as StyleSheet41, Text as Text20, View as View45 } from "react-native";
4465
+ import { Fragment as Fragment6, jsx as jsx54, jsxs as jsxs45 } from "react/jsx-runtime";
2759
4466
  var items = [];
2760
4467
  var listeners2 = /* @__PURE__ */ new Set();
2761
4468
  var counter = 0;
@@ -2779,87 +4486,104 @@ function dismiss(id) {
2779
4486
  emit();
2780
4487
  gone.forEach((t) => t.onDismiss?.());
2781
4488
  }
2782
- var tone = (name) => (title, options) => show(title, { ...options, tone: name });
4489
+ var tone2 = (name) => (title, options) => show(title, { ...options, tone: name });
2783
4490
  var toast = Object.assign(show, {
2784
- success: tone("success"),
2785
- warning: tone("warning"),
2786
- error: tone("error"),
2787
- info: tone("info"),
4491
+ success: tone2("success"),
4492
+ warning: tone2("warning"),
4493
+ error: tone2("error"),
4494
+ info: tone2("info"),
2788
4495
  dismiss
2789
4496
  });
2790
4497
  function ToastView({ item, closeLabel, duration }) {
2791
- const { theme, radius: radius3 } = useTheme();
4498
+ const { theme, radius: radius3, haptic } = useTheme();
2792
4499
  const reduce = useReducedMotion();
2793
- const [enter] = React22.useState(() => new Animated13.Value(reduce ? 1 : 0));
2794
- React22.useEffect(() => {
4500
+ const [swipe] = React37.useState(() => new Animated21.Value(0));
4501
+ const drag = React37.useMemo(
4502
+ () => PanResponder4.create({
4503
+ onMoveShouldSetPanResponder: (_, g) => Math.abs(g.dx) > 8 && Math.abs(g.dx) > Math.abs(g.dy),
4504
+ onPanResponderMove: (_, g) => swipe.setValue(g.dx),
4505
+ onPanResponderRelease: (_, g) => {
4506
+ if (Math.abs(g.dx) > 96 || Math.abs(g.vx) > 0.9) {
4507
+ Animated21.timing(swipe, { toValue: Math.sign(g.dx) * 480, duration: 160, useNativeDriver: true }).start(() => dismiss(item.id));
4508
+ } else Animated21.spring(swipe, { toValue: 0, useNativeDriver: true }).start();
4509
+ }
4510
+ }),
4511
+ [swipe, item.id]
4512
+ );
4513
+ React37.useEffect(() => {
4514
+ if (item.tone === "success" || item.tone === "warning") haptic(item.tone);
4515
+ if (item.tone === "error") haptic("warning");
4516
+ }, [item.id]);
4517
+ const [enter] = React37.useState(() => new Animated21.Value(reduce ? 1 : 0));
4518
+ React37.useEffect(() => {
2795
4519
  if (reduce) enter.setValue(1);
2796
- else Animated13.timing(enter, { toValue: 1, duration: 220, useNativeDriver: true }).start();
4520
+ else Animated21.timing(enter, { toValue: 1, duration: 220, useNativeDriver: true }).start();
2797
4521
  }, [enter, reduce]);
2798
- React22.useEffect(() => {
2799
- AccessibilityInfo8.announceForAccessibility(item.description ? `${item.title}. ${item.description}` : item.title);
4522
+ React37.useEffect(() => {
4523
+ AccessibilityInfo12.announceForAccessibility(item.description ? `${item.title}. ${item.description}` : item.title);
2800
4524
  }, [item.title, item.description]);
2801
4525
  const ms = item.duration ?? duration;
2802
- React22.useEffect(() => {
4526
+ React37.useEffect(() => {
2803
4527
  if (!Number.isFinite(ms)) return;
2804
4528
  const timer2 = setTimeout(() => dismiss(item.id), ms);
2805
4529
  return () => clearTimeout(timer2);
2806
4530
  }, [item.id, ms]);
2807
4531
  const edge = { success: theme.success, warning: theme.warning, error: theme.danger, info: theme.info, default: theme.borderDefault }[item.tone ?? "default"];
2808
- const text = /* @__PURE__ */ jsxs25(Fragment3, { children: [
2809
- item.icon ? /* @__PURE__ */ jsx32(View25, { "aria-hidden": true, children: item.icon }) : null,
2810
- /* @__PURE__ */ jsxs25(View25, { style: styles21.content, children: [
2811
- /* @__PURE__ */ jsx32(Txt, { variant: "label", numberOfLines: 2, children: item.title }),
2812
- item.description ? /* @__PURE__ */ jsx32(Txt, { variant: "caption", tone: "secondary", numberOfLines: 3, children: item.description }) : null
4532
+ const text = /* @__PURE__ */ jsxs45(Fragment6, { children: [
4533
+ item.icon ? /* @__PURE__ */ jsx54(View45, { "aria-hidden": true, children: item.icon }) : null,
4534
+ /* @__PURE__ */ jsxs45(View45, { style: styles41.content, children: [
4535
+ /* @__PURE__ */ jsx54(Txt, { variant: "label", numberOfLines: 2, children: item.title }),
4536
+ item.description ? /* @__PURE__ */ jsx54(Txt, { variant: "caption", tone: "secondary", numberOfLines: 3, children: item.description }) : null
2813
4537
  ] })
2814
4538
  ] });
2815
- const body = /* @__PURE__ */ jsxs25(Fragment3, { children: [
2816
- item.onPress ? /* @__PURE__ */ jsx32(
2817
- Pressable10,
4539
+ const body = /* @__PURE__ */ jsxs45(Fragment6, { children: [
4540
+ item.onPress ? /* @__PURE__ */ jsx54(
4541
+ Pressable22,
2818
4542
  {
2819
4543
  role: "button",
2820
4544
  onPress: () => {
2821
4545
  item.onPress?.();
2822
4546
  dismiss(item.id);
2823
4547
  },
2824
- style: ({ pressed }) => [styles21.main, { opacity: pressed ? 0.8 : 1 }],
4548
+ style: ({ pressed }) => [styles41.main, { opacity: pressed ? 0.8 : 1 }],
2825
4549
  children: text
2826
4550
  }
2827
- ) : /* @__PURE__ */ jsx32(View25, { style: styles21.main, children: text }),
2828
- item.action ? /* @__PURE__ */ jsx32(
2829
- Pressable10,
4551
+ ) : /* @__PURE__ */ jsx54(View45, { style: styles41.main, children: text }),
4552
+ item.action ? /* @__PURE__ */ jsx54(
4553
+ Pressable22,
2830
4554
  {
2831
4555
  role: "button",
2832
4556
  onPress: () => {
2833
4557
  item.action?.onPress();
2834
4558
  dismiss(item.id);
2835
4559
  },
2836
- style: [styles21.action, { backgroundColor: theme.accent, borderRadius: radius3.sm }],
2837
- children: /* @__PURE__ */ jsx32(Text13, { style: [styles21.actionLabel, { color: theme.onAccent }], children: item.action.label })
4560
+ style: [styles41.action, { backgroundColor: theme.accent, borderRadius: radius3.sm }],
4561
+ children: /* @__PURE__ */ jsx54(Text20, { style: [styles41.actionLabel, { color: theme.onAccent }], children: item.action.label })
2838
4562
  }
2839
4563
  ) : null,
2840
- /* @__PURE__ */ jsx32(Pressable10, { role: "button", "aria-label": closeLabel, hitSlop: 10, onPress: () => dismiss(item.id), style: styles21.close, children: /* @__PURE__ */ jsx32(Text13, { style: [styles21.cross, { color: theme.textSecondary }], children: "\xD7" }) })
4564
+ /* @__PURE__ */ jsx54(Pressable22, { role: "button", "aria-label": closeLabel, hitSlop: 10, onPress: () => dismiss(item.id), style: styles41.close, children: /* @__PURE__ */ jsx54(Text20, { style: [styles41.cross, { color: theme.textSecondary }], children: "\xD7" }) })
2841
4565
  ] });
2842
4566
  const frame = [
2843
- styles21.toast,
4567
+ styles41.toast,
2844
4568
  { backgroundColor: theme.surface2, borderColor: theme.borderDefault, borderLeftColor: edge, borderRadius: radius3.lg, shadowColor: theme.scrimStrong }
2845
4569
  ];
2846
- const motion3 = { transform: [{ translateY: enter.interpolate({ inputRange: [0, 1], outputRange: [-8, 0] }) }] };
2847
- return /* @__PURE__ */ jsx32(Animated13.View, { "aria-live": "polite", style: motion3, children: /* @__PURE__ */ jsx32(View25, { style: frame, children: body }) });
4570
+ const motion3 = { transform: [{ translateY: enter.interpolate({ inputRange: [0, 1], outputRange: [-8, 0] }) }, { translateX: swipe }] };
4571
+ return /* @__PURE__ */ jsx54(Animated21.View, { "aria-live": "polite", style: motion3, ...drag.panHandlers, children: /* @__PURE__ */ jsx54(View45, { style: frame, children: body }) });
2848
4572
  }
2849
4573
  function Toaster({ closeLabel, position = "top", offset = 12, duration = 6e3, max = 3 }) {
2850
- const all = React22.useSyncExternalStore(subscribe2, snapshot, snapshot);
4574
+ const all = React37.useSyncExternalStore(subscribe2, snapshot, snapshot);
2851
4575
  const shown = all.slice(-max);
2852
4576
  if (shown.length === 0) return null;
2853
- return /* @__PURE__ */ jsx32(View25, { pointerEvents: "box-none", style: [styles21.stack, position === "top" ? { top: offset } : { bottom: offset }], children: (position === "top" ? shown : [...shown].reverse()).map((item) => /* @__PURE__ */ jsx32(ToastView, { item, closeLabel, duration }, item.id)) });
4577
+ return /* @__PURE__ */ jsx54(View45, { pointerEvents: "box-none", style: [styles41.stack, position === "top" ? { top: offset } : { bottom: offset }], children: (position === "top" ? shown : [...shown].reverse()).map((item) => /* @__PURE__ */ jsx54(ToastView, { item, closeLabel, duration }, item.id)) });
2854
4578
  }
2855
- var styles21 = StyleSheet21.create({
4579
+ var styles41 = StyleSheet41.create({
2856
4580
  stack: { position: "absolute", left: 12, right: 12, gap: 8, zIndex: 100 },
2857
4581
  toast: {
2858
4582
  flexDirection: "row",
2859
4583
  alignItems: "center",
2860
4584
  gap: 10,
2861
4585
  padding: 12,
2862
- borderWidth: StyleSheet21.hairlineWidth,
4586
+ borderWidth: StyleSheet41.hairlineWidth,
2863
4587
  borderLeftWidth: 4,
2864
4588
  shadowOpacity: 0.3,
2865
4589
  shadowRadius: 16,
@@ -2874,6 +4598,8 @@ var styles21 = StyleSheet21.create({
2874
4598
  cross: { fontSize: 18, lineHeight: 20, fontWeight: "700" }
2875
4599
  });
2876
4600
  export {
4601
+ ActionSheet,
4602
+ ActivityFeed,
2877
4603
  Avatar,
2878
4604
  AvatarGroup,
2879
4605
  AvatarRoot,
@@ -2891,31 +4617,53 @@ export {
2891
4617
  CardTitle,
2892
4618
  Checkbox,
2893
4619
  Chip,
4620
+ Combobox,
2894
4621
  Countdown,
2895
4622
  DateField,
2896
4623
  DateWheel,
2897
4624
  DayStrip,
4625
+ DescriptionList,
2898
4626
  EmptyState,
2899
4627
  ErrorState,
4628
+ Fab,
2900
4629
  GoalGauge,
4630
+ Header,
2901
4631
  IconButton,
4632
+ ImageViewer,
2902
4633
  KrizakaMark,
4634
+ Loader,
4635
+ LoaderGlyph,
2903
4636
  LoadingState,
2904
4637
  Mascot,
2905
4638
  MascotState,
4639
+ Meter,
2906
4640
  MonthPicker,
4641
+ NumberTicker,
4642
+ Onboarding,
2907
4643
  OrazakaMark,
2908
4644
  OrochiaMark,
4645
+ OtpInput,
2909
4646
  Pagination,
4647
+ PermissionPrompt,
2910
4648
  Phoenix,
2911
4649
  ProductMark,
2912
4650
  ProfileCard,
2913
4651
  Progress,
4652
+ PullToRefresh,
4653
+ RadioGroup,
2914
4654
  SearchField,
2915
4655
  Segmented,
4656
+ Select,
4657
+ Sheet,
2916
4658
  Skeleton,
4659
+ Slider,
2917
4660
  Spinner,
4661
+ Stepper,
2918
4662
  SuccessState,
4663
+ SwipeableRow,
4664
+ Switch,
4665
+ TabBar,
4666
+ Tabs,
2919
4667
  TextField,
2920
4668
  ThemeProvider,
2921
4669
  TimePicker,
@@ -2932,6 +4680,7 @@ export {
2932
4680
  ageOn,
2933
4681
  alpha,
2934
4682
  calendarLabels,
4683
+ comboboxLabels,
2935
4684
  composeDate,
2936
4685
  dateFieldLabels,
2937
4686
  datePartsOrder,
@@ -2940,13 +4689,16 @@ export {
2940
4689
  isRealDate,
2941
4690
  latestBirthDate,
2942
4691
  monthNames,
4692
+ prefetchNeighbours,
2943
4693
  splitDuration,
2944
4694
  textStyles,
2945
4695
  timeSlots,
2946
4696
  timeToMinutes,
2947
4697
  toast,
2948
4698
  todayIso,
4699
+ useCollapsingHeader,
2949
4700
  useCountdown,
4701
+ useDelayedWait,
2950
4702
  useReducedMotion,
2951
4703
  useTheme,
2952
4704
  uses12Hours