@krizaka/ui 3.29.0 → 3.31.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 (403) hide show
  1. package/README.md +4 -8
  2. package/dist/action-bar.js +3 -3
  3. package/dist/action-bar.js.map +1 -1
  4. package/dist/argument-card.d.ts +1 -1
  5. package/dist/argument-card.js +2 -2
  6. package/dist/argument-card.js.map +1 -1
  7. package/dist/blocks.css +19 -60
  8. package/dist/{button-BmCrLCq7.d.ts → button-Cm9pFH3P.d.ts} +10 -9
  9. package/dist/button.d.ts +11 -10
  10. package/dist/button.js +1 -1
  11. package/dist/captcha.js +1 -1
  12. package/dist/card-grid.d.ts +5 -12
  13. package/dist/card-grid.js +4 -12
  14. package/dist/card-grid.js.map +1 -1
  15. package/dist/card.d.ts +7 -7
  16. package/dist/card.js +2 -2
  17. package/dist/card.js.map +1 -1
  18. package/dist/{chunk-OUWPBSSL.js → chunk-2AJ4NJUF.js} +8 -9
  19. package/dist/chunk-2AJ4NJUF.js.map +1 -0
  20. package/dist/{chunk-MQPC3P4T.js → chunk-2DGLWTPS.js} +3 -3
  21. package/dist/chunk-2DGLWTPS.js.map +1 -0
  22. package/dist/{chunk-DZU6RMYD.js → chunk-3DHNN5V7.js} +15 -9
  23. package/dist/chunk-3DHNN5V7.js.map +1 -0
  24. package/dist/{chunk-TFJDIOFK.js → chunk-4E5IUZHR.js} +3 -3
  25. package/dist/chunk-4E5IUZHR.js.map +1 -0
  26. package/dist/{chunk-HAQWKORZ.js → chunk-4JO5GSSD.js} +1 -37
  27. package/dist/chunk-4JO5GSSD.js.map +1 -0
  28. package/dist/{chunk-APNIVNIX.js → chunk-IBDTAMPF.js} +3 -4
  29. package/dist/chunk-IBDTAMPF.js.map +1 -0
  30. package/dist/{chunk-LYOPPBMC.js → chunk-KIBICUZK.js} +2 -2
  31. package/dist/{chunk-HBZPJ3EP.js → chunk-NJFCSVPT.js} +2 -2
  32. package/dist/{chunk-KM6VAKIE.js → chunk-RE5WJ4QP.js} +2 -2
  33. package/dist/chunk-RE5WJ4QP.js.map +1 -0
  34. package/dist/{chunk-CHOJUCVE.js → chunk-SJS6RJIT.js} +15 -9
  35. package/dist/chunk-SJS6RJIT.js.map +1 -0
  36. package/dist/{chunk-6ZYRUOTA.js → chunk-UV4HBVH7.js} +15 -9
  37. package/dist/chunk-UV4HBVH7.js.map +1 -0
  38. package/dist/command.js +2 -2
  39. package/dist/confirm-button.d.ts +1 -1
  40. package/dist/confirm-button.js +1 -1
  41. package/dist/continue-prompt.js +14 -8
  42. package/dist/continue-prompt.js.map +1 -1
  43. package/dist/data-table.js +2 -2
  44. package/dist/dialog.js +2 -2
  45. package/dist/engine-flow.d.ts +25 -2
  46. package/dist/engine-flow.js +27 -6
  47. package/dist/engine-flow.js.map +1 -1
  48. package/dist/force-update-screen.js +2 -2
  49. package/dist/force-update-screen.js.map +1 -1
  50. package/dist/genui.js +3 -3
  51. package/dist/glow-card.d.ts +5 -4
  52. package/dist/glow-card.js +2 -8
  53. package/dist/glow-card.js.map +1 -1
  54. package/dist/image-cropper.js +1 -1
  55. package/dist/index.js +4 -4
  56. package/dist/index.js.map +1 -1
  57. package/dist/iso.d.ts +1 -1
  58. package/dist/iso.js.map +1 -1
  59. package/dist/landscape.js +4 -4
  60. package/dist/landscape.js.map +1 -1
  61. package/dist/link-card.d.ts +3 -6
  62. package/dist/link-card.js +1 -1
  63. package/dist/maintenance-screen.js +1 -1
  64. package/dist/map.d.ts +50 -5
  65. package/dist/map.js +202 -66
  66. package/dist/map.js.map +1 -1
  67. package/dist/match-dialog.js +1 -1
  68. package/dist/media-gallery.js +1 -1
  69. package/dist/media-gallery.js.map +1 -1
  70. package/dist/media-grid.js +2 -2
  71. package/dist/motion.css +52 -122
  72. package/dist/motion.d.ts +2 -2
  73. package/dist/motion.js +1 -1
  74. package/dist/native/map.js +64 -64
  75. package/dist/native/map.js.map +1 -1
  76. package/dist/native.js +30 -30
  77. package/dist/native.js.map +1 -1
  78. package/dist/nav-bar.d.ts +12 -3
  79. package/dist/nav-bar.js +19 -12
  80. package/dist/nav-bar.js.map +1 -1
  81. package/dist/pointer-light.d.ts +6 -9
  82. package/dist/pointer-light.js +9 -5
  83. package/dist/pointer-light.js.map +1 -1
  84. package/dist/radio-group.js +2 -2
  85. package/dist/radio-group.js.map +1 -1
  86. package/dist/service-card.js +1 -1
  87. package/dist/service-card.js.map +1 -1
  88. package/dist/site-footer.d.ts +1 -1
  89. package/dist/site-footer.js +2 -2
  90. package/dist/{sites-CHp_vELn.d.ts → sites-B4prB793.d.ts} +2 -2
  91. package/dist/sites.d.ts +2 -2
  92. package/dist/sites.js +6 -7
  93. package/dist/sites.js.map +1 -1
  94. package/dist/slider.js +1 -1
  95. package/dist/slider.js.map +1 -1
  96. package/dist/story.css +5 -12
  97. package/dist/theme.d.ts +1 -1
  98. package/dist/theme.js +1 -1
  99. package/dist/update-prompt.js +2 -2
  100. package/dist/update-prompt.js.map +1 -1
  101. package/dist/vertical-video.js +1 -1
  102. package/dist/video-player.js +2 -2
  103. package/dist/video-player.js.map +1 -1
  104. package/package.json +5 -5
  105. package/registry/action-bar.json +1 -1
  106. package/registry/app-shell.json +4 -4
  107. package/registry/argument-card.json +7 -16
  108. package/registry/auth-layout.json +4 -4
  109. package/registry/button.json +20 -20
  110. package/registry/card-grid.json +21 -24
  111. package/registry/card.json +7 -7
  112. package/registry/component-page.json +2 -2
  113. package/registry/confirm-button.json +6 -6
  114. package/registry/contact-page.json +2 -2
  115. package/registry/cover-hero.json +3 -3
  116. package/registry/dashboard-layout.json +2 -2
  117. package/registry/detail-layout.json +4 -4
  118. package/registry/docs-hub-page.json +2 -2
  119. package/registry/empty-state.json +1 -1
  120. package/registry/engine-flow.json +74 -3
  121. package/registry/examples/app-shell/admin-console.js +1 -1
  122. package/registry/examples/app-shell/admin-console.tsx +1 -1
  123. package/registry/examples/app-shell/basic.js +1 -1
  124. package/registry/examples/app-shell/basic.tsx +1 -1
  125. package/registry/examples/app-shell/desktop.js +1 -1
  126. package/registry/examples/app-shell/desktop.tsx +1 -1
  127. package/registry/examples/app-shell/orochia-studio.js +1 -1
  128. package/registry/examples/app-shell/orochia-studio.tsx +1 -1
  129. package/registry/examples/argument-card/hover-quiet.js +1 -1
  130. package/registry/examples/argument-card/hover-quiet.tsx +1 -1
  131. package/registry/examples/auth-layout/onboarding.js +2 -2
  132. package/registry/examples/auth-layout/onboarding.tsx +2 -2
  133. package/registry/examples/auth-layout/sign-in.js +2 -2
  134. package/registry/examples/auth-layout/sign-in.tsx +2 -2
  135. package/registry/examples/auth-layout/verify.js +1 -1
  136. package/registry/examples/auth-layout/verify.tsx +1 -1
  137. package/registry/examples/avatar/native/presence.dark.png +0 -0
  138. package/registry/examples/avatar/native/presence.light.png +0 -0
  139. package/registry/examples/badge/native/tones.dark.png +0 -0
  140. package/registry/examples/badge/native/tones.light.png +0 -0
  141. package/registry/examples/button/native/disabled.dark.png +0 -0
  142. package/registry/examples/button/native/disabled.light.png +0 -0
  143. package/registry/examples/button/native/gradient.dark.png +0 -0
  144. package/registry/examples/button/native/gradient.light.png +0 -0
  145. package/registry/examples/button/native/icon-only.dark.png +0 -0
  146. package/registry/examples/button/native/icon-only.light.png +0 -0
  147. package/registry/examples/button/native/icon.dark.png +0 -0
  148. package/registry/examples/button/native/icon.light.png +0 -0
  149. package/registry/examples/button/native/loading.dark.png +0 -0
  150. package/registry/examples/button/native/loading.light.png +0 -0
  151. package/registry/examples/button/native/primary.dark.png +0 -0
  152. package/registry/examples/button/native/primary.light.png +0 -0
  153. package/registry/examples/button/native/sizes.dark.png +0 -0
  154. package/registry/examples/button/native/sizes.light.png +0 -0
  155. package/registry/examples/button/signature.js +2 -2
  156. package/registry/examples/button/signature.tsx +4 -4
  157. package/registry/examples/card/interactive-link.tsx +1 -1
  158. package/registry/examples/card/native/body.dark.png +0 -0
  159. package/registry/examples/card/native/body.light.png +0 -0
  160. package/registry/examples/card/native/default.dark.png +0 -0
  161. package/registry/examples/card/native/default.light.png +0 -0
  162. package/registry/examples/card/native/elevated.dark.png +0 -0
  163. package/registry/examples/card/native/elevated.light.png +0 -0
  164. package/registry/examples/card-grid/hover-quiet.js +1 -1
  165. package/registry/examples/card-grid/hover-quiet.tsx +1 -1
  166. package/registry/examples/chat/native/assistant.dark.png +0 -0
  167. package/registry/examples/chat/native/assistant.light.png +0 -0
  168. package/registry/examples/chat/native/conversation.dark.png +0 -0
  169. package/registry/examples/chat/native/conversation.light.png +0 -0
  170. package/registry/examples/chat/native/inbox.dark.png +0 -0
  171. package/registry/examples/chat/native/inbox.light.png +0 -0
  172. package/registry/examples/checkbox/native/terms.dark.png +0 -0
  173. package/registry/examples/checkbox/native/terms.light.png +0 -0
  174. package/registry/examples/chip/native/multiple.dark.png +0 -0
  175. package/registry/examples/chip/native/multiple.light.png +0 -0
  176. package/registry/examples/chip/native/single.dark.png +0 -0
  177. package/registry/examples/chip/native/single.light.png +0 -0
  178. package/registry/examples/chip/native/toggle.dark.png +0 -0
  179. package/registry/examples/chip/native/toggle.light.png +0 -0
  180. package/registry/examples/component-page/button.js +2 -2
  181. package/registry/examples/component-page/button.tsx +2 -2
  182. package/registry/examples/contact-page/team.js +1 -1
  183. package/registry/examples/contact-page/team.tsx +1 -1
  184. package/registry/examples/cover-hero/plain.js +1 -1
  185. package/registry/examples/cover-hero/plain.tsx +1 -1
  186. package/registry/examples/cover-hero/shop.js +1 -1
  187. package/registry/examples/cover-hero/shop.tsx +1 -1
  188. package/registry/examples/dashboard-layout/orazaka-eric.js +2 -2
  189. package/registry/examples/dashboard-layout/orazaka-eric.tsx +2 -2
  190. package/registry/examples/date-picker/native/calendar.dark.png +0 -0
  191. package/registry/examples/date-picker/native/calendar.light.png +0 -0
  192. package/registry/examples/date-picker/native/day-strip.dark.png +0 -0
  193. package/registry/examples/date-picker/native/day-strip.light.png +0 -0
  194. package/registry/examples/date-picker/native/month-year.dark.png +0 -0
  195. package/registry/examples/date-picker/native/month-year.light.png +0 -0
  196. package/registry/examples/date-picker/native/time-slots.dark.png +0 -0
  197. package/registry/examples/date-picker/native/time-slots.light.png +0 -0
  198. package/registry/examples/description-list/native/job-details.dark.png +0 -0
  199. package/registry/examples/description-list/native/job-details.light.png +0 -0
  200. package/registry/examples/detail-layout/checkout.js +1 -1
  201. package/registry/examples/detail-layout/checkout.tsx +1 -1
  202. package/registry/examples/detail-layout/job.js +1 -1
  203. package/registry/examples/detail-layout/job.tsx +1 -1
  204. package/registry/examples/detail-layout/video.js +2 -2
  205. package/registry/examples/detail-layout/video.tsx +2 -2
  206. package/registry/examples/dialog/native/sheet.dark.png +0 -0
  207. package/registry/examples/dialog/native/sheet.light.png +0 -0
  208. package/registry/examples/docs-hub-page/krizaka.js +1 -1
  209. package/registry/examples/docs-hub-page/krizaka.tsx +1 -1
  210. package/registry/examples/empty-state/library.js +1 -1
  211. package/registry/examples/empty-state/library.tsx +1 -1
  212. package/registry/examples/empty-state/native/default.dark.png +0 -0
  213. package/registry/examples/empty-state/native/default.light.png +0 -0
  214. package/registry/examples/fab/native/extended.dark.png +0 -0
  215. package/registry/examples/fab/native/extended.light.png +0 -0
  216. package/registry/examples/force-update-screen/native/default.dark.png +0 -0
  217. package/registry/examples/force-update-screen/native/default.light.png +0 -0
  218. package/registry/examples/form/native/amount.dark.png +0 -0
  219. package/registry/examples/form/native/amount.light.png +0 -0
  220. package/registry/examples/form/native/audience.dark.png +0 -0
  221. package/registry/examples/form/native/audience.light.png +0 -0
  222. package/registry/examples/form/native/profile.dark.png +0 -0
  223. package/registry/examples/form/native/profile.light.png +0 -0
  224. package/registry/examples/form/native/settings.dark.png +0 -0
  225. package/registry/examples/form/native/settings.light.png +0 -0
  226. package/registry/examples/form/native/sign-up.dark.png +0 -0
  227. package/registry/examples/form/native/sign-up.light.png +0 -0
  228. package/registry/examples/form/native/upload.dark.png +0 -0
  229. package/registry/examples/form/native/upload.light.png +0 -0
  230. package/registry/examples/glow-card/spotlight.tsx +1 -1
  231. package/registry/examples/goal-gauge/native/default.dark.png +0 -0
  232. package/registry/examples/goal-gauge/native/default.light.png +0 -0
  233. package/registry/examples/landing-page/krizaka.js +3 -3
  234. package/registry/examples/landing-page/krizaka.tsx +3 -3
  235. package/registry/examples/link-card/hover-quiet.js +1 -1
  236. package/registry/examples/link-card/hover-quiet.tsx +1 -1
  237. package/registry/examples/loader/native/block.dark.png +0 -0
  238. package/registry/examples/loader/native/block.light.png +0 -0
  239. package/registry/examples/map/native/location-picker.dark.png +0 -0
  240. package/registry/examples/map/native/location-picker.light.png +0 -0
  241. package/registry/examples/map/route.js +36 -0
  242. package/registry/examples/map/route.tsx +35 -0
  243. package/registry/examples/marketing-layout/pricing.js +1 -1
  244. package/registry/examples/marketing-layout/pricing.tsx +1 -1
  245. package/registry/examples/marketing-layout/product-page.js +1 -1
  246. package/registry/examples/marketing-layout/product-page.tsx +2 -2
  247. package/registry/examples/mascot-state/native/default.dark.png +0 -0
  248. package/registry/examples/mascot-state/native/default.light.png +0 -0
  249. package/registry/examples/mascots/native/crane.dark.png +0 -0
  250. package/registry/examples/mascots/native/crane.light.png +0 -0
  251. package/registry/examples/mascots/native/default.dark.png +0 -0
  252. package/registry/examples/mascots/native/default.light.png +0 -0
  253. package/registry/examples/mascots/native/lovebird.dark.png +0 -0
  254. package/registry/examples/mascots/native/lovebird.light.png +0 -0
  255. package/registry/examples/mascots/native/phoenix.dark.png +0 -0
  256. package/registry/examples/mascots/native/phoenix.light.png +0 -0
  257. package/registry/examples/match-dialog/native/its-a-match.dark.png +0 -0
  258. package/registry/examples/match-dialog/native/its-a-match.light.png +0 -0
  259. package/registry/examples/media-capture/native/photo.dark.png +0 -0
  260. package/registry/examples/media-capture/native/photo.light.png +0 -0
  261. package/registry/examples/meta-row/native/video.dark.png +0 -0
  262. package/registry/examples/meta-row/native/video.light.png +0 -0
  263. package/registry/examples/meter/native/credits.dark.png +0 -0
  264. package/registry/examples/meter/native/credits.light.png +0 -0
  265. package/registry/examples/meter/native/split-ring.dark.png +0 -0
  266. package/registry/examples/meter/native/split-ring.light.png +0 -0
  267. package/registry/examples/nav-bar/family-product.js +1 -1
  268. package/registry/examples/nav-bar/family-product.tsx +1 -1
  269. package/registry/examples/onboarding/native/first-launch.dark.png +0 -0
  270. package/registry/examples/onboarding/native/first-launch.light.png +0 -0
  271. package/registry/examples/permission-prompt/native/blocked.dark.png +0 -0
  272. package/registry/examples/permission-prompt/native/blocked.light.png +0 -0
  273. package/registry/examples/permission-prompt/native/camera.dark.png +0 -0
  274. package/registry/examples/permission-prompt/native/camera.light.png +0 -0
  275. package/registry/examples/photo-grid/native/profile-photos.dark.png +0 -0
  276. package/registry/examples/photo-grid/native/profile-photos.light.png +0 -0
  277. package/registry/examples/pricing-page/credits.js +3 -3
  278. package/registry/examples/pricing-page/credits.tsx +3 -3
  279. package/registry/examples/product-page/orazaka.js +2 -2
  280. package/registry/examples/product-page/orazaka.tsx +2 -2
  281. package/registry/examples/profile-card/native/default.dark.png +0 -0
  282. package/registry/examples/profile-card/native/default.light.png +0 -0
  283. package/registry/examples/progress/native/bar.dark.png +0 -0
  284. package/registry/examples/progress/native/bar.light.png +0 -0
  285. package/registry/examples/progress/native/indeterminate.dark.png +0 -0
  286. package/registry/examples/progress/native/indeterminate.light.png +0 -0
  287. package/registry/examples/progress/native/ring.dark.png +0 -0
  288. package/registry/examples/progress/native/ring.light.png +0 -0
  289. package/registry/examples/radio-group/native/buttons.dark.png +0 -0
  290. package/registry/examples/radio-group/native/buttons.light.png +0 -0
  291. package/registry/examples/radio-group/native/cards.dark.png +0 -0
  292. package/registry/examples/radio-group/native/cards.light.png +0 -0
  293. package/registry/examples/radio-group/native/list.dark.png +0 -0
  294. package/registry/examples/radio-group/native/list.light.png +0 -0
  295. package/registry/examples/screen/native/auth.dark.png +0 -0
  296. package/registry/examples/screen/native/auth.light.png +0 -0
  297. package/registry/examples/screen/native/chat.dark.png +0 -0
  298. package/registry/examples/screen/native/chat.light.png +0 -0
  299. package/registry/examples/screen/native/profile.dark.png +0 -0
  300. package/registry/examples/screen/native/profile.light.png +0 -0
  301. package/registry/examples/screen/native/settings.dark.png +0 -0
  302. package/registry/examples/screen/native/settings.light.png +0 -0
  303. package/registry/examples/search-field/native/cancel.dark.png +0 -0
  304. package/registry/examples/search-field/native/cancel.light.png +0 -0
  305. package/registry/examples/settings-layout/account.js +1 -1
  306. package/registry/examples/settings-layout/account.tsx +1 -1
  307. package/registry/examples/settings-layout/native/account.dark.png +0 -0
  308. package/registry/examples/settings-layout/native/account.light.png +0 -0
  309. package/registry/examples/settings-layout/sections.js +1 -1
  310. package/registry/examples/settings-layout/sections.tsx +1 -1
  311. package/registry/examples/showcase/native/slides.dark.png +0 -0
  312. package/registry/examples/showcase/native/slides.light.png +0 -0
  313. package/registry/examples/slider/native/default.dark.png +0 -0
  314. package/registry/examples/slider/native/default.light.png +0 -0
  315. package/registry/examples/slider/native/range.dark.png +0 -0
  316. package/registry/examples/slider/native/range.light.png +0 -0
  317. package/registry/examples/slider/native/stepped.dark.png +0 -0
  318. package/registry/examples/slider/native/stepped.light.png +0 -0
  319. package/registry/examples/slider/native/vertical.dark.png +0 -0
  320. package/registry/examples/slider/native/vertical.light.png +0 -0
  321. package/registry/examples/spinner/native/sizes.dark.png +0 -0
  322. package/registry/examples/spinner/native/sizes.light.png +0 -0
  323. package/registry/examples/split-view/messages.js +1 -1
  324. package/registry/examples/split-view/messages.tsx +1 -1
  325. package/registry/examples/status-page/building.js +1 -1
  326. package/registry/examples/status-page/building.tsx +1 -1
  327. package/registry/examples/step-progress/native/sign-up.dark.png +0 -0
  328. package/registry/examples/step-progress/native/sign-up.light.png +0 -0
  329. package/registry/examples/stepper/native/run.dark.png +0 -0
  330. package/registry/examples/stepper/native/run.light.png +0 -0
  331. package/registry/examples/sticky-action/phone.js +1 -1
  332. package/registry/examples/sticky-action/phone.tsx +1 -1
  333. package/registry/examples/switch/native/default.dark.png +0 -0
  334. package/registry/examples/switch/native/default.light.png +0 -0
  335. package/registry/examples/switch/native/settings.dark.png +0 -0
  336. package/registry/examples/switch/native/settings.light.png +0 -0
  337. package/registry/examples/tab-bar/native/main-sections.dark.png +0 -0
  338. package/registry/examples/tab-bar/native/main-sections.light.png +0 -0
  339. package/registry/examples/tabs/native/sections.dark.png +0 -0
  340. package/registry/examples/tabs/native/sections.light.png +0 -0
  341. package/registry/examples/tag-selector/native/interests.dark.png +0 -0
  342. package/registry/examples/tag-selector/native/interests.light.png +0 -0
  343. package/registry/examples/toast/native/snackbar.dark.png +0 -0
  344. package/registry/examples/toast/native/snackbar.light.png +0 -0
  345. package/registry/examples/toast/native/tones.dark.png +0 -0
  346. package/registry/examples/toast/native/tones.light.png +0 -0
  347. package/registry/examples/txt/native/tones.dark.png +0 -0
  348. package/registry/examples/txt/native/tones.light.png +0 -0
  349. package/registry/examples/update-prompt/native/default.dark.png +0 -0
  350. package/registry/examples/update-prompt/native/default.light.png +0 -0
  351. package/registry/examples/verified-badge/native/verified.dark.png +0 -0
  352. package/registry/examples/verified-badge/native/verified.light.png +0 -0
  353. package/registry/examples/vertical-video/native/rail.dark.png +0 -0
  354. package/registry/examples/vertical-video/native/rail.light.png +0 -0
  355. package/registry/examples/waveform/native/card.dark.png +0 -0
  356. package/registry/examples/waveform/native/card.light.png +0 -0
  357. package/registry/force-update-screen.json +1 -1
  358. package/registry/form.json +6 -6
  359. package/registry/glow-card.json +19 -19
  360. package/registry/index.json +20 -21
  361. package/registry/iso.json +7 -7
  362. package/registry/landing-page.json +2 -2
  363. package/registry/landscape.json +1 -1
  364. package/registry/link-card.json +15 -24
  365. package/registry/map.json +235 -6
  366. package/registry/marketing-layout.json +3 -3
  367. package/registry/media-gallery.json +1 -1
  368. package/registry/nav-bar.json +32 -4
  369. package/registry/pointer-light.json +17 -22
  370. package/registry/pricing-page.json +2 -2
  371. package/registry/product-page.json +2 -2
  372. package/registry/progress.json +2 -2
  373. package/registry/radio-group.json +1 -1
  374. package/registry/rail-nav.json +2 -2
  375. package/registry/service-card.json +1 -1
  376. package/registry/settings-layout.json +3 -3
  377. package/registry/site-footer.json +2 -2
  378. package/registry/sites.json +1 -1
  379. package/registry/slider.json +1 -1
  380. package/registry/split-view.json +2 -2
  381. package/registry/status-page.json +1 -1
  382. package/registry/sticky-action.json +2 -2
  383. package/registry/update-prompt.json +1 -1
  384. package/registry/video-player.json +1 -1
  385. package/dist/chunk-6ZYRUOTA.js.map +0 -1
  386. package/dist/chunk-AB5D3KBG.js +0 -37
  387. package/dist/chunk-AB5D3KBG.js.map +0 -1
  388. package/dist/chunk-APNIVNIX.js.map +0 -1
  389. package/dist/chunk-CHOJUCVE.js.map +0 -1
  390. package/dist/chunk-DZU6RMYD.js.map +0 -1
  391. package/dist/chunk-HAQWKORZ.js.map +0 -1
  392. package/dist/chunk-KM6VAKIE.js.map +0 -1
  393. package/dist/chunk-MQPC3P4T.js.map +0 -1
  394. package/dist/chunk-OUWPBSSL.js.map +0 -1
  395. package/dist/chunk-TFJDIOFK.js.map +0 -1
  396. package/registry/examples/argument-card/hover-light.js +0 -17
  397. package/registry/examples/argument-card/hover-light.tsx +0 -19
  398. package/registry/examples/link-card/hover-light.d.ts +0 -4
  399. package/registry/examples/link-card/hover-light.js +0 -18
  400. package/registry/examples/link-card/hover-light.tsx +0 -20
  401. /package/dist/{chunk-LYOPPBMC.js.map → chunk-KIBICUZK.js.map} +0 -0
  402. /package/dist/{chunk-HBZPJ3EP.js.map → chunk-NJFCSVPT.js.map} +0 -0
  403. /package/registry/examples/{argument-card/hover-light.d.ts → map/route.d.ts} +0 -0
