@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
@@ -2,8 +2,8 @@
2
2
  "name": "glow-card",
3
3
  "type": "primitive",
4
4
  "title": "Glow card",
5
- "summary": "A card lit by the brand: a bloom of the accent follows the pointer across it, and its border is a ring of the brand gradient that turns and brightens under the pointer or the focus.",
6
- "description": "A card lit by the brand: a bloom of the accent follows the pointer across it, and its border is a ring of the brand gradient that turns and brightens under the pointer or the focus.",
5
+ "summary": "A card ringed by the brand: its border is a still hairline of the brand gradient, a step brighter under the pointer or the focus, fuller on a featured card. Nothing follows the pointer, nothing turns (krizaka-ui#393).",
6
+ "description": "A card ringed by the brand: its border is a still hairline of the brand gradient, a step brighter under the pointer or the focus, fuller on a featured card. Nothing follows the pointer, nothing turns (krizaka-ui#393).",
7
7
  "status": "beta",
8
8
  "deprecated": null,
9
9
  "category": "layout",
@@ -32,24 +32,24 @@
32
32
  "use": "card"
33
33
  },
34
34
  {
35
- "when": "Around content the reader studies (a form, a table): light that moves distracts."
35
+ "when": "Around content the reader studies (a form, a table): a coloured ring competes with it."
36
36
  }
37
37
  ],
38
38
  "bestPractices": [
39
39
  "One grid of glowing cards per page; `alive` on one card at most.",
40
- "Make the whole card the link with `asChild` when it leads somewhere — the focus lights it like the pointer.",
40
+ "Make the whole card the link with `asChild` when it leads somewhere — the focus brightens its ring like the pointer.",
41
41
  "Colours come from the brand (`.brand-<id>`): never pass one."
42
42
  ],
43
43
  "accessibility": {
44
44
  "keyboard": [
45
45
  {
46
46
  "keys": "Tab",
47
- "action": "Focusing the card (or a control inside it) lights its ring, as the pointer does."
47
+ "action": "Focusing the card (or a control inside it) brightens its ring, as the pointer does."
48
48
  }
49
49
  ],
50
50
  "notes": [
51
- "Decorative light only (pseudo-elements): nothing is added to the accessibility tree; the card's semantics are yours.",
52
- "Under `prefers-reduced-motion` the ring rests at a fixed angle — still lit on hover and focus, never turning.",
51
+ "A decorative ring only (a pseudo-element): nothing is added to the accessibility tree; the card's semantics are yours.",
52
+ "Nothing moves or turns, with or without `prefers-reduced-motion`; only the ring's opacity changes, in 150 ms.",
53
53
  "Its loops pause off screen and while the page settles (MotionObserver)."
54
54
  ]
55
55
  },