@@ -333,7 +333,7 @@
333
333
  "why": "A creator moves between the sections of an app and reads this week's figures at home.",
334
334
  "path": "examples/app-shell/orochia-studio.tsx",
335
335
  "module": "@krizaka/ui/registry/examples/app-shell/orochia-studio",
336
- "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AppShell } from \"@krizaka/ui/app-shell\";\nimport { Avatar } from \"@krizaka/ui/avatar\";\nimport { Badge } from \"@krizaka/ui/badge\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { DashboardLayout, Widget } from \"@krizaka/ui/dashboard-layout\";\nimport { Meter } from \"@krizaka/ui/meter\";\nimport { Stat } from \"@krizaka/ui/stat\";\n\nconst icon = (d: string) => (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d={d} />\n </svg>\n);\nconst NAV = [\n { id: \"home\", label: \"Home\", d: \"M4 11 12 4l8 7v9H4z\", current: true },\n { id: \"videos\", label: \"Videos\", d: \"M4 6h12v12H4zM16 10l4-2v8l-4-2\", badge: 2 },\n { id: \"auctions\", label: \"Auctions\", d: \"M5 19h10M8 5l6 6M11 2l6 6M6 13l4-4\" },\n { id: \"challenges\", label: \"Challenges\", d: \"M12 3v18M5 7h10l-2 3 2 3H5\" },\n];\nconst MONEY = [\n { id: \"earnings\", label: \"Earnings\", d: \"M4 18h16M7 14l3-3 3 2 5-6\" },\n { id: \"payouts\", label: \"Payouts\", d: \"M3 7h18v10H3zM12 12h.01\" },\n];\nconst SALES = [\n { what: \"Unlock · “Night shoot, part 2”\", who: \"Léa M.\", net: \"€4.50\" },\n { what: \"Tip\", who: \"Samir K.\", net: \"€9.00\" },\n { what: \"Auction won · “Backstage cut”\", who: \"Inès B.\", net: \"€61.20\" },\n];\n\n// TEMPLATE — Orochia's creator studio, Elena's home: the shell (sidebar of the studio, drawer on a phone) around a\n// dashboard — this week's figures, the payout on its way, the latest sales, the next auction. On a phone the sidebar\n// is a drawer, the stats stack two by two, every widget takes the full width.\nexport default function AppShellOrochiaStudio() {\n return (\n <div className=\"brand-orochia\">\n <AppShell.Root>\n <AppShell.Sidebar\n label=\"Studio\"\n brand={<><ProductLogo id=\"orochia\" size={24} animated={false} /> Orochia</>}\n collapseLabels={[\"Collapse\", \"Expand\"]}\n closeLabel=\"Close the menu\"\n footer={\n <div className=\"flex items-center gap-2.5 px-2 py-2 text-sm\">\n <Avatar fallback=\"EV\" size=\"sm\" />\n <span className=\"min-w-0 truncate font-medium\">Elena Varga</span>\n </div>\n }\n >\n {NAV.map((n) => (\n <AppShell.Item key={n.id} href={`#${n.id}`} icon={icon(n.d)} label={n.label} current={n.current} badge={n.badge} />\n ))}\n <AppShell.Group>Money</AppShell.Group>\n {MONEY.map((n) => (\n <AppShell.Item key={n.id} href={`#${n.id}`} icon={icon(n.d)} label={n.label} />\n ))}\n </AppShell.Sidebar>\n <AppShell.Body>\n <AppShell.Header\n title=\"Studio\"\n menuLabel=\"Open the menu\"\n actions={<Button size=\"sm\" variant=\"primary\" shape=\"cut\">Upload a video</Button>}\n />\n <AppShell.Main>\n <DashboardLayout headingAs=\"h2\" eyebrow=\"This week\" title=\"Good morning, Elena\" description=\"Three sales since yesterday — your auction ends tonight.\">\n <Widget level={3} title=\"Your week\" span=\"full\">\n <div className=\"grid grid-cols-2 gap-6 md:grid-cols-4\">\n <Stat label=\"Views\" value=\"12.4k\" trend=\"up\" trendLabel=\"+8 %\" hint=\"7 days\" />\n <Stat label=\"Supporters\" value=\"318\" trend=\"up\" trendLabel=\"+21\" hint=\"7 days\" />\n <Stat label=\"Earned\" value=\"€902\" trend=\"up\" trendLabel=\"+14 %\" hint=\"after the 10 % fee\" />\n <Stat label=\"Unlocks\" value=\"146\" trend=\"flat\" trendLabel=\"±0\" hint=\"7 days\" />\n </div>\n </Widget>\n <Widget level={3} title=\"Next payout\" description=\"Every Monday, from €20\" span={2}>\n <Meter label=\"Towards your payout\" value={74} max={100} valueText=\"€74 of €100 goal\" showLabel />\n <p className=\"mt-3 text-sm text-fg-secondary\">€902 will reach your bank on Monday.</p>\n </Widget>\n <Widget level={3} title=\"Auction\" description=\"“Backstage cut”\" span={2} action={<Badge tone=\"accent\" dot>Open</Badge>}>\n <p className=\"font-display text-3xl font-extrabold text-fg\">€68</p>\n <p className=\"text-sm text-fg-secondary\">7 bids · ends tonight at 21:00</p>\n </Widget>\n <Widget level={3} title=\"Latest sales\" span=\"full\" action={<Button size=\"sm\" variant=\"ghost\">See all</Button>}>\n <ul className=\"divide-y divide-border-subtle\">\n {SALES.map((s) => (\n <li key={s.what} className=\"flex items-center justify-between gap-3 py-2.5 text-sm\">\n <span className=\"min-w-0\">\n <span className=\"block truncate font-medium text-fg\">{s.what}</span>\n <span className=\"text-fg-secondary\">{s.who}</span>\n </span>\n <span className=\"font-mono font-semibold text-fg-success\">{s.net}</span>\n </li>\n ))}\n </ul>\n </Widget>\n </DashboardLayout>\n </AppShell.Main>\n </AppShell.Body>\n </AppShell.Root>\n </div>\n );\n}\n"
336
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AppShell } from \"@krizaka/ui/app-shell\";\nimport { Avatar } from \"@krizaka/ui/avatar\";\nimport { Badge } from \"@krizaka/ui/badge\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { DashboardLayout, Widget } from \"@krizaka/ui/dashboard-layout\";\nimport { Meter } from \"@krizaka/ui/meter\";\nimport { Stat } from \"@krizaka/ui/stat\";\n\nconst icon = (d: string) => (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d={d} />\n </svg>\n);\nconst NAV = [\n { id: \"home\", label: \"Home\", d: \"M4 11 12 4l8 7v9H4z\", current: true },\n { id: \"videos\", label: \"Videos\", d: \"M4 6h12v12H4zM16 10l4-2v8l-4-2\", badge: 2 },\n { id: \"auctions\", label: \"Auctions\", d: \"M5 19h10M8 5l6 6M11 2l6 6M6 13l4-4\" },\n { id: \"challenges\", label: \"Challenges\", d: \"M12 3v18M5 7h10l-2 3 2 3H5\" },\n];\nconst MONEY = [\n { id: \"earnings\", label: \"Earnings\", d: \"M4 18h16M7 14l3-3 3 2 5-6\" },\n { id: \"payouts\", label: \"Payouts\", d: \"M3 7h18v10H3zM12 12h.01\" },\n];\nconst SALES = [\n { what: \"Unlock · “Night shoot, part 2”\", who: \"Léa M.\", net: \"€4.50\" },\n { what: \"Tip\", who: \"Samir K.\", net: \"€9.00\" },\n { what: \"Auction won · “Backstage cut”\", who: \"Inès B.\", net: \"€61.20\" },\n];\n\n// TEMPLATE — Orochia's creator studio, Elena's home: the shell (sidebar of the studio, drawer on a phone) around a\n// dashboard — this week's figures, the payout on its way, the latest sales, the next auction. On a phone the sidebar\n// is a drawer, the stats stack two by two, every widget takes the full width.\nexport default function AppShellOrochiaStudio() {\n return (\n <div className=\"brand-orochia\">\n <AppShell.Root>\n <AppShell.Sidebar\n label=\"Studio\"\n brand={<><ProductLogo id=\"orochia\" size={24} animated={false} /> Orochia</>}\n collapseLabels={[\"Collapse\", \"Expand\"]}\n closeLabel=\"Close the menu\"\n footer={\n <div className=\"flex items-center gap-2.5 px-2 py-2 text-sm\">\n <Avatar fallback=\"EV\" size=\"sm\" />\n <span className=\"min-w-0 truncate font-medium\">Elena Varga</span>\n </div>\n }\n >\n {NAV.map((n) => (\n <AppShell.Item key={n.id} href={`#${n.id}`} icon={icon(n.d)} label={n.label} current={n.current} badge={n.badge} />\n ))}\n <AppShell.Group>Money</AppShell.Group>\n {MONEY.map((n) => (\n <AppShell.Item key={n.id} href={`#${n.id}`} icon={icon(n.d)} label={n.label} />\n ))}\n </AppShell.Sidebar>\n <AppShell.Body>\n <AppShell.Header\n title=\"Studio\"\n menuLabel=\"Open the menu\"\n actions={<Button size=\"sm\" variant=\"primary\">Upload a video</Button>}\n />\n <AppShell.Main>\n <DashboardLayout headingAs=\"h2\" eyebrow=\"This week\" title=\"Good morning, Elena\" description=\"Three sales since yesterday — your auction ends tonight.\">\n <Widget level={3} title=\"Your week\" span=\"full\">\n <div className=\"grid grid-cols-2 gap-6 md:grid-cols-4\">\n <Stat label=\"Views\" value=\"12.4k\" trend=\"up\" trendLabel=\"+8 %\" hint=\"7 days\" />\n <Stat label=\"Supporters\" value=\"318\" trend=\"up\" trendLabel=\"+21\" hint=\"7 days\" />\n <Stat label=\"Earned\" value=\"€902\" trend=\"up\" trendLabel=\"+14 %\" hint=\"after the 10 % fee\" />\n <Stat label=\"Unlocks\" value=\"146\" trend=\"flat\" trendLabel=\"±0\" hint=\"7 days\" />\n </div>\n </Widget>\n <Widget level={3} title=\"Next payout\" description=\"Every Monday, from €20\" span={2}>\n <Meter label=\"Towards your payout\" value={74} max={100} valueText=\"€74 of €100 goal\" showLabel />\n <p className=\"mt-3 text-sm text-fg-secondary\">€902 will reach your bank on Monday.</p>\n </Widget>\n <Widget level={3} title=\"Auction\" description=\"“Backstage cut”\" span={2} action={<Badge tone=\"accent\" dot>Open</Badge>}>\n <p className=\"font-display text-3xl font-extrabold text-fg\">€68</p>\n <p className=\"text-sm text-fg-secondary\">7 bids · ends tonight at 21:00</p>\n </Widget>\n <Widget level={3} title=\"Latest sales\" span=\"full\" action={<Button size=\"sm\" variant=\"ghost\">See all</Button>}>\n <ul className=\"divide-y divide-border-subtle\">\n {SALES.map((s) => (\n <li key={s.what} className=\"flex items-center justify-between gap-3 py-2.5 text-sm\">\n <span className=\"min-w-0\">\n <span className=\"block truncate font-medium text-fg\">{s.what}</span>\n <span className=\"text-fg-secondary\">{s.who}</span>\n </span>\n <span className=\"font-mono font-semibold text-fg-success\">{s.net}</span>\n </li>\n ))}\n </ul>\n </Widget>\n </DashboardLayout>\n </AppShell.Main>\n </AppShell.Body>\n </AppShell.Root>\n </div>\n );\n}\n"
337
337
  },
338
338
  {
339
339
  "name": "admin-console",
@@ -344,7 +344,7 @@
344
344
  "why": "An administrator works a queue: scans it, sorts it and acts on many rows at once.",
345
345
  "path": "examples/app-shell/admin-console.tsx",
346
346
  "module": "@krizaka/ui/registry/examples/app-shell/admin-console",
347
- "code": "\"use client\";\n\nimport { ProductLogo } from \"@krizaka/ui\";\nimport { AppShell } from \"@krizaka/ui/app-shell\";\nimport { Badge } from \"@krizaka/ui/badge\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { DashboardLayout, Widget } from \"@krizaka/ui/dashboard-layout\";\nimport { DataTable, type DataTableColumn } from \"@krizaka/ui/data-table\";\n\nconst icon = (d: string) => (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d={d} />\n </svg>\n);\n\ntype Request = { id: string; creator: string; kind: string; status: \"pending\" | \"approved\" | \"refused\"; age: string };\nconst REQUESTS: Request[] = [\n { id: \"v-1042\", creator: \"Elena Varga\", kind: \"Identity check\", status: \"pending\", age: \"12 min\" },\n { id: \"v-1041\", creator: \"Noah Petit\", kind: \"Payout account\", status: \"pending\", age: \"40 min\" },\n { id: \"v-1039\", creator: \"Maya Chen\", kind: \"Identity check\", status: \"approved\", age: \"2 h\" },\n { id: \"v-1036\", creator: \"Tom Lebrun\", kind: \"Age check (18+)\", status: \"refused\", age: \"5 h\" },\n];\nconst tone = { pending: \"warning\", approved: \"success\", refused: \"danger\" } as const;\nconst columns: DataTableColumn<Request>[] = [\n { id: \"creator\", header: \"Creator\", sortable: true, card: \"title\" },\n { id: \"kind\", header: \"Request\" },\n { id: \"status\", header: \"Status\", cell: (r) => <Badge tone={tone[r.status]} dot>{r.status}</Badge> },\n { id: \"age\", header: \"Waiting\", align: \"end\" },\n];\n\n// TEMPLATE — an administration console (Orochia admin): the shell with the console's sections, a queue of requests to\n// review as a sortable table with bulk actions — cards on a phone — and the counts that say how long the queue is.\nexport default function AppShellAdminConsole() {\n return (\n <AppShell.Root>\n <AppShell.Sidebar label=\"Administration\" brand={<><ProductLogo id=\"orochia\" size={24} animated={false} /> Admin</>} closeLabel=\"Close the menu\" collapseLabels={[\"Collapse\", \"Expand\"]}>\n <AppShell.Group>Review</AppShell.Group>\n <AppShell.Item href=\"#verification\" icon={icon(\"M12 3l8 4v5c0 5-3.5 8-8 9-4.5-1-8-4-8-9V7z\")} label=\"Verification\" current badge={2} />\n <AppShell.Item href=\"#moderation\" icon={icon(\"M4 5h16v11H9l-5 4z\")} label=\"Moderation\" badge={5} />\n <AppShell.Group>Money</AppShell.Group>\n <AppShell.Item href=\"#payouts\" icon={icon(\"M3 7h18v10H3zM12 12h.01\")} label=\"Payouts\" />\n <AppShell.Item href=\"#ledger\" icon={icon(\"M5 4h14v16H5zM8 8h8M8 12h8M8 16h5\")} label=\"Ledger\" />\n <AppShell.Group>System</AppShell.Group>\n <AppShell.Item href=\"#backups\" icon={icon(\"M4 7c0-2 16-2 16 0v10c0 2-16 2-16 0zM4 12c0 2 16 2 16 0\")} label=\"Backups\" />\n </AppShell.Sidebar>\n <AppShell.Body>\n <AppShell.Header title=\"Verification\" menuLabel=\"Open the menu\" actions={<Button size=\"sm\" variant=\"secondary\" shape=\"cut\">Export</Button>} />\n <AppShell.Main>\n <DashboardLayout headingAs=\"h2\" title=\"Requests to review\" description=\"Oldest first. A decision is logged with your name.\">\n <Widget level={3} title=\"Pending\" description=\"identity and payout\">\n <p className=\"font-display text-3xl font-extrabold text-fg\">2</p>\n </Widget>\n <Widget level={3} title=\"Oldest wait\">\n <p className=\"font-display text-3xl font-extrabold text-fg\">40 min</p>\n </Widget>\n <Widget level={3} title=\"Queue\" span=\"full\">\n <DataTable caption=\"Verification requests\" rows={REQUESTS} columns={columns} getRowId={(r) => r.id} rowLabel={(r) => `${r.creator}, ${r.kind}`} selectable />\n </Widget>\n </DashboardLayout>\n </AppShell.Main>\n </AppShell.Body>\n </AppShell.Root>\n );\n}\n"
347
+ "code": "\"use client\";\n\nimport { ProductLogo } from \"@krizaka/ui\";\nimport { AppShell } from \"@krizaka/ui/app-shell\";\nimport { Badge } from \"@krizaka/ui/badge\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { DashboardLayout, Widget } from \"@krizaka/ui/dashboard-layout\";\nimport { DataTable, type DataTableColumn } from \"@krizaka/ui/data-table\";\n\nconst icon = (d: string) => (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d={d} />\n </svg>\n);\n\ntype Request = { id: string; creator: string; kind: string; status: \"pending\" | \"approved\" | \"refused\"; age: string };\nconst REQUESTS: Request[] = [\n { id: \"v-1042\", creator: \"Elena Varga\", kind: \"Identity check\", status: \"pending\", age: \"12 min\" },\n { id: \"v-1041\", creator: \"Noah Petit\", kind: \"Payout account\", status: \"pending\", age: \"40 min\" },\n { id: \"v-1039\", creator: \"Maya Chen\", kind: \"Identity check\", status: \"approved\", age: \"2 h\" },\n { id: \"v-1036\", creator: \"Tom Lebrun\", kind: \"Age check (18+)\", status: \"refused\", age: \"5 h\" },\n];\nconst tone = { pending: \"warning\", approved: \"success\", refused: \"danger\" } as const;\nconst columns: DataTableColumn<Request>[] = [\n { id: \"creator\", header: \"Creator\", sortable: true, card: \"title\" },\n { id: \"kind\", header: \"Request\" },\n { id: \"status\", header: \"Status\", cell: (r) => <Badge tone={tone[r.status]} dot>{r.status}</Badge> },\n { id: \"age\", header: \"Waiting\", align: \"end\" },\n];\n\n// TEMPLATE — an administration console (Orochia admin): the shell with the console's sections, a queue of requests to\n// review as a sortable table with bulk actions — cards on a phone — and the counts that say how long the queue is.\nexport default function AppShellAdminConsole() {\n return (\n <AppShell.Root>\n <AppShell.Sidebar label=\"Administration\" brand={<><ProductLogo id=\"orochia\" size={24} animated={false} /> Admin</>} closeLabel=\"Close the menu\" collapseLabels={[\"Collapse\", \"Expand\"]}>\n <AppShell.Group>Review</AppShell.Group>\n <AppShell.Item href=\"#verification\" icon={icon(\"M12 3l8 4v5c0 5-3.5 8-8 9-4.5-1-8-4-8-9V7z\")} label=\"Verification\" current badge={2} />\n <AppShell.Item href=\"#moderation\" icon={icon(\"M4 5h16v11H9l-5 4z\")} label=\"Moderation\" badge={5} />\n <AppShell.Group>Money</AppShell.Group>\n <AppShell.Item href=\"#payouts\" icon={icon(\"M3 7h18v10H3zM12 12h.01\")} label=\"Payouts\" />\n <AppShell.Item href=\"#ledger\" icon={icon(\"M5 4h14v16H5zM8 8h8M8 12h8M8 16h5\")} label=\"Ledger\" />\n <AppShell.Group>System</AppShell.Group>\n <AppShell.Item href=\"#backups\" icon={icon(\"M4 7c0-2 16-2 16 0v10c0 2-16 2-16 0zM4 12c0 2 16 2 16 0\")} label=\"Backups\" />\n </AppShell.Sidebar>\n <AppShell.Body>\n <AppShell.Header title=\"Verification\" menuLabel=\"Open the menu\" actions={<Button size=\"sm\" variant=\"secondary\">Export</Button>} />\n <AppShell.Main>\n <DashboardLayout headingAs=\"h2\" title=\"Requests to review\" description=\"Oldest first. A decision is logged with your name.\">\n <Widget level={3} title=\"Pending\" description=\"identity and payout\">\n <p className=\"font-display text-3xl font-extrabold text-fg\">2</p>\n </Widget>\n <Widget level={3} title=\"Oldest wait\">\n <p className=\"font-display text-3xl font-extrabold text-fg\">40 min</p>\n </Widget>\n <Widget level={3} title=\"Queue\" span=\"full\">\n <DataTable caption=\"Verification requests\" rows={REQUESTS} columns={columns} getRowId={(r) => r.id} rowLabel={(r) => `${r.creator}, ${r.kind}`} selectable />\n </Widget>\n </DashboardLayout>\n </AppShell.Main>\n </AppShell.Body>\n </AppShell.Root>\n );\n}\n"
348
348
  },
349
349
  {
350
350
  "name": "basic",
@@ -352,7 +352,7 @@
352
352
  "description": "Sidebar with a group and a count, header with an action, the content.",
353
353
  "path": "examples/app-shell/basic.tsx",
354
354
  "module": "@krizaka/ui/registry/examples/app-shell/basic",
355
- "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AppShell } from \"@krizaka/ui/app-shell\";\nimport { Button } from \"@krizaka/ui/button\";\n\nconst dot = <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden><circle cx=\"12\" cy=\"12\" r=\"7\" /></svg>;\n\n// The shell alone: the sidebar (it collapses to its icons on a desktop, opens as a drawer on a phone), the header, the\n// content. Your router's links go in `AppShell.Item asChild`.\nexport default function AppShellBasic() {\n return (\n <AppShell.Root className=\"min-h-[32rem]\">\n <AppShell.Sidebar\n label=\"Studio\"\n brand={<><ProductLogo id=\"orochia\" size={24} animated={false} /> Studio</>}\n collapseLabels={[\"Collapse\", \"Expand\"]}\n closeLabel=\"Close the menu\"\n >\n <AppShell.Item href=\"#home\" icon={dot} label=\"Home\" current />\n <AppShell.Item href=\"#videos\" icon={dot} label=\"Videos\" badge={3} />\n <AppShell.Group>Money</AppShell.Group>\n <AppShell.Item href=\"#earnings\" icon={dot} label=\"Earnings\" />\n </AppShell.Sidebar>\n <AppShell.Body>\n <AppShell.Header title=\"Home\" menuLabel=\"Open the menu\" actions={<Button size=\"sm\" variant=\"primary\" shape=\"cut\">Upload</Button>} />\n <AppShell.Main>\n <p className=\"text-sm text-fg-secondary\">The screen's content.</p>\n </AppShell.Main>\n </AppShell.Body>\n </AppShell.Root>\n );\n}\n"
355
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AppShell } from \"@krizaka/ui/app-shell\";\nimport { Button } from \"@krizaka/ui/button\";\n\nconst dot = <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden><circle cx=\"12\" cy=\"12\" r=\"7\" /></svg>;\n\n// The shell alone: the sidebar (it collapses to its icons on a desktop, opens as a drawer on a phone), the header, the\n// content. Your router's links go in `AppShell.Item asChild`.\nexport default function AppShellBasic() {\n return (\n <AppShell.Root className=\"min-h-[32rem]\">\n <AppShell.Sidebar\n label=\"Studio\"\n brand={<><ProductLogo id=\"orochia\" size={24} animated={false} /> Studio</>}\n collapseLabels={[\"Collapse\", \"Expand\"]}\n closeLabel=\"Close the menu\"\n >\n <AppShell.Item href=\"#home\" icon={dot} label=\"Home\" current />\n <AppShell.Item href=\"#videos\" icon={dot} label=\"Videos\" badge={3} />\n <AppShell.Group>Money</AppShell.Group>\n <AppShell.Item href=\"#earnings\" icon={dot} label=\"Earnings\" />\n </AppShell.Sidebar>\n <AppShell.Body>\n <AppShell.Header title=\"Home\" menuLabel=\"Open the menu\" actions={<Button size=\"sm\" variant=\"primary\">Upload</Button>} />\n <AppShell.Main>\n <p className=\"text-sm text-fg-secondary\">The screen's content.</p>\n </AppShell.Main>\n </AppShell.Body>\n </AppShell.Root>\n );\n}\n"
356
356
  },