@@ -63,13 +63,13 @@
63
63
  "props": [
64
64
  {
65
65
  "component": "GlowCard",
66
- "description": "A card lit by the brand: a bloom that follows the pointer, a gradient ring that turns. Content is yours.",
66
+ "description": "A card ringed by the brand: a still hairline of its gradient, a step brighter under the pointer. Content is yours.",
67
67
  "props": [
68
68
  {
69
69
  "name": "alive",
70
70
  "type": "boolean",
71
71
  "default": "false",
72
- "description": "The ring turns slowly even at rest (a featured card). Otherwise it rests until hovered or focused.",
72
+ "description": "A featured card: the ring is fuller at rest. It never turns.",
73
73
  "required": false
74
74
  },
75
75
  {
@@ -83,7 +83,7 @@
83
83
  "name": "glow",
84
84
  "type": "\"both\" | \"border\" | \"spotlight\"",
85
85
  "default": "both",
86
- "description": "What answers: `border` (the turning gradient ring), `spotlight` (the bloom under the pointer), or `both`.",
86
+ "description": "`border` (a still hairline ring of the brand gradient) or `both`. `spotlight` (the bloom under the pointer) is\ndeprecated since 3.31 (krizaka-ui#393) and draws nothing.",
87
87
  "required": false
88
88
  }
89
89
  ]
@@ -93,7 +93,7 @@
93
93
  {
94
94
  "name": "plans",
95
95
  "title": "Plans",
96
- "description": "Three plans: the light follows the pointer across them; the featured one's ring turns at rest.",
96
+ "description": "Three plans: each ring brightens under the pointer; the featured one's ring is fuller at rest.",
97
97
  "path": "examples/glow-card/plans.tsx",
98
98
  "module": "@krizaka/ui/registry/examples/glow-card/plans",
99
99
  "code": "import { Button } from \"@krizaka/ui/button\";\nimport { GlowCard } from \"@krizaka/ui/glow-card\";\n\nconst plans = [\n { name: \"Community\", price: \"Free\", line: \"Self-hosted, every feature.\", action: \"Start free\" },\n { name: \"Team\", price: \"€19\", line: \"Shared workspaces and roles.\", action: \"Choose Team\", featured: true },\n { name: \"Sovereign\", price: \"Custom\", line: \"Your servers, our support.\", action: \"Talk to us\" },\n];\n\n// Plans: move the pointer across them — the light follows, the ring brightens. The featured plan's ring turns at rest.\n// The columns follow the box they are in (a container query), not the screen: three side by side only when each has room\n// for its price and its button; the buttons span their card and stand on one line at the bottom.\nexport default function GlowCardPlans() {\n return (\n <div className=\"@container w-full max-w-3xl\">\n <div className=\"grid gap-3 @lg:grid-cols-3\">\n {plans.map((p) => (\n <GlowCard key={p.name} alive={p.featured} className=\"flex min-w-0 flex-col gap-2 p-5\">\n <h3 className=\"font-display text-base font-semibold text-fg\">{p.name}</h3>\n <p className=\"font-display text-3xl font-bold tracking-tight text-fg\">{p.price}</p>\n <p className=\"mb-3 text-sm text-fg-secondary\">{p.line}</p>\n <Button variant={p.featured ? \"gradient\" : \"outline\"} size=\"sm\" className=\"mt-auto w-full\">\n {p.action}\n </Button>\n </GlowCard>\n ))}\n </div>\n </div>\n );\n}\n"
@@ -101,7 +101,7 @@
101
101
  {
102
102
  "name": "link-card",
103
103
  "title": "A card that is a link",
104
- "description": "`asChild` on an `<a>`, `glow=\"border\"`: the focus lights the ring.",
104
+ "description": "`asChild` on an `<a>`, `glow=\"border\"`: the focus brightens the ring.",
105
105
  "path": "examples/glow-card/link-card.tsx",
106
106
  "module": "@krizaka/ui/registry/examples/glow-card/link-card",
107
107
  "code": "import { GlowCard } from \"@krizaka/ui/glow-card\";\n\n// `asChild`: the card is the link. The focus lights the ring as the pointer does — keyboard readers get the same answer.\nexport default function GlowCardLink() {\n return (\n <GlowCard asChild glow=\"border\" className=\"block max-w-sm no-underline focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\">\n <a href=\"#docs\">\n <span className=\"block font-display text-lg font-semibold text-fg\">Read the documentation</span>\n <span className=\"mt-1 block text-sm text-fg-secondary\">Every component, its examples and its props — generated from the code.</span>\n </a>\n </GlowCard>\n );\n}\n"
@@ -109,10 +109,10 @@
109
109
  {
110
110
  "name": "spotlight",
111
111
  "title": "Spotlight only",
112
- "description": "`glow=\"spotlight\"`: the bloom alone, for a dense grid.",
112
+ "description": "`glow=\"spotlight\"` is deprecated (krizaka-ui#393): the bloom is retired, the card draws no ring.",
113
113
  "path": "examples/glow-card/spotlight.tsx",
114
114
  "module": "@krizaka/ui/registry/examples/glow-card/spotlight",
115
- "code": "import { GlowCard } from \"@krizaka/ui/glow-card\";\n\n// `glow=\"spotlight\"`: only the bloom under the pointer, for a dense grid where rings would be too much.\nexport default function GlowCardSpotlight() {\n return (\n <div className=\"grid w-full max-w-lg grid-cols-2 gap-3\">\n {[\"Tips\", \"Unlocks\", \"Auctions\", \"Challenges\"].map((name) => (\n <GlowCard key={name} glow=\"spotlight\" className=\"p-4\">\n <p className=\"font-semibold text-fg\">{name}</p>\n <p className=\"text-xs text-fg-secondary\">90 % to the creator</p>\n </GlowCard>\n ))}\n </div>\n );\n}\n"
115
+ "code": "import { GlowCard } from \"@krizaka/ui/glow-card\";\n\n// `glow=\"spotlight\"` is deprecated (krizaka-ui#393): the bloom under the pointer is retired, so these cards draw no ring.\nexport default function GlowCardSpotlight() {\n return (\n <div className=\"grid w-full max-w-lg grid-cols-2 gap-3\">\n {[\"Tips\", \"Unlocks\", \"Auctions\", \"Challenges\"].map((name) => (\n <GlowCard key={name} glow=\"spotlight\" className=\"p-4\">\n <p className=\"font-semibold text-fg\">{name}</p>\n <p className=\"text-xs text-fg-secondary\">90 % to the creator</p>\n </GlowCard>\n ))}\n </div>\n );\n}\n"
116
116
  }
117
117
  ]
118
118
  },
@@ -120,7 +120,7 @@
120
120
  "files": [
121
121
  {
122
122
  "path": "glow-card/glow-card.tsx",
123
- "content": "// Client (the pointer). A card that answers light: a soft bloom of the brand accent follows the pointer across it, and\n// its border is a ring of the brand gradient that turns slowly and brightens under the pointer or the focus. Composited\n// properties only (CSS variables, opacity); no animation frame — the pointer writes two variables. Under reduced motion\n// the ring rests at a fixed angle and the light stays where it is: a designed still frame, not a switched-off one.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport type GlowCardProps = React.ComponentProps<\"div\"> & {\n /**\n * What answers: `border` (the turning gradient ring), `spotlight` (the bloom under the pointer), or `both`.\n * @default \"both\"\n */\n glow?: \"border\" | \"spotlight\" | \"both\";\n /** Renders your element (a link, an article) with the card's look and behaviour. */\n asChild?: boolean;\n /**\n * The ring turns slowly even at rest (a featured card). Otherwise it rests until hovered or focused.\n * @default false\n */\n alive?: boolean;\n};\n\n/** A card lit by the brand: a bloom that follows the pointer, a gradient ring that turns. Content is yours. */\nexport function GlowCard({ glow = \"both\", asChild, alive, className, onPointerMove, ...props }: GlowCardProps) {\n const Comp = asChild ? Slot.Root : \"div\";\n return (\n <Comp\n data-glow={glow}\n data-alive={alive ? \"\" : undefined}\n className={cn(\"kz-glow kz-loop relative isolate rounded-2xl border border-border-default bg-surface-1 p-6\", className)}\n onPointerMove={(e: React.PointerEvent<HTMLDivElement>) => {\n const box = e.currentTarget.getBoundingClientRect();\n e.currentTarget.style.setProperty(\"--kz-glow-x\", `${e.clientX - box.left}px`);\n e.currentTarget.style.setProperty(\"--kz-glow-y\", `${e.clientY - box.top}px`);\n onPointerMove?.(e);\n }}\n {...props}\n />\n );\n}\n"
123
+ "content": "// Client (the pointer). A card that answers light: a soft bloom of the brand accent follows the pointer across it, and\n// its border is a ring of the brand gradient that turns slowly and brightens under the pointer or the focus. Composited\n// properties only (CSS variables, opacity); no animation frame — the pointer writes two variables. Under reduced motion\n// the ring rests at a fixed angle and the light stays where it is: a designed still frame, not a switched-off one.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport type GlowCardProps = React.ComponentProps<\"div\"> & {\n /**\n * `border` (a still hairline ring of the brand gradient) or `both`. `spotlight` (the bloom under the pointer) is\n * deprecated since 3.31 (krizaka-ui#393) and draws nothing.\n * @default \"both\"\n */\n glow?: \"border\" | \"spotlight\" | \"both\";\n /** Renders your element (a link, an article) with the card's look and behaviour. */\n asChild?: boolean;\n /**\n * A featured card: the ring is fuller at rest. It never turns.\n * @default false\n */\n alive?: boolean;\n};\n\n/** A card ringed by the brand: a still hairline of its gradient, a step brighter under the pointer. Content is yours. */\nexport function GlowCard({ glow = \"both\", asChild, alive, className, ...props }: GlowCardProps) {\n const Comp = asChild ? Slot.Root : \"div\";\n return (\n <Comp\n data-glow={glow}\n data-alive={alive ? \"\" : undefined}\n className={cn(\"kz-glow relative isolate rounded-2xl border border-border-default bg-surface-1 p-6\", className)}\n {...props}\n />\n );\n}\n"
124
124
  },
125
125
  {
126
126
  "path": "glow-card/index.ts",
@@ -128,7 +128,7 @@
128
128
  },
129
129
  {
130
130
  "path": "glow-card/meta.ts",
131
- "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Glow card\",\n summary:\n \"A card lit by the brand: a bloom of the accent follows the pointer across it, and its border is a ring of the brand gradient that turns and brightens under the pointer or the focus.\",\n status: \"beta\",\n category: \"layout\",\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 \"Cards that invite a choice: plans, products, the entry points of a landing page.\",\n \"One featured card among others (`alive`): its ring turns at rest.\",\n ],\n whenNotToUse: [\n { when: \"For the cards of an app's lists and feeds: a calm card reads better there.\", use: \"card\" },\n { when: \"Around content the reader studies (a form, a table): light that moves distracts.\" },\n ],\n bestPractices: [\n \"One grid of glowing cards per page; `alive` on one card at most.\",\n \"Make the whole card the link with `asChild` when it leads somewhere — the focus lights it like the pointer.\",\n \"Colours come from the brand (`.brand-<id>`): never pass one.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Tab\", action: \"Focusing the card (or a control inside it) lights its ring, as the pointer does.\" }],\n notes: [\n \"Decorative light only (pseudo-elements): nothing is added to the accessibility tree; the card's semantics are yours.\",\n \"Under `prefers-reduced-motion` the ring rests at a fixed angle — still lit on hover and focus, never turning.\",\n \"Its loops pause off screen and while the page settles (MotionObserver).\",\n ],\n },\n related: [\"card\", \"button\"],\n web: {\n imports: [\"GlowCard\"],\n examples: [\n { name: \"plans\", title: \"Plans\", description: \"Three plans: the light follows the pointer across them; the featured one's ring turns at rest.\" },\n { name: \"link-card\", title: \"A card that is a link\", description: \"`asChild` on an `<a>`, `glow=\\\"border\\\"`: the focus lights the ring.\" },\n { name: \"spotlight\", title: \"Spotlight only\", description: \"`glow=\\\"spotlight\\\"`: the bloom alone, for a dense grid.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
131
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Glow card\",\n summary:\n \"A card ringed by the brand: its border is a still hairline of the brand gradient, a step brighter under the pointer or the focus, fuller on a featured card. Nothing follows the pointer, nothing turns (krizaka-ui#393).\",\n status: \"beta\",\n category: \"layout\",\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 \"Cards that invite a choice: plans, products, the entry points of a landing page.\",\n \"One featured card among others (`alive`): its ring turns at rest.\",\n ],\n whenNotToUse: [\n { when: \"For the cards of an app's lists and feeds: a calm card reads better there.\", use: \"card\" },\n { when: \"Around content the reader studies (a form, a table): a coloured ring competes with it.\" },\n ],\n bestPractices: [\n \"One grid of glowing cards per page; `alive` on one card at most.\",\n \"Make the whole card the link with `asChild` when it leads somewhere — the focus brightens its ring like the pointer.\",\n \"Colours come from the brand (`.brand-<id>`): never pass one.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Tab\", action: \"Focusing the card (or a control inside it) brightens its ring, as the pointer does.\" }],\n notes: [\n \"A decorative ring only (a pseudo-element): nothing is added to the accessibility tree; the card's semantics are yours.\",\n \"Nothing moves or turns, with or without `prefers-reduced-motion`; only the ring's opacity changes, in 150 ms.\",\n \"Its loops pause off screen and while the page settles (MotionObserver).\",\n ],\n },\n related: [\"card\", \"button\"],\n web: {\n imports: [\"GlowCard\"],\n examples: [\n { name: \"plans\", title: \"Plans\", description: \"Three plans: each ring brightens under the pointer; the featured one's ring is fuller at rest.\" },\n { name: \"link-card\", title: \"A card that is a link\", description: \"`asChild` on an `<a>`, `glow=\\\"border\\\"`: the focus brightens the ring.\" },\n { name: \"spotlight\", title: \"Spotlight only\", description: \"`glow=\\\"spotlight\\\"` is deprecated (krizaka-ui#393): the bloom is retired, the card draws no ring.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
132
132
  },
133
133
  {
134
134
  "path": "meta.ts",
@@ -148,13 +148,13 @@
148
148
  "props": [
149
149
  {
150
150
  "component": "GlowCard",
151
- "description": "A card lit by the brand: a bloom that follows the pointer, a gradient ring that turns. Content is yours.",
151
+ "description": "A card ringed by the brand: a still hairline of its gradient, a step brighter under the pointer. Content is yours.",
152
152
  "props": [
153
153
  {
154
154
  "name": "alive",
155
155
  "type": "boolean",
156
156
  "default": "false",
157
- "description": "The ring turns slowly even at rest (a featured card). Otherwise it rests until hovered or focused.",
157
+ "description": "A featured card: the ring is fuller at rest. It never turns.",
158
158
  "required": false
159
159
  },
160
160
  {
@@ -168,7 +168,7 @@
168
168
  "name": "glow",
169
169
  "type": "\"both\" | \"border\" | \"spotlight\"",
170
170
  "default": "both",
171
- "description": "What answers: `border` (the turning gradient ring), `spotlight` (the bloom under the pointer), or `both`.",
171
+ "description": "`border` (a still hairline ring of the brand gradient) or `both`. `spotlight` (the bloom under the pointer) is\ndeprecated since 3.31 (krizaka-ui#393) and draws nothing.",
172
172
  "required": false
173
173
  }
174
174
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krizaka/ui",
3
- "version": "3.29.0",
3
+ "version": "3.31.0",
4
4
  "templatePurposes": {
5
5
  "convince": {
6
6
  "title": "Convince",
@@ -719,7 +719,7 @@
719
719
  }
720
720
  },
721
721
  "examples": {
722
- "web": 5,
722
+ "web": 4,
723
723
  "native": 0
724
724
  },
725
725
  "dependencies": [],
@@ -860,8 +860,8 @@
860
860
  "name": "button",
861
861
  "type": "primitive",
862
862
  "title": "Button",
863
- "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.",
864
- "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.",
863
+ "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.",
864
+ "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.",
865
865
  "status": "stable",
866
866
  "category": "actions",
867
867
  "platforms": "both",
@@ -959,8 +959,8 @@
959
959
  "name": "card-grid",
960
960
  "type": "primitive",
961
961
  "title": "Card grid",
962
- "summary": "A responsive grid of cards: as many columns as the width allows (one on a phone), the cells of a row at one height, a staggered reveal and the light that follows the pointer.",
963
- "description": "A responsive grid of cards: as many columns as the width allows (one on a phone), the cells of a row at one height, a staggered reveal and the light that follows the pointer.",
962
+ "summary": "A responsive grid of cards: as many columns as the width allows (one on a phone), the cells of a row at one height, a staggered reveal; each card keeps its own quiet hover.",
963
+ "description": "A responsive grid of cards: as many columns as the width allows (one on a phone), the cells of a row at one height, a staggered reveal; each card keeps its own quiet hover.",
964
964
  "status": "beta",
965
965
  "category": "blocks",
966
966
  "platforms": "web",
@@ -985,8 +985,7 @@
985
985
  "dependencies": [],
986
986
  "registryDependencies": [
987
987
  "cn",
988
- "link-card",
989
- "pointer-light"
988
+ "link-card"
990
989
  ]
991
990
  },
992
991
  {
@@ -2429,8 +2428,8 @@
2429
2428
  "name": "glow-card",
2430
2429
  "type": "primitive",
2431
2430
  "title": "Glow card",
2432
- "summary": "A card lit by the brand: a bloom of the accent follows the pointer across it, and its border is a ring of the brand gradient that turns and brightens under the pointer or the focus.",
2433
- "description": "A card lit by the brand: a bloom of the accent follows the pointer across it, and its border is a ring of the brand gradient that turns and brightens under the pointer or the focus.",
2431
+ "summary": "A card ringed by the brand: its border is a still hairline of the brand gradient, a step brighter under the pointer or the focus, fuller on a featured card. Nothing follows the pointer, nothing turns (krizaka-ui#393).",
2432
+ "description": "A card ringed by the brand: its border is a still hairline of the brand gradient, a step brighter under the pointer or the focus, fuller on a featured card. Nothing follows the pointer, nothing turns (krizaka-ui#393).",
2434
2433
  "status": "beta",
2435
2434
  "category": "layout",
2436
2435
  "platforms": "web",
@@ -2839,8 +2838,8 @@
2839
2838
  "name": "link-card",
2840
2839
  "type": "primitive",
2841
2840
  "title": "Link card",
2842
- "summary": "An entry point where the whole card is one link: an icon tile, a title, one sentence and the way in — compact, the same on every page, lifting and lighting under the pointer or the focus.",
2843
- "description": "An entry point where the whole card is one link: an icon tile, a title, one sentence and the way in — compact, the same on every page, lifting and lighting under the pointer or the focus.",
2841
+ "summary": "An entry point where the whole card is one link: an icon tile, a title, one sentence and the way in — compact, the same on every page; under the pointer its surface and hairline go one step up, nothing moves.",
2842
+ "description": "An entry point where the whole card is one link: an icon tile, a title, one sentence and the way in — compact, the same on every page; under the pointer its surface and hairline go one step up, nothing moves.",
2844
2843
  "status": "beta",
2845
2844
  "category": "blocks",
2846
2845
  "platforms": "web",
@@ -2859,7 +2858,7 @@
2859
2858
  }
2860
2859
  },
2861
2860
  "examples": {
2862
- "web": 5,
2861
+ "web": 4,
2863
2862
  "native": 0
2864
2863
  },
2865
2864
  "dependencies": [],
@@ -3014,11 +3013,11 @@
3014
3013
  }
3015
3014
  },
3016
3015
  "examples": {
3017
- "web": 4,
3016
+ "web": 5,
3018
3017
  "native": 2
3019
3018
  },
3020
3019
  "dependencies": [
3021
- "@krizaka/tokens@^3.29.0",
3020
+ "@krizaka/tokens@^3.31.0",
3022
3021
  "@protomaps/basemaps@5.7.2",
3023
3022
  "tailwind-variants@^3.3.1"
3024
3023
  ],
@@ -3457,7 +3456,7 @@
3457
3456
  "native": 0
3458
3457
  },
3459
3458
  "dependencies": [
3460
- "@krizaka/tokens@^3.29.0",
3459
+ "@krizaka/tokens@^3.31.0",
3461
3460
  "radix-ui@^1.7.0",
3462
3461
  "tailwind-variants@^3.3.1"
3463
3462
  ],
@@ -3778,9 +3777,9 @@
3778
3777
  "name": "pointer-light",
3779
3778
  "type": "primitive",
3780
3779
  "title": "Pointer light",
3781
- "summary": "The light that follows the pointer over a group of cards: one passive listener writes the pointer's position into the card it is over, the card's CSS draws the light.",
3782
- "description": "The light that follows the pointer over a group of cards: one passive listener writes the pointer's position into the card it is over, the card's CSS draws the light.",
3783
- "status": "beta",
3780
+ "summary": "Deprecated (krizaka-ui#393): it drew a light that followed the pointer over cards. It now does nothing — the cards have one quiet hover of their own.",
3781
+ "description": "Deprecated (krizaka-ui#393): it drew a light that followed the pointer over cards. It now does nothing — the cards have one quiet hover of their own.",
3782
+ "status": "deprecated",
3784
3783
  "category": "blocks",
3785
3784
  "platforms": "web",
3786
3785
  "parity": {
@@ -4089,7 +4088,7 @@
4089
4088
  "native": 0
4090
4089
  },
4091
4090
  "dependencies": [
4092
- "@krizaka/tokens@^3.29.0",
4091
+ "@krizaka/tokens@^3.31.0",
4093
4092
  "radix-ui@^1.7.0",
4094
4093
  "tailwind-variants@^3.3.1"
4095
4094
  ],
@@ -4432,7 +4431,7 @@
4432
4431
  "native": 0
4433
4432
  },
4434
4433
  "dependencies": [
4435
- "@krizaka/tokens@^3.29.0",
4434
+ "@krizaka/tokens@^3.31.0",
4436
4435
  "radix-ui@^1.7.0",
4437
4436
  "tailwind-variants@^3.3.1"
4438
4437
  ],
package/registry/iso.json CHANGED
@@ -49,7 +49,7 @@
49
49
  "keyboard": [
50
50
  {
51
51
  "keys": "Tab",
52
- "action": "Visits each named object of the scene: it lifts and shows its label, as under the pointer."
52
+ "action": "Visits each named object of the scene: it brightens and shows its label, as under the pointer."
53
53
  }
54
54
  ],
55
55
  "notes": [
@@ -434,7 +434,7 @@
434
434
  "name": "label",
435
435
  "type": "string",
436
436
  "default": null,
437
- "description": "The name shown when the pointer (or the focus) lifts the object — passed translated. It also makes it focusable.",
437
+ "description": "The name shown when the pointer (or the focus) is on the object — passed translated. It also makes it focusable.",
438
438
  "required": false
439
439
  },
440
440
  {
@@ -655,7 +655,7 @@
655
655
  "name": "label",
656
656
  "type": "string",
657
657
  "default": null,
658
- "description": "The name shown when the pointer (or the focus) lifts the object — passed translated. It also makes it focusable.",
658
+ "description": "The name shown when the pointer (or the focus) is on the object — passed translated. It also makes it focusable.",
659
659
  "required": false
660
660
  },
661
661
  {
@@ -733,11 +733,11 @@
733
733
  },
734
734
  {
735
735
  "path": "iso/iso.tsx",
736
- "content": "// Server-safe: no state, no effect, no context — static SVG computed at render time, animated by motion.css (`kz-iso-*`,\n// shipped by the preset), so a hero costs no client JavaScript. `useId` only (allowed in Server Components): every scene\n// owns its gradient and mask ids. Classes are joined with `cx`: no tailwind-variants in this entry.\nimport * as React from \"react\";\n\nimport { cx as cn } from \"../cx\";\nimport { cutRect, depthOf, type Face, hexagon, isoCircle, onCircle, pathOf, prism, project, pts, type Vec2, viewBoxOf } from \"./geometry\";\n\n/** How a solid is lit: the page's surfaces (`base`), the brand accent, accent → accent-2, or frosted glass. */\nexport type IsoMaterial = \"base\" | \"accent\" | \"accent2\" | \"glass\";\n/** The footprint of a prism: a hexagon (the marks), a rectangle with 45° cut corners (the icons) or a plain one. */\nexport type IsoShape = \"hex\" | \"cut\" | \"rect\";\n/** A pictogram drawn on the top of a tile. */\nexport type IsoGlyph = \"dots\" | \"lines\" | \"play\" | \"coin\" | \"lock\" | \"arrow\" | \"flag\" | \"heart\" | \"node\" | \"none\";\n\ntype Style = React.CSSProperties & Record<`--${string}`, string | number>;\n\nconst uid = (raw: string) => raw.replace(/[^a-zA-Z0-9_-]/g, \"\");\nconst footprint = (shape: IsoShape, [x, y]: Vec2, size: number | Vec2, cut?: number): Vec2[] => {\n const [w, d] = typeof size === \"number\" ? [size, size] : size;\n if (shape === \"hex\") return hexagon(x, y, w / 2);\n return cutRect(x, y, w, d, shape === \"rect\" ? 0 : (cut ?? Math.min(w, d) / 6));\n};\n\nexport interface IsoSceneProps extends Omit<React.ComponentProps<\"svg\">, \"children\"> {\n /** The accessible name of the scene (\"A server stack under a dome\") — passed translated. Without it the scene is decorative. */\n label?: string;\n /** A longer text version of what the scene shows, read by assistive technology. */\n description?: string;\n /**\n * Half the size of the floor, in world units: what the camera frames.\n * @default 240\n */\n extent?: number;\n /**\n * Height above the floor the camera keeps in view, in world units.\n * @default 260\n */\n top?: number;\n /**\n * The perspective grid on the floor, fading into the page.\n * @default true\n */\n grid?: boolean;\n /**\n * The spacing of the grid's lines.\n * @default 40\n */\n step?: number;\n /**\n * Motion (entrance, breathing, flow, float). `false` draws the still frame — the one prefers-reduced-motion shows.\n * @default true\n */\n animated?: boolean;\n /** The objects, painted in order: put the farthest first (or use `IsoHub`, which sorts them). */\n children?: React.ReactNode;\n}\n\n/**\n * The stage: an isometric camera over a perspective grid that fades into the page. Its animations pause off screen and\n * wait for the page to settle (MotionObserver); everything stops under prefers-reduced-motion.\n */\nexport function IsoScene({ label, description, extent = 240, top = 260, grid = true, step = 40, animated = true, viewBox, className, children, ...props }: IsoSceneProps) {\n const id = uid(React.useId());\n const lines: string[] = [];\n for (let v = -extent; v <= extent; v += step) {\n lines.push(pathOf([project([v, -extent, 0]), project([v, extent, 0])]), pathOf([project([-extent, v, 0]), project([extent, v, 0])]));\n }\n const fade = isoCircle(0, 0, 0, extent * 0.9);\n const named = label ? { role: \"group\" as const, \"aria-label\": label } : { \"aria-hidden\": true as const };\n return (\n <svg\n viewBox={viewBox ?? viewBoxOf(extent, top)}\n focusable=\"false\"\n data-motion-scope=\"\"\n data-animated={animated}\n className={cn(\"kz-iso\", className)}\n {...named}\n {...props}\n >\n {description && <desc>{description}</desc>}\n {grid && (\n <>\n <defs>\n <radialGradient id={`${id}-fade`}>\n <stop offset=\"0%\" stopColor=\"white\" stopOpacity=\"1\" />\n <stop offset=\"100%\" stopColor=\"white\" stopOpacity=\"0\" />\n </radialGradient>\n <mask id={`${id}-floor`}>\n <ellipse cx={fade.cx} cy={fade.cy} rx={fade.rx} ry={fade.ry} fill={`url(#${id}-fade)`} />\n </mask>\n </defs>\n <path d={lines.join(\"\")} className=\"kz-iso-floor\" mask={`url(#${id}-floor)`} />\n </>\n )}\n {children}\n </svg>\n );\n}\n\n/** A loop only when the scene moves: `animated={false}` on the item keeps it still. */\nconst loop = (animated: boolean | undefined) => (animated === false ? undefined : \"kz-loop\");\n\ninterface ItemProps {\n /** The name shown when the pointer (or the focus) lifts the object — passed translated. It also makes it focusable. */\n label?: string;\n /**\n * Its rank in the entrance: objects rise into place one after the other.\n * @default 0\n */\n index?: number;\n /**\n * Motion: entrance and loops. `false` keeps this object still.\n * @default true\n */\n animated?: boolean;\n /** Extra classes on the object's group. */\n className?: string;\n}\n\n/** An object of the scene: rises at the entrance, lifts under the pointer or the focus and shows its label. */\nfunction Item({ label, index = 0, animated, anchor, align = \"center\", className, children }: ItemProps & { anchor: Vec2; align?: \"center\" | \"start\"; children: React.ReactNode }) {\n const named = label ? { role: \"img\" as const, \"aria-label\": label, tabIndex: 0 } : {};\n return (\n <g className={cn(\"kz-iso-item\", className)} style={{ \"--kz-iso-i\": index } as Style} {...named}>\n <g className={cn(\"kz-iso-lift\", animated !== false && \"kz-iso-rise\")}>{children}</g>\n {label && <Tip at={anchor} text={label} align={align} />}\n </g>\n );\n}\n\n/**\n * A label in a pill (decorative: the object carries the name). `center`: above the point (a floating tile). `start`:\n * beside it, to the right, with a leader — for a stage of a stack, whose upper stages would cover a label above it.\n */\nfunction Tip({ at: [x, y], text, align }: { at: Vec2; text: string; align: \"center\" | \"start\" }) {\n const w = Math.max(40, text.length * 6.6 + 20);\n if (align === \"start\") {\n return (\n <g className=\"kz-iso-tip\" aria-hidden>\n <path d={`M${Math.round(x + 3)} ${Math.round(y)}h18`} className=\"kz-iso-leader\" />\n <rect x={x + 21} y={y - 11} width={w} height={22} rx={7} strokeWidth={1} />\n <text x={x + 21 + w / 2} y={y + 4} textAnchor=\"middle\">\n {text}\n </text>\n </g>\n );\n }\n return (\n <g className=\"kz-iso-tip\" aria-hidden>\n <rect x={x - w / 2} y={y - 34} width={w} height={22} rx={7} strokeWidth={1} />\n <text x={x} y={y - 19} textAnchor=\"middle\">\n {text}\n </text>\n </g>\n );\n}\n\nfunction Solid({ faces, material }: { faces: Face[]; material: IsoMaterial }) {\n return (\n <g className={\"kz-iso-\" + material}>\n {faces.map((face, i) => (\n <polygon key={i} points={face.points} className={\"kz-iso-face kz-iso-\" + face.kind} />\n ))}\n </g>\n );\n}\n\nexport interface IsoPrismProps extends ItemProps {\n /**\n * The centre of its footprint on the floor plan (x, y).\n * @default [0, 0]\n */\n at?: Vec2;\n /**\n * The height of its base above the floor.\n * @default 0\n */\n z?: number;\n /** Its height. */\n height: number;\n /**\n * hex · cut (45° cut corners) · rect.\n * @default \"cut\"\n */\n shape?: IsoShape;\n /**\n * Its width (a number: square or hexagon's diameter) or width × depth.\n * @default 120\n */\n size?: number | Vec2;\n /** The size of the 45° cut (`shape=\"cut\"`); a sixth of the smaller side by default. */\n cut?: number;\n /**\n * How it is lit.\n * @default \"base\"\n */\n material?: IsoMaterial;\n /** A dotted light strip around its front (the LEDs of a server), blinking slowly. */\n strip?: boolean;\n}\n\n/** A vertical prism — hexagonal, cut-corner or rectangular — that stacks with others on `z`. */\nexport function IsoPrism({ at = [0, 0], z = 0, height, shape = \"cut\", size = 120, cut, material = \"base\", strip, animated, ...item }: IsoPrismProps) {\n const foot = footprint(shape, at, size, cut);\n const [w, d] = typeof size === \"number\" ? [size, size] : size;\n return (\n <Item {...item} animated={animated} anchor={project(shape === \"hex\" ? [at[0] + w / 4, at[1] - w * 0.433, z + height / 2] : [at[0] + w / 2, at[1] - d / 2, z + height / 2])} align=\"start\">\n <Solid faces={prism(foot, z, height)} material={material} />\n {strip && <Strip at={at} w={w} d={d} c={shape === \"rect\" ? 0 : (cut ?? Math.min(w, d) / 6)} z={z + height / 2 + 1} animated={animated} hex={shape === \"hex\"} />}\n </Item>\n );\n}\n\nfunction Strip({ at: [cx, cy], w, d, c, z, hex, animated }: { at: Vec2; w: number; d: number; c: number; z: number; hex: boolean; animated?: boolean }) {\n const front: Vec2[] = hex\n ? [0, 1, 2].map((k) => onCircle(w / 2, k * 60 - 60, [cx, cy]))\n : [[cx + w / 2, cy - d / 2 + c], [cx + w / 2, cy + d / 2 - c], [cx + w / 2 - c, cy + d / 2], [cx - w / 2 + c, cy + d / 2]];\n return <polyline points={pts(front.map(([x, y]) => project([x, y, z])))} className={cn(\"kz-iso-strip\", loop(animated))} />;\n}\n\n/** One stage of an `IsoStack`. */\nexport interface IsoLayer {\n /** The stage's name, shown when it is lifted — passed translated. */\n label?: string;\n /**\n * Its height.\n * @default 22\n */\n height?: number;\n /**\n * How it is lit.\n * @default \"base\"\n */\n material?: IsoMaterial;\n}\n\nexport interface IsoStackProps {\n /** The stages, bottom first; they stack one after the other at the entrance. */\n layers: readonly IsoLayer[];\n /**\n * The centre of the stack on the floor plan.\n * @default [0, 0]\n */\n at?: Vec2;\n /**\n * The footprint of the stages.\n * @default \"cut\"\n */\n shape?: IsoShape;\n /**\n * The width of the stages.\n * @default 120\n */\n size?: number;\n /**\n * The space between two stages.\n * @default 4\n */\n gap?: number;\n /**\n * A hexagonal plinth under the stack.\n * @default true\n */\n plinth?: boolean;\n /**\n * A lit hexagonal core on top, its node glowing; a string names it.\n * @default true\n */\n core?: boolean | string;\n /**\n * The rank of the first stage in the scene's entrance.\n * @default 0\n */\n index?: number;\n /**\n * Motion: entrance and loops. `false` keeps the stack still.\n * @default true\n */\n animated?: boolean;\n}\n\n/** A stack of stages on a plinth with a lit core on top — a server, a model, a pile of layers — driven by data. */\nexport function IsoStack({ layers, at = [0, 0], shape = \"cut\", size = 120, gap = 4, plinth = true, core = true, index = 0, animated }: IsoStackProps) {\n const base = plinth ? 12 + gap : 0;\n const heights = layers.map((layer) => layer.height ?? 22);\n const stages = layers.map((layer, k) => ({ ...layer, k, height: heights[k]!, z: base + heights.slice(0, k).reduce((sum, h) => sum + h + gap, 0) }));\n const top = base + heights.reduce((sum, h) => sum + h + gap, 0);\n return (\n <g>\n {plinth && <IsoPrism at={at} height={12} shape=\"hex\" size={size * 1.86} index={index} animated={animated} />}\n {stages.map((s) => (\n <IsoPrism\n key={s.k}\n at={at}\n z={s.z}\n height={s.height}\n shape={shape}\n size={size}\n material={s.material ?? \"base\"}\n strip={(s.material ?? \"base\") === \"base\"}\n label={s.label}\n index={index + 1 + s.k}\n animated={animated}\n />\n ))}\n {core && (\n <>\n <IsoPrism at={at} z={top} height={16} shape=\"hex\" size={size / 2} material=\"accent\" index={index + 1 + stages.length} animated={animated} label={typeof core === \"string\" ? core : undefined} />\n <IsoNode at={at} z={top + 22} index={index + 2 + stages.length} animated={animated} />\n </>\n )}\n </g>\n );\n}\n\nexport interface IsoNodeProps {\n /**\n * Where, on the floor plan.\n * @default [0, 0]\n */\n at?: Vec2;\n /**\n * Its height.\n * @default 0\n */\n z?: number;\n /**\n * The radius of the node.\n * @default 7\n */\n r?: number;\n /**\n * The radius of its glow (0: none).\n * @default 70\n */\n glow?: number;\n /**\n * Its rank in the entrance.\n * @default 0\n */\n index?: number;\n /**\n * Motion: the glow breathes. `false` keeps it still.\n * @default true\n */\n animated?: boolean;\n}\n\n/** The Krizaka node: a point of light in the accent, breathing in its glow. */\nexport function IsoNode({ at = [0, 0], z = 0, r = 7, glow = 70, index = 0, animated }: IsoNodeProps) {\n const id = uid(React.useId());\n const [x, y] = project([at[0], at[1], z]);\n return (\n <g className={cn(animated !== false && \"kz-iso-rise\")} style={{ \"--kz-iso-i\": index } as Style}>\n {glow > 0 && (\n <>\n <defs>\n <radialGradient id={`${id}-glow`}>\n <stop offset=\"0%\" className=\"kz-iso-glow-stop\" stopOpacity=\"0.55\" />\n <stop offset=\"100%\" className=\"kz-iso-glow-stop\" stopOpacity=\"0\" />\n </radialGradient>\n </defs>\n <circle cx={x} cy={y} r={glow} fill={`url(#${id}-glow)`} className={cn(\"kz-iso-breathe\", loop(animated))} />\n </>\n )}\n <circle cx={x} cy={y} r={r} className={cn(\"kz-iso-node kz-iso-breathe\", loop(animated))} />\n </g>\n );\n}\n\nexport interface IsoDomeProps {\n /**\n * Its centre on the floor plan.\n * @default [0, 0]\n */\n at?: Vec2;\n /**\n * The radius of its rim on the floor.\n * @default 158\n */\n radius?: number;\n /**\n * Its height.\n * @default 250\n */\n height?: number;\n /** Its name (\"Your infrastructure\") — passed translated; shown at the top of the dome, always. */\n label?: string;\n /**\n * Motion: a sheen travels along the dome. `false` keeps it still.\n * @default true\n */\n animated?: boolean;\n}\n\n/**\n * A dome of light over what it protects: a rim on the floor, a glass arc, a sheen that travels along it. Draw its rim\n * before the objects it covers and the dome after them (`part=\"rim\"`, `part=\"arc\"`), or let `IsoHub` do it.\n */\nexport function IsoDome({ at = [0, 0], radius = 158, height = 250, label, animated, part = \"both\" }: IsoDomeProps & {\n /**\n * `rim` (the floor ellipse, drawn first), `arc` (the glass, drawn last) or `both`.\n * @default \"both\"\n */\n part?: \"rim\" | \"arc\" | \"both\";\n}) {\n const e = isoCircle(at[0], at[1], 0, radius);\n const arc = `M${e.cx - e.rx} ${e.cy} A ${e.rx} ${height} 0 0 1 ${e.cx + e.rx} ${e.cy}`;\n return (\n <>\n {part !== \"arc\" && <ellipse cx={e.cx} cy={e.cy} rx={e.rx} ry={e.ry} className=\"kz-iso-rim\" />}\n {part !== \"rim\" && (\n <g>\n <path d={arc} className=\"kz-iso-dome\" />\n <path d={arc} className={cn(\"kz-iso-dome-sheen\", loop(animated))} pathLength={440} />\n {label && <IsoLabel at={at} z={height + 10} text={label} />}\n </g>\n )}\n </>\n );\n}\n\nexport interface IsoTileProps extends ItemProps {\n /** Its centre on the floor plan. */\n at: Vec2;\n /**\n * The height it floats at.\n * @default 90\n */\n z?: number;\n /**\n * Width × depth.\n * @default [76, 52]\n */\n size?: Vec2;\n /**\n * The pictogram on its top.\n * @default \"none\"\n */\n glyph?: IsoGlyph;\n /**\n * How it is lit.\n * @default \"accent\"\n */\n material?: IsoMaterial;\n /**\n * It floats gently.\n * @default true\n */\n float?: boolean;\n}\n\n/** A satellite: a thin cut-corner tile that floats beside the hero object, a pictogram on its top. */\nexport function IsoTile({ at, z = 90, size = [76, 52], glyph = \"none\", material = \"accent\", float = true, animated, ...item }: IsoTileProps) {\n const [w, d] = size;\n const top = z + 9;\n const shadow = isoCircle(at[0], at[1], 0, Math.min(w, d) * 0.55);\n const foot = project([at[0], at[1], 0]);\n return (\n <Item {...item} animated={animated} anchor={project([at[0], at[1], top])}>\n {z > 0 && (\n <>\n <ellipse cx={shadow.cx} cy={shadow.cy} rx={shadow.rx} ry={shadow.ry} className=\"kz-iso-shadow\" />\n <path d={pathOf([foot, project([at[0], at[1], z])])} className=\"kz-iso-tether\" />\n </>\n )}\n <g className={cn(float && \"kz-iso-float\", float && loop(animated))}>\n <Solid faces={prism(cutRect(at[0], at[1], w, d, Math.min(w, d) / 4), z, 9)} material={material} />\n <Glyph glyph={glyph} at={at} z={top} s={Math.min(w, d) * 0.3} />\n </g>\n </Item>\n );\n}\n\nfunction Glyph({ glyph, at: [cx, cy], z, s }: { glyph: IsoGlyph; at: Vec2; z: number; s: number }) {\n const p = (u: number, v: number) => project([cx + u * s, cy + v * s, z]);\n const line = (points: [number, number][], close = false) => <path d={pathOf(points.map(([u, v]) => p(u, v)), close)} className=\"kz-iso-glyph\" />;\n switch (glyph) {\n case \"dots\":\n return <>{[-0.8, 0, 0.8].map((u) => <circle key={u} cx={p(u, 0)[0]} cy={p(u, 0)[1]} r={s * 0.16} className=\"kz-iso-glyph-fill\" />)}</>;\n case \"lines\":\n return <>{[-0.6, 0, 0.6].map((v) => <React.Fragment key={v}>{line([[-0.9, v], [0.7, v]])}</React.Fragment>)}</>;\n case \"play\":\n return line([[-0.5, -0.7], [0.8, 0], [-0.5, 0.7]], true);\n case \"coin\":\n return (\n <>\n <path d={pathOf(hexagon(0, 0, 0.9).map(([u, v]) => p(u, v)), true)} className=\"kz-iso-glyph\" />\n <circle cx={p(0, 0)[0]} cy={p(0, 0)[1]} r={s * 0.18} className=\"kz-iso-glyph-fill\" />\n </>\n );\n case \"lock\":\n return (\n <>\n {line([[-0.6, -0.1], [0.6, -0.1], [0.6, 0.8], [-0.6, 0.8]], true)}\n {line([[-0.35, -0.1], [-0.35, -0.5], [-0.15, -0.75], [0.15, -0.75], [0.35, -0.5], [0.35, -0.1]])}\n </>\n );\n case \"arrow\":\n return (\n <>\n {line([[0.8, 0.8], [-0.6, -0.6]])}\n {line([[-0.6, 0.1], [-0.6, -0.6], [0.1, -0.6]])}\n </>\n );\n case \"flag\":\n return (\n <>\n {line([[-0.7, 0.9], [-0.7, -0.9]])}\n {line([[-0.7, -0.9], [0.8, -0.55], [-0.7, -0.1]], true)}\n </>\n );\n case \"heart\":\n return line([[0, 0.85], [-0.85, 0], [-0.85, -0.45], [-0.45, -0.8], [0, -0.45], [0.45, -0.8], [0.85, -0.45], [0.85, 0]], true);\n case \"node\":\n return <circle cx={p(0, 0)[0]} cy={p(0, 0)[1]} r={s * 0.3} className=\"kz-iso-glyph-fill\" />;\n default:\n return null;\n }\n}\n\nexport interface IsoLinkProps {\n /** Where it starts, on the floor plan. */\n from: Vec2;\n /** Where it ends, on the floor plan. */\n to: Vec2;\n /**\n * The height it runs at.\n * @default 0\n */\n z?: number;\n /**\n * `elbow` follows the floor's axes, like a circuit; `straight` goes directly.\n * @default \"elbow\"\n */\n route?: \"elbow\" | \"straight\";\n /**\n * Which way the light flows: `out` from `from` to `to`, `in` back.\n * @default \"out\"\n */\n direction?: \"out\" | \"in\";\n /**\n * Particles of light travelling along it (0: only the dashes flow).\n * @default 2\n */\n particles?: number;\n /**\n * Seconds a particle takes to cross it.\n * @default 3.6\n */\n duration?: number;\n /** A value written on it (\"90 %\", \"Tips\") — passed translated. */\n label?: string;\n /**\n * Motion: the flow and the particles. `false` draws them still, resting along the link.\n * @default true\n */\n animated?: boolean;\n}\n\n/** A dotted link on the floor, light flowing along it and particles crossing it — a flow between two objects. */\nexport function IsoLink({ from, to, z = 0, route = \"elbow\", direction = \"out\", particles = 2, duration = 3.6, label, animated }: IsoLinkProps) {\n const corner: Vec2 = [to[0], from[1]];\n const plan = route === \"elbow\" && from[0] !== to[0] && from[1] !== to[1] ? [from, corner, to] : [from, to];\n const ordered = direction === \"in\" ? [...plan].reverse() : plan;\n const d = pathOf(ordered.map(([x, y]) => project([x, y, z])));\n const mid = plan.length === 3 ? corner : ([(from[0] + to[0]) / 2, (from[1] + to[1]) / 2] as Vec2);\n return (\n <g>\n <path d={d} className={cn(\"kz-iso-link\", loop(animated))} />\n {Array.from({ length: particles }, (_, k) => (\n <circle\n key={k}\n r={3.2}\n className={cn(\"kz-iso-particle\", loop(animated))}\n style={\n {\n offsetPath: `path(\"${d}\")`,\n \"--kz-iso-at\": `${Math.round(((k + 0.5) / particles) * 100)}%`,\n \"--kz-iso-dur\": `${duration}s`,\n \"--kz-iso-delay\": `${(-duration * k) / particles}s`,\n } as Style\n }\n />\n ))}\n {label && <IsoLabel at={mid} z={z} text={label} />}\n </g>\n );\n}\n\nexport interface IsoLabelProps {\n /** Where, on the floor plan. */\n at: Vec2;\n /**\n * Its height.\n * @default 0\n */\n z?: number;\n /** The text — passed translated. */\n text: string;\n /** A first part in the accent, bolder (\"90 %\" before \" to the creator\"). */\n strong?: string;\n}\n\n/** A label in a pill, always visible, pinned to a point of the scene (a share, a name). */\nexport function IsoLabel({ at, z = 0, text, strong }: IsoLabelProps) {\n const [x, y] = project([at[0], at[1], z]);\n const chars = text.length + (strong ? strong.length + 1 : 0);\n const w = chars * 6.8 + 22;\n return (\n <g className=\"kz-iso-link-label\" aria-hidden>\n <rect x={x - w / 2} y={y - 12} width={w} height={24} rx={8} strokeWidth={1} />\n <text x={x} y={y + 4} textAnchor=\"middle\">\n {strong && <tspan className=\"kz-iso-strong\">{strong} </tspan>}\n {text}\n </text>\n </g>\n );\n}\n\n/** A satellite of an `IsoHub`. */\nexport interface IsoSatellite {\n /** Its name, shown when lifted — passed translated. */\n label: string;\n /**\n * Its pictogram.\n * @default \"none\"\n */\n glyph?: IsoGlyph;\n /**\n * The flow on its link: `in` toward the centre, `out` from it, `none` without a link.\n * @default \"in\"\n */\n flow?: \"in\" | \"out\" | \"none\";\n /** A value written on its link (\"+ €5\") — passed translated. */\n value?: string;\n /**\n * How it is lit.\n * @default \"accent\"\n */\n material?: IsoMaterial;\n}\n\nexport interface IsoHubProps extends Omit<IsoSceneProps, \"children\"> {\n /** The hero object in the centre: its stages, bottom first. */\n layers: readonly IsoLayer[];\n /**\n * The footprint of the stages.\n * @default \"cut\"\n */\n shape?: IsoShape;\n /**\n * The width of the stages.\n * @default 120\n */\n size?: number;\n /**\n * A lit core on top of the stack; a string names it.\n * @default true\n */\n core?: boolean | string;\n /** A dome over the centre: `true`, or its name (\"Your servers\"). */\n dome?: boolean | string;\n /**\n * The objects around the centre, joined to it by flows of light. The first half stands on the left, the rest on the\n * right, top to bottom: never in front of the hero, never hidden behind it.\n */\n satellites?: readonly IsoSatellite[];\n /**\n * The distance of the satellites from the centre.\n * @default 210\n */\n radius?: number;\n /** The angle of each satellite, in degrees (0: lower right, 90: lower left, 180: upper left, 270: upper right), to place them by hand. */\n angles?: readonly number[];\n /** A label pinned above the centre, its first part in the accent: `{ strong: \"90 %\", text: \"to the creator\" }`. */\n highlight?: { readonly strong?: string; readonly text: string };\n}\n\n/** Left side (centred on 135°) then right side (centred on −45°), top to bottom, 64° apart. */\nfunction sideAngles(n: number): number[] {\n const left = Math.ceil(n / 2);\n const right = n - left;\n const spread = (m: number, centre: number, sign: 1 | -1) => Array.from({ length: m }, (_, i) => centre + sign * ((m - 1) / 2 - i) * 64);\n return [...spread(left, 135, 1), ...spread(right, -45, -1)];\n}\n\n/**\n * The hero, driven by data: a stack under an optional dome, satellites on both sides, a flow of light between each\n * satellite and the centre. Objects are painted back to front and the camera frames exactly what is drawn.\n */\nexport function IsoHub({ layers, shape, size = 120, core, dome, satellites = [], radius = 210, angles, highlight, animated, viewBox, extent, ...scene }: IsoHubProps) {\n const auto = sideAngles(satellites.length);\n const placed = satellites.map((s, k) => {\n const angle = angles?.[k] ?? auto[k] ?? 0;\n const at = onCircle(radius, angle);\n // The farther back, the higher it floats: two tiles of a side never cover each other.\n return { ...s, angle, at, z: Math.round(78 - (depthOf(at) / radius) * 26), k };\n });\n const back = placed.filter((s) => depthOf(s.at) < 0);\n const front = placed.filter((s) => depthOf(s.at) >= 0);\n const stackHeight = layers.reduce((h, l) => h + (l.height ?? 22) + 4, 16) + (core === false ? 0 : 38);\n const domeR = size * 1.32;\n const domeH = Math.max(stackHeight + 80, 200);\n const crown = dome ? domeH + 24 : stackHeight + (highlight ? 62 : 12);\n // The frame: every object's screen extent (tiles with room for their label, the plinth, the dome or the crown).\n const points: Vec2[] = [\n ...placed.flatMap(({ at: [x, y], z }) => [project([x - 46, y - 46, z + 52]), project([x + 46, y + 46, z]), project([x + 46, y - 46, z]), project([x - 46, y + 46, z])]),\n ...hexagon(0, 0, size * (dome ? 1.4 : 0.95)).map(([x, y]) => project([x, y, 0])),\n project([0, 0, crown + 20]),\n ];\n const xs = points.map(([x]) => x);\n const ys = points.map(([, y]) => y);\n const half = Math.max(...xs.map(Math.abs)) + 20;\n const box = [-half, Math.min(...ys) - 12, half * 2, Math.max(...ys) - Math.min(...ys) + 40].map((n) => Math.round(n)).join(\" \");\n const tile = (s: (typeof placed)[number]) => (\n <IsoTile key={s.k} at={s.at} z={s.z} glyph={s.glyph} material={s.material} label={s.label} index={layers.length + 3 + s.k} animated={animated} />\n );\n const link = (s: (typeof placed)[number]) =>\n s.flow === \"none\" ? null : (\n <IsoLink\n key={`l${s.k}`}\n from={s.at}\n to={onCircle(size * (dome ? 1.32 : 0.8), s.angle)}\n route=\"straight\"\n direction={s.flow === \"out\" ? \"in\" : \"out\"}\n label={s.value}\n animated={animated}\n />\n );\n return (\n <IsoScene animated={animated} extent={extent ?? Math.round(radius * 1.45 + 60)} viewBox={viewBox ?? box} {...scene}>\n {placed.map(link)}\n {dome && <IsoDome radius={domeR} part=\"rim\" animated={animated} />}\n {back.map(tile)}\n <IsoStack layers={layers} shape={shape} size={size} core={core} animated={animated} />\n {dome && <IsoDome radius={domeR} height={domeH} part=\"arc\" animated={animated} label={typeof dome === \"string\" ? dome : undefined} />}\n {highlight && <IsoLabel at={[0, 0]} z={stackHeight + (dome ? 24 : 46)} strong={highlight.strong} text={highlight.text} />}\n {front.map(tile)}\n </IsoScene>\n );\n}\n"
736
+ "content": "// Server-safe: no state, no effect, no context — static SVG computed at render time, animated by motion.css (`kz-iso-*`,\n// shipped by the preset), so a hero costs no client JavaScript. `useId` only (allowed in Server Components): every scene\n// owns its gradient and mask ids. Classes are joined with `cx`: no tailwind-variants in this entry.\nimport * as React from \"react\";\n\nimport { cx as cn } from \"../cx\";\nimport { cutRect, depthOf, type Face, hexagon, isoCircle, onCircle, pathOf, prism, project, pts, type Vec2, viewBoxOf } from \"./geometry\";\n\n/** How a solid is lit: the page's surfaces (`base`), the brand accent, accent → accent-2, or frosted glass. */\nexport type IsoMaterial = \"base\" | \"accent\" | \"accent2\" | \"glass\";\n/** The footprint of a prism: a hexagon (the marks), a rectangle with 45° cut corners (the icons) or a plain one. */\nexport type IsoShape = \"hex\" | \"cut\" | \"rect\";\n/** A pictogram drawn on the top of a tile. */\nexport type IsoGlyph = \"dots\" | \"lines\" | \"play\" | \"coin\" | \"lock\" | \"arrow\" | \"flag\" | \"heart\" | \"node\" | \"none\";\n\ntype Style = React.CSSProperties & Record<`--${string}`, string | number>;\n\nconst uid = (raw: string) => raw.replace(/[^a-zA-Z0-9_-]/g, \"\");\nconst footprint = (shape: IsoShape, [x, y]: Vec2, size: number | Vec2, cut?: number): Vec2[] => {\n const [w, d] = typeof size === \"number\" ? [size, size] : size;\n if (shape === \"hex\") return hexagon(x, y, w / 2);\n return cutRect(x, y, w, d, shape === \"rect\" ? 0 : (cut ?? Math.min(w, d) / 6));\n};\n\nexport interface IsoSceneProps extends Omit<React.ComponentProps<\"svg\">, \"children\"> {\n /** The accessible name of the scene (\"A server stack under a dome\") — passed translated. Without it the scene is decorative. */\n label?: string;\n /** A longer text version of what the scene shows, read by assistive technology. */\n description?: string;\n /**\n * Half the size of the floor, in world units: what the camera frames.\n * @default 240\n */\n extent?: number;\n /**\n * Height above the floor the camera keeps in view, in world units.\n * @default 260\n */\n top?: number;\n /**\n * The perspective grid on the floor, fading into the page.\n * @default true\n */\n grid?: boolean;\n /**\n * The spacing of the grid's lines.\n * @default 40\n */\n step?: number;\n /**\n * Motion (entrance, breathing, flow, float). `false` draws the still frame — the one prefers-reduced-motion shows.\n * @default true\n */\n animated?: boolean;\n /** The objects, painted in order: put the farthest first (or use `IsoHub`, which sorts them). */\n children?: React.ReactNode;\n}\n\n/**\n * The stage: an isometric camera over a perspective grid that fades into the page. Its animations pause off screen and\n * wait for the page to settle (MotionObserver); everything stops under prefers-reduced-motion.\n */\nexport function IsoScene({ label, description, extent = 240, top = 260, grid = true, step = 40, animated = true, viewBox, className, children, ...props }: IsoSceneProps) {\n const id = uid(React.useId());\n const lines: string[] = [];\n for (let v = -extent; v <= extent; v += step) {\n lines.push(pathOf([project([v, -extent, 0]), project([v, extent, 0])]), pathOf([project([-extent, v, 0]), project([extent, v, 0])]));\n }\n const fade = isoCircle(0, 0, 0, extent * 0.9);\n const named = label ? { role: \"group\" as const, \"aria-label\": label } : { \"aria-hidden\": true as const };\n return (\n <svg\n viewBox={viewBox ?? viewBoxOf(extent, top)}\n focusable=\"false\"\n data-motion-scope=\"\"\n data-animated={animated}\n className={cn(\"kz-iso\", className)}\n {...named}\n {...props}\n >\n {description && <desc>{description}</desc>}\n {grid && (\n <>\n <defs>\n <radialGradient id={`${id}-fade`}>\n <stop offset=\"0%\" stopColor=\"white\" stopOpacity=\"1\" />\n <stop offset=\"100%\" stopColor=\"white\" stopOpacity=\"0\" />\n </radialGradient>\n <mask id={`${id}-floor`}>\n <ellipse cx={fade.cx} cy={fade.cy} rx={fade.rx} ry={fade.ry} fill={`url(#${id}-fade)`} />\n </mask>\n </defs>\n <path d={lines.join(\"\")} className=\"kz-iso-floor\" mask={`url(#${id}-floor)`} />\n </>\n )}\n {children}\n </svg>\n );\n}\n\n/** A loop only when the scene moves: `animated={false}` on the item keeps it still. */\nconst loop = (animated: boolean | undefined) => (animated === false ? undefined : \"kz-loop\");\n\ninterface ItemProps {\n /** The name shown when the pointer (or the focus) is on the object — passed translated. It also makes it focusable. */\n label?: string;\n /**\n * Its rank in the entrance: objects rise into place one after the other.\n * @default 0\n */\n index?: number;\n /**\n * Motion: entrance and loops. `false` keeps this object still.\n * @default true\n */\n animated?: boolean;\n /** Extra classes on the object's group. */\n className?: string;\n}\n\n/** An object of the scene: rises at the entrance, brightens under the pointer or the focus and shows its label. */\nfunction Item({ label, index = 0, animated, anchor, align = \"center\", className, children }: ItemProps & { anchor: Vec2; align?: \"center\" | \"start\"; children: React.ReactNode }) {\n const named = label ? { role: \"img\" as const, \"aria-label\": label, tabIndex: 0 } : {};\n return (\n <g className={cn(\"kz-iso-item\", className)} style={{ \"--kz-iso-i\": index } as Style} {...named}>\n <g className={cn(\"kz-iso-lift\", animated !== false && \"kz-iso-rise\")}>{children}</g>\n {label && <Tip at={anchor} text={label} align={align} />}\n </g>\n );\n}\n\n/**\n * A label in a pill (decorative: the object carries the name). `center`: above the point (a floating tile). `start`:\n * beside it, to the right, with a leader — for a stage of a stack, whose upper stages would cover a label above it.\n */\nfunction Tip({ at: [x, y], text, align }: { at: Vec2; text: string; align: \"center\" | \"start\" }) {\n const w = Math.max(40, text.length * 6.6 + 20);\n if (align === \"start\") {\n return (\n <g className=\"kz-iso-tip\" aria-hidden>\n <path d={`M${Math.round(x + 3)} ${Math.round(y)}h18`} className=\"kz-iso-leader\" />\n <rect x={x + 21} y={y - 11} width={w} height={22} rx={7} strokeWidth={1} />\n <text x={x + 21 + w / 2} y={y + 4} textAnchor=\"middle\">\n {text}\n </text>\n </g>\n );\n }\n return (\n <g className=\"kz-iso-tip\" aria-hidden>\n <rect x={x - w / 2} y={y - 34} width={w} height={22} rx={7} strokeWidth={1} />\n <text x={x} y={y - 19} textAnchor=\"middle\">\n {text}\n </text>\n </g>\n );\n}\n\nfunction Solid({ faces, material }: { faces: Face[]; material: IsoMaterial }) {\n return (\n <g className={\"kz-iso-\" + material}>\n {faces.map((face, i) => (\n <polygon key={i} points={face.points} className={\"kz-iso-face kz-iso-\" + face.kind} />\n ))}\n </g>\n );\n}\n\nexport interface IsoPrismProps extends ItemProps {\n /**\n * The centre of its footprint on the floor plan (x, y).\n * @default [0, 0]\n */\n at?: Vec2;\n /**\n * The height of its base above the floor.\n * @default 0\n */\n z?: number;\n /** Its height. */\n height: number;\n /**\n * hex · cut (45° cut corners) · rect.\n * @default \"cut\"\n */\n shape?: IsoShape;\n /**\n * Its width (a number: square or hexagon's diameter) or width × depth.\n * @default 120\n */\n size?: number | Vec2;\n /** The size of the 45° cut (`shape=\"cut\"`); a sixth of the smaller side by default. */\n cut?: number;\n /**\n * How it is lit.\n * @default \"base\"\n */\n material?: IsoMaterial;\n /** A dotted light strip around its front (the LEDs of a server), blinking slowly. */\n strip?: boolean;\n}\n\n/** A vertical prism — hexagonal, cut-corner or rectangular — that stacks with others on `z`. */\nexport function IsoPrism({ at = [0, 0], z = 0, height, shape = \"cut\", size = 120, cut, material = \"base\", strip, animated, ...item }: IsoPrismProps) {\n const foot = footprint(shape, at, size, cut);\n const [w, d] = typeof size === \"number\" ? [size, size] : size;\n return (\n <Item {...item} animated={animated} anchor={project(shape === \"hex\" ? [at[0] + w / 4, at[1] - w * 0.433, z + height / 2] : [at[0] + w / 2, at[1] - d / 2, z + height / 2])} align=\"start\">\n <Solid faces={prism(foot, z, height)} material={material} />\n {strip && <Strip at={at} w={w} d={d} c={shape === \"rect\" ? 0 : (cut ?? Math.min(w, d) / 6)} z={z + height / 2 + 1} animated={animated} hex={shape === \"hex\"} />}\n </Item>\n );\n}\n\nfunction Strip({ at: [cx, cy], w, d, c, z, hex, animated }: { at: Vec2; w: number; d: number; c: number; z: number; hex: boolean; animated?: boolean }) {\n const front: Vec2[] = hex\n ? [0, 1, 2].map((k) => onCircle(w / 2, k * 60 - 60, [cx, cy]))\n : [[cx + w / 2, cy - d / 2 + c], [cx + w / 2, cy + d / 2 - c], [cx + w / 2 - c, cy + d / 2], [cx - w / 2 + c, cy + d / 2]];\n return <polyline points={pts(front.map(([x, y]) => project([x, y, z])))} className={cn(\"kz-iso-strip\", loop(animated))} />;\n}\n\n/** One stage of an `IsoStack`. */\nexport interface IsoLayer {\n /** The stage's name, shown when it is lifted — passed translated. */\n label?: string;\n /**\n * Its height.\n * @default 22\n */\n height?: number;\n /**\n * How it is lit.\n * @default \"base\"\n */\n material?: IsoMaterial;\n}\n\nexport interface IsoStackProps {\n /** The stages, bottom first; they stack one after the other at the entrance. */\n layers: readonly IsoLayer[];\n /**\n * The centre of the stack on the floor plan.\n * @default [0, 0]\n */\n at?: Vec2;\n /**\n * The footprint of the stages.\n * @default \"cut\"\n */\n shape?: IsoShape;\n /**\n * The width of the stages.\n * @default 120\n */\n size?: number;\n /**\n * The space between two stages.\n * @default 4\n */\n gap?: number;\n /**\n * A hexagonal plinth under the stack.\n * @default true\n */\n plinth?: boolean;\n /**\n * A lit hexagonal core on top, its node glowing; a string names it.\n * @default true\n */\n core?: boolean | string;\n /**\n * The rank of the first stage in the scene's entrance.\n * @default 0\n */\n index?: number;\n /**\n * Motion: entrance and loops. `false` keeps the stack still.\n * @default true\n */\n animated?: boolean;\n}\n\n/** A stack of stages on a plinth with a lit core on top — a server, a model, a pile of layers — driven by data. */\nexport function IsoStack({ layers, at = [0, 0], shape = \"cut\", size = 120, gap = 4, plinth = true, core = true, index = 0, animated }: IsoStackProps) {\n const base = plinth ? 12 + gap : 0;\n const heights = layers.map((layer) => layer.height ?? 22);\n const stages = layers.map((layer, k) => ({ ...layer, k, height: heights[k]!, z: base + heights.slice(0, k).reduce((sum, h) => sum + h + gap, 0) }));\n const top = base + heights.reduce((sum, h) => sum + h + gap, 0);\n return (\n <g>\n {plinth && <IsoPrism at={at} height={12} shape=\"hex\" size={size * 1.86} index={index} animated={animated} />}\n {stages.map((s) => (\n <IsoPrism\n key={s.k}\n at={at}\n z={s.z}\n height={s.height}\n shape={shape}\n size={size}\n material={s.material ?? \"base\"}\n strip={(s.material ?? \"base\") === \"base\"}\n label={s.label}\n index={index + 1 + s.k}\n animated={animated}\n />\n ))}\n {core && (\n <>\n <IsoPrism at={at} z={top} height={16} shape=\"hex\" size={size / 2} material=\"accent\" index={index + 1 + stages.length} animated={animated} label={typeof core === \"string\" ? core : undefined} />\n <IsoNode at={at} z={top + 22} index={index + 2 + stages.length} animated={animated} />\n </>\n )}\n </g>\n );\n}\n\nexport interface IsoNodeProps {\n /**\n * Where, on the floor plan.\n * @default [0, 0]\n */\n at?: Vec2;\n /**\n * Its height.\n * @default 0\n */\n z?: number;\n /**\n * The radius of the node.\n * @default 7\n */\n r?: number;\n /**\n * The radius of its glow (0: none).\n * @default 70\n */\n glow?: number;\n /**\n * Its rank in the entrance.\n * @default 0\n */\n index?: number;\n /**\n * Motion: the glow breathes. `false` keeps it still.\n * @default true\n */\n animated?: boolean;\n}\n\n/** The Krizaka node: a point of light in the accent, breathing in its glow. */\nexport function IsoNode({ at = [0, 0], z = 0, r = 7, glow = 70, index = 0, animated }: IsoNodeProps) {\n const id = uid(React.useId());\n const [x, y] = project([at[0], at[1], z]);\n return (\n <g className={cn(animated !== false && \"kz-iso-rise\")} style={{ \"--kz-iso-i\": index } as Style}>\n {glow > 0 && (\n <>\n <defs>\n <radialGradient id={`${id}-glow`}>\n <stop offset=\"0%\" className=\"kz-iso-glow-stop\" stopOpacity=\"0.55\" />\n <stop offset=\"100%\" className=\"kz-iso-glow-stop\" stopOpacity=\"0\" />\n </radialGradient>\n </defs>\n <circle cx={x} cy={y} r={glow} fill={`url(#${id}-glow)`} className={cn(\"kz-iso-breathe\", loop(animated))} />\n </>\n )}\n <circle cx={x} cy={y} r={r} className={cn(\"kz-iso-node kz-iso-breathe\", loop(animated))} />\n </g>\n );\n}\n\nexport interface IsoDomeProps {\n /**\n * Its centre on the floor plan.\n * @default [0, 0]\n */\n at?: Vec2;\n /**\n * The radius of its rim on the floor.\n * @default 158\n */\n radius?: number;\n /**\n * Its height.\n * @default 250\n */\n height?: number;\n /** Its name (\"Your infrastructure\") — passed translated; shown at the top of the dome, always. */\n label?: string;\n /**\n * Motion: a sheen travels along the dome. `false` keeps it still.\n * @default true\n */\n animated?: boolean;\n}\n\n/**\n * A dome of light over what it protects: a rim on the floor, a glass arc, a sheen that travels along it. Draw its rim\n * before the objects it covers and the dome after them (`part=\"rim\"`, `part=\"arc\"`), or let `IsoHub` do it.\n */\nexport function IsoDome({ at = [0, 0], radius = 158, height = 250, label, animated, part = \"both\" }: IsoDomeProps & {\n /**\n * `rim` (the floor ellipse, drawn first), `arc` (the glass, drawn last) or `both`.\n * @default \"both\"\n */\n part?: \"rim\" | \"arc\" | \"both\";\n}) {\n const e = isoCircle(at[0], at[1], 0, radius);\n const arc = `M${e.cx - e.rx} ${e.cy} A ${e.rx} ${height} 0 0 1 ${e.cx + e.rx} ${e.cy}`;\n return (\n <>\n {part !== \"arc\" && <ellipse cx={e.cx} cy={e.cy} rx={e.rx} ry={e.ry} className=\"kz-iso-rim\" />}\n {part !== \"rim\" && (\n <g>\n <path d={arc} className=\"kz-iso-dome\" />\n <path d={arc} className={cn(\"kz-iso-dome-sheen\", loop(animated))} pathLength={440} />\n {label && <IsoLabel at={at} z={height + 10} text={label} />}\n </g>\n )}\n </>\n );\n}\n\nexport interface IsoTileProps extends ItemProps {\n /** Its centre on the floor plan. */\n at: Vec2;\n /**\n * The height it floats at.\n * @default 90\n */\n z?: number;\n /**\n * Width × depth.\n * @default [76, 52]\n */\n size?: Vec2;\n /**\n * The pictogram on its top.\n * @default \"none\"\n */\n glyph?: IsoGlyph;\n /**\n * How it is lit.\n * @default \"accent\"\n */\n material?: IsoMaterial;\n /**\n * It floats gently.\n * @default true\n */\n float?: boolean;\n}\n\n/** A satellite: a thin cut-corner tile that floats beside the hero object, a pictogram on its top. */\nexport function IsoTile({ at, z = 90, size = [76, 52], glyph = \"none\", material = \"accent\", float = true, animated, ...item }: IsoTileProps) {\n const [w, d] = size;\n const top = z + 9;\n const shadow = isoCircle(at[0], at[1], 0, Math.min(w, d) * 0.55);\n const foot = project([at[0], at[1], 0]);\n return (\n <Item {...item} animated={animated} anchor={project([at[0], at[1], top])}>\n {z > 0 && (\n <>\n <ellipse cx={shadow.cx} cy={shadow.cy} rx={shadow.rx} ry={shadow.ry} className=\"kz-iso-shadow\" />\n <path d={pathOf([foot, project([at[0], at[1], z])])} className=\"kz-iso-tether\" />\n </>\n )}\n <g className={cn(float && \"kz-iso-float\", float && loop(animated))}>\n <Solid faces={prism(cutRect(at[0], at[1], w, d, Math.min(w, d) / 4), z, 9)} material={material} />\n <Glyph glyph={glyph} at={at} z={top} s={Math.min(w, d) * 0.3} />\n </g>\n </Item>\n );\n}\n\nfunction Glyph({ glyph, at: [cx, cy], z, s }: { glyph: IsoGlyph; at: Vec2; z: number; s: number }) {\n const p = (u: number, v: number) => project([cx + u * s, cy + v * s, z]);\n const line = (points: [number, number][], close = false) => <path d={pathOf(points.map(([u, v]) => p(u, v)), close)} className=\"kz-iso-glyph\" />;\n switch (glyph) {\n case \"dots\":\n return <>{[-0.8, 0, 0.8].map((u) => <circle key={u} cx={p(u, 0)[0]} cy={p(u, 0)[1]} r={s * 0.16} className=\"kz-iso-glyph-fill\" />)}</>;\n case \"lines\":\n return <>{[-0.6, 0, 0.6].map((v) => <React.Fragment key={v}>{line([[-0.9, v], [0.7, v]])}</React.Fragment>)}</>;\n case \"play\":\n return line([[-0.5, -0.7], [0.8, 0], [-0.5, 0.7]], true);\n case \"coin\":\n return (\n <>\n <path d={pathOf(hexagon(0, 0, 0.9).map(([u, v]) => p(u, v)), true)} className=\"kz-iso-glyph\" />\n <circle cx={p(0, 0)[0]} cy={p(0, 0)[1]} r={s * 0.18} className=\"kz-iso-glyph-fill\" />\n </>\n );\n case \"lock\":\n return (\n <>\n {line([[-0.6, -0.1], [0.6, -0.1], [0.6, 0.8], [-0.6, 0.8]], true)}\n {line([[-0.35, -0.1], [-0.35, -0.5], [-0.15, -0.75], [0.15, -0.75], [0.35, -0.5], [0.35, -0.1]])}\n </>\n );\n case \"arrow\":\n return (\n <>\n {line([[0.8, 0.8], [-0.6, -0.6]])}\n {line([[-0.6, 0.1], [-0.6, -0.6], [0.1, -0.6]])}\n </>\n );\n case \"flag\":\n return (\n <>\n {line([[-0.7, 0.9], [-0.7, -0.9]])}\n {line([[-0.7, -0.9], [0.8, -0.55], [-0.7, -0.1]], true)}\n </>\n );\n case \"heart\":\n return line([[0, 0.85], [-0.85, 0], [-0.85, -0.45], [-0.45, -0.8], [0, -0.45], [0.45, -0.8], [0.85, -0.45], [0.85, 0]], true);\n case \"node\":\n return <circle cx={p(0, 0)[0]} cy={p(0, 0)[1]} r={s * 0.3} className=\"kz-iso-glyph-fill\" />;\n default:\n return null;\n }\n}\n\nexport interface IsoLinkProps {\n /** Where it starts, on the floor plan. */\n from: Vec2;\n /** Where it ends, on the floor plan. */\n to: Vec2;\n /**\n * The height it runs at.\n * @default 0\n */\n z?: number;\n /**\n * `elbow` follows the floor's axes, like a circuit; `straight` goes directly.\n * @default \"elbow\"\n */\n route?: \"elbow\" | \"straight\";\n /**\n * Which way the light flows: `out` from `from` to `to`, `in` back.\n * @default \"out\"\n */\n direction?: \"out\" | \"in\";\n /**\n * Particles of light travelling along it (0: only the dashes flow).\n * @default 2\n */\n particles?: number;\n /**\n * Seconds a particle takes to cross it.\n * @default 3.6\n */\n duration?: number;\n /** A value written on it (\"90 %\", \"Tips\") — passed translated. */\n label?: string;\n /**\n * Motion: the flow and the particles. `false` draws them still, resting along the link.\n * @default true\n */\n animated?: boolean;\n}\n\n/** A dotted link on the floor, light flowing along it and particles crossing it — a flow between two objects. */\nexport function IsoLink({ from, to, z = 0, route = \"elbow\", direction = \"out\", particles = 2, duration = 3.6, label, animated }: IsoLinkProps) {\n const corner: Vec2 = [to[0], from[1]];\n const plan = route === \"elbow\" && from[0] !== to[0] && from[1] !== to[1] ? [from, corner, to] : [from, to];\n const ordered = direction === \"in\" ? [...plan].reverse() : plan;\n const d = pathOf(ordered.map(([x, y]) => project([x, y, z])));\n const mid = plan.length === 3 ? corner : ([(from[0] + to[0]) / 2, (from[1] + to[1]) / 2] as Vec2);\n return (\n <g>\n <path d={d} className={cn(\"kz-iso-link\", loop(animated))} />\n {Array.from({ length: particles }, (_, k) => (\n <circle\n key={k}\n r={3.2}\n className={cn(\"kz-iso-particle\", loop(animated))}\n style={\n {\n offsetPath: `path(\"${d}\")`,\n \"--kz-iso-at\": `${Math.round(((k + 0.5) / particles) * 100)}%`,\n \"--kz-iso-dur\": `${duration}s`,\n \"--kz-iso-delay\": `${(-duration * k) / particles}s`,\n } as Style\n }\n />\n ))}\n {label && <IsoLabel at={mid} z={z} text={label} />}\n </g>\n );\n}\n\nexport interface IsoLabelProps {\n /** Where, on the floor plan. */\n at: Vec2;\n /**\n * Its height.\n * @default 0\n */\n z?: number;\n /** The text — passed translated. */\n text: string;\n /** A first part in the accent, bolder (\"90 %\" before \" to the creator\"). */\n strong?: string;\n}\n\n/** A label in a pill, always visible, pinned to a point of the scene (a share, a name). */\nexport function IsoLabel({ at, z = 0, text, strong }: IsoLabelProps) {\n const [x, y] = project([at[0], at[1], z]);\n const chars = text.length + (strong ? strong.length + 1 : 0);\n const w = chars * 6.8 + 22;\n return (\n <g className=\"kz-iso-link-label\" aria-hidden>\n <rect x={x - w / 2} y={y - 12} width={w} height={24} rx={8} strokeWidth={1} />\n <text x={x} y={y + 4} textAnchor=\"middle\">\n {strong && <tspan className=\"kz-iso-strong\">{strong} </tspan>}\n {text}\n </text>\n </g>\n );\n}\n\n/** A satellite of an `IsoHub`. */\nexport interface IsoSatellite {\n /** Its name, shown when lifted — passed translated. */\n label: string;\n /**\n * Its pictogram.\n * @default \"none\"\n */\n glyph?: IsoGlyph;\n /**\n * The flow on its link: `in` toward the centre, `out` from it, `none` without a link.\n * @default \"in\"\n */\n flow?: \"in\" | \"out\" | \"none\";\n /** A value written on its link (\"+ €5\") — passed translated. */\n value?: string;\n /**\n * How it is lit.\n * @default \"accent\"\n */\n material?: IsoMaterial;\n}\n\nexport interface IsoHubProps extends Omit<IsoSceneProps, \"children\"> {\n /** The hero object in the centre: its stages, bottom first. */\n layers: readonly IsoLayer[];\n /**\n * The footprint of the stages.\n * @default \"cut\"\n */\n shape?: IsoShape;\n /**\n * The width of the stages.\n * @default 120\n */\n size?: number;\n /**\n * A lit core on top of the stack; a string names it.\n * @default true\n */\n core?: boolean | string;\n /** A dome over the centre: `true`, or its name (\"Your servers\"). */\n dome?: boolean | string;\n /**\n * The objects around the centre, joined to it by flows of light. The first half stands on the left, the rest on the\n * right, top to bottom: never in front of the hero, never hidden behind it.\n */\n satellites?: readonly IsoSatellite[];\n /**\n * The distance of the satellites from the centre.\n * @default 210\n */\n radius?: number;\n /** The angle of each satellite, in degrees (0: lower right, 90: lower left, 180: upper left, 270: upper right), to place them by hand. */\n angles?: readonly number[];\n /** A label pinned above the centre, its first part in the accent: `{ strong: \"90 %\", text: \"to the creator\" }`. */\n highlight?: { readonly strong?: string; readonly text: string };\n}\n\n/** Left side (centred on 135°) then right side (centred on −45°), top to bottom, 64° apart. */\nfunction sideAngles(n: number): number[] {\n const left = Math.ceil(n / 2);\n const right = n - left;\n const spread = (m: number, centre: number, sign: 1 | -1) => Array.from({ length: m }, (_, i) => centre + sign * ((m - 1) / 2 - i) * 64);\n return [...spread(left, 135, 1), ...spread(right, -45, -1)];\n}\n\n/**\n * The hero, driven by data: a stack under an optional dome, satellites on both sides, a flow of light between each\n * satellite and the centre. Objects are painted back to front and the camera frames exactly what is drawn.\n */\nexport function IsoHub({ layers, shape, size = 120, core, dome, satellites = [], radius = 210, angles, highlight, animated, viewBox, extent, ...scene }: IsoHubProps) {\n const auto = sideAngles(satellites.length);\n const placed = satellites.map((s, k) => {\n const angle = angles?.[k] ?? auto[k] ?? 0;\n const at = onCircle(radius, angle);\n // The farther back, the higher it floats: two tiles of a side never cover each other.\n return { ...s, angle, at, z: Math.round(78 - (depthOf(at) / radius) * 26), k };\n });\n const back = placed.filter((s) => depthOf(s.at) < 0);\n const front = placed.filter((s) => depthOf(s.at) >= 0);\n const stackHeight = layers.reduce((h, l) => h + (l.height ?? 22) + 4, 16) + (core === false ? 0 : 38);\n const domeR = size * 1.32;\n const domeH = Math.max(stackHeight + 80, 200);\n const crown = dome ? domeH + 24 : stackHeight + (highlight ? 62 : 12);\n // The frame: every object's screen extent (tiles with room for their label, the plinth, the dome or the crown).\n const points: Vec2[] = [\n ...placed.flatMap(({ at: [x, y], z }) => [project([x - 46, y - 46, z + 52]), project([x + 46, y + 46, z]), project([x + 46, y - 46, z]), project([x - 46, y + 46, z])]),\n ...hexagon(0, 0, size * (dome ? 1.4 : 0.95)).map(([x, y]) => project([x, y, 0])),\n project([0, 0, crown + 20]),\n ];\n const xs = points.map(([x]) => x);\n const ys = points.map(([, y]) => y);\n const half = Math.max(...xs.map(Math.abs)) + 20;\n const box = [-half, Math.min(...ys) - 12, half * 2, Math.max(...ys) - Math.min(...ys) + 40].map((n) => Math.round(n)).join(\" \");\n const tile = (s: (typeof placed)[number]) => (\n <IsoTile key={s.k} at={s.at} z={s.z} glyph={s.glyph} material={s.material} label={s.label} index={layers.length + 3 + s.k} animated={animated} />\n );\n const link = (s: (typeof placed)[number]) =>\n s.flow === \"none\" ? null : (\n <IsoLink\n key={`l${s.k}`}\n from={s.at}\n to={onCircle(size * (dome ? 1.32 : 0.8), s.angle)}\n route=\"straight\"\n direction={s.flow === \"out\" ? \"in\" : \"out\"}\n label={s.value}\n animated={animated}\n />\n );\n return (\n <IsoScene animated={animated} extent={extent ?? Math.round(radius * 1.45 + 60)} viewBox={viewBox ?? box} {...scene}>\n {placed.map(link)}\n {dome && <IsoDome radius={domeR} part=\"rim\" animated={animated} />}\n {back.map(tile)}\n <IsoStack layers={layers} shape={shape} size={size} core={core} animated={animated} />\n {dome && <IsoDome radius={domeR} height={domeH} part=\"arc\" animated={animated} label={typeof dome === \"string\" ? dome : undefined} />}\n {highlight && <IsoLabel at={[0, 0]} z={stackHeight + (dome ? 24 : 46)} strong={highlight.strong} text={highlight.text} />}\n {front.map(tile)}\n </IsoScene>\n );\n}\n"
737
737
  },
738
738
  {
739
739
  "path": "iso/meta.ts",
740
- "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Iso\",\n summary:\n \"The isometric kit: luminous objects built from the Krizaka vocabulary (hexagons, cut corners, the node) on a perspective grid — a hero driven by data (`IsoHub`) or composed from primitives.\",\n status: \"beta\",\n category: \"layout\",\n platforms: \"web\",\n parity: { native: { status: \"n/a\", reason: \"An isometric drawing of a site's hero.\" }, desktop: { status: \"n/a\", reason: \"A public site's page, not a window of the Mac app.\" } },\n whenToUse: [\n \"The hero illustration of a product or marketing page: what the product is, drawn as one object with two to four satellites.\",\n \"To show a flow toward or out of something (requests into a server, support toward a creator) with values written on it.\",\n \"An architecture teaser where a diagram would be too much: one object per layer, named on hover and focus.\",\n ],\n whenNotToUse: [\n { when: \"For a real architecture or data flow the reader must study: draw a schema with a text version.\" },\n { when: \"As the background of a section: the light, the dome and the grid of a backdrop are lighter.\", use: \"section-backdrop\" },\n { when: \"More than one per screen: the hero object is unique, the rest of the page stays calm.\" },\n ],\n bestPractices: [\n \"Start with `IsoHub`: stages, satellites and a highlight are data; the hub places satellites on both sides (never in front of the hero, never hidden behind it) and frames exactly what it draws.\",\n \"Name the scene (`label`) and say in `description` what it shows; name the objects (`label`) to make them explorable with the pointer and the keyboard — leave everything unnamed for a purely decorative scene.\",\n \"Put the scene in a brand (`.brand-<id>`): the light, the core and the flows follow the accent, in both themes.\",\n \"Composing by hand: paint back to front, and number the entrance with `index` so objects rise in a meaningful order.\",\n \"Pass words translated: labels, values on links, the highlight.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Tab\", action: \"Visits each named object of the scene: it lifts and shows its label, as under the pointer.\" }],\n notes: [\n \"A named scene is a `group` with its `label` and its `description` (`<desc>`); an unnamed one is decorative (`aria-hidden`).\",\n \"Each named object is an image (`role=\\\"img\\\"`) named by its label and focusable; the drawn labels are decorative copies.\",\n \"Under `prefers-reduced-motion` (and with `animated={false}`) the scene is a composed still frame: objects in place, light resting along the links — not an animation cut halfway.\",\n \"Server-rendered static SVG, no client JavaScript; with `MotionObserver` mounted its loops pause off screen and wait for the page to settle.\",\n ],\n },\n related: [\"section-backdrop\", \"number-ticker\"],\n web: {\n imports: [\"IsoHub\", \"IsoScene\", \"IsoPrism\", \"IsoStack\", \"IsoDome\", \"IsoTile\", \"IsoLink\", \"IsoNode\", \"IsoLabel\"],\n examples: [\n {\n name: \"orazaka-hero\",\n title: \"Sovereign servers (Orazaka)\",\n description: \"Three named stages under a dome, a lit core; chats and documents flow in, answers flow out. Hover or tab to explore.\",\n },\n {\n name: \"orochia-hero\",\n title: \"Support toward a creator (Orochia)\",\n description: \"The creator in the centre, tips, unlocks, auctions and challenges flowing toward them, their amounts on the links, 90 % pinned above.\",\n },\n { name: \"compose\", title: \"Composed by hand\", description: \"The primitives — scene, links, dome, prisms, node, tiles — painted back to front with an entrance order.\" },\n { name: \"still\", title: \"Still frame\", description: \"`animated={false}`: the composed picture prefers-reduced-motion shows.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
740
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Iso\",\n summary:\n \"The isometric kit: luminous objects built from the Krizaka vocabulary (hexagons, cut corners, the node) on a perspective grid — a hero driven by data (`IsoHub`) or composed from primitives.\",\n status: \"beta\",\n category: \"layout\",\n platforms: \"web\",\n parity: { native: { status: \"n/a\", reason: \"An isometric drawing of a site's hero.\" }, desktop: { status: \"n/a\", reason: \"A public site's page, not a window of the Mac app.\" } },\n whenToUse: [\n \"The hero illustration of a product or marketing page: what the product is, drawn as one object with two to four satellites.\",\n \"To show a flow toward or out of something (requests into a server, support toward a creator) with values written on it.\",\n \"An architecture teaser where a diagram would be too much: one object per layer, named on hover and focus.\",\n ],\n whenNotToUse: [\n { when: \"For a real architecture or data flow the reader must study: draw a schema with a text version.\" },\n { when: \"As the background of a section: the light, the dome and the grid of a backdrop are lighter.\", use: \"section-backdrop\" },\n { when: \"More than one per screen: the hero object is unique, the rest of the page stays calm.\" },\n ],\n bestPractices: [\n \"Start with `IsoHub`: stages, satellites and a highlight are data; the hub places satellites on both sides (never in front of the hero, never hidden behind it) and frames exactly what it draws.\",\n \"Name the scene (`label`) and say in `description` what it shows; name the objects (`label`) to make them explorable with the pointer and the keyboard — leave everything unnamed for a purely decorative scene.\",\n \"Put the scene in a brand (`.brand-<id>`): the light, the core and the flows follow the accent, in both themes.\",\n \"Composing by hand: paint back to front, and number the entrance with `index` so objects rise in a meaningful order.\",\n \"Pass words translated: labels, values on links, the highlight.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Tab\", action: \"Visits each named object of the scene: it brightens and shows its label, as under the pointer.\" }],\n notes: [\n \"A named scene is a `group` with its `label` and its `description` (`<desc>`); an unnamed one is decorative (`aria-hidden`).\",\n \"Each named object is an image (`role=\\\"img\\\"`) named by its label and focusable; the drawn labels are decorative copies.\",\n \"Under `prefers-reduced-motion` (and with `animated={false}`) the scene is a composed still frame: objects in place, light resting along the links — not an animation cut halfway.\",\n \"Server-rendered static SVG, no client JavaScript; with `MotionObserver` mounted its loops pause off screen and wait for the page to settle.\",\n ],\n },\n related: [\"section-backdrop\", \"number-ticker\"],\n web: {\n imports: [\"IsoHub\", \"IsoScene\", \"IsoPrism\", \"IsoStack\", \"IsoDome\", \"IsoTile\", \"IsoLink\", \"IsoNode\", \"IsoLabel\"],\n examples: [\n {\n name: \"orazaka-hero\",\n title: \"Sovereign servers (Orazaka)\",\n description: \"Three named stages under a dome, a lit core; chats and documents flow in, answers flow out. Hover or tab to explore.\",\n },\n {\n name: \"orochia-hero\",\n title: \"Support toward a creator (Orochia)\",\n description: \"The creator in the centre, tips, unlocks, auctions and challenges flowing toward them, their amounts on the links, 90 % pinned above.\",\n },\n { name: \"compose\", title: \"Composed by hand\", description: \"The primitives — scene, links, dome, prisms, node, tiles — painted back to front with an entrance order.\" },\n { name: \"still\", title: \"Still frame\", description: \"`animated={false}`: the composed picture prefers-reduced-motion shows.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
741
741
  },
742
742
  {
743
743
  "path": "meta.ts",
@@ -1118,7 +1118,7 @@
1118
1118
  "name": "label",
1119
1119
  "type": "string",
1120
1120
  "default": null,
1121
- "description": "The name shown when the pointer (or the focus) lifts the object — passed translated. It also makes it focusable.",
1121
+ "description": "The name shown when the pointer (or the focus) is on the object — passed translated. It also makes it focusable.",
1122
1122
  "required": false
1123
1123
  },
1124
1124
  {
@@ -1339,7 +1339,7 @@
1339
1339
  "name": "label",
1340
1340
  "type": "string",
1341
1341
  "default": null,
1342
- "description": "The name shown when the pointer (or the focus) lifts the object — passed translated. It also makes it focusable.",
1342
+ "description": "The name shown when the pointer (or the focus) is on the object — passed translated. It also makes it focusable.",
1343
1343
  "required": false
1344
1344
  },
1345
1345
  {
@@ -144,7 +144,7 @@
144
144
  "why": "A visitor gets the promise in one screen, the product alive, the proofs and one call to act.",
145
145
  "path": "examples/landing-page/krizaka.tsx",
146
146
  "module": "@krizaka/ui/registry/examples/landing-page/krizaka",
147
- "code": "import { Button } from \"@krizaka/ui/button\";\nimport { LandingPage } from \"@krizaka/ui/landing-page\";\nimport { Meter } from \"@krizaka/ui/meter\";\n\n// TEMPLATE — a company's landing (krizaka.com): the promise beside the product alive, a band of proofs, the features\n// as a bento where the main one takes the room, the closing call. On a phone the window follows the words, the bento\n// is one column, the proofs stack.\nexport default function LandingPageKrizaka() {\n return (\n <LandingPage\n eyebrow=\"Software studio · Montréal\"\n title=\"Products that keep what is yours\"\n lead=\"Krizaka builds sovereign AI and a platform where creators are paid — open source, on your servers or ours.\"\n actions={\n <>\n <Button variant=\"primary\" size=\"lg\" shape=\"cut\" shimmer>See the products</Button>\n <Button variant=\"secondary\" size=\"lg\" shape=\"cut\">Read the docs</Button>\n </>\n }\n visualLabel=\"orazaka.local — console\"\n visual={\n <div className=\"grid gap-3 p-5\">\n <p className=\"font-mono text-xs text-fg-secondary\">$ npx orazaka install</p>\n <p className=\"font-mono text-xs text-fg-success\">✓ 1,284 answers this week, none left the server</p>\n <Meter label=\"Credits\" value={3800} max={12000} valueText=\"3,800 of 12,000\" showLabel />\n </div>\n }\n proofs={[\n { value: \"34\", label: \"public repositories\" },\n { value: \"Apache-2.0\", label: \"every line\" },\n { value: \"0\", label: \"telemetry calls\" },\n ]}\n featuresHeading={{ eyebrow: \"What we build\", title: \"Three products, one way of building\" }}\n features={[\n { id: \"orazaka\", size: \"lg\", title: \"Orazaka — the AI that never leaves home\", text: \"Chat, image, voice and video on your own server, one governed pipeline.\" },\n { id: \"orochia\", title: \"Orochia\", text: \"Creators paid 90 % of what fans spend.\" },\n { id: \"yasakia\", title: \"Yasakia\", text: \"Meet by talking first — coming.\" },\n { id: \"blocks\", size: \"md\", title: \"Open building blocks\", text: \"Users, billing, notifications — on Maven Central and npm.\" },\n { id: \"ui\", size: \"md\", title: \"One design system\", text: \"Krizaka UI, web and mobile, documented from its code.\" },\n ]}\n closing={{ title: \"Something to build together?\", body: \"Tell us what you need; a person answers within two days.\", actions: <Button variant=\"primary\" size=\"lg\" shape=\"cut\">Contact us</Button> }}\n />\n );\n}\n"
147
+ "code": "import { Button } from \"@krizaka/ui/button\";\nimport { LandingPage } from \"@krizaka/ui/landing-page\";\nimport { Meter } from \"@krizaka/ui/meter\";\n\n// TEMPLATE — a company's landing (krizaka.com): the promise beside the product alive, a band of proofs, the features\n// as a bento where the main one takes the room, the closing call. On a phone the window follows the words, the bento\n// is one column, the proofs stack.\nexport default function LandingPageKrizaka() {\n return (\n <LandingPage\n eyebrow=\"Software studio · Montréal\"\n title=\"Products that keep what is yours\"\n lead=\"Krizaka builds sovereign AI and a platform where creators are paid — open source, on your servers or ours.\"\n actions={\n <>\n <Button variant=\"primary\" size=\"lg\">See the products</Button>\n <Button variant=\"secondary\" size=\"lg\">Read the docs</Button>\n </>\n }\n visualLabel=\"orazaka.local — console\"\n visual={\n <div className=\"grid gap-3 p-5\">\n <p className=\"font-mono text-xs text-fg-secondary\">$ npx orazaka install</p>\n <p className=\"font-mono text-xs text-fg-success\">✓ 1,284 answers this week, none left the server</p>\n <Meter label=\"Credits\" value={3800} max={12000} valueText=\"3,800 of 12,000\" showLabel />\n </div>\n }\n proofs={[\n { value: \"34\", label: \"public repositories\" },\n { value: \"Apache-2.0\", label: \"every line\" },\n { value: \"0\", label: \"telemetry calls\" },\n ]}\n featuresHeading={{ eyebrow: \"What we build\", title: \"Three products, one way of building\" }}\n features={[\n { id: \"orazaka\", size: \"lg\", title: \"Orazaka — the AI that never leaves home\", text: \"Chat, image, voice and video on your own server, one governed pipeline.\" },\n { id: \"orochia\", title: \"Orochia\", text: \"Creators paid 90 % of what fans spend.\" },\n { id: \"yasakia\", title: \"Yasakia\", text: \"Meet by talking first — coming.\" },\n { id: \"blocks\", size: \"md\", title: \"Open building blocks\", text: \"Users, billing, notifications — on Maven Central and npm.\" },\n { id: \"ui\", size: \"md\", title: \"One design system\", text: \"Krizaka UI, web and mobile, documented from its code.\" },\n ]}\n closing={{ title: \"Something to build together?\", body: \"Tell us what you need; a person answers within two days.\", actions: <Button variant=\"primary\" size=\"lg\">Contact us</Button> }}\n />\n );\n}\n"
148
148
  }
149
149
  ]