357
357
  {
358
358
  "name": "desktop",
@@ -360,7 +360,7 @@
360
360
  "description": "The Orazaka Mac app's window (`desktop`): the title bar moves the window and clears the traffic lights, no drawer, the desktop's density, ⌘1–⌘3 to the sections.",
361
361
  "path": "examples/app-shell/desktop.tsx",
362
362
  "module": "@krizaka/ui/registry/examples/app-shell/desktop",
363
- "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AppShell } from \"@krizaka/ui/app-shell\";\nimport { Badge } from \"@krizaka/ui/badge\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Progress } from \"@krizaka/ui/progress\";\n\nconst dot = <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden><circle cx=\"12\" cy=\"12\" r=\"7\" /></svg>;\n\n// The Mac app's window (Tauri 2, ADR-002): `desktop` — the title bar moves the window and clears the traffic lights, no\n// drawer, desktop density. The menu bar answers the same keys (`acceleratorOf(\"mod+1\")` → `CmdOrCtrl+1`).\nexport default function AppShellDesktop() {\n return (\n <AppShell.Root desktop style={{ [\"--kz-window-height\" as string]: \"34rem\" }}>\n <AppShell.Sidebar label=\"Orazaka\" brand={<><ProductLogo id=\"orazaka\" size={22} animated={false} /> Orazaka</>} collapseLabels={[\"Collapse\", \"Expand\"]} closeLabel=\"Close\">\n <AppShell.Item href=\"#workspace\" icon={dot} label=\"Workspace\" shortcut=\"mod+1\" />\n <AppShell.Item href=\"#models\" icon={dot} label=\"Models\" shortcut=\"mod+2\" current />\n <AppShell.Item href=\"#jobs\" icon={dot} label=\"Jobs\" shortcut=\"mod+3\" badge={2} />\n <AppShell.Group>Machine</AppShell.Group>\n <AppShell.Item href=\"#backups\" icon={dot} label=\"Backups\" />\n <AppShell.Item href=\"#logs\" icon={dot} label=\"Logs\" />\n </AppShell.Sidebar>\n <AppShell.Body>\n <AppShell.Header title=\"Models\" menuLabel=\"Open the menu\" actions={<Button size=\"sm\" variant=\"primary\" shape=\"cut\">Add a model</Button>} />\n <AppShell.Main className=\"space-y-4\">\n <div className=\"flex items-center justify-between gap-3 rounded-lg border border-border-subtle bg-surface-1 p-4\">\n <div className=\"min-w-0 flex-1 space-y-2\">\n <p className=\"text-sm font-semibold\">qwen2.5 7B · chat</p>\n <Progress value={64} label=\"Downloading qwen2.5 7B\" />\n </div>\n <Badge tone=\"accent\">3.1 of 4.8 GB</Badge>\n </div>\n <p className=\"text-[13px] text-fg-secondary\">Models run on this Mac (Metal). Nothing leaves your network.</p>\n </AppShell.Main>\n </AppShell.Body>\n </AppShell.Root>\n );\n}\n"
363
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AppShell } from \"@krizaka/ui/app-shell\";\nimport { Badge } from \"@krizaka/ui/badge\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Progress } from \"@krizaka/ui/progress\";\n\nconst dot = <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden><circle cx=\"12\" cy=\"12\" r=\"7\" /></svg>;\n\n// The Mac app's window (Tauri 2, ADR-002): `desktop` — the title bar moves the window and clears the traffic lights, no\n// drawer, desktop density. The menu bar answers the same keys (`acceleratorOf(\"mod+1\")` → `CmdOrCtrl+1`).\nexport default function AppShellDesktop() {\n return (\n <AppShell.Root desktop style={{ [\"--kz-window-height\" as string]: \"34rem\" }}>\n <AppShell.Sidebar label=\"Orazaka\" brand={<><ProductLogo id=\"orazaka\" size={22} animated={false} /> Orazaka</>} collapseLabels={[\"Collapse\", \"Expand\"]} closeLabel=\"Close\">\n <AppShell.Item href=\"#workspace\" icon={dot} label=\"Workspace\" shortcut=\"mod+1\" />\n <AppShell.Item href=\"#models\" icon={dot} label=\"Models\" shortcut=\"mod+2\" current />\n <AppShell.Item href=\"#jobs\" icon={dot} label=\"Jobs\" shortcut=\"mod+3\" badge={2} />\n <AppShell.Group>Machine</AppShell.Group>\n <AppShell.Item href=\"#backups\" icon={dot} label=\"Backups\" />\n <AppShell.Item href=\"#logs\" icon={dot} label=\"Logs\" />\n </AppShell.Sidebar>\n <AppShell.Body>\n <AppShell.Header title=\"Models\" menuLabel=\"Open the menu\" actions={<Button size=\"sm\" variant=\"primary\">Add a model</Button>} />\n <AppShell.Main className=\"space-y-4\">\n <div className=\"flex items-center justify-between gap-3 rounded-lg border border-border-subtle bg-surface-1 p-4\">\n <div className=\"min-w-0 flex-1 space-y-2\">\n <p className=\"text-sm font-semibold\">qwen2.5 7B · chat</p>\n <Progress value={64} label=\"Downloading qwen2.5 7B\" />\n </div>\n <Badge tone=\"accent\">3.1 of 4.8 GB</Badge>\n </div>\n <p className=\"text-[13px] text-fg-secondary\">Models run on this Mac (Metal). Nothing leaves your network.</p>\n </AppShell.Main>\n </AppShell.Body>\n </AppShell.Root>\n );\n}\n"
364
364
  }
365
365
  ]
366
366
  },
@@ -41,8 +41,7 @@
41
41
  "What it does, the bird's quote and the long version are never on the face: a detail page (`more`), or `panelLabel`.",
42
42
  "One idea per card; one bird per idea: small in the corner (`mark`), its quote (`rule`) where the card unfolds.",
43
43
  "Give each subject its hue with `--kz-hue` on the card (or a wrapper); the brand's accent otherwise.",
44
- "Secondary actions as an icon `ActionBar` in `actions`; the way in as `more`.",
45
- "`hover=\"quiet\"` for reasons read as prose (a product's argument, a policy): no glow, a lift and a ring on focus. The default `light` keeps the pointer's light."
44
+ "Secondary actions as an icon `ActionBar` in `actions`; the way in as `more`."
46
45
  ],
47
46
  "accessibility": {
48
47
  "keyboard": [
@@ -54,7 +53,7 @@
54
53
  "notes": [
55
54
  "An `article` named by its title; the hook's label is read before the line (visually hidden); the fold is a native `details` element.",
56
55
  "The way in is described by the card's title (`aria-describedby`), so several `Read more` links stay distinct.",
57
- "The lift, the light and the panel's chevron stop under `prefers-reduced-motion`; the quiet hover keeps its surface and ring, and never lifts."
56
+ "One quiet hover (krizaka-ui#393): the surface and the hairline go one step up in a short colour transition — nothing moves, no light follows the pointer; a ring on the whole card when a link inside takes the keyboard focus. The panel's chevron stops under `prefers-reduced-motion`."
58
57
  ]
59
58
  },
60
59
  "related": [
@@ -109,7 +108,7 @@
109
108
  "name": "hover",
110
109
  "type": "CardHover",
111
110
  "default": null,
112
- "description": "The hover of the card: `light` (the pointer's light, the default) or `quiet` (no glow, a lift, a ring on focus).",
111
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — every card has the one quiet hover. Removed in 4.0.",
113
112
  "required": false
114
113
  },
115
114
  {
@@ -203,21 +202,13 @@
203
202
  "module": "@krizaka/ui/registry/examples/argument-card/grid",
204
203
  "code": "import { ArgumentCard } from \"@krizaka/ui/argument-card\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\n\nconst reasons = [\n { id: \"local\", title: \"Local inference\", hook: \"Elsewhere, every prompt crosses the ocean.\" },\n { id: \"pipeline\", title: \"One pipeline\", hook: \"Elsewhere, each feature guards itself — or forgets.\" },\n { id: \"telemetry\", title: \"Zero telemetry\", hook: \"Elsewhere, usage data is the price of the free tier.\" },\n];\n\n// A product page's reasons, side by side: each card the same height, the hook at the same place on every card.\nexport default function ArgumentCardGrid() {\n return (\n <CardGrid className=\"w-full max-w-5xl\" min={260} reveal={false}>\n {reasons.map((r) => (\n <ArgumentCard key={r.id} id={`why-${r.id}`} title={r.title} hook={{ label: \"The trap elsewhere\", text: r.hook }} more={{ href: `#${r.id}`, label: \"Details\" }} />\n ))}\n </CardGrid>\n );\n}\n"
205
204
  },
206
- {
207
- "name": "hover-light",
208
- "title": "The light hover",
209
- "description": "`hover=\"light\"`, the default: the pointer's light and the coloured lift, said explicitly.",
210
- "path": "examples/argument-card/hover-light.tsx",
211
- "module": "@krizaka/ui/registry/examples/argument-card/hover-light",
212
- "code": "import { ArgumentCard } from \"@krizaka/ui/argument-card\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\n\nconst reasons = [\n { id: \"local\", title: \"Local inference\", hook: \"Elsewhere, every prompt crosses the ocean.\" },\n { id: \"pipeline\", title: \"One pipeline\", hook: \"Elsewhere, each feature guards itself — or forgets.\" },\n { id: \"telemetry\", title: \"Zero telemetry\", hook: \"Elsewhere, usage data is the price of the free tier.\" },\n];\n\n// The default hover, said explicitly: the pointer's light on the reasons.\nexport default function ArgumentCardHoverLight() {\n return (\n <CardGrid className=\"w-full max-w-5xl\" min={260} reveal={false}>\n {reasons.map((r) => (\n <ArgumentCard key={r.id} hover=\"light\" id={`light-${r.id}`} title={r.title} hook={{ label: \"The trap elsewhere\", text: r.hook }} more={{ href: `#${r.id}`, label: \"Details\" }} />\n ))}\n </CardGrid>\n );\n}\n"
213
- },
214
205
  {
215
206
  "name": "hover-quiet",
216
207
  "title": "The quiet hover",
217
208
  "description": "`hover=\"quiet\"` on a grid of reasons: no glow, a lift, a ring on focus.",
218
209
  "path": "examples/argument-card/hover-quiet.tsx",
219
210
  "module": "@krizaka/ui/registry/examples/argument-card/hover-quiet",
220
- "code": "import { ArgumentCard } from \"@krizaka/ui/argument-card\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\n\nconst reasons = [\n { id: \"local\", title: \"Local inference\", hook: \"Elsewhere, every prompt crosses the ocean.\" },\n { id: \"pipeline\", title: \"One pipeline\", hook: \"Elsewhere, each feature guards itself — or forgets.\" },\n { id: \"telemetry\", title: \"Zero telemetry\", hook: \"Elsewhere, usage data is the price of the free tier.\" },\n];\n\n// The quiet hover on the reasons: no glow, a lift, a ring on focus. The grid is quiet, so every card is.\nexport default function ArgumentCardHoverQuiet() {\n return (\n <CardGrid className=\"w-full max-w-5xl\" min={260} reveal={false} hover=\"quiet\">\n {reasons.map((r) => (\n <ArgumentCard key={r.id} id={`quiet-${r.id}`} title={r.title} hook={{ label: \"The trap elsewhere\", text: r.hook }} more={{ href: `#${r.id}`, label: \"Details\" }} />\n ))}\n </CardGrid>\n );\n}\n"
211
+ "code": "import { ArgumentCard } from \"@krizaka/ui/argument-card\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\n\nconst reasons = [\n { id: \"local\", title: \"Local inference\", hook: \"Elsewhere, every prompt crosses the ocean.\" },\n { id: \"pipeline\", title: \"One pipeline\", hook: \"Elsewhere, each feature guards itself — or forgets.\" },\n { id: \"telemetry\", title: \"Zero telemetry\", hook: \"Elsewhere, usage data is the price of the free tier.\" },\n];\n\n// The quiet hover on the reasons: no glow, a lift, a ring on focus. The grid is quiet, so every card is.\nexport default function ArgumentCardHoverQuiet() {\n return (\n <CardGrid className=\"w-full max-w-5xl\" min={260} reveal={false}>\n {reasons.map((r) => (\n <ArgumentCard key={r.id} id={`quiet-${r.id}`} title={r.title} hook={{ label: \"The trap elsewhere\", text: r.hook }} more={{ href: `#${r.id}`, label: \"Details\" }} />\n ))}\n </CardGrid>\n );\n}\n"
221
212
  }
222
213
  ]
223
214
  },
@@ -225,7 +216,7 @@
225
216
  "files": [
226
217
  {
227
218
  "path": "argument-card/argument-card.tsx",
228
- "content": "// Server-safe. A card that argues (blocks.css), compact: who (icon, name, facts) → the trap in one line → the way in.\n// The long version — what it does, the rule a bird stands for, the reasons — waits in a panel the reader opens (a\n// native <details>: keyboard, screen readers, no script). Cards of a row share their height; the panel and the foot\n// sit at the bottom, at the same place on every card.\nimport type * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { ArrowGlyph, ChevronGlyph } from \"../glyphs\";\nimport { type CardHover, cardHoverClass } from \"../link-card/link-card\";\nimport { type Fact, Facts } from \"../page/page\";\n\nexport type ArgumentCardProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The id of the title: the card's accessible name. */\n id: string;\n /** The title: the subject (a building block, a feature, a plan). */\n title: React.ReactNode;\n /** The icon tile (a signature icon): decorative. */\n icon?: React.ReactNode;\n /** A mono line under the title (a repository, a package). */\n meta?: React.ReactNode;\n /** Small, in the top corner: the bird whose rule it is (a `Mascot` of 40 px, still). Decorative. */\n mark?: React.ReactNode;\n /** Compact facts under the line: registry and version, a status said honestly. */\n facts?: readonly Fact[];\n /**\n * The problem in ONE line (≤ 90 characters): what a reader keeps if they read nothing else. `label` (`The trap`) is\n * read by assistive technology before it, not shown.\n */\n hook: { label: React.ReactNode; text: React.ReactNode };\n /** Unfolded only: what it does, as a few short points, with their label (`What it does`). */\n points?: { label: React.ReactNode; items: readonly React.ReactNode[] };\n /** Unfolded only: the rule told by a bird (a `MascotQuote`, `variant=\"inline\"`). */\n rule?: React.ReactNode;\n /** Unfolded only: the long version, as labelled paragraphs. */\n details?: readonly { label: React.ReactNode; text: React.ReactNode }[];\n /**\n * Without a detail page: the words that unfold the card in place (`Details`) — a native `<details>` holding the\n * points, the rule and the long version. Ignored with `more`: the detail page holds them.\n */\n panelLabel?: React.ReactNode;\n /** The way in: a detail page — one short action at the foot (`Details`). With it, the card is only its face. */\n more?: { href: string; label: React.ReactNode };\n /** Discreet secondary actions at the foot, on the right (an `ActionBar` with `variant=\"icons\"`). */\n actions?: React.ReactNode;\n /**\n * The title's level.\n * @default 3\n */\n level?: 2 | 3 | 4;\n /** The app's link component for internal addresses (Next's `Link`); an `<a>` otherwise. */\n linkAs?: LinkComponent;\n /** The hover of the card: `light` (the pointer's light, the default) or `quiet` (no glow, a lift, a ring on focus). */\n hover?: CardHover;\n};\n\n/**\n * A card that argues, compact (about a third of a full card): who (icon, name, meta; the bird small in the corner) →\n * the problem in one line → compact facts → one short action. What it does, the bird's rule and the long version are\n * never on the face: they live on the detail page (`more`) or in the card unfolded in place (`panelLabel`).\n */\nexport function ArgumentCard({ id, title, icon, meta, mark, facts, hook, points, rule, details, panelLabel, more, actions, level = 3, linkAs, hover, className, ...props }: ArgumentCardProps) {\n const H = `h${level}` as \"h2\" | \"h3\" | \"h4\";\n const fold = !more && panelLabel && (points || rule || (details && details.length > 0));\n return (\n <article className={cn(\"kz-block-card kz-arg\", cardHoverClass(hover), className)} data-kz-light=\"\" aria-labelledby={id} {...props}>\n <div className=\"kz-arg-head\">\n {icon && (\n <span className=\"kz-block-icon\" aria-hidden>\n {icon}\n </span>\n )}\n <div className=\"kz-arg-id\">\n <H id={id} className=\"kz-arg-title\">\n {title}\n </H>\n {meta && <p className=\"kz-arg-meta\">{meta}</p>}\n </div>\n {mark && (\n <span className=\"kz-arg-mark\" aria-hidden>\n {mark}\n </span>\n )}\n </div>\n <p className=\"kz-arg-line\">\n <span className=\"kz-sr-only\">{hook.label} — </span>\n {hook.text}\n </p>\n {facts && facts.length > 0 && <Facts items={facts} />}\n {fold && (\n <details className=\"kz-arg-panel\">\n <summary>\n {panelLabel} <ChevronGlyph className=\"h-3.5 w-3.5\" />\n </summary>\n <div className=\"kz-arg-panel-body\">\n {points && (\n <div>\n <p className=\"kz-label\">{points.label}</p>\n <ul className=\"kz-list\">\n {points.items.map((item, i) => (\n <li key={i}>{item}</li>\n ))}\n </ul>\n </div>\n )}\n {details && details.length > 0 && (\n <dl>\n {details.map((d, i) => (\n <div key={i}>\n <dt className=\"kz-label\">{d.label}</dt>\n <dd>{d.text}</dd>\n </div>\n ))}\n </dl>\n )}\n {rule}\n </div>\n </details>\n )}\n {(more || actions) && (\n <div className=\"kz-arg-foot\">\n {more ? (\n <BlockLink href={more.href} linkAs={linkAs} className=\"kz-arg-more\" aria-describedby={id}>\n {more.label} <ArrowGlyph className=\"h-3.5 w-3.5\" />\n </BlockLink>\n ) : (\n <span />\n )}\n {actions}\n </div>\n )}\n </article>\n );\n}\n"
219
+ "content": "// Server-safe. A card that argues (blocks.css), compact: who (icon, name, facts) → the trap in one line → the way in.\n// The long version — what it does, the rule a bird stands for, the reasons — waits in a panel the reader opens (a\n// native <details>: keyboard, screen readers, no script). Cards of a row share their height; the panel and the foot\n// sit at the bottom, at the same place on every card.\nimport type * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { ArrowGlyph, ChevronGlyph } from \"../glyphs\";\nimport { type CardHover, cardHoverClass } from \"../link-card/link-card\";\nimport { type Fact, Facts } from \"../page/page\";\n\nexport type ArgumentCardProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The id of the title: the card's accessible name. */\n id: string;\n /** The title: the subject (a building block, a feature, a plan). */\n title: React.ReactNode;\n /** The icon tile (a signature icon): decorative. */\n icon?: React.ReactNode;\n /** A mono line under the title (a repository, a package). */\n meta?: React.ReactNode;\n /** Small, in the top corner: the bird whose rule it is (a `Mascot` of 40 px, still). Decorative. */\n mark?: React.ReactNode;\n /** Compact facts under the line: registry and version, a status said honestly. */\n facts?: readonly Fact[];\n /**\n * The problem in ONE line (≤ 90 characters): what a reader keeps if they read nothing else. `label` (`The trap`) is\n * read by assistive technology before it, not shown.\n */\n hook: { label: React.ReactNode; text: React.ReactNode };\n /** Unfolded only: what it does, as a few short points, with their label (`What it does`). */\n points?: { label: React.ReactNode; items: readonly React.ReactNode[] };\n /** Unfolded only: the rule told by a bird (a `MascotQuote`, `variant=\"inline\"`). */\n rule?: React.ReactNode;\n /** Unfolded only: the long version, as labelled paragraphs. */\n details?: readonly { label: React.ReactNode; text: React.ReactNode }[];\n /**\n * Without a detail page: the words that unfold the card in place (`Details`) — a native `<details>` holding the\n * points, the rule and the long version. Ignored with `more`: the detail page holds them.\n */\n panelLabel?: React.ReactNode;\n /** The way in: a detail page — one short action at the foot (`Details`). With it, the card is only its face. */\n more?: { href: string; label: React.ReactNode };\n /** Discreet secondary actions at the foot, on the right (an `ActionBar` with `variant=\"icons\"`). */\n actions?: React.ReactNode;\n /**\n * The title's level.\n * @default 3\n */\n level?: 2 | 3 | 4;\n /** The app's link component for internal addresses (Next's `Link`); an `<a>` otherwise. */\n linkAs?: LinkComponent;\n /** @deprecated Since 3.31 (krizaka-ui#393): does nothing — every card has the one quiet hover. Removed in 4.0. */\n hover?: CardHover;\n};\n\n/**\n * A card that argues, compact (about a third of a full card): who (icon, name, meta; the bird small in the corner) →\n * the problem in one line → compact facts → one short action. What it does, the bird's rule and the long version are\n * never on the face: they live on the detail page (`more`) or in the card unfolded in place (`panelLabel`).\n */\nexport function ArgumentCard({ id, title, icon, meta, mark, facts, hook, points, rule, details, panelLabel, more, actions, level = 3, linkAs, hover, className, ...props }: ArgumentCardProps) {\n const H = `h${level}` as \"h2\" | \"h3\" | \"h4\";\n const fold = !more && panelLabel && (points || rule || (details && details.length > 0));\n return (\n <article className={cn(\"kz-block-card kz-arg\", cardHoverClass(hover), className)} aria-labelledby={id} {...props}>\n <div className=\"kz-arg-head\">\n {icon && (\n <span className=\"kz-block-icon\" aria-hidden>\n {icon}\n </span>\n )}\n <div className=\"kz-arg-id\">\n <H id={id} className=\"kz-arg-title\">\n {title}\n </H>\n {meta && <p className=\"kz-arg-meta\">{meta}</p>}\n </div>\n {mark && (\n <span className=\"kz-arg-mark\" aria-hidden>\n {mark}\n </span>\n )}\n </div>\n <p className=\"kz-arg-line\">\n <span className=\"kz-sr-only\">{hook.label} — </span>\n {hook.text}\n </p>\n {facts && facts.length > 0 && <Facts items={facts} />}\n {fold && (\n <details className=\"kz-arg-panel\">\n <summary>\n {panelLabel} <ChevronGlyph className=\"h-3.5 w-3.5\" />\n </summary>\n <div className=\"kz-arg-panel-body\">\n {points && (\n <div>\n <p className=\"kz-label\">{points.label}</p>\n <ul className=\"kz-list\">\n {points.items.map((item, i) => (\n <li key={i}>{item}</li>\n ))}\n </ul>\n </div>\n )}\n {details && details.length > 0 && (\n <dl>\n {details.map((d, i) => (\n <div key={i}>\n <dt className=\"kz-label\">{d.label}</dt>\n <dd>{d.text}</dd>\n </div>\n ))}\n </dl>\n )}\n {rule}\n </div>\n </details>\n )}\n {(more || actions) && (\n <div className=\"kz-arg-foot\">\n {more ? (\n <BlockLink href={more.href} linkAs={linkAs} className=\"kz-arg-more\" aria-describedby={id}>\n {more.label} <ArrowGlyph className=\"h-3.5 w-3.5\" />\n </BlockLink>\n ) : (\n <span />\n )}\n {actions}\n </div>\n )}\n </article>\n );\n}\n"
229
220
  },
230
221
  {
231
222
  "path": "argument-card/index.ts",
@@ -233,7 +224,7 @@
233
224
  },
234
225
  {
235
226
  "path": "argument-card/meta.ts",
236
- "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Argument card\",\n summary:\n \"A compact card that argues — about a third of a full card: who (icon, name, the bird in the corner), the trap in one line, facts and one short action; the long version lives on a detail page or unfolds in place.\",\n status: \"beta\",\n category: \"blocks\",\n platforms: \"web\",\n parity: { native: { status: \"n/a\", reason: \"A block of a public site's page; an app screen on a phone is built from Screen, Header and Card.\", use: \"card\" }, desktop: { status: \"n/a\", reason: \"A public site's page, not a window of the Mac app.\" } },\n whenToUse: [\n \"The reasons of a product page, the building blocks of an open-source page, the options of a decision.\",\n \"When each subject has a problem to state before its solution, and a reader who scans before reading.\",\n ],\n whenNotToUse: [\n { when: \"When the card only leads somewhere.\", use: \"link-card\" },\n { when: \"For the decisions behind a choice, compared side by side.\", use: \"decision-list\" },\n ],\n bestPractices: [\n \"The hook is ONE line (≤ 90 characters, regular weight) a reader keeps in five seconds — never three bold lines.\",\n \"What it does, the bird's quote and the long version are never on the face: a detail page (`more`), or `panelLabel`.\",\n \"One idea per card; one bird per idea: small in the corner (`mark`), its quote (`rule`) where the card unfolds.\",\n \"Give each subject its hue with `--kz-hue` on the card (or a wrapper); the brand's accent otherwise.\",\n \"Secondary actions as an icon `ActionBar` in `actions`; the way in as `more`.\",\n \"`hover=\\\"quiet\\\"` for reasons read as prose (a product's argument, a policy): no glow, a lift and a ring on focus. The default `light` keeps the pointer's light.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Enter / Space\", action: \"On the panel's summary, opens or closes the long version.\" }],\n notes: [\n \"An `article` named by its title; the hook's label is read before the line (visually hidden); the fold is a native `details` element.\",\n \"The way in is described by the card's title (`aria-describedby`), so several `Read more` links stay distinct.\",\n \"The lift, the light and the panel's chevron stop under `prefers-reduced-motion`; the quiet hover keeps its surface and ring, and never lifts.\",\n ],\n },\n related: [\"card-grid\", \"mascot-quote\", \"action-bar\"],\n web: {\n imports: [\"ArgumentCard\"],\n examples: [\n { name: \"building-block\", title: \"A building block\", description: \"Compact: the duck in the corner, the trap in one line, facts, one short action and an icon action.\" },\n { name: \"unfold\", title: \"Unfolded in place\", description: \"No detail page: `panelLabel` unfolds what it does, the cost and the pigeon's rule.\" },\n { name: \"grid\", title: \"Three reasons\", description: \"A product's reasons side by side in a grid: the hook and the way in, no panel.\" },\n { name: \"hover-light\", title: \"The light hover\", description: \"`hover=\\\"light\\\"`, the default: the pointer's light and the coloured lift, said explicitly.\" },\n { name: \"hover-quiet\", title: \"The quiet hover\", description: \"`hover=\\\"quiet\\\"` on a grid of reasons: no glow, a lift, a ring on focus.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
227
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Argument card\",\n summary:\n \"A compact card that argues — about a third of a full card: who (icon, name, the bird in the corner), the trap in one line, facts and one short action; the long version lives on a detail page or unfolds in place.\",\n status: \"beta\",\n category: \"blocks\",\n platforms: \"web\",\n parity: { native: { status: \"n/a\", reason: \"A block of a public site's page; an app screen on a phone is built from Screen, Header and Card.\", use: \"card\" }, desktop: { status: \"n/a\", reason: \"A public site's page, not a window of the Mac app.\" } },\n whenToUse: [\n \"The reasons of a product page, the building blocks of an open-source page, the options of a decision.\",\n \"When each subject has a problem to state before its solution, and a reader who scans before reading.\",\n ],\n whenNotToUse: [\n { when: \"When the card only leads somewhere.\", use: \"link-card\" },\n { when: \"For the decisions behind a choice, compared side by side.\", use: \"decision-list\" },\n ],\n bestPractices: [\n \"The hook is ONE line (≤ 90 characters, regular weight) a reader keeps in five seconds — never three bold lines.\",\n \"What it does, the bird's quote and the long version are never on the face: a detail page (`more`), or `panelLabel`.\",\n \"One idea per card; one bird per idea: small in the corner (`mark`), its quote (`rule`) where the card unfolds.\",\n \"Give each subject its hue with `--kz-hue` on the card (or a wrapper); the brand's accent otherwise.\",\n \"Secondary actions as an icon `ActionBar` in `actions`; the way in as `more`.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Enter / Space\", action: \"On the panel's summary, opens or closes the long version.\" }],\n notes: [\n \"An `article` named by its title; the hook's label is read before the line (visually hidden); the fold is a native `details` element.\",\n \"The way in is described by the card's title (`aria-describedby`), so several `Read more` links stay distinct.\",\n \"One quiet hover (krizaka-ui#393): the surface and the hairline go one step up in a short colour transition — nothing moves, no light follows the pointer; a ring on the whole card when a link inside takes the keyboard focus. The panel's chevron stops under `prefers-reduced-motion`.\",\n ],\n },\n related: [\"card-grid\", \"mascot-quote\", \"action-bar\"],\n web: {\n imports: [\"ArgumentCard\"],\n examples: [\n { name: \"building-block\", title: \"A building block\", description: \"Compact: the duck in the corner, the trap in one line, facts, one short action and an icon action.\" },\n { name: \"unfold\", title: \"Unfolded in place\", description: \"No detail page: `panelLabel` unfolds what it does, the cost and the pigeon's rule.\" },\n { name: \"grid\", title: \"Three reasons\", description: \"A product's reasons side by side in a grid: the hook and the way in, no panel.\" },\n { name: \"hover-quiet\", title: \"The quiet hover\", description: \"`hover=\\\"quiet\\\"` on a grid of reasons: no glow, a lift, a ring on focus.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
237
228
  },
238
229
  {
239
230
  "path": "block-link.tsx",
@@ -302,7 +293,7 @@
302
293
  "name": "hover",
303
294
  "type": "CardHover",
304
295
  "default": null,
305
- "description": "The hover of the card: `light` (the pointer's light, the default) or `quiet` (no glow, a lift, a ring on focus).",
296
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — every card has the one quiet hover. Removed in 4.0.",
306
297
  "required": false
307
298
  },
308
299
  {
@@ -129,7 +129,7 @@
129
129
  "why": "A returning person signs in fast, with the product's promise beside the form.",
130
130
  "path": "examples/auth-layout/sign-in.tsx",
131
131
  "module": "@krizaka/ui/registry/examples/auth-layout/sign-in",
132
- "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AuthLayout } from \"@krizaka/ui/auth-layout\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Field, Input } from \"@krizaka/ui/field\";\nimport { Mascot } from \"@krizaka/ui/mascots\";\n\n// TEMPLATE — Orochia's sign-in: the brand panel (its gradient, the promise, a creator's sentence) beside a calm form;\n// on a phone one column, the mark above the form, the fields at full width with 44 px targets.\nexport default function AuthLayoutSignIn() {\n return (\n <div className=\"brand-orochia\">\n <AuthLayout\n brand={<><ProductLogo id=\"orochia\" size={28} animated={false} /> Orochia</>}\n promise=\"Your fans pay you, not an algorithm.\"\n aside={\n <div className=\"flex items-end gap-3\">\n <Mascot bird=\"flamingo\" mood=\"welcome\" size={64} />\n <p>“90 % of every tip, unlock and auction reaches me — on Monday.” — Elena, creator</p>\n </div>\n }\n asideFooter=\"© Krizaka · Montréal\"\n title=\"Welcome back\"\n description=\"Sign in to your studio.\"\n footer={<>No account yet? <a className=\"font-semibold text-fg-accent\" href=\"#sign-up\">Create one</a></>}\n legal={<>By signing in you accept the <a className=\"underline\" href=\"#terms\">terms</a> and the <a className=\"underline\" href=\"#privacy\">privacy policy</a>.</>}\n >\n <form className=\"flex flex-col gap-4\">\n <Field.Root>\n <Field.Label htmlFor=\"sign-in-email\">Email</Field.Label>\n <Input id=\"sign-in-email\" type=\"email\" autoComplete=\"email\" placeholder=\"you@example.com\" />\n </Field.Root>\n <Field.Root>\n <Field.Label htmlFor=\"sign-in-password\">Password</Field.Label>\n <Input id=\"sign-in-password\" type=\"password\" autoComplete=\"current-password\" />\n <Field.Hint><a className=\"text-fg-accent\" href=\"#reset\">Forgot it?</a></Field.Hint>\n </Field.Root>\n <Button type=\"submit\" variant=\"primary\" size=\"lg\" shape=\"cut\" shimmer className=\"w-full\">\n Sign in\n </Button>\n <Button type=\"button\" variant=\"secondary\" size=\"lg\" shape=\"cut\" className=\"w-full\">\n Use a passkey\n </Button>\n </form>\n </AuthLayout>\n </div>\n );\n}\n"
132
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AuthLayout } from \"@krizaka/ui/auth-layout\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Field, Input } from \"@krizaka/ui/field\";\nimport { Mascot } from \"@krizaka/ui/mascots\";\n\n// TEMPLATE — Orochia's sign-in: the brand panel (its gradient, the promise, a creator's sentence) beside a calm form;\n// on a phone one column, the mark above the form, the fields at full width with 44 px targets.\nexport default function AuthLayoutSignIn() {\n return (\n <div className=\"brand-orochia\">\n <AuthLayout\n brand={<><ProductLogo id=\"orochia\" size={28} animated={false} /> Orochia</>}\n promise=\"Your fans pay you, not an algorithm.\"\n aside={\n <div className=\"flex items-end gap-3\">\n <Mascot bird=\"flamingo\" mood=\"welcome\" size={64} />\n <p>“90 % of every tip, unlock and auction reaches me — on Monday.” — Elena, creator</p>\n </div>\n }\n asideFooter=\"© Krizaka · Montréal\"\n title=\"Welcome back\"\n description=\"Sign in to your studio.\"\n footer={<>No account yet? <a className=\"font-semibold text-fg-accent\" href=\"#sign-up\">Create one</a></>}\n legal={<>By signing in you accept the <a className=\"underline\" href=\"#terms\">terms</a> and the <a className=\"underline\" href=\"#privacy\">privacy policy</a>.</>}\n >\n <form className=\"flex flex-col gap-4\">\n <Field.Root>\n <Field.Label htmlFor=\"sign-in-email\">Email</Field.Label>\n <Input id=\"sign-in-email\" type=\"email\" autoComplete=\"email\" placeholder=\"you@example.com\" />\n </Field.Root>\n <Field.Root>\n <Field.Label htmlFor=\"sign-in-password\">Password</Field.Label>\n <Input id=\"sign-in-password\" type=\"password\" autoComplete=\"current-password\" />\n <Field.Hint><a className=\"text-fg-accent\" href=\"#reset\">Forgot it?</a></Field.Hint>\n </Field.Root>\n <Button type=\"submit\" variant=\"primary\" size=\"lg\" className=\"w-full\">\n Sign in\n </Button>\n <Button type=\"button\" variant=\"secondary\" size=\"lg\" className=\"w-full\">\n Use a passkey\n </Button>\n </form>\n </AuthLayout>\n </div>\n );\n}\n"
133
133
  },