150
150
  },
@@ -175,7 +175,7 @@
175
175
  ],
176
176
  "demo": {
177
177
  "path": "examples/landing-page/krizaka.tsx",
178
- "content": "import { Button } from \"@krizaka/ui/button\";\nimport { LandingPage } from \"@krizaka/ui/landing-page\";\nimport { Meter } from \"@krizaka/ui/meter\";\n\n// TEMPLATE — a company's landing (krizaka.com): the promise beside the product alive, a band of proofs, the features\n// as a bento where the main one takes the room, the closing call. On a phone the window follows the words, the bento\n// is one column, the proofs stack.\nexport default function LandingPageKrizaka() {\n return (\n <LandingPage\n eyebrow=\"Software studio · Montréal\"\n title=\"Products that keep what is yours\"\n lead=\"Krizaka builds sovereign AI and a platform where creators are paid — open source, on your servers or ours.\"\n actions={\n <>\n <Button variant=\"primary\" size=\"lg\" shape=\"cut\" shimmer>See the products</Button>\n <Button variant=\"secondary\" size=\"lg\" shape=\"cut\">Read the docs</Button>\n </>\n }\n visualLabel=\"orazaka.local — console\"\n visual={\n <div className=\"grid gap-3 p-5\">\n <p className=\"font-mono text-xs text-fg-secondary\">$ npx orazaka install</p>\n <p className=\"font-mono text-xs text-fg-success\">✓ 1,284 answers this week, none left the server</p>\n <Meter label=\"Credits\" value={3800} max={12000} valueText=\"3,800 of 12,000\" showLabel />\n </div>\n }\n proofs={[\n { value: \"34\", label: \"public repositories\" },\n { value: \"Apache-2.0\", label: \"every line\" },\n { value: \"0\", label: \"telemetry calls\" },\n ]}\n featuresHeading={{ eyebrow: \"What we build\", title: \"Three products, one way of building\" }}\n features={[\n { id: \"orazaka\", size: \"lg\", title: \"Orazaka — the AI that never leaves home\", text: \"Chat, image, voice and video on your own server, one governed pipeline.\" },\n { id: \"orochia\", title: \"Orochia\", text: \"Creators paid 90 % of what fans spend.\" },\n { id: \"yasakia\", title: \"Yasakia\", text: \"Meet by talking first — coming.\" },\n { id: \"blocks\", size: \"md\", title: \"Open building blocks\", text: \"Users, billing, notifications — on Maven Central and npm.\" },\n { id: \"ui\", size: \"md\", title: \"One design system\", text: \"Krizaka UI, web and mobile, documented from its code.\" },\n ]}\n closing={{ title: \"Something to build together?\", body: \"Tell us what you need; a person answers within two days.\", actions: <Button variant=\"primary\" size=\"lg\" shape=\"cut\">Contact us</Button> }}\n />\n );\n}\n"
178
+ "content": "import { Button } from \"@krizaka/ui/button\";\nimport { LandingPage } from \"@krizaka/ui/landing-page\";\nimport { Meter } from \"@krizaka/ui/meter\";\n\n// TEMPLATE — a company's landing (krizaka.com): the promise beside the product alive, a band of proofs, the features\n// as a bento where the main one takes the room, the closing call. On a phone the window follows the words, the bento\n// is one column, the proofs stack.\nexport default function LandingPageKrizaka() {\n return (\n <LandingPage\n eyebrow=\"Software studio · Montréal\"\n title=\"Products that keep what is yours\"\n lead=\"Krizaka builds sovereign AI and a platform where creators are paid — open source, on your servers or ours.\"\n actions={\n <>\n <Button variant=\"primary\" size=\"lg\">See the products</Button>\n <Button variant=\"secondary\" size=\"lg\">Read the docs</Button>\n </>\n }\n visualLabel=\"orazaka.local — console\"\n visual={\n <div className=\"grid gap-3 p-5\">\n <p className=\"font-mono text-xs text-fg-secondary\">$ npx orazaka install</p>\n <p className=\"font-mono text-xs text-fg-success\">✓ 1,284 answers this week, none left the server</p>\n <Meter label=\"Credits\" value={3800} max={12000} valueText=\"3,800 of 12,000\" showLabel />\n </div>\n }\n proofs={[\n { value: \"34\", label: \"public repositories\" },\n { value: \"Apache-2.0\", label: \"every line\" },\n { value: \"0\", label: \"telemetry calls\" },\n ]}\n featuresHeading={{ eyebrow: \"What we build\", title: \"Three products, one way of building\" }}\n features={[\n { id: \"orazaka\", size: \"lg\", title: \"Orazaka — the AI that never leaves home\", text: \"Chat, image, voice and video on your own server, one governed pipeline.\" },\n { id: \"orochia\", title: \"Orochia\", text: \"Creators paid 90 % of what fans spend.\" },\n { id: \"yasakia\", title: \"Yasakia\", text: \"Meet by talking first — coming.\" },\n { id: \"blocks\", size: \"md\", title: \"Open building blocks\", text: \"Users, billing, notifications — on Maven Central and npm.\" },\n { id: \"ui\", size: \"md\", title: \"One design system\", text: \"Krizaka UI, web and mobile, documented from its code.\" },\n ]}\n closing={{ title: \"Something to build together?\", body: \"Tell us what you need; a person answers within two days.\", actions: <Button variant=\"primary\" size=\"lg\">Contact us</Button> }}\n />\n );\n}\n"
179
179
  },
180
180
  "props": [
181
181
  {