134
134
  {
135
135
  "name": "onboarding",
@@ -140,7 +140,7 @@
140
140
  "why": "A new person completes a setup one step at a time, knowing how many remain.",
141
141
  "path": "examples/auth-layout/onboarding.tsx",
142
142
  "module": "@krizaka/ui/registry/examples/auth-layout/onboarding",
143
- "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AuthLayout } from \"@krizaka/ui/auth-layout\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Field, Input } from \"@krizaka/ui/field\";\nimport { Stepper } from \"@krizaka/ui/stepper\";\n\nconst labels = { done: \"Done\", current: \"Current step\", upcoming: \"Upcoming\", error: \"Failed\" };\n\n// TEMPLATE — onboarding a creator (Orochia): the steps said in words above the form of the current one; the brand panel\n// says why it is worth it. On a phone the steps stay horizontal and compact above the fields.\nexport default function AuthLayoutOnboarding() {\n return (\n <div className=\"brand-orochia\">\n <AuthLayout\n brand={<><ProductLogo id=\"orochia\" size={28} animated={false} /> Orochia</>}\n promise=\"Three steps, then your first video.\"\n aside={<p>Your identity is checked once, by a person, and never shown to your fans.</p>}\n asideFooter=\"© Krizaka · Montréal\"\n title=\"Your payout account\"\n description=\"Where your earnings go every Monday.\"\n >\n <Stepper\n aria-label=\"Onboarding\"\n orientation=\"horizontal\"\n labels={labels}\n current={1}\n steps={[{ title: \"Profile\" }, { title: \"Payouts\" }, { title: \"Identity\" }]}\n />\n <form className=\"flex flex-col gap-4\">\n <Field.Root>\n <Field.Label htmlFor=\"onboarding-holder\">Account holder</Field.Label>\n <Input id=\"onboarding-holder\" autoComplete=\"name\" defaultValue=\"Elena Varga\" />\n </Field.Root>\n <Field.Root>\n <Field.Label htmlFor=\"onboarding-iban\">IBAN</Field.Label>\n <Input id=\"onboarding-iban\" inputMode=\"text\" placeholder=\"FR76 …\" aria-describedby=\"onboarding-iban-hint\" />\n <Field.Hint id=\"onboarding-iban-hint\">Checked before your first payout.</Field.Hint>\n </Field.Root>\n <div className=\"flex gap-2\">\n <Button type=\"button\" variant=\"secondary\" size=\"lg\" shape=\"cut\" className=\"flex-1\">Back</Button>\n <Button type=\"submit\" variant=\"primary\" size=\"lg\" shape=\"cut\" className=\"flex-1\">Continue</Button>\n </div>\n </form>\n </AuthLayout>\n </div>\n );\n}\n"
143
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AuthLayout } from \"@krizaka/ui/auth-layout\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Field, Input } from \"@krizaka/ui/field\";\nimport { Stepper } from \"@krizaka/ui/stepper\";\n\nconst labels = { done: \"Done\", current: \"Current step\", upcoming: \"Upcoming\", error: \"Failed\" };\n\n// TEMPLATE — onboarding a creator (Orochia): the steps said in words above the form of the current one; the brand panel\n// says why it is worth it. On a phone the steps stay horizontal and compact above the fields.\nexport default function AuthLayoutOnboarding() {\n return (\n <div className=\"brand-orochia\">\n <AuthLayout\n brand={<><ProductLogo id=\"orochia\" size={28} animated={false} /> Orochia</>}\n promise=\"Three steps, then your first video.\"\n aside={<p>Your identity is checked once, by a person, and never shown to your fans.</p>}\n asideFooter=\"© Krizaka · Montréal\"\n title=\"Your payout account\"\n description=\"Where your earnings go every Monday.\"\n >\n <Stepper\n aria-label=\"Onboarding\"\n orientation=\"horizontal\"\n labels={labels}\n current={1}\n steps={[{ title: \"Profile\" }, { title: \"Payouts\" }, { title: \"Identity\" }]}\n />\n <form className=\"flex flex-col gap-4\">\n <Field.Root>\n <Field.Label htmlFor=\"onboarding-holder\">Account holder</Field.Label>\n <Input id=\"onboarding-holder\" autoComplete=\"name\" defaultValue=\"Elena Varga\" />\n </Field.Root>\n <Field.Root>\n <Field.Label htmlFor=\"onboarding-iban\">IBAN</Field.Label>\n <Input id=\"onboarding-iban\" inputMode=\"text\" placeholder=\"FR76 …\" aria-describedby=\"onboarding-iban-hint\" />\n <Field.Hint id=\"onboarding-iban-hint\">Checked before your first payout.</Field.Hint>\n </Field.Root>\n <div className=\"flex gap-2\">\n <Button type=\"button\" variant=\"secondary\" size=\"lg\" className=\"flex-1\">Back</Button>\n <Button type=\"submit\" variant=\"primary\" size=\"lg\" className=\"flex-1\">Continue</Button>\n </div>\n </form>\n </AuthLayout>\n </div>\n );\n}\n"
144
144
  },
145
145
  {
146
146
  "name": "verify",
@@ -148,7 +148,7 @@
148
148
  "description": "The smallest entry screen: a code.",
149
149
  "path": "examples/auth-layout/verify.tsx",
150
150
  "module": "@krizaka/ui/registry/examples/auth-layout/verify",
151
- "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AuthLayout } from \"@krizaka/ui/auth-layout\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Field, Input } from \"@krizaka/ui/field\";\n\n// The smallest entry screen: no promise, the brand panel still carries the product's gradient on a desktop.\nexport default function AuthLayoutVerify() {\n return (\n <AuthLayout brand={<><ProductLogo id=\"krizaka\" size={28} animated={false} /> Krizaka</>} title=\"Check your email\" description=\"We sent a 6-digit code to eric@tremblay.ca.\">\n <form className=\"flex flex-col gap-4\">\n <Field.Root>\n <Field.Label htmlFor=\"verify-code\">Code</Field.Label>\n <Input id=\"verify-code\" inputMode=\"numeric\" autoComplete=\"one-time-code\" maxLength={6} />\n </Field.Root>\n <Button type=\"submit\" variant=\"primary\" size=\"lg\" shape=\"cut\" className=\"w-full\">Verify</Button>\n </form>\n </AuthLayout>\n );\n}\n"
151
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AuthLayout } from \"@krizaka/ui/auth-layout\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Field, Input } from \"@krizaka/ui/field\";\n\n// The smallest entry screen: no promise, the brand panel still carries the product's gradient on a desktop.\nexport default function AuthLayoutVerify() {\n return (\n <AuthLayout brand={<><ProductLogo id=\"krizaka\" size={28} animated={false} /> Krizaka</>} title=\"Check your email\" description=\"We sent a 6-digit code to eric@tremblay.ca.\">\n <form className=\"flex flex-col gap-4\">\n <Field.Root>\n <Field.Label htmlFor=\"verify-code\">Code</Field.Label>\n <Input id=\"verify-code\" inputMode=\"numeric\" autoComplete=\"one-time-code\" maxLength={6} />\n </Field.Root>\n <Button type=\"submit\" variant=\"primary\" size=\"lg\" className=\"w-full\">Verify</Button>\n </form>\n </AuthLayout>\n );\n}\n"
152
152
  }
153
153
  ]
154
154
  },
@@ -179,7 +179,7 @@
179
179
  ],
180
180
  "demo": {
181
181
  "path": "examples/auth-layout/sign-in.tsx",
182
- "content": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AuthLayout } from \"@krizaka/ui/auth-layout\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Field, Input } from \"@krizaka/ui/field\";\nimport { Mascot } from \"@krizaka/ui/mascots\";\n\n// TEMPLATE — Orochia's sign-in: the brand panel (its gradient, the promise, a creator's sentence) beside a calm form;\n// on a phone one column, the mark above the form, the fields at full width with 44 px targets.\nexport default function AuthLayoutSignIn() {\n return (\n <div className=\"brand-orochia\">\n <AuthLayout\n brand={<><ProductLogo id=\"orochia\" size={28} animated={false} /> Orochia</>}\n promise=\"Your fans pay you, not an algorithm.\"\n aside={\n <div className=\"flex items-end gap-3\">\n <Mascot bird=\"flamingo\" mood=\"welcome\" size={64} />\n <p>“90 % of every tip, unlock and auction reaches me — on Monday.” — Elena, creator</p>\n </div>\n }\n asideFooter=\"© Krizaka · Montréal\"\n title=\"Welcome back\"\n description=\"Sign in to your studio.\"\n footer={<>No account yet? <a className=\"font-semibold text-fg-accent\" href=\"#sign-up\">Create one</a></>}\n legal={<>By signing in you accept the <a className=\"underline\" href=\"#terms\">terms</a> and the <a className=\"underline\" href=\"#privacy\">privacy policy</a>.</>}\n >\n <form className=\"flex flex-col gap-4\">\n <Field.Root>\n <Field.Label htmlFor=\"sign-in-email\">Email</Field.Label>\n <Input id=\"sign-in-email\" type=\"email\" autoComplete=\"email\" placeholder=\"you@example.com\" />\n </Field.Root>\n <Field.Root>\n <Field.Label htmlFor=\"sign-in-password\">Password</Field.Label>\n <Input id=\"sign-in-password\" type=\"password\" autoComplete=\"current-password\" />\n <Field.Hint><a className=\"text-fg-accent\" href=\"#reset\">Forgot it?</a></Field.Hint>\n </Field.Root>\n <Button type=\"submit\" variant=\"primary\" size=\"lg\" shape=\"cut\" shimmer className=\"w-full\">\n Sign in\n </Button>\n <Button type=\"button\" variant=\"secondary\" size=\"lg\" shape=\"cut\" className=\"w-full\">\n Use a passkey\n </Button>\n </form>\n </AuthLayout>\n </div>\n );\n}\n"
182
+ "content": "import { ProductLogo } from \"@krizaka/ui\";\nimport { AuthLayout } from \"@krizaka/ui/auth-layout\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { Field, Input } from \"@krizaka/ui/field\";\nimport { Mascot } from \"@krizaka/ui/mascots\";\n\n// TEMPLATE — Orochia's sign-in: the brand panel (its gradient, the promise, a creator's sentence) beside a calm form;\n// on a phone one column, the mark above the form, the fields at full width with 44 px targets.\nexport default function AuthLayoutSignIn() {\n return (\n <div className=\"brand-orochia\">\n <AuthLayout\n brand={<><ProductLogo id=\"orochia\" size={28} animated={false} /> Orochia</>}\n promise=\"Your fans pay you, not an algorithm.\"\n aside={\n <div className=\"flex items-end gap-3\">\n <Mascot bird=\"flamingo\" mood=\"welcome\" size={64} />\n <p>“90 % of every tip, unlock and auction reaches me — on Monday.” — Elena, creator</p>\n </div>\n }\n asideFooter=\"© Krizaka · Montréal\"\n title=\"Welcome back\"\n description=\"Sign in to your studio.\"\n footer={<>No account yet? <a className=\"font-semibold text-fg-accent\" href=\"#sign-up\">Create one</a></>}\n legal={<>By signing in you accept the <a className=\"underline\" href=\"#terms\">terms</a> and the <a className=\"underline\" href=\"#privacy\">privacy policy</a>.</>}\n >\n <form className=\"flex flex-col gap-4\">\n <Field.Root>\n <Field.Label htmlFor=\"sign-in-email\">Email</Field.Label>\n <Input id=\"sign-in-email\" type=\"email\" autoComplete=\"email\" placeholder=\"you@example.com\" />\n </Field.Root>\n <Field.Root>\n <Field.Label htmlFor=\"sign-in-password\">Password</Field.Label>\n <Input id=\"sign-in-password\" type=\"password\" autoComplete=\"current-password\" />\n <Field.Hint><a className=\"text-fg-accent\" href=\"#reset\">Forgot it?</a></Field.Hint>\n </Field.Root>\n <Button type=\"submit\" variant=\"primary\" size=\"lg\" className=\"w-full\">\n Sign in\n </Button>\n <Button type=\"button\" variant=\"secondary\" size=\"lg\" className=\"w-full\">\n Use a passkey\n </Button>\n </form>\n </AuthLayout>\n </div>\n );\n}\n"
183
183
  },
184
184
  "props": [
185
185
  {
@@ -2,8 +2,8 @@
2
2
  "name": "button",
3
3
  "type": "primitive",
4
4
  "title": "Button",
5
- "summary": "The action: six looks, three sizes, three shapes (rounded, pill, the Krizaka cut corners) — and the whole life of an action built in: a wait traced by the loader glyph, its progress, a success or a failure drawn and announced.",
6
- "description": "The action: six looks, three sizes, three shapes (rounded, pill, the Krizaka cut corners) — and the whole life of an action built in: a wait traced by the loader glyph, its progress, a success or a failure drawn and announced.",
5
+ "summary": "The action: six looks, three sizes, two shapes (an 8 px radius, the pill) — and the whole life of an action built in: a wait traced by the loader glyph, its progress, a success or a failure drawn and announced.",
6
+ "description": "The action: six looks, three sizes, two shapes (an 8 px radius, the pill) — and the whole life of an action built in: a wait traced by the loader glyph, its progress, a success or a failure drawn and announced.",
7
7
  "status": "stable",
8
8
  "deprecated": null,
9
9
  "category": "actions",
@@ -46,7 +46,7 @@
46
46
  "One primary per view; the danger variant only for what destroys or cannot be undone.",
47
47
  "`loading` while the action runs: the button is disabled, says it is busy and draws the glyph; add `progress` when you know how far it is.",
48
48
  "End with `status` (`success` / `error`) and `announce` the result in words: sighted people see the check, everyone hears “Saved”. Clear the status after a moment.",
49
- "`shape=\"cut\"`, `shimmer` and `magnetic` are the signature: keep them for the one action a page is about.",
49
+ "One shape for every action (an 8 px radius, the radius of a field); the pill only for a chip-like action. The hover changes a colour, never the position. `shape=\"cut\"`, `shimmer` and `magnetic` are deprecated since 3.31 (krizaka-ui#393) and do nothing.",
50
50
  "Style a link without the component with `buttonVariants({ variant, size })`."
51
51
  ],
52
52
  "accessibility": {
@@ -114,7 +114,7 @@
114
114
  "name": "magnetic",
115
115
  "type": "boolean",
116
116
  "default": null,
117
- "description": "The button leans a few pixels toward a fine pointer (driven by `MotionObserver`; never under reduced motion or on touch).",
117
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — a button never moves under the pointer. Removed in 4.0.",
118
118
  "required": false
119
119
  },
120
120
  {
@@ -128,14 +128,14 @@
128
128
  "name": "shape",
129
129
  "type": "\"rounded\" | \"pill\" | \"cut\"",
130
130
  "default": "rounded",
131
- "description": "rounded · pill · cut (45° corners, the Krizaka chamfer).",
131
+ "description": "`rounded` (an 8 px radius, the radius of a field) · `pill`. `cut` is deprecated (krizaka-ui#393: the chamfer is\nretired) — it draws `rounded` and warns in development; it will be removed in 4.0.",
132
132
  "required": false
133
133
  },
134
134
  {
135
135
  "name": "shimmer",
136
136
  "type": "boolean",
137
137
  "default": null,
138
- "description": "A sheen of light crosses the button on hover — for the one action a page is about.",
138
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — the hover is quiet. Removed in 4.0.",
139
139
  "required": false
140
140
  },
141
141
  {
@@ -204,7 +204,7 @@
204
204
  "name": "magnetic",
205
205
  "type": "boolean",
206
206
  "default": null,
207
- "description": "The button leans a few pixels toward a fine pointer (driven by `MotionObserver`; never under reduced motion or on touch).",
207
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — a button never moves under the pointer. Removed in 4.0.",
208
208
  "required": false
209
209
  },
210
210
  {
@@ -218,14 +218,14 @@
218
218
  "name": "shape",
219
219
  "type": "\"rounded\" | \"pill\" | \"cut\"",
220
220
  "default": "rounded",
221
- "description": "rounded · pill · cut (45° corners, the Krizaka chamfer).",
221
+ "description": "`rounded` (an 8 px radius, the radius of a field) · `pill`. `cut` is deprecated (krizaka-ui#393: the chamfer is\nretired) — it draws `rounded` and warns in development; it will be removed in 4.0.",
222
222
  "required": false
223
223
  },
224
224
  {
225
225
  "name": "shimmer",
226
226
  "type": "boolean",
227
227
  "default": null,
228
- "description": "A sheen of light crosses the button on hover — for the one action a page is about.",
228
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — the hover is quiet. Removed in 4.0.",
229
229
  "required": false
230
230
  },
231
231
  {
@@ -280,10 +280,10 @@
280
280
  {
281
281
  "name": "signature",
282
282
  "title": "The signature action",
283
- "description": "`shape=\"cut\"`, the gradient, `shimmer` and `magnetic`: the one call to action of a hero; the arrow leans forward on hover.",
283
+ "description": "The gradient beside a quiet outline: the one call to action of a hero; the arrow leans forward on hover, the button never moves.",
284
284
  "path": "examples/button/signature.tsx",
285
285
  "module": "@krizaka/ui/registry/examples/button/signature",
286
- "code": "import { Button } from \"@krizaka/ui/button\";\n\n// The one action a page is about: cut corners, the brand gradient, a sheen on hover, a lean toward the pointer\n// (`magnetic`, with MotionObserver mounted). The arrow of a signature icon leans forward on hover too.\nexport default function ButtonSignature() {\n return (\n <div className=\"flex flex-wrap items-center gap-3\">\n <Button variant=\"gradient\" size=\"lg\" shape=\"cut\" shimmer magnetic>\n Start free\n <svg data-kz-icon=\"ForwardIcon\" viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M5 12h14M13 6l6 6-6 6\" />\n </svg>\n </Button>\n <Button variant=\"outline\" size=\"lg\" shape=\"cut\">\n Talk to us\n </Button>\n </div>\n );\n}\n"
286
+ "code": "import { Button } from \"@krizaka/ui/button\";\n\n// The one action a page is about: the brand gradient beside a quiet outline. The arrow of a signature icon leans\n// forward on hover; the button itself never moves (krizaka-ui#393).\nexport default function ButtonSignature() {\n return (\n <div className=\"flex flex-wrap items-center gap-3\">\n <Button variant=\"gradient\" size=\"lg\">\n Start free\n <svg data-kz-icon=\"ForwardIcon\" viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M5 12h14M13 6l6 6-6 6\" />\n </svg>\n </Button>\n <Button variant=\"outline\" size=\"lg\">\n Talk to us\n </Button>\n </div>\n );\n}\n"
287
287
  },
288
288
  {
289
289
  "name": "primary",
@@ -643,7 +643,7 @@
643
643
  "files": [
644
644
  {
645
645
  "path": "button/button.tsx",
646
- "content": "// Server-safe: no hook, no context. `buttonVariants` styles a <Link> or a Server Component without the component.\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { LoaderGlyph } from \"../spinner/glyph\";\nimport { buttonRecipe } from \"./recipe\";\n\nexport const buttonVariants = tv(buttonRecipe);\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n ButtonVariants & {\n /**\n * The look: `primary` (the accent), `gradient` (accent → accent-2), `secondary` (a raised surface), `outline`,\n * `ghost`, `danger`.\n * @default \"secondary\"\n */\n variant?: ButtonVariants[\"variant\"];\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"md\"\n */\n size?: ButtonVariants[\"size\"];\n /**\n * rounded · pill · cut (45° corners, the Krizaka chamfer).\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */\n asChild?: boolean;\n /**\n * Disables and signals the wait (aria-busy, data-loading) and shows the Krizaka loader glyph before the label; the\n * button keeps its colour.\n */\n loading?: boolean;\n /**\n * Between 0 and 1, while `loading`: the glyph's trace and a light fill across the button grow to the value (an\n * upload, an export).\n */\n progress?: number | null;\n /**\n * How the action ended: `success` draws a check, `error` a cross (and the button shakes its head once); a ring of\n * the status colour opens around it. Clear it to return to rest.\n */\n status?: \"success\" | \"error\" | null;\n /** A message announced politely by assistive technology when it changes (“Saved”, “Upload failed”) — passed translated. */\n announce?: string;\n /**\n * Shows the glyph while `loading` / with a `status`. `false`: you draw your own.\n * @default true\n */\n indicator?: boolean;\n /** A sheen of light crosses the button on hover — for the one action a page is about. */\n shimmer?: boolean;\n /** The button leans a few pixels toward a fine pointer (driven by `MotionObserver`; never under reduced motion or on touch). */\n magnetic?: boolean;\n };\n\nconst STATUS_TEXT = { success: \"text-fg-success\", error: \"text-fg-danger\" } as const;\n\nexport function Button({\n asChild,\n loading,\n progress,\n status,\n announce,\n indicator = true,\n shimmer,\n magnetic,\n variant,\n size,\n shape,\n className,\n disabled,\n children,\n ...props\n}: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n const known = loading && typeof progress === \"number\" && Number.isFinite(progress);\n const ratio = known ? Math.min(1, Math.max(0, progress)) : 0;\n const glyph = indicator && !asChild && (loading || status) ? (status ?? \"loading\") : null;\n // On a filled variant the glyph stays in the label's colour; on the others it takes the status colour.\n const filled = variant === \"primary\" || variant === \"gradient\";\n const button = (\n <Comp\n type={asChild ? undefined : \"button\"}\n aria-busy={loading || undefined}\n data-loading={loading ? \"\" : undefined}\n data-variant={variant ?? \"secondary\"}\n data-kz-status={status ?? undefined}\n data-kz-magnetic={magnetic ? \"\" : undefined}\n disabled={asChild ? undefined : disabled || loading}\n aria-disabled={asChild && (disabled || loading) ? true : undefined}\n className={buttonVariants({\n variant,\n size,\n shape,\n className: cn(known && \"relative isolate overflow-hidden\", shimmer && \"kz-sheen\", className),\n })}\n {...props}\n >\n {asChild ? (\n children\n ) : (\n <>\n {known && (\n <span aria-hidden className=\"absolute inset-y-0 left-0 -z-10 bg-current opacity-15 transition-[width] duration-500\" style={{ width: `${ratio * 100}%` }} />\n )}\n {glyph && (\n <span\n aria-hidden\n data-slot=\"indicator\"\n className=\"-my-1 grid grid-cols-[1fr] transition-[grid-template-columns,margin,opacity] duration-300 starting:-mr-2 starting:grid-cols-[0fr] starting:opacity-0\"\n >\n <span className=\"overflow-hidden\">\n <LoaderGlyph state={glyph} value={known ? ratio : null} className={cn(\"h-4 w-4\", glyph !== \"loading\" && !filled && STATUS_TEXT[glyph])} />\n </span>\n </span>\n )}\n {children}\n </>\n )}\n </Comp>\n );\n if (announce === undefined || asChild) return button;\n return (\n <>\n {button}\n <span role=\"status\" className=\"sr-only\">\n {announce}\n </span>\n </>\n );\n}\n\nexport type IconButtonProps = Omit<ButtonProps, \"size\"> & {\n /** The accessible name (and tooltip) of the button — required, passed translated. */\n label: string;\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"icon\"\n */\n size?: ButtonProps[\"size\"];\n};\n\n/** An icon-only button: `label` is required, it is its accessible name. Loading or with a status, the glyph takes the icon's place. */\nexport function IconButton({ label, size = \"icon\", children, ...props }: IconButtonProps) {\n const swap = props.indicator !== false && !props.asChild && (props.loading || props.status);\n return (\n <Button aria-label={label} title={label} size={size} {...props}>\n {swap ? null : children}\n </Button>\n );\n}\n"
646
+ "content": "// Server-safe: no hook, no context. `buttonVariants` styles a <Link> or a Server Component without the component.\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { LoaderGlyph } from \"../spinner/glyph\";\nimport { buttonRecipe } from \"./recipe\";\n\nexport const buttonVariants = tv(buttonRecipe);\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n ButtonVariants & {\n /**\n * The look: `primary` (the accent), `gradient` (accent → accent-2), `secondary` (a raised surface), `outline`,\n * `ghost`, `danger`.\n * @default \"secondary\"\n */\n variant?: ButtonVariants[\"variant\"];\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"md\"\n */\n size?: ButtonVariants[\"size\"];\n /**\n * `rounded` (an 8 px radius, the radius of a field) · `pill`. `cut` is deprecated (krizaka-ui#393: the chamfer is\n * retired) — it draws `rounded` and warns in development; it will be removed in 4.0.\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */\n asChild?: boolean;\n /**\n * Disables and signals the wait (aria-busy, data-loading) and shows the Krizaka loader glyph before the label; the\n * button keeps its colour.\n */\n loading?: boolean;\n /**\n * Between 0 and 1, while `loading`: the glyph's trace and a light fill across the button grow to the value (an\n * upload, an export).\n */\n progress?: number | null;\n /**\n * How the action ended: `success` draws a check, `error` a cross (and the button shakes its head once); a ring of\n * the status colour opens around it. Clear it to return to rest.\n */\n status?: \"success\" | \"error\" | null;\n /** A message announced politely by assistive technology when it changes (“Saved”, “Upload failed”) — passed translated. */\n announce?: string;\n /**\n * Shows the glyph while `loading` / with a `status`. `false`: you draw your own.\n * @default true\n */\n indicator?: boolean;\n /** @deprecated Since 3.31 (krizaka-ui#393): does nothing — the hover is quiet. Removed in 4.0. */\n shimmer?: boolean;\n /** @deprecated Since 3.31 (krizaka-ui#393): does nothing — a button never moves under the pointer. Removed in 4.0. */\n magnetic?: boolean;\n };\n\nconst STATUS_TEXT = { success: \"text-fg-success\", error: \"text-fg-danger\" } as const;\n\nlet warnedCut = false;\n/** `shape=\"cut\"` (the chamfer) is retired: one warning per page in development, never in production. */\nfunction warnCut() {\n if (warnedCut || typeof process === \"undefined\" || process.env.NODE_ENV === \"production\") return;\n warnedCut = true;\n console.warn('@krizaka/ui/button: shape=\"cut\" is deprecated (krizaka-ui#393) and now draws the default rounded shape. Remove the prop.');\n}\n\nexport function Button({\n asChild,\n loading,\n progress,\n status,\n announce,\n indicator = true,\n shimmer: _shimmer,\n magnetic: _magnetic,\n variant,\n size,\n shape,\n className,\n disabled,\n children,\n ...props\n}: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n if (shape === \"cut\") warnCut();\n const known = loading && typeof progress === \"number\" && Number.isFinite(progress);\n const ratio = known ? Math.min(1, Math.max(0, progress)) : 0;\n const glyph = indicator && !asChild && (loading || status) ? (status ?? \"loading\") : null;\n // On a filled variant the glyph stays in the label's colour; on the others it takes the status colour.\n const filled = variant === \"primary\" || variant === \"gradient\";\n const button = (\n <Comp\n type={asChild ? undefined : \"button\"}\n aria-busy={loading || undefined}\n data-loading={loading ? \"\" : undefined}\n data-variant={variant ?? \"secondary\"}\n data-kz-status={status ?? undefined}\n disabled={asChild ? undefined : disabled || loading}\n aria-disabled={asChild && (disabled || loading) ? true : undefined}\n className={buttonVariants({\n variant,\n size,\n shape,\n className: cn(known && \"relative isolate overflow-hidden\", className),\n })}\n {...props}\n >\n {asChild ? (\n children\n ) : (\n <>\n {known && (\n <span aria-hidden className=\"absolute inset-y-0 left-0 -z-10 bg-current opacity-15 transition-[width] duration-500\" style={{ width: `${ratio * 100}%` }} />\n )}\n {glyph && (\n <span\n aria-hidden\n data-slot=\"indicator\"\n className=\"-my-1 grid grid-cols-[1fr] transition-[grid-template-columns,margin,opacity] duration-300 starting:-mr-2 starting:grid-cols-[0fr] starting:opacity-0\"\n >\n <span className=\"overflow-hidden\">\n <LoaderGlyph state={glyph} value={known ? ratio : null} className={cn(\"h-4 w-4\", glyph !== \"loading\" && !filled && STATUS_TEXT[glyph])} />\n </span>\n </span>\n )}\n {children}\n </>\n )}\n </Comp>\n );\n if (announce === undefined || asChild) return button;\n return (\n <>\n {button}\n <span role=\"status\" className=\"sr-only\">\n {announce}\n </span>\n </>\n );\n}\n\nexport type IconButtonProps = Omit<ButtonProps, \"size\"> & {\n /** The accessible name (and tooltip) of the button — required, passed translated. */\n label: string;\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"icon\"\n */\n size?: ButtonProps[\"size\"];\n};\n\n/** An icon-only button: `label` is required, it is its accessible name. Loading or with a status, the glyph takes the icon's place. */\nexport function IconButton({ label, size = \"icon\", children, ...props }: IconButtonProps) {\n const swap = props.indicator !== false && !props.asChild && (props.loading || props.status);\n return (\n <Button aria-label={label} title={label} size={size} {...props}>\n {swap ? null : children}\n </Button>\n );\n}\n"
647
647
  },
648
648
  {
649
649
  "path": "button/index.ts",
@@ -651,11 +651,11 @@
651
651
  },
652
652
  {
653
653
  "path": "button/meta.ts",
654
- "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Button\",\n summary:\n \"The action: six looks, three sizes, three shapes (rounded, pill, the Krizaka cut corners) — and the whole life of an action built in: a wait traced by the loader glyph, its progress, a success or a failure drawn and announced.\",\n status: \"stable\",\n category: \"actions\",\n platforms: \"both\",\n parity: { desktop: \"web\" },\n whenToUse: [\n \"To run an action: submit a form, open a dialog, start an upload, save a draft.\",\n \"One `primary` button for the main action of a view; `secondary`, `outline` or `ghost` for the others.\",\n \"`IconButton` for a compact action shown by its icon alone (close, add, more), with a `label` for its name.\",\n ],\n whenNotToUse: [\n { when: \"To go to another page: use a link (`asChild` with your router's `<Link>` keeps the button look).\" },\n { when: \"To turn a setting on or off, with an immediate effect.\", use: \"switch\" },\n { when: \"For a destructive action that needs a second press to confirm, in place.\", use: \"confirm-button\" },\n { when: \"To choose one option among several, or filter a list.\", use: \"chip\" },\n ],\n bestPractices: [\n \"Name the action with a verb: “Save”, “Send the invitation” — not “OK” or “Yes”.\",\n \"One primary per view; the danger variant only for what destroys or cannot be undone.\",\n \"`loading` while the action runs: the button is disabled, says it is busy and draws the glyph; add `progress` when you know how far it is.\",\n \"End with `status` (`success` / `error`) and `announce` the result in words: sighted people see the check, everyone hears “Saved”. Clear the status after a moment.\",\n \"`shape=\\\"cut\\\"`, `shimmer` and `magnetic` are the signature: keep them for the one action a page is about.\",\n \"Style a link without the component with `buttonVariants({ variant, size })`.\",\n ],\n accessibility: {\n keyboard: [\n { keys: \"Enter / Space\", action: \"Runs the action.\" },\n { keys: \"Tab\", action: \"Moves the focus to the next control; the focus ring uses `--kz-ring`.\" },\n ],\n notes: [\n \"A native `<button type=\\\"button\\\">`: the role, the focus and the keyboard come from the platform.\",\n \"`IconButton` requires `label`: it becomes the `aria-label` of a button that shows no text.\",\n \"`loading` sets `aria-busy` and disables the button; `disabled` keeps it out of the tab order.\",\n \"`announce` renders a polite live region next to the button: the result of the action is heard, not only seen.\",\n \"Under `prefers-reduced-motion` nothing moves (no shake, no lean, no sheen): the check, the cross and the status colour still say it.\",\n ],\n },\n related: [\"confirm-button\", \"dialog\", \"dropdown-menu\", \"tooltip\"],\n web: {\n imports: [\"Button\", \"IconButton\"],\n examples: [\n { name: \"save-flow\", title: \"Save, then confirm\", description: \"Press it: the glyph traces the wait, a check draws itself, “Changes saved” is announced, then it returns to rest.\" },\n { name: \"upload-progress\", title: \"An export with progress\", description: \"`progress`: the trace and a light fill grow across the button; it keeps its width and its colour.\" },\n { name: \"error\", title: \"A failure\", description: \"`status=\\\"error\\\"`: a cross, one shake of the head, a ring of the danger colour — and the reason announced.\" },\n { name: \"signature\", title: \"The signature action\", description: \"`shape=\\\"cut\\\"`, the gradient, `shimmer` and `magnetic`: the one call to action of a hero; the arrow leans forward on hover.\" },\n { name: \"primary\", title: \"Primary\", description: \"The main action of a view: the accent.\" },\n { name: \"gradient\", title: \"Gradient\", description: \"The brand's signature, accent → accent-2: a hero or a closing call to action, once per page.\" },\n { name: \"secondary\", title: \"Secondary\", description: \"The default: a raised surface, for the other actions.\" },\n { name: \"outline\", title: \"Outline\", description: \"A lighter action next to a primary one.\" },\n { name: \"ghost\", title: \"Ghost\", description: \"In toolbars and dense lists: no frame until hovered.\" },\n { name: \"danger\", title: \"Danger\", description: \"A destructive action: the border and the tint carry the danger, the label stays legible in both themes.\" },\n { name: \"sizes\", title: \"Sizes\", description: \"`sm`, `md` (default) and `lg`.\" },\n { name: \"pill\", title: \"Pill\", description: \"`shape=\\\"pill\\\"`: fully rounded.\" },\n { name: \"disabled\", title: \"Disabled\", description: \"Not available yet: out of the tab order.\" },\n { name: \"loading\", title: \"Loading\", description: \"While the action runs: disabled, `aria-busy`, `data-loading`, the glyph before the label.\" },\n { name: \"as-child-link\", title: \"As a link\", description: \"`asChild` renders your `<a>` (or router link) with the button's look.\" },\n { name: \"icon\", title: \"Icon button\", description: \"`IconButton`: a square button holding an icon; `label` is its accessible name.\" },\n ],\n },\n native: {\n imports: [\"Button\", \"IconButton\"],\n differences: [\n \"The text is the `label` prop (a string), not children: it is also the accessible name.\",\n \"`onPress` instead of `onClick` (a `Pressable`); haptics, if any, belong to your `onPress`.\",\n \"`icon` places an icon before the label; there is no `asChild`.\",\n \"`loading` shows the platform's `ActivityIndicator` in place of the icon.\",\n \"`variant=\\\"gradient\\\"` draws its fill with react-native-svg (React Native has no CSS gradient).\",\n ],\n examples: [\n { name: \"primary\", title: \"Primary\", description: \"The main action of a screen.\" },\n { name: \"gradient\", title: \"Gradient\", description: \"accent → accent-2, drawn with react-native-svg: the hero action of a screen.\" },\n { name: \"secondary\", title: \"Secondary\", description: \"The default look.\" },\n { name: \"outline\", title: \"Outline\", description: \"A lighter action.\" },\n { name: \"ghost\", title: \"Ghost\", description: \"No frame: toolbars, headers.\" },\n { name: \"danger\", title: \"Danger\", description: \"A destructive action.\" },\n { name: \"sizes\", title: \"Sizes\", description: \"`sm`, `md`, `lg`, and `shape=\\\"pill\\\"`.\" },\n { name: \"icon\", title: \"With an icon\", description: \"`icon` before the label.\" },\n { name: \"disabled\", title: \"Disabled\", description: \"Not available yet.\" },\n { name: \"loading\", title: \"Loading\", description: \"Disabled and busy, a spinner in place of the icon.\" },\n { name: \"icon-only\", title: \"Icon button\", description: \"`IconButton`: `label` is required, it is the accessible name.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
654
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Button\",\n summary:\n \"The action: six looks, three sizes, two shapes (an 8 px radius, the pill) — and the whole life of an action built in: a wait traced by the loader glyph, its progress, a success or a failure drawn and announced.\",\n status: \"stable\",\n category: \"actions\",\n platforms: \"both\",\n parity: { desktop: \"web\" },\n whenToUse: [\n \"To run an action: submit a form, open a dialog, start an upload, save a draft.\",\n \"One `primary` button for the main action of a view; `secondary`, `outline` or `ghost` for the others.\",\n \"`IconButton` for a compact action shown by its icon alone (close, add, more), with a `label` for its name.\",\n ],\n whenNotToUse: [\n { when: \"To go to another page: use a link (`asChild` with your router's `<Link>` keeps the button look).\" },\n { when: \"To turn a setting on or off, with an immediate effect.\", use: \"switch\" },\n { when: \"For a destructive action that needs a second press to confirm, in place.\", use: \"confirm-button\" },\n { when: \"To choose one option among several, or filter a list.\", use: \"chip\" },\n ],\n bestPractices: [\n \"Name the action with a verb: “Save”, “Send the invitation” — not “OK” or “Yes”.\",\n \"One primary per view; the danger variant only for what destroys or cannot be undone.\",\n \"`loading` while the action runs: the button is disabled, says it is busy and draws the glyph; add `progress` when you know how far it is.\",\n \"End with `status` (`success` / `error`) and `announce` the result in words: sighted people see the check, everyone hears “Saved”. Clear the status after a moment.\",\n \"One shape for every action (an 8 px radius, the radius of a field); the pill only for a chip-like action. The hover changes a colour, never the position. `shape=\\\"cut\\\"`, `shimmer` and `magnetic` are deprecated since 3.31 (krizaka-ui#393) and do nothing.\",\n \"Style a link without the component with `buttonVariants({ variant, size })`.\",\n ],\n accessibility: {\n keyboard: [\n { keys: \"Enter / Space\", action: \"Runs the action.\" },\n { keys: \"Tab\", action: \"Moves the focus to the next control; the focus ring uses `--kz-ring`.\" },\n ],\n notes: [\n \"A native `<button type=\\\"button\\\">`: the role, the focus and the keyboard come from the platform.\",\n \"`IconButton` requires `label`: it becomes the `aria-label` of a button that shows no text.\",\n \"`loading` sets `aria-busy` and disables the button; `disabled` keeps it out of the tab order.\",\n \"`announce` renders a polite live region next to the button: the result of the action is heard, not only seen.\",\n \"Under `prefers-reduced-motion` nothing moves (no shake, no lean, no sheen): the check, the cross and the status colour still say it.\",\n ],\n },\n related: [\"confirm-button\", \"dialog\", \"dropdown-menu\", \"tooltip\"],\n web: {\n imports: [\"Button\", \"IconButton\"],\n examples: [\n { name: \"save-flow\", title: \"Save, then confirm\", description: \"Press it: the glyph traces the wait, a check draws itself, “Changes saved” is announced, then it returns to rest.\" },\n { name: \"upload-progress\", title: \"An export with progress\", description: \"`progress`: the trace and a light fill grow across the button; it keeps its width and its colour.\" },\n { name: \"error\", title: \"A failure\", description: \"`status=\\\"error\\\"`: a cross, one shake of the head, a ring of the danger colour — and the reason announced.\" },\n { name: \"signature\", title: \"The signature action\", description: \"The gradient beside a quiet outline: the one call to action of a hero; the arrow leans forward on hover, the button never moves.\" },\n { name: \"primary\", title: \"Primary\", description: \"The main action of a view: the accent.\" },\n { name: \"gradient\", title: \"Gradient\", description: \"The brand's signature, accent → accent-2: a hero or a closing call to action, once per page.\" },\n { name: \"secondary\", title: \"Secondary\", description: \"The default: a raised surface, for the other actions.\" },\n { name: \"outline\", title: \"Outline\", description: \"A lighter action next to a primary one.\" },\n { name: \"ghost\", title: \"Ghost\", description: \"In toolbars and dense lists: no frame until hovered.\" },\n { name: \"danger\", title: \"Danger\", description: \"A destructive action: the border and the tint carry the danger, the label stays legible in both themes.\" },\n { name: \"sizes\", title: \"Sizes\", description: \"`sm`, `md` (default) and `lg`.\" },\n { name: \"pill\", title: \"Pill\", description: \"`shape=\\\"pill\\\"`: fully rounded.\" },\n { name: \"disabled\", title: \"Disabled\", description: \"Not available yet: out of the tab order.\" },\n { name: \"loading\", title: \"Loading\", description: \"While the action runs: disabled, `aria-busy`, `data-loading`, the glyph before the label.\" },\n { name: \"as-child-link\", title: \"As a link\", description: \"`asChild` renders your `<a>` (or router link) with the button's look.\" },\n { name: \"icon\", title: \"Icon button\", description: \"`IconButton`: a square button holding an icon; `label` is its accessible name.\" },\n ],\n },\n native: {\n imports: [\"Button\", \"IconButton\"],\n differences: [\n \"The text is the `label` prop (a string), not children: it is also the accessible name.\",\n \"`onPress` instead of `onClick` (a `Pressable`); haptics, if any, belong to your `onPress`.\",\n \"`icon` places an icon before the label; there is no `asChild`.\",\n \"`loading` shows the platform's `ActivityIndicator` in place of the icon.\",\n \"`variant=\\\"gradient\\\"` draws its fill with react-native-svg (React Native has no CSS gradient).\",\n ],\n examples: [\n { name: \"primary\", title: \"Primary\", description: \"The main action of a screen.\" },\n { name: \"gradient\", title: \"Gradient\", description: \"accent → accent-2, drawn with react-native-svg: the hero action of a screen.\" },\n { name: \"secondary\", title: \"Secondary\", description: \"The default look.\" },\n { name: \"outline\", title: \"Outline\", description: \"A lighter action.\" },\n { name: \"ghost\", title: \"Ghost\", description: \"No frame: toolbars, headers.\" },\n { name: \"danger\", title: \"Danger\", description: \"A destructive action.\" },\n { name: \"sizes\", title: \"Sizes\", description: \"`sm`, `md`, `lg`, and `shape=\\\"pill\\\"`.\" },\n { name: \"icon\", title: \"With an icon\", description: \"`icon` before the label.\" },\n { name: \"disabled\", title: \"Disabled\", description: \"Not available yet.\" },\n { name: \"loading\", title: \"Loading\", description: \"Disabled and busy, a spinner in place of the icon.\" },\n { name: \"icon-only\", title: \"Icon button\", description: \"`IconButton`: `label` is required, it is the accessible name.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
655
655
  },
656
656
  {
657
657
  "path": "button/recipe.ts",
658
- "content": "// The button's variants, written once as classes of the Krizaka tokens: the web wears them with `tv(buttonRecipe)`\n// (button.tsx), React Native reads the same classes into styles (native/button.tsx, `nativeRecipe`).\nimport { defineRecipe } from \"../recipes/define\";\n\nexport const buttonRecipe = defineRecipe({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98] \" +\n // Busy is not unavailable: a loading button keeps its colour (it is disabled only so it is not pressed twice).\n \"[&[data-loading]]:opacity-100\",\n variants: {\n variant: {\n primary: \"bg-accent text-on-accent shadow-sm hover:bg-accent-hover\",\n // The brand's signature: accent → accent-2 (on-accent reads on both stops, tested in @krizaka/tokens).\n gradient: \"bg-linear-to-r from-accent to-accent-2 text-on-accent shadow-sm hover:brightness-110\",\n secondary: \"border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3\",\n outline: \"border border-border-default bg-transparent text-fg hover:border-accent hover:text-fg-accent\",\n ghost: \"text-fg-secondary hover:bg-surface-2 hover:text-fg\",\n // The border and the tint carry the danger; the label stays the primary text role, legible on the tint at rest\n // and hovered over every surface (`text-fg-danger` is for text set directly on a surface).\n danger: \"border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20\",\n },\n size: { sm: \"h-8 px-3 text-xs\", md: \"h-10 px-4 text-sm\", lg: \"h-12 px-6 text-sm\", icon: \"h-10 w-10\" },\n // `cut`: the Krizaka chamfer — 45° corners (CSS corner-shape, where supported; rounded elsewhere). The border, the\n // focus ring and the hover follow the cut, unlike a clip-path.\n shape: { rounded: \"rounded-lg\", pill: \"rounded-full\", cut: \"rounded-[10px] [corner-shape:bevel]\" },\n },\n defaultVariants: { variant: \"secondary\", size: \"md\", shape: \"rounded\" },\n});\n"
658
+ "content": "// The button's variants, written once as classes of the Krizaka tokens: the web wears them with `tv(buttonRecipe)`\n// (button.tsx), React Native reads the same classes into styles (native/button.tsx, `nativeRecipe`).\nimport { defineRecipe } from \"../recipes/define\";\n\nexport const buttonRecipe = defineRecipe({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition duration-150 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98] \" +\n // Busy is not unavailable: a loading button keeps its colour (it is disabled only so it is not pressed twice).\n \"[&[data-loading]]:opacity-100\",\n variants: {\n variant: {\n primary: \"bg-accent text-on-accent shadow-sm hover:bg-accent-hover\",\n // The brand's signature: accent → accent-2 (on-accent reads on both stops, tested in @krizaka/tokens).\n gradient: \"bg-linear-to-r from-accent to-accent-2 text-on-accent shadow-sm hover:brightness-110\",\n secondary: \"border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3\",\n outline: \"border border-border-default bg-transparent text-fg hover:border-accent hover:text-fg-accent\",\n ghost: \"text-fg-secondary hover:bg-surface-2 hover:text-fg\",\n // The border and the tint carry the danger; the label stays the primary text role, legible on the tint at rest\n // and hovered over every surface (`text-fg-danger` is for text set directly on a surface).\n danger: \"border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20\",\n },\n size: { sm: \"h-8 px-3 text-xs\", md: \"h-10 px-4 text-sm\", lg: \"h-12 px-6 text-sm\", icon: \"h-10 w-10\" },\n // One clean shape (krizaka-ui#393): an 8 px radius (`--kz-radius-sm`, the radius of a field — a button beside an\n // input lines up with it), the pill on demand. `cut` (the retired chamfer) is a deprecated alias of `rounded`.\n shape: { rounded: \"rounded-sm\", pill: \"rounded-full\", cut: \"rounded-sm\" },\n },\n defaultVariants: { variant: \"secondary\", size: \"md\", shape: \"rounded\" },\n});\n"
659
659
  },
660
660
  {
661
661
  "path": "meta.ts",
@@ -712,7 +712,7 @@
712
712
  "name": "magnetic",
713
713
  "type": "boolean",
714
714
  "default": null,
715
- "description": "The button leans a few pixels toward a fine pointer (driven by `MotionObserver`; never under reduced motion or on touch).",
715
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — a button never moves under the pointer. Removed in 4.0.",
716
716
  "required": false
717
717
  },
718
718
  {
@@ -726,14 +726,14 @@
726
726
  "name": "shape",
727
727
  "type": "\"rounded\" | \"pill\" | \"cut\"",
728
728
  "default": "rounded",
729
- "description": "rounded · pill · cut (45° corners, the Krizaka chamfer).",
729
+ "description": "`rounded` (an 8 px radius, the radius of a field) · `pill`. `cut` is deprecated (krizaka-ui#393: the chamfer is\nretired) — it draws `rounded` and warns in development; it will be removed in 4.0.",
730
730
  "required": false
731
731
  },
732
732
  {
733
733
  "name": "shimmer",
734
734
  "type": "boolean",
735
735
  "default": null,
736
- "description": "A sheen of light crosses the button on hover — for the one action a page is about.",
736
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — the hover is quiet. Removed in 4.0.",
737
737
  "required": false
738
738
  },
739
739
  {
@@ -802,7 +802,7 @@
802
802
  "name": "magnetic",
803
803
  "type": "boolean",
804
804
  "default": null,
805
- "description": "The button leans a few pixels toward a fine pointer (driven by `MotionObserver`; never under reduced motion or on touch).",
805
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — a button never moves under the pointer. Removed in 4.0.",
806
806
  "required": false
807
807
  },
808
808
  {
@@ -816,14 +816,14 @@
816
816
  "name": "shape",
817
817
  "type": "\"rounded\" | \"pill\" | \"cut\"",
818
818
  "default": "rounded",
819
- "description": "rounded · pill · cut (45° corners, the Krizaka chamfer).",
819
+ "description": "`rounded` (an 8 px radius, the radius of a field) · `pill`. `cut` is deprecated (krizaka-ui#393: the chamfer is\nretired) — it draws `rounded` and warns in development; it will be removed in 4.0.",
820
820
  "required": false
821
821
  },
822
822
  {
823
823
  "name": "shimmer",
824
824
  "type": "boolean",
825
825
  "default": null,
826
- "description": "A sheen of light crosses the button on hover — for the one action a page is about.",
826
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — the hover is quiet. Removed in 4.0.",
827
827
  "required": false
828
828
  },
829
829
  {