@krizaka/ui 3.30.0 → 3.32.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.
- package/README.md +4 -8
- package/dist/action-bar.js +3 -3
- package/dist/action-bar.js.map +1 -1
- package/dist/argument-card.d.ts +1 -1
- package/dist/argument-card.js +2 -2
- package/dist/argument-card.js.map +1 -1
- package/dist/blocks.css +19 -60
- package/dist/{button-BmCrLCq7.d.ts → button-Cm9pFH3P.d.ts} +10 -9
- package/dist/button.d.ts +11 -10
- package/dist/button.js +1 -1
- package/dist/captcha.js +1 -1
- package/dist/card-grid.d.ts +5 -12
- package/dist/card-grid.js +4 -12
- package/dist/card-grid.js.map +1 -1
- package/dist/card.d.ts +7 -7
- package/dist/card.js +2 -2
- package/dist/card.js.map +1 -1
- package/dist/{chunk-GYKQ52HX.js → chunk-2AJ4NJUF.js} +2 -2
- package/dist/{chunk-MQPC3P4T.js → chunk-2DGLWTPS.js} +3 -3
- package/dist/chunk-2DGLWTPS.js.map +1 -0
- package/dist/{chunk-DZU6RMYD.js → chunk-3DHNN5V7.js} +15 -9
- package/dist/chunk-3DHNN5V7.js.map +1 -0
- package/dist/{chunk-TFJDIOFK.js → chunk-4E5IUZHR.js} +3 -3
- package/dist/chunk-4E5IUZHR.js.map +1 -0
- package/dist/{chunk-HAQWKORZ.js → chunk-4JO5GSSD.js} +1 -37
- package/dist/chunk-4JO5GSSD.js.map +1 -0
- package/dist/{chunk-APNIVNIX.js → chunk-IBDTAMPF.js} +3 -4
- package/dist/chunk-IBDTAMPF.js.map +1 -0
- package/dist/{chunk-LYOPPBMC.js → chunk-KIBICUZK.js} +2 -2
- package/dist/{chunk-HBZPJ3EP.js → chunk-NJFCSVPT.js} +2 -2
- package/dist/{chunk-KM6VAKIE.js → chunk-RE5WJ4QP.js} +2 -2
- package/dist/chunk-RE5WJ4QP.js.map +1 -0
- package/dist/{chunk-CHOJUCVE.js → chunk-SJS6RJIT.js} +15 -9
- package/dist/chunk-SJS6RJIT.js.map +1 -0
- package/dist/{chunk-6ZYRUOTA.js → chunk-UV4HBVH7.js} +15 -9
- package/dist/chunk-UV4HBVH7.js.map +1 -0
- package/dist/command.js +2 -2
- package/dist/confirm-button.d.ts +1 -1
- package/dist/confirm-button.js +1 -1
- package/dist/continue-prompt.js +14 -8
- package/dist/continue-prompt.js.map +1 -1
- package/dist/data-table.js +2 -2
- package/dist/dialog.js +2 -2
- package/dist/engine-flow.d.ts +25 -2
- package/dist/engine-flow.js +27 -6
- package/dist/engine-flow.js.map +1 -1
- package/dist/force-update-screen.js +2 -2
- package/dist/force-update-screen.js.map +1 -1
- package/dist/genui.js +3 -3
- package/dist/glow-card.d.ts +5 -4
- package/dist/glow-card.js +2 -8
- package/dist/glow-card.js.map +1 -1
- package/dist/image-cropper.js +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/iso.d.ts +1 -1
- package/dist/iso.js.map +1 -1
- package/dist/landscape.js +4 -4
- package/dist/landscape.js.map +1 -1
- package/dist/link-card.d.ts +3 -6
- package/dist/link-card.js +1 -1
- package/dist/maintenance-screen.js +1 -1
- package/dist/map.d.ts +50 -5
- package/dist/map.js +202 -66
- package/dist/map.js.map +1 -1
- package/dist/match-dialog.js +1 -1
- package/dist/media-gallery.js +1 -1
- package/dist/media-gallery.js.map +1 -1
- package/dist/media-grid.js +2 -2
- package/dist/motion.css +52 -122
- package/dist/motion.d.ts +2 -2
- package/dist/motion.js +1 -1
- package/dist/native/map.js +64 -64
- package/dist/native/map.js.map +1 -1
- package/dist/native.js +30 -30
- package/dist/native.js.map +1 -1
- package/dist/nav-bar.js +2 -2
- package/dist/pointer-light.d.ts +6 -9
- package/dist/pointer-light.js +9 -5
- package/dist/pointer-light.js.map +1 -1
- package/dist/radio-group.js +2 -2
- package/dist/radio-group.js.map +1 -1
- package/dist/service-card.js +1 -1
- package/dist/service-card.js.map +1 -1
- package/dist/site-footer.js +2 -2
- package/dist/slider.js +1 -1
- package/dist/slider.js.map +1 -1
- package/dist/story.css +5 -12
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +1 -1
- package/dist/update-prompt.js +2 -2
- package/dist/update-prompt.js.map +1 -1
- package/dist/vertical-video.js +1 -1
- package/dist/video-player.js +2 -2
- package/dist/video-player.js.map +1 -1
- package/package.json +8 -8
- package/registry/action-bar.json +1 -1
- package/registry/app-shell.json +4 -4
- package/registry/argument-card.json +7 -16
- package/registry/auth-layout.json +4 -4
- package/registry/button.json +20 -20
- package/registry/card-grid.json +21 -24
- package/registry/card.json +7 -7
- package/registry/component-page.json +2 -2
- package/registry/confirm-button.json +6 -6
- package/registry/contact-page.json +2 -2
- package/registry/cover-hero.json +3 -3
- package/registry/dashboard-layout.json +2 -2
- package/registry/detail-layout.json +4 -4
- package/registry/docs-hub-page.json +2 -2
- package/registry/empty-state.json +1 -1
- package/registry/engine-flow.json +74 -3
- package/registry/examples/app-shell/admin-console.js +1 -1
- package/registry/examples/app-shell/admin-console.tsx +1 -1
- package/registry/examples/app-shell/basic.js +1 -1
- package/registry/examples/app-shell/basic.tsx +1 -1
- package/registry/examples/app-shell/desktop.js +1 -1
- package/registry/examples/app-shell/desktop.tsx +1 -1
- package/registry/examples/app-shell/orochia-studio.js +1 -1
- package/registry/examples/app-shell/orochia-studio.tsx +1 -1
- package/registry/examples/argument-card/hover-quiet.js +1 -1
- package/registry/examples/argument-card/hover-quiet.tsx +1 -1
- package/registry/examples/auth-layout/onboarding.js +2 -2
- package/registry/examples/auth-layout/onboarding.tsx +2 -2
- package/registry/examples/auth-layout/sign-in.js +2 -2
- package/registry/examples/auth-layout/sign-in.tsx +2 -2
- package/registry/examples/auth-layout/verify.js +1 -1
- package/registry/examples/auth-layout/verify.tsx +1 -1
- package/registry/examples/avatar/native/presence.dark.png +0 -0
- package/registry/examples/avatar/native/presence.light.png +0 -0
- package/registry/examples/badge/native/tones.dark.png +0 -0
- package/registry/examples/badge/native/tones.light.png +0 -0
- package/registry/examples/button/native/disabled.dark.png +0 -0
- package/registry/examples/button/native/disabled.light.png +0 -0
- package/registry/examples/button/native/gradient.dark.png +0 -0
- package/registry/examples/button/native/gradient.light.png +0 -0
- package/registry/examples/button/native/icon-only.dark.png +0 -0
- package/registry/examples/button/native/icon-only.light.png +0 -0
- package/registry/examples/button/native/icon.dark.png +0 -0
- package/registry/examples/button/native/icon.light.png +0 -0
- package/registry/examples/button/native/loading.dark.png +0 -0
- package/registry/examples/button/native/loading.light.png +0 -0
- package/registry/examples/button/native/primary.dark.png +0 -0
- package/registry/examples/button/native/primary.light.png +0 -0
- package/registry/examples/button/native/sizes.dark.png +0 -0
- package/registry/examples/button/native/sizes.light.png +0 -0
- package/registry/examples/button/signature.js +2 -2
- package/registry/examples/button/signature.tsx +4 -4
- package/registry/examples/card/interactive-link.tsx +1 -1
- package/registry/examples/card/native/body.dark.png +0 -0
- package/registry/examples/card/native/body.light.png +0 -0
- package/registry/examples/card/native/default.dark.png +0 -0
- package/registry/examples/card/native/default.light.png +0 -0
- package/registry/examples/card/native/elevated.dark.png +0 -0
- package/registry/examples/card/native/elevated.light.png +0 -0
- package/registry/examples/card-grid/hover-quiet.js +1 -1
- package/registry/examples/card-grid/hover-quiet.tsx +1 -1
- package/registry/examples/chat/native/assistant.dark.png +0 -0
- package/registry/examples/chat/native/assistant.light.png +0 -0
- package/registry/examples/chat/native/conversation.dark.png +0 -0
- package/registry/examples/chat/native/conversation.light.png +0 -0
- package/registry/examples/chat/native/inbox.dark.png +0 -0
- package/registry/examples/chat/native/inbox.light.png +0 -0
- package/registry/examples/checkbox/native/terms.dark.png +0 -0
- package/registry/examples/checkbox/native/terms.light.png +0 -0
- package/registry/examples/chip/native/multiple.dark.png +0 -0
- package/registry/examples/chip/native/multiple.light.png +0 -0
- package/registry/examples/chip/native/single.dark.png +0 -0
- package/registry/examples/chip/native/single.light.png +0 -0
- package/registry/examples/chip/native/toggle.dark.png +0 -0
- package/registry/examples/chip/native/toggle.light.png +0 -0
- package/registry/examples/component-page/button.js +2 -2
- package/registry/examples/component-page/button.tsx +2 -2
- package/registry/examples/contact-page/team.js +1 -1
- package/registry/examples/contact-page/team.tsx +1 -1
- package/registry/examples/cover-hero/plain.js +1 -1
- package/registry/examples/cover-hero/plain.tsx +1 -1
- package/registry/examples/cover-hero/shop.js +1 -1
- package/registry/examples/cover-hero/shop.tsx +1 -1
- package/registry/examples/dashboard-layout/orazaka-eric.js +2 -2
- package/registry/examples/dashboard-layout/orazaka-eric.tsx +2 -2
- package/registry/examples/date-picker/native/calendar.dark.png +0 -0
- package/registry/examples/date-picker/native/calendar.light.png +0 -0
- package/registry/examples/date-picker/native/day-strip.dark.png +0 -0
- package/registry/examples/date-picker/native/day-strip.light.png +0 -0
- package/registry/examples/date-picker/native/month-year.dark.png +0 -0
- package/registry/examples/date-picker/native/month-year.light.png +0 -0
- package/registry/examples/date-picker/native/time-slots.dark.png +0 -0
- package/registry/examples/date-picker/native/time-slots.light.png +0 -0
- package/registry/examples/description-list/native/job-details.dark.png +0 -0
- package/registry/examples/description-list/native/job-details.light.png +0 -0
- package/registry/examples/detail-layout/checkout.js +1 -1
- package/registry/examples/detail-layout/checkout.tsx +1 -1
- package/registry/examples/detail-layout/job.js +1 -1
- package/registry/examples/detail-layout/job.tsx +1 -1
- package/registry/examples/detail-layout/video.js +2 -2
- package/registry/examples/detail-layout/video.tsx +2 -2
- package/registry/examples/dialog/native/sheet.dark.png +0 -0
- package/registry/examples/dialog/native/sheet.light.png +0 -0
- package/registry/examples/docs-hub-page/krizaka.js +1 -1
- package/registry/examples/docs-hub-page/krizaka.tsx +1 -1
- package/registry/examples/empty-state/library.js +1 -1
- package/registry/examples/empty-state/library.tsx +1 -1
- package/registry/examples/empty-state/native/default.dark.png +0 -0
- package/registry/examples/empty-state/native/default.light.png +0 -0
- package/registry/examples/fab/native/extended.dark.png +0 -0
- package/registry/examples/fab/native/extended.light.png +0 -0
- package/registry/examples/force-update-screen/native/default.dark.png +0 -0
- package/registry/examples/force-update-screen/native/default.light.png +0 -0
- package/registry/examples/form/native/amount.dark.png +0 -0
- package/registry/examples/form/native/amount.light.png +0 -0
- package/registry/examples/form/native/audience.dark.png +0 -0
- package/registry/examples/form/native/audience.light.png +0 -0
- package/registry/examples/form/native/profile.dark.png +0 -0
- package/registry/examples/form/native/profile.light.png +0 -0
- package/registry/examples/form/native/settings.dark.png +0 -0
- package/registry/examples/form/native/settings.light.png +0 -0
- package/registry/examples/form/native/sign-up.dark.png +0 -0
- package/registry/examples/form/native/sign-up.light.png +0 -0
- package/registry/examples/form/native/upload.dark.png +0 -0
- package/registry/examples/form/native/upload.light.png +0 -0
- package/registry/examples/glow-card/spotlight.tsx +1 -1
- package/registry/examples/goal-gauge/native/default.dark.png +0 -0
- package/registry/examples/goal-gauge/native/default.light.png +0 -0
- package/registry/examples/landing-page/krizaka.js +3 -3
- package/registry/examples/landing-page/krizaka.tsx +3 -3
- package/registry/examples/link-card/hover-quiet.js +1 -1
- package/registry/examples/link-card/hover-quiet.tsx +1 -1
- package/registry/examples/loader/native/block.dark.png +0 -0
- package/registry/examples/loader/native/block.light.png +0 -0
- package/registry/examples/map/native/location-picker.dark.png +0 -0
- package/registry/examples/map/native/location-picker.light.png +0 -0
- package/registry/examples/map/route.js +36 -0
- package/registry/examples/map/route.tsx +35 -0
- package/registry/examples/marketing-layout/pricing.js +1 -1
- package/registry/examples/marketing-layout/pricing.tsx +1 -1
- package/registry/examples/marketing-layout/product-page.js +1 -1
- package/registry/examples/marketing-layout/product-page.tsx +2 -2
- package/registry/examples/mascot-state/native/default.dark.png +0 -0
- package/registry/examples/mascot-state/native/default.light.png +0 -0
- package/registry/examples/mascots/native/crane.dark.png +0 -0
- package/registry/examples/mascots/native/crane.light.png +0 -0
- package/registry/examples/mascots/native/default.dark.png +0 -0
- package/registry/examples/mascots/native/default.light.png +0 -0
- package/registry/examples/mascots/native/lovebird.dark.png +0 -0
- package/registry/examples/mascots/native/lovebird.light.png +0 -0
- package/registry/examples/mascots/native/phoenix.dark.png +0 -0
- package/registry/examples/mascots/native/phoenix.light.png +0 -0
- package/registry/examples/match-dialog/native/its-a-match.dark.png +0 -0
- package/registry/examples/match-dialog/native/its-a-match.light.png +0 -0
- package/registry/examples/media-capture/native/photo.dark.png +0 -0
- package/registry/examples/media-capture/native/photo.light.png +0 -0
- package/registry/examples/meta-row/native/video.dark.png +0 -0
- package/registry/examples/meta-row/native/video.light.png +0 -0
- package/registry/examples/meter/native/credits.dark.png +0 -0
- package/registry/examples/meter/native/credits.light.png +0 -0
- package/registry/examples/meter/native/split-ring.dark.png +0 -0
- package/registry/examples/meter/native/split-ring.light.png +0 -0
- package/registry/examples/nav-bar/family-product.js +1 -1
- package/registry/examples/nav-bar/family-product.tsx +1 -1
- package/registry/examples/onboarding/native/first-launch.dark.png +0 -0
- package/registry/examples/onboarding/native/first-launch.light.png +0 -0
- package/registry/examples/permission-prompt/native/blocked.dark.png +0 -0
- package/registry/examples/permission-prompt/native/blocked.light.png +0 -0
- package/registry/examples/permission-prompt/native/camera.dark.png +0 -0
- package/registry/examples/permission-prompt/native/camera.light.png +0 -0
- package/registry/examples/photo-grid/native/profile-photos.dark.png +0 -0
- package/registry/examples/photo-grid/native/profile-photos.light.png +0 -0
- package/registry/examples/pricing-page/credits.js +3 -3
- package/registry/examples/pricing-page/credits.tsx +3 -3
- package/registry/examples/product-page/orazaka.js +2 -2
- package/registry/examples/product-page/orazaka.tsx +2 -2
- package/registry/examples/profile-card/native/default.dark.png +0 -0
- package/registry/examples/profile-card/native/default.light.png +0 -0
- package/registry/examples/progress/native/bar.dark.png +0 -0
- package/registry/examples/progress/native/bar.light.png +0 -0
- package/registry/examples/progress/native/indeterminate.dark.png +0 -0
- package/registry/examples/progress/native/indeterminate.light.png +0 -0
- package/registry/examples/progress/native/ring.dark.png +0 -0
- package/registry/examples/progress/native/ring.light.png +0 -0
- package/registry/examples/radio-group/native/buttons.dark.png +0 -0
- package/registry/examples/radio-group/native/buttons.light.png +0 -0
- package/registry/examples/radio-group/native/cards.dark.png +0 -0
- package/registry/examples/radio-group/native/cards.light.png +0 -0
- package/registry/examples/radio-group/native/list.dark.png +0 -0
- package/registry/examples/radio-group/native/list.light.png +0 -0
- package/registry/examples/screen/native/auth.dark.png +0 -0
- package/registry/examples/screen/native/auth.light.png +0 -0
- package/registry/examples/screen/native/chat.dark.png +0 -0
- package/registry/examples/screen/native/chat.light.png +0 -0
- package/registry/examples/screen/native/profile.dark.png +0 -0
- package/registry/examples/screen/native/profile.light.png +0 -0
- package/registry/examples/screen/native/settings.dark.png +0 -0
- package/registry/examples/screen/native/settings.light.png +0 -0
- package/registry/examples/search-field/native/cancel.dark.png +0 -0
- package/registry/examples/search-field/native/cancel.light.png +0 -0
- package/registry/examples/settings-layout/account.js +1 -1
- package/registry/examples/settings-layout/account.tsx +1 -1
- package/registry/examples/settings-layout/native/account.dark.png +0 -0
- package/registry/examples/settings-layout/native/account.light.png +0 -0
- package/registry/examples/settings-layout/sections.js +1 -1
- package/registry/examples/settings-layout/sections.tsx +1 -1
- package/registry/examples/showcase/native/slides.dark.png +0 -0
- package/registry/examples/showcase/native/slides.light.png +0 -0
- package/registry/examples/slider/native/default.dark.png +0 -0
- package/registry/examples/slider/native/default.light.png +0 -0
- package/registry/examples/slider/native/range.dark.png +0 -0
- package/registry/examples/slider/native/range.light.png +0 -0
- package/registry/examples/slider/native/stepped.dark.png +0 -0
- package/registry/examples/slider/native/stepped.light.png +0 -0
- package/registry/examples/slider/native/vertical.dark.png +0 -0
- package/registry/examples/slider/native/vertical.light.png +0 -0
- package/registry/examples/spinner/native/sizes.dark.png +0 -0
- package/registry/examples/spinner/native/sizes.light.png +0 -0
- package/registry/examples/split-view/messages.js +1 -1
- package/registry/examples/split-view/messages.tsx +1 -1
- package/registry/examples/status-page/building.js +1 -1
- package/registry/examples/status-page/building.tsx +1 -1
- package/registry/examples/step-progress/native/sign-up.dark.png +0 -0
- package/registry/examples/step-progress/native/sign-up.light.png +0 -0
- package/registry/examples/stepper/native/run.dark.png +0 -0
- package/registry/examples/stepper/native/run.light.png +0 -0
- package/registry/examples/sticky-action/phone.js +1 -1
- package/registry/examples/sticky-action/phone.tsx +1 -1
- package/registry/examples/switch/native/default.dark.png +0 -0
- package/registry/examples/switch/native/default.light.png +0 -0
- package/registry/examples/switch/native/settings.dark.png +0 -0
- package/registry/examples/switch/native/settings.light.png +0 -0
- package/registry/examples/tab-bar/native/main-sections.dark.png +0 -0
- package/registry/examples/tab-bar/native/main-sections.light.png +0 -0
- package/registry/examples/tabs/native/sections.dark.png +0 -0
- package/registry/examples/tabs/native/sections.light.png +0 -0
- package/registry/examples/tag-selector/native/interests.dark.png +0 -0
- package/registry/examples/tag-selector/native/interests.light.png +0 -0
- package/registry/examples/toast/native/snackbar.dark.png +0 -0
- package/registry/examples/toast/native/snackbar.light.png +0 -0
- package/registry/examples/toast/native/tones.dark.png +0 -0
- package/registry/examples/toast/native/tones.light.png +0 -0
- package/registry/examples/txt/native/tones.dark.png +0 -0
- package/registry/examples/txt/native/tones.light.png +0 -0
- package/registry/examples/update-prompt/native/default.dark.png +0 -0
- package/registry/examples/update-prompt/native/default.light.png +0 -0
- package/registry/examples/verified-badge/native/verified.dark.png +0 -0
- package/registry/examples/verified-badge/native/verified.light.png +0 -0
- package/registry/examples/vertical-video/native/rail.dark.png +0 -0
- package/registry/examples/vertical-video/native/rail.light.png +0 -0
- package/registry/examples/waveform/native/card.dark.png +0 -0
- package/registry/examples/waveform/native/card.light.png +0 -0
- package/registry/force-update-screen.json +1 -1
- package/registry/form.json +6 -6
- package/registry/glow-card.json +19 -19
- package/registry/index.json +20 -21
- package/registry/iso.json +7 -7
- package/registry/landing-page.json +2 -2
- package/registry/landscape.json +1 -1
- package/registry/link-card.json +15 -24
- package/registry/map.json +235 -6
- package/registry/marketing-layout.json +3 -3
- package/registry/media-gallery.json +1 -1
- package/registry/nav-bar.json +3 -3
- package/registry/pointer-light.json +17 -22
- package/registry/pricing-page.json +2 -2
- package/registry/product-page.json +2 -2
- package/registry/progress.json +2 -2
- package/registry/radio-group.json +1 -1
- package/registry/rail-nav.json +2 -2
- package/registry/service-card.json +1 -1
- package/registry/settings-layout.json +3 -3
- package/registry/site-footer.json +2 -2
- package/registry/slider.json +1 -1
- package/registry/split-view.json +2 -2
- package/registry/status-page.json +1 -1
- package/registry/sticky-action.json +2 -2
- package/registry/update-prompt.json +1 -1
- package/registry/video-player.json +1 -1
- package/dist/chunk-6ZYRUOTA.js.map +0 -1
- package/dist/chunk-AB5D3KBG.js +0 -37
- package/dist/chunk-AB5D3KBG.js.map +0 -1
- package/dist/chunk-APNIVNIX.js.map +0 -1
- package/dist/chunk-CHOJUCVE.js.map +0 -1
- package/dist/chunk-DZU6RMYD.js.map +0 -1
- package/dist/chunk-HAQWKORZ.js.map +0 -1
- package/dist/chunk-KM6VAKIE.js.map +0 -1
- package/dist/chunk-MQPC3P4T.js.map +0 -1
- package/dist/chunk-TFJDIOFK.js.map +0 -1
- package/registry/examples/argument-card/hover-light.js +0 -17
- package/registry/examples/argument-card/hover-light.tsx +0 -19
- package/registry/examples/link-card/hover-light.d.ts +0 -4
- package/registry/examples/link-card/hover-light.js +0 -18
- package/registry/examples/link-card/hover-light.tsx +0 -20
- /package/dist/{chunk-GYKQ52HX.js.map → chunk-2AJ4NJUF.js.map} +0 -0
- /package/dist/{chunk-LYOPPBMC.js.map → chunk-KIBICUZK.js.map} +0 -0
- /package/dist/{chunk-HBZPJ3EP.js.map → chunk-NJFCSVPT.js.map} +0 -0
- /package/registry/examples/{argument-card/hover-light.d.ts → map/route.d.ts} +0 -0
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
|
|
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)
|
|
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)
|
|
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
|
|
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)
|
|
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)
|
|
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\"
|
|
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\"
|
|
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
|
{
|
package/registry/landscape.json
CHANGED
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
133
|
"path": "landscape/landscape.tsx",
|
|
134
|
-
"content": "// The Krizaka landscape — a valley at dusk under a constellation: three ranges of peaks, a phoenix over a river of\n// two flames, trees of light, a treehouse, and the flock at work (the falcon on watch, the owl, the duck at its\n// laptop, the flamingo). The brand layer's illustration, like the marks: drawn in code, ids unique per instance, its\n// own colours by default (`tone=\"own\"`) or the host brand's sky and peaks (`tone=\"brand\"`). Decorative.\nimport type * as React from \"react\";\nimport { useId } from \"react\";\n\nimport { cn } from \"../cn\";\n\n/** The sky and the peaks: the Krizaka dusk (`own`), or the host brand's accents (`brand`). Birds keep their colours. */\nconst TONES = {\n own: {\n \"--kzl-sun\": \"#f59e0b\",\n \"--kzl-sun-2\": \"#ec4899\",\n \"--kzl-sun-3\": \"#6366f1\",\n \"--kzl-far\": \"#6366f1\",\n \"--kzl-far-2\": \"#4f46e5\",\n \"--kzl-far-line\": \"#818cf8\",\n \"--kzl-mid\": \"#06b6d4\",\n \"--kzl-mid-2\": \"#0891b2\",\n \"--kzl-mid-line\": \"#22d3ee\",\n \"--kzl-near\": \"#d946ef\",\n \"--kzl-near-2\": \"#a855f7\",\n \"--kzl-near-line\": \"#e879f9\",\n \"--kzl-aurora-l\": \"#00f2fe\",\n \"--kzl-aurora-r\": \"#ec4899\",\n },\n brand: {\n \"--kzl-sun\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-sun-2\": \"var(--kz-accent)\",\n \"--kzl-sun-3\": \"var(--kz-accent)\",\n \"--kzl-far\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-far-2\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-far-line\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-mid\": \"color-mix(in srgb, var(--kz-accent) 55%, var(--kz-accent-2, var(--kz-accent)))\",\n \"--kzl-mid-2\": \"color-mix(in srgb, var(--kz-accent) 55%, var(--kz-accent-2, var(--kz-accent)))\",\n \"--kzl-mid-line\": \"color-mix(in srgb, var(--kz-accent) 55%, var(--kz-accent-2, var(--kz-accent)))\",\n \"--kzl-near\": \"var(--kz-accent)\",\n \"--kzl-near-2\": \"var(--kz-accent)\",\n \"--kzl-near-line\": \"var(--kz-accent)\",\n \"--kzl-aurora-l\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-aurora-r\": \"var(--kz-accent)\",\n },\n} as const;\n\nconst CSS = `\n.kzl { pointer-events: none; overflow: hidden; }\n.kzl-fade { position: absolute; bottom: 0; left: 0; right: 0; height: 120px; pointer-events: none; z-index: 3;\n background: linear-gradient(to top, var(--kz-surface-0) 0%, transparent 100%); }\n /* --- Cyber Phoenix & Flame Flow animations --- */\n @keyframes kzl-phoenix-flow-purple {\n from { stroke-dashoffset: 350; }\n to { stroke-dashoffset: 0; }\n }\n @keyframes kzl-phoenix-flow-gold {\n from { stroke-dashoffset: 0; }\n to { stroke-dashoffset: 350; }\n }\n @keyframes kzl-phoenix-bob {\n 0%, 100% { transform: translateY(0) scale(1); }\n 50% { transform: translateY(-8px) scale(1.02); }\n }\n @keyframes kzl-wing-flap-l-phoenix {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(-10deg) translateY(-2px); }\n }\n @keyframes kzl-wing-flap-r-phoenix {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(10deg) translateY(-2px); }\n }\n @keyframes kzl-core-glow {\n 0%, 100% { fill: #ffef5c; filter: drop-shadow(0 0 1px #ffef5c); }\n 50% { fill: #ffffff; filter: drop-shadow(0 0 5px #ff3c00); }\n }\n\n .kzl-cyber-phoenix {\n animation: kzl-phoenix-bob 4s ease-in-out infinite;\n transform-origin: 600px 325px;\n transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n }\n .kzl-cyber-phoenix:hover {\n transform: translateY(-4px) scale(1.08);\n }\n .kzl-phoenix-wing-l {\n animation: kzl-wing-flap-l-phoenix 2.5s ease-in-out infinite;\n }\n .kzl-phoenix-wing-r {\n animation: kzl-wing-flap-r-phoenix 2.5s ease-in-out infinite;\n }\n .kzl-cyber-phoenix:hover .kzl-phoenix-wing-l {\n animation: kzl-wing-flap-l-phoenix 0.6s linear infinite;\n }\n .kzl-cyber-phoenix:hover .kzl-phoenix-wing-r {\n animation: kzl-wing-flap-r-phoenix 0.6s linear infinite;\n }\n .kzl-phoenix-core {\n animation: kzl-core-glow 1.5s ease-in-out infinite;\n }\n\n /* --- Pulse Animations --- */\n @keyframes kzl-opacity-pulse {\n 0%, 100% { opacity: 0.35; }\n 50% { opacity: 0.95; }\n }\n .kzl-pulse-slow {\n animation: kzl-opacity-pulse 4s ease-in-out infinite;\n }\n @keyframes kzl-sun-pulse {\n 0%, 100% { opacity: 0.16; transform: scale(0.96); }\n 50% { opacity: 0.32; transform: scale(1.04); }\n }\n .kzl-sun-pulsing {\n animation: kzl-sun-pulse 6s ease-in-out infinite;\n transform-origin: 600px 200px;\n }\n\n /* --- Rising local data pulses --- */\n @keyframes kzl-rise-fade-1 {\n 0% { transform: translateY(80px) scale(0.5); opacity: 0; }\n 40% { opacity: 0.8; }\n 100% { transform: translateY(-30px) scale(1.3); opacity: 0; }\n }\n @keyframes kzl-rise-fade-2 {\n 0% { transform: translateY(60px) scale(0.4); opacity: 0; }\n 50% { opacity: 0.9; }\n 100% { transform: translateY(-50px) scale(1.2); opacity: 0; }\n }\n .kzl-rising-pulse-1 {\n animation: kzl-rise-fade-1 4s cubic-bezier(0.1, 0.8, 0.3, 1) infinite;\n transform-origin: center;\n }\n .kzl-rising-pulse-2 {\n animation: kzl-rise-fade-2 5s cubic-bezier(0.1, 0.8, 0.3, 1) infinite 1.5s;\n transform-origin: center;\n }\n\n /* --- Mascot Hover Animations (Stable Hitboxes) --- */\n .kzl-bird-graphics {\n transform-box: fill-box;\n transform-origin: center;\n transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n }\n .kzl-bird-hitbox:hover .kzl-bird-graphics {\n transform: scale(1.08) translateY(-4px);\n }\n\n /* --- Bird Eye Blinking/Glowing Animations --- */\n .kzl-falcon-eye {\n animation: kzl-falcon-eye-pulse 2.5s ease-in-out infinite;\n }\n .kzl-duck-eye {\n transform-box: fill-box;\n transform-origin: center;\n animation: kzl-eye-blink 5s ease-in-out infinite 1s;\n }\n .kzl-flamingo-eye {\n transform-box: fill-box;\n transform-origin: center;\n animation: kzl-eye-blink 6s ease-in-out infinite 2.5s;\n }\n .kzl-owl-eye {\n transform-box: fill-box;\n transform-origin: center;\n animation: kzl-eye-blink 4s ease-in-out infinite 0.5s;\n }\n\n @keyframes kzl-eye-blink {\n 0%, 90%, 100% {\n transform: scaleY(1);\n }\n 95% {\n transform: scaleY(0.15);\n }\n }\n\n @keyframes kzl-falcon-eye-pulse {\n 0%, 100% { fill: #00f2fe; filter: drop-shadow(0 0 2px #00f2fe); }\n 50% { fill: #00ff66; filter: drop-shadow(0 0 5px #00ff66); }\n }\n\n /* FalconBot constant loop animations */\n .kzl-falcon-bot .kzl-head-group {\n animation: kzl-head-bob 4s ease-in-out infinite;\n }\n .kzl-falcon-bot .kzl-wing-left {\n animation: kzl-wing-flap-left 3s ease-in-out infinite;\n }\n .kzl-falcon-bot .kzl-wing-right {\n animation: kzl-wing-flap-right 3s ease-in-out infinite;\n }\n .kzl-falcon-bot .kzl-sentry-laser {\n animation: kzl-scan-flicker 5s ease-in-out infinite;\n }\n\n @keyframes kzl-scan-flicker {\n 0%, 100% { opacity: 0; }\n 10%, 90% { opacity: 0.15; }\n 50% { opacity: 0.5; }\n }\n @keyframes kzl-head-bob {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 50% { transform: translateY(-2px) rotate(2deg); }\n }\n @keyframes kzl-wing-flap-left {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(-8deg) scaleX(1.05); }\n }\n @keyframes kzl-wing-flap-right {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(8deg) scaleX(1.05); }\n }\n\n /* Developer Duck constant loop animations */\n .kzl-developer-duck .kzl-head-group {\n animation: kzl-duck-look 6s ease-in-out infinite;\n }\n .kzl-developer-duck .kzl-wing-left-type {\n animation: kzl-wing-type-l 0.5s ease-in-out infinite;\n }\n .kzl-developer-duck .kzl-wing-right-type {\n animation: kzl-wing-type-r 0.5s ease-in-out infinite 0.25s;\n }\n .kzl-developer-duck .kzl-laptop-screen {\n animation: kzl-screen-flicker-idle 3s ease-in-out infinite;\n }\n .kzl-developer-duck .kzl-holo-projection {\n animation: kzl-holo-flicker 6s ease-in-out infinite;\n }\n .kzl-developer-duck .kzl-holo-elements {\n animation: kzl-holo-elements-rise 6s ease-in-out infinite;\n }\n\n @keyframes kzl-screen-flicker-idle {\n 0%, 100% { opacity: 0.7; }\n 50% { opacity: 0.95; filter: drop-shadow(0 0 3px var(--kz-accent)); }\n }\n @keyframes kzl-holo-flicker {\n 0%, 100% { opacity: 0; }\n 20%, 80% { opacity: 0.35; }\n 50% { opacity: 0.65; }\n }\n @keyframes kzl-holo-elements-rise {\n 0% { transform: translateY(10px); opacity: 0; }\n 50% { opacity: 0.8; }\n 100% { transform: translateY(-15px); opacity: 0; }\n }\n @keyframes kzl-duck-look {\n 0%, 100% { transform: rotate(0deg); }\n 30% { transform: rotate(-5deg); }\n 70% { transform: rotate(5deg); }\n }\n @keyframes kzl-wing-type-l {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 50% { transform: translateY(-3px) rotate(-4deg); }\n }\n @keyframes kzl-wing-type-r {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 50% { transform: translateY(-3px) rotate(4deg); }\n }\n\n /* Flamingo Bot constant loop animations */\n .kzl-flamingo-bot .kzl-head-group {\n animation: kzl-flamingo-head-bob 5s ease-in-out infinite;\n }\n .kzl-flamingo-bot .kzl-flamingo-neck {\n animation: kzl-flamingo-neck-sway 7s ease-in-out infinite;\n transform-origin: 20px 74px;\n }\n .kzl-flamingo-bot .kzl-flamingo-wing {\n animation: kzl-flamingo-wing-flap 4s ease-in-out infinite;\n }\n\n @keyframes kzl-flamingo-neck-sway {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(-3deg) scaleY(1.02); }\n }\n @keyframes kzl-flamingo-head-bob {\n 0%, 100% { transform: translate(8px, 12px) translateY(0) rotate(0deg); }\n 50% { transform: translate(8px, 12px) translateY(-5px) rotate(-3deg); }\n }\n @keyframes kzl-flamingo-wing-flap {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 50% { transform: translateY(-2px) rotate(-6deg); }\n }\n\n /* Owl Bot constant loop animations */\n .kzl-owl-bot {\n animation: kzl-owl-sway 5s ease-in-out infinite;\n transform-origin: center;\n }\n @keyframes kzl-owl-sway {\n 0%, 100% { transform: rotate(0deg) translateY(0); }\n 50% { transform: rotate(-3deg) translateY(-2px); }\n }\n\n /* Treehouse hover glow */\n .kzl-cyber-treehouse:hover .kzl-window-glow {\n fill: #f59e0b;\n filter: drop-shadow(0 0 10px #f59e0b);\n }\n\n /* Floating tech particles */\n @keyframes kzl-float-up-down {\n 0%, 100% { transform: translateY(0); opacity: 0.4; }\n 50% { transform: translateY(-24px); opacity: 0.95; }\n }\n .kzl-float-particle-1 { animation: kzl-float-up-down 4.2s ease-in-out infinite; }\n .kzl-float-particle-2 { animation: kzl-float-up-down 5.2s ease-in-out infinite 1.2s; }\n .kzl-float-particle-3 { animation: kzl-float-up-down 4.7s ease-in-out infinite 0.6s; }\n .kzl-float-particle-4 { animation: kzl-float-up-down 6.2s ease-in-out infinite 2.2s; }\n\n @media (max-width: 1024px) {\n .kzl-mobile-hide {\n display: none !important;\n }\n }\n/* Still: with animated={false}, off screen, and under reduced motion — every loop holds its first frame. */\n.kzl[data-still] *, .kzl[data-offscreen] * { animation-play-state: paused !important; }\n@media (prefers-reduced-motion: reduce) {\n .kzl * { animation-play-state: paused !important; transition: none !important; }\n}\n`;\n\nexport type LandscapeProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> & {\n /**\n * `own`: the Krizaka dusk (indigo, cyan and magenta peaks). `brand`: the sky and the peaks in the host brand's\n * accents (`.brand-<id>`). The birds and the phoenix keep their own colours.\n * @default \"own\"\n */\n tone?: \"own\" | \"brand\";\n /**\n * The flock at work in the valley (hidden under 1024 px wide either way).\n * @default true\n */\n flock?: boolean;\n /**\n * The phoenix and its river of two flames.\n * @default true\n */\n phoenix?: boolean;\n /**\n * The slow loops (the sun, the stars, the flames, the birds). `false` holds the first frame; always held under\n * `prefers-reduced-motion` and while off screen (with `MotionObserver`).\n * @default true\n */\n animated?: boolean;\n /**\n * `absolute`: fills its positioned parent, anchored at the bottom (a backdrop). `relative`: a block in the flow — give\n * it a height.\n * @default \"absolute\"\n */\n position?: \"absolute\" | \"relative\";\n /**\n * Fades the bottom into the page's surface.\n * @default true\n */\n fade?: boolean;\n};\n\n/** The Krizaka landscape: a decorative backdrop for a hero or a page's end (`aria-hidden`). */\nexport function Landscape({ tone = \"own\", flock = true, phoenix = true, animated = true, position = \"absolute\", fade = true, className, style, ...props }: LandscapeProps) {\n const u = \"kzl\" + useId().replace(/[^a-zA-Z0-9_-]/g, \"\");\n const box: React.CSSProperties =\n position === \"absolute\" ? { position: \"absolute\", inset: \"auto 0 0 0\", height: \"100%\", width: \"100%\" } : { position: \"relative\", width: \"100%\", height: 440 };\n return (\n <div\n aria-hidden\n data-motion-scope=\"\"\n data-still={animated ? undefined : \"\"}\n className={cn(\"kzl\", className)}\n style={{ ...box, ...(TONES[tone] as React.CSSProperties), ...style }}\n {...props}\n >\n <style>{CSS}</style>\n <svg width=\"100%\" height=\"100%\" viewBox=\"0 50 1200 520\" preserveAspectRatio=\"xMidYMax slice\" fill=\"none\" style={{ display: \"block\", pointerEvents: \"none\" }}>\n <defs>\n {/* Vibrant Cyber Sun Glow */}\n <radialGradient id={`${u}-sun-glow`} cx=\"50%\" cy=\"50%\" r=\"50%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-sun)\" stopOpacity=\"0.45\" />\n <stop offset=\"30%\" stopColor=\"var(--kzl-sun-2)\" stopOpacity=\"0.28\" />\n <stop offset=\"70%\" stopColor=\"var(--kzl-sun-3)\" stopOpacity=\"0.16\" />\n <stop offset=\"100%\" stopColor=\"transparent\" stopOpacity=\"0\" />\n </radialGradient>\n\n {/* Mountains Vibrant Gradients */}\n <linearGradient id={`${u}-mtn-back`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-far)\" stopOpacity=\"0.75\" /> {/* indigo */}\n <stop offset=\"50%\" stopColor=\"var(--kzl-far-2)\" stopOpacity=\"0.45\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n <linearGradient id={`${u}-mtn-mid`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-mid)\" stopOpacity=\"0.7\" /> {/* cyan */}\n <stop offset=\"50%\" stopColor=\"var(--kzl-mid-2)\" stopOpacity=\"0.4\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n <linearGradient id={`${u}-mtn-front`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-near)\" stopOpacity=\"0.8\" /> {/* pink */}\n <stop offset=\"50%\" stopColor=\"var(--kzl-near-2)\" stopOpacity=\"0.5\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n\n {/* Vibrant Mascot Gradients */}\n <linearGradient id={`${u}-falcon-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#ff9f00\" />\n <stop offset=\"100%\" stopColor=\"#ff2a00\" />\n </linearGradient>\n <linearGradient id={`${u}-duck-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#f43f5e\" />\n <stop offset=\"100%\" stopColor=\"#be123c\" />\n </linearGradient>\n <linearGradient id={`${u}-flamingo-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#3b82f6\" />\n <stop offset=\"100%\" stopColor=\"#1d4ed8\" />\n </linearGradient>\n <linearGradient id={`${u}-owl-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#a78bfa\" />\n <stop offset=\"100%\" stopColor=\"#6d28d9\" />\n </linearGradient>\n\n {/* Hologram Projections */}\n <linearGradient id={`${u}-holo-grad`} x1=\"0%\" y1=\"100%\" x2=\"0%\" y2=\"0%\">\n <stop offset=\"0%\" stopColor=\"#10b981\" stopOpacity=\"0.5\" />\n <stop offset=\"100%\" stopColor=\"#10b981\" stopOpacity=\"0\" />\n </linearGradient>\n\n {/* Rival flame gradients for the Cyber-Phoenix */}\n <linearGradient id={`${u}-phoenix-gold-grad`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#ffb000\" />\n <stop offset=\"100%\" stopColor=\"#ff3c00\" />\n </linearGradient>\n <linearGradient id={`${u}-phoenix-purple-grad`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#c084fc\" />\n <stop offset=\"100%\" stopColor=\"#db2777\" />\n </linearGradient>\n <linearGradient id={`${u}-phoenix-body-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kz-surface-3)\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-2)\" />\n </linearGradient>\n\n {/* Glowing stream gradients */}\n <linearGradient id={`${u}-gold-glow`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#ff3c00\" stopOpacity=\"0.95\" />\n <stop offset=\"50%\" stopColor=\"#ffb000\" stopOpacity=\"0.75\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n <linearGradient id={`${u}-purple-glow`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#db2777\" stopOpacity=\"0.95\" />\n <stop offset=\"50%\" stopColor=\"#a78bfa\" stopOpacity=\"0.75\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n\n {/* River mask to fade out at the bottom */}\n <linearGradient id={`${u}-river-mask-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"85%\" stopColor=\"white\" />\n <stop offset=\"100%\" stopColor=\"black\" />\n </linearGradient>\n <mask id={`${u}-river-fade-mask`}>\n <rect x=\"0\" y=\"0\" width=\"1200\" height=\"1000\" fill={`url(#${u}-river-mask-grad)`} />\n </mask>\n\n {/* Cyber trees gradient */}\n <linearGradient id={`${u}-tree-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kz-accent)\" stopOpacity=\"0.35\" />\n <stop offset=\"100%\" stopColor=\"transparent\" />\n </linearGradient>\n\n {/* Cyber Bench Gradient */}\n <linearGradient id={`${u}-bench-grad`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n <stop offset=\"0%\" stopColor=\"var(--kz-surface-3)\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-2)\" />\n </linearGradient>\n\n {/* Cyber Aurora Glows */}\n <radialGradient id={`${u}-aurora-left`} cx=\"20%\" cy=\"30%\" r=\"50%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-aurora-l)\" stopOpacity=\"0.22\" />\n <stop offset=\"100%\" stopColor=\"transparent\" stopOpacity=\"0\" />\n </radialGradient>\n <radialGradient id={`${u}-aurora-right`} cx=\"80%\" cy=\"25%\" r=\"50%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-aurora-r)\" stopOpacity=\"0.22\" />\n <stop offset=\"100%\" stopColor=\"transparent\" stopOpacity=\"0\" />\n </radialGradient>\n </defs>\n\n <g transform=\"translate(0, 60)\">\n {/* ─── Cyber Aurora Backdrop ─── */}\n <circle cx=\"200\" cy=\"180\" r=\"600\" fill={`url(#${u}-aurora-left)`} />\n <circle cx=\"1000\" cy=\"150\" r=\"600\" fill={`url(#${u}-aurora-right)`} />\n\n {/* ─── Ethereal Sun and Sky Network Nodes (Constellations) ─── */}\n <circle cx=\"600\" cy=\"200\" r=\"380\" fill={`url(#${u}-sun-glow)`} />\n <circle cx=\"600\" cy=\"200\" r=\"64\" fill=\"var(--kzl-sun)\" opacity=\"0.16\" className=\"kzl-sun-pulsing\" />\n\n {/* Constellation grid lines in the sky */}\n <g opacity=\"0.3\" stroke=\"var(--kz-accent)\" strokeWidth=\"1\">\n <line x1=\"300\" y1=\"120\" x2=\"380\" y2=\"80\" />\n <line x1=\"380\" y1=\"80\" x2=\"450\" y2=\"110\" />\n <line x1=\"450\" y1=\"110\" x2=\"300\" y2=\"120\" />\n <line x1=\"450\" y1=\"110\" x2=\"520\" y2=\"60\" />\n <line x1=\"750\" y1=\"80\" x2=\"840\" y2=\"130\" />\n <line x1=\"840\" y1=\"130\" x2=\"900\" y2=\"70\" />\n <line x1=\"900\" y1=\"70\" x2=\"750\" y2=\"80\" />\n </g>\n {/* Constellation node points */}\n <g fill=\"var(--kz-accent)\" opacity=\"0.65\">\n <circle cx=\"300\" cy=\"120\" r=\"3.5\" />\n <circle cx=\"380\" cy=\"80\" r=\"5\" className=\"kzl-pulse-slow\" />\n <circle cx=\"450\" cy=\"110\" r=\"3\" />\n <circle cx=\"520\" cy=\"60\" r=\"4.5\" />\n <circle cx=\"750\" cy=\"80\" r=\"4.5\" />\n <circle cx=\"840\" cy=\"130\" r=\"3.5\" />\n <circle cx=\"900\" cy=\"70\" r=\"6\" className=\"kzl-pulse-slow\" />\n </g>\n\n {/* ─── Layered Mountains (with Digital Contours) ─── */}\n {/* Far Peaks */}\n <path d=\"M 150 480 L 420 280 L 680 480 Z\" fill={`url(#${u}-mtn-back)`} stroke=\"var(--kzl-far-line)\" strokeWidth=\"1.5\" />\n <path d=\"M 520 480 L 780 230 L 1050 480 Z\" fill={`url(#${u}-mtn-back)`} stroke=\"var(--kzl-far-line)\" strokeWidth=\"1.5\" />\n\n {/* Mid Peaks */}\n <path d=\"M -50 500 L 220 320 L 500 500 Z\" fill={`url(#${u}-mtn-mid)`} stroke=\"var(--kzl-mid-line)\" strokeWidth=\"1.5\" />\n <path d=\"M 700 500 L 980 300 L 1250 500 Z\" fill={`url(#${u}-mtn-mid)`} stroke=\"var(--kzl-mid-line)\" strokeWidth=\"1.5\" />\n\n {/* Wireframe grids on mountains (Contour lines) */}\n <g stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.18\">\n {/* Mid peak left contours */}\n <line x1=\"30\" y1=\"440\" x2=\"410\" y2=\"440\" />\n <line x1=\"85\" y1=\"400\" x2=\"355\" y2=\"400\" />\n <line x1=\"140\" y1=\"360\" x2=\"300\" y2=\"360\" />\n {/* Mid peak right contours */}\n <line x1=\"770\" y1=\"450\" x2=\"1180\" y2=\"450\" />\n <line x1=\"825\" y1=\"410\" x2=\"1125\" y2=\"410\" />\n <line x1=\"880\" y1=\"370\" x2=\"1070\" y2=\"370\" />\n </g>\n\n {/* Front Peaks */}\n <path d=\"M 100 520 L 360 380 L 620 520 Z\" fill={`url(#${u}-mtn-front)`} stroke=\"var(--kzl-near-line)\" strokeWidth=\"1.8\" />\n <path d=\"M 580 520 L 850 350 L 1100 520 Z\" fill={`url(#${u}-mtn-front)`} stroke=\"var(--kzl-near-line)\" strokeWidth=\"1.8\" />\n\n {phoenix && (\n <>\n {/* ─── Cyber-Phoenix & Dual Glowing Flame Trails ─── */}\n {/* Dual Cascading Flame Trails */}\n {/* Left Purple Flame Trail */}\n <path\n d=\"M 590 340 C 570 370, 610 390, 590 410 C 570 430, 490 440, 510 480 C 530 520, 670 530, 700 560 C 720 580, 750 600, 730 630 C 710 660, 630 670, 650 710 C 660 730, 690 740, 700 760 C 710 780, 670 800, 650 830 C 630 860, 680 890, 690 920 C 695 935, 705 945, 710 1000\"\n fill=\"none\"\n stroke={`url(#${u}-purple-glow)`}\n strokeWidth=\"6\"\n strokeLinecap=\"round\"\n opacity=\"0.6\"\n mask={`url(#${u}-river-fade-mask)`}\n style={{\n filter: \"drop-shadow(0 0 6px rgba(219, 39, 119, 0.4))\",\n }}\n />\n <path\n d=\"M 590 340 C 570 370, 610 390, 590 410 C 570 430, 490 440, 510 480 C 530 520, 670 530, 700 560 C 720 580, 750 600, 730 630 C 710 660, 630 670, 650 710 C 660 730, 690 740, 700 760 C 710 780, 670 800, 650 830 C 630 860, 680 890, 690 920 C 695 935, 705 945, 710 1000\"\n fill=\"none\"\n stroke=\"#db2777\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n opacity=\"0.9\"\n mask={`url(#${u}-river-fade-mask)`}\n style={{\n strokeDasharray: \"25, 20\",\n animation: \"kzl-phoenix-flow-purple 8s linear infinite\",\n pointerEvents: \"none\",\n filter: \"drop-shadow(0 0 3px #db2777)\",\n }}\n />\n\n {/* Right Gold Flame Trail */}\n <path\n d=\"M 610 340 C 590 370, 630 390, 610 410 C 590 430, 510 440, 530 480 C 550 520, 690 530, 720 560 C 740 580, 770 600, 750 630 C 730 660, 650 670, 670 710 C 680 730, 710 740, 720 760 C 730 780, 690 800, 670 830 C 650 860, 700 890, 710 920 C 715 935, 725 945, 730 1000\"\n fill=\"none\"\n stroke={`url(#${u}-gold-glow)`}\n strokeWidth=\"6\"\n strokeLinecap=\"round\"\n opacity=\"0.6\"\n mask={`url(#${u}-river-fade-mask)`}\n style={{\n filter: \"drop-shadow(0 0 6px rgba(251, 191, 36, 0.4))\",\n }}\n />\n <path\n d=\"M 610 340 C 590 370, 630 390, 610 410 C 590 430, 510 440, 530 480 C 550 520, 690 530, 720 560 C 740 580, 770 600, 750 630 C 730 660, 650 670, 670 710 C 680 730, 710 740, 720 760 C 730 780, 690 800, 670 830 C 650 860, 700 890, 710 920 C 715 935, 725 945, 730 1000\"\n fill=\"none\"\n stroke=\"#fbbf24\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n opacity=\"0.9\"\n mask={`url(#${u}-river-fade-mask)`}\n style={{\n strokeDasharray: \"35, 15\",\n animation: \"kzl-phoenix-flow-gold 6s linear infinite\",\n pointerEvents: \"none\",\n filter: \"drop-shadow(0 0 3px #fbbf24)\",\n }}\n />\n\n {/* Hoverable Cyber-Phoenix Soaring in the Valley Center */}\n <g className=\"kzl-cyber-phoenix\" style={{ cursor: \"pointer\", pointerEvents: \"auto\" }}>\n {/* Main Body diamond capsule */}\n <polygon\n points=\"600,310 608,325 600,345 592,325\"\n fill={`url(#${u}-phoenix-body-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n />\n {/* Glowing Phoenix Core */}\n <circle cx=\"600\" cy=\"325\" r=\"3\" fill=\"#ffef5c\" className=\"kzl-phoenix-core\" />\n\n {/* Head */}\n <circle cx=\"600\" cy=\"302\" r=\"6\" fill={`url(#${u}-phoenix-body-grad)`} stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n {/* Visor */}\n <rect x=\"598\" y=\"300\" width=\"4\" height=\"2\" rx=\"0.5\" fill=\"#00f2fe\" />\n {/* Head Crest */}\n <polygon points=\"600,296 603,290 600,293 597,290\" fill=\"#ff3c00\" />\n\n {/* Left Wing (Purple mechanical fire) */}\n <path\n d=\"M 592 322 C 555 310, 520 325, 498 348 C 525 348, 545 338, 568 340 C 582 341, 588 333, 592 322 Z\"\n fill={`url(#${u}-phoenix-purple-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1\"\n className=\"kzl-phoenix-wing-l\"\n style={{ transformOrigin: \"592px 322px\" }}\n />\n\n {/* Right Wing (Gold mechanical fire) */}\n <path\n d=\"M 608 322 C 645 310, 680 325, 702 348 C 675 348, 655 338, 632 340 C 618 341, 612 333, 608 322 Z\"\n fill={`url(#${u}-phoenix-gold-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1\"\n className=\"kzl-phoenix-wing-r\"\n style={{ transformOrigin: \"608px 322px\" }}\n />\n </g>\n\n </>\n )}\n {/* ─── Cyber Trees & Hexagonal Foliage (Nature + Tech) ─── */}\n {/* Left Tree */}\n <g transform=\"translate(180, 360)\">\n {/* Server trunk */}\n <line x1=\"0\" y1=\"120\" x2=\"0\" y2=\"40\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"4\" />\n <rect x=\"-8\" y=\"50\" width=\"16\" height=\"28\" rx=\"2\" fill=\"var(--kz-surface-2)\" stroke=\"var(--kz-border-subtle)\" />\n {/* LED dots on trunk */}\n <circle cx=\"0\" cy=\"58\" r=\"1.5\" fill=\"var(--kz-accent)\" />\n <circle cx=\"0\" cy=\"66\" r=\"1.5\" fill=\"var(--kz-accent)\" opacity=\"0.6\" />\n {/* Hexagonal foliage */}\n <polygon points=\"0,-10 35,10 35,50 0,70 -35,50 -35,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.4\" />\n <polygon points=\"0,-5 25,10 25,40 0,55 -25,40 -25,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.6\" />\n </g>\n\n {/* Treehouse Tree (Center-Left) */}\n <g transform=\"translate(420, 320)\">\n {/* Trunk */}\n <line x1=\"0\" y1=\"180\" x2=\"0\" y2=\"60\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"5\" />\n <line x1=\"0\" y1=\"110\" x2=\"35\" y2=\"90\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"3.5\" />\n {/* Foliage */}\n <polygon points=\"0,-20 52,10 52,70 0,100 -52,70 -52,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.35\" />\n <polygon points=\"0,-10 38,10 38,55 0,75 -38,55 -38,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.5\" />\n\n {/* Hexagonal Treehouse */}\n <g transform=\"translate(0, 50)\" style={{ pointerEvents: \"auto\", cursor: \"pointer\" }} className=\"kzl-cyber-treehouse\">\n <polygon points=\"0,-30 26,-15 26,15 0,30 -26,15 -26,-15\" fill=\"var(--kz-surface-3)\" stroke=\"var(--kz-accent)\" strokeWidth=\"1.5\" />\n {/* Window */}\n <circle cx=\"0\" cy=\"0\" r=\"8\" fill=\"var(--kz-surface-1)\" stroke=\"var(--kz-border-strong)\" />\n <circle cx=\"0\" cy=\"0\" r=\"4\" fill=\"var(--kz-accent)\" className=\"kzl-window-glow\" />\n {/* Ladder */}\n <path d=\"M -6 30 L -6 95 M 6 30 L 6 95 M -6 42 L 6 42 M -6 54 L 6 54 M -6 66 L 6 66 M -6 78 L 6 78 M -6 90 L 6 90\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.5\" />\n {/* Animated green local data pulses rising from treehouse */}\n <circle cx=\"0\" cy=\"-45\" r=\"3\" fill=\"#10b981\" className=\"kzl-rising-pulse-1\" />\n <circle cx=\"15\" cy=\"-35\" r=\"2\" fill=\"#10b981\" className=\"kzl-rising-pulse-2\" />\n </g>\n </g>\n\n {/* Right Tree */}\n <g transform=\"translate(1000, 340)\">\n <line x1=\"0\" y1=\"160\" x2=\"0\" y2=\"60\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"4\" />\n <polygon points=\"0,-15 42,10 42,60 0,85 -42,60 -42,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.4\" />\n <polygon points=\"0,-5 28,10 28,42 0,60 -28,42 -28,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.6\" />\n </g>\n\n {/* ─── Cyber Tech Bench (Center-Right) ─── */}\n <g transform=\"translate(740, 480)\">\n {/* Bench support legs */}\n <line x1=\"20\" y1=\"35\" x2=\"20\" y2=\"60\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"4\" />\n <line x1=\"140\" y1=\"35\" x2=\"140\" y2=\"60\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"4\" />\n {/* Bench seat */}\n <rect x=\"0\" y=\"22\" width=\"160\" height=\"12\" rx=\"4\" fill={`url(#${u}-bench-grad)`} stroke=\"var(--kz-border-default)\" strokeWidth=\"1.2\" />\n {/* Bench backrest */}\n <rect x=\"0\" y=\"0\" width=\"160\" height=\"10\" rx=\"3\" fill={`url(#${u}-bench-grad)`} stroke=\"var(--kz-border-default)\" strokeWidth=\"1.2\" transform=\"rotate(-5, 80, 5)\" />\n {/* Backrest brackets */}\n <line x1=\"15\" y1=\"10\" x2=\"15\" y2=\"24\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"3\" />\n <line x1=\"145\" y1=\"10\" x2=\"145\" y2=\"24\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"3\" />\n </g>\n\n {flock && (\n <>\n {/* ─── MASCOT BIRD 4: Cyber Owl (Teal/Indigo - Left Tree) ─── */}\n <g transform=\"translate(180, 275) scale(1.4)\" className=\"kzl-bird-hitbox kzl-mobile-hide\">\n <rect x=\"-20\" y=\"-15\" width=\"40\" height=\"70\" fill=\"transparent\" style={{ cursor: \"pointer\", pointerEvents: \"all\" }} />\n <g className=\"kzl-bird-graphics kzl-owl-bot\">\n {/* Shadow */}\n <ellipse cx=\"0\" cy=\"50\" rx=\"16\" ry=\"4\" fill=\"rgba(0,0,0,0.15)\" />\n {/* Body */}\n <path\n d=\"M -15,10 C -15,-10, 15,-10, 15,10 C 15,30, 10,45, 0,45 C -10,45, -15,30, -15,10 Z\"\n fill={`url(#${u}-owl-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n />\n {/* Belly plate */}\n <path\n d=\"M -8,15 C -8,5, 8,5, 8,15 C 8,28, 5,35, 0,35 C -5,35, -8,28, -8,15 Z\"\n fill=\"#00f2fe\"\n opacity=\"0.35\"\n />\n {/* Eyes */}\n <circle cx=\"-6\" cy=\"2\" r=\"5\" fill=\"var(--kz-surface-0)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n <circle cx=\"6\" cy=\"2\" r=\"5\" fill=\"var(--kz-surface-0)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n <circle cx=\"-6\" cy=\"2\" r=\"2\" fill=\"#00ff66\" className=\"kzl-owl-eye\" />\n <circle cx=\"6\" cy=\"2\" r=\"2\" fill=\"#00ff66\" className=\"kzl-owl-eye\" />\n {/* Beak */}\n <polygon points=\"-2,4 2,4 0,10\" fill=\"#fbbf24\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n {/* Horns / Ears */}\n <polygon points=\"-12,-8 -6,-4 -14,2\" fill=\"#7c3aed\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n <polygon points=\"12,-8 6,-4 14,2\" fill=\"#7c3aed\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n </g>\n </g>\n\n {/* ─── MASCOT BIRD 1: Cyber-Sentry Falcon (Orange - Left) ─── */}\n <g transform=\"translate(120, 360) scale(1.65)\" className=\"kzl-bird-hitbox kzl-mobile-hide\">\n <rect x=\"-10\" y=\"0\" width=\"70\" height=\"90\" fill=\"transparent\" style={{ cursor: \"pointer\", pointerEvents: \"all\" }} />\n <g className=\"kzl-bird-graphics kzl-falcon-bot\">\n {/* Shadow */}\n <ellipse cx=\"25\" cy=\"85\" rx=\"30\" ry=\"6\" fill=\"rgba(0,0,0,0.15)\" />\n \n {/* Legs */}\n <line x1=\"16\" y1=\"65\" x2=\"12\" y2=\"85\" stroke=\"#f97316\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n <line x1=\"34\" y1=\"65\" x2=\"38\" y2=\"85\" stroke=\"#f97316\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n {/* Feet claws */}\n <path d=\"M 6 85 L 14 85 M 34 85 L 44 85\" stroke=\"#f97316\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n\n {/* Body */}\n <path\n d=\"M 5 35 C 5 20, 45 20, 45 35 C 45 58, 38 68, 25 68 C 12 68, 5 58, 5 35 Z\"\n fill={`url(#${u}-falcon-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.5\"\n />\n {/* Belly plate */}\n <path\n d=\"M 12 38 C 12 28, 38 28, 38 38 C 38 52, 32 58, 25 58 C 18 58, 12 52, 12 38 Z\"\n fill=\"#ff9800\"\n opacity=\"0.85\"\n />\n\n {/* Wings */}\n <path\n d=\"M 2 30 C -8 40, -4 60, 10 58 C 5 50, 4 38, 2 30 Z\"\n fill=\"#d84315\"\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n className=\"kzl-wing-left\"\n style={{ transformOrigin: \"2px 30px\" }}\n />\n <path\n d=\"M 48 30 C 58 40, 54 60, 40 58 C 45 50, 46 38, 48 30 Z\"\n fill=\"#d84315\"\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n className=\"kzl-wing-right\"\n style={{ transformOrigin: \"48px 30px\" }}\n />\n\n {/* Tail feathers */}\n <path d=\"M 20 66 L 15 80 L 25 76 L 35 80 L 30 66\" fill=\"#bf360c\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n\n {/* Head */}\n <g className=\"kzl-head-group\" style={{ transformOrigin: \"25px 28px\" }}>\n <circle cx=\"25\" cy=\"22\" r=\"18\" fill={`url(#${u}-falcon-grad)`} stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.5\" />\n \n {/* Beak */}\n <polygon points=\"21,24 29,24 25,36\" fill=\"#ffb300\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n\n {/* Visor */}\n <rect x=\"9\" y=\"10\" width=\"32\" height=\"10\" rx=\"3\" fill=\"var(--kz-surface-0)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n {/* Lenses */}\n <circle cx=\"17\" cy=\"15\" r=\"2.5\" fill=\"#00f2fe\" className=\"kzl-falcon-eye\" />\n <circle cx=\"33\" cy=\"15\" r=\"2.5\" fill=\"#00f2fe\" className=\"kzl-falcon-eye\" />\n {/* Wire */}\n <path d=\"M 41 15 C 44 15, 43 25, 41 28\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" fill=\"none\" />\n </g>\n\n {/* Sentry Scan Laser Overlay */}\n <polygon points=\"25,28 -60,180 110,180\" fill={`url(#${u}-holo-grad)`} className=\"kzl-sentry-laser\" opacity=\"0\" style={{ transformOrigin: \"25px 28px\", pointerEvents: \"none\" }} />\n </g>\n </g>\n\n {/* ─── MASCOT BIRD 2: Developer Duck (Pink - Center Bench) ─── */}\n <g transform=\"translate(750, 355) scale(1.75)\" className=\"kzl-bird-hitbox kzl-mobile-hide\">\n <rect x=\"-10\" y=\"5\" width=\"70\" height=\"75\" fill=\"transparent\" style={{ cursor: \"pointer\", pointerEvents: \"all\" }} />\n <g className=\"kzl-bird-graphics kzl-developer-duck\">\n {/* Sitting body */}\n <path\n d=\"M 5 45 C 5 30, 45 30, 45 45 C 45 62, 38 72, 25 72 C 12 72, 5 62, 5 45 Z\"\n fill={`url(#${u}-duck-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.5\"\n />\n {/* Belly light */}\n <path\n d=\"M 12 48 C 12 40, 38 40, 38 48 C 38 60, 32 64, 25 64 C 18 64, 12 60, 12 48 Z\"\n fill=\"#f472b6\"\n opacity=\"0.85\"\n />\n\n {/* Wings typing */}\n <path\n d=\"M -2 40 C -8 46, -4 55, 10 52\"\n fill=\"none\"\n stroke=\"#db2777\"\n strokeWidth=\"8\"\n strokeLinecap=\"round\"\n className=\"kzl-wing-left-type\"\n />\n <path\n d=\"M 52 40 C 58 46, 54 55, 40 52\"\n fill=\"none\"\n stroke=\"#db2777\"\n strokeWidth=\"8\"\n strokeLinecap=\"round\"\n className=\"kzl-wing-right-type\"\n />\n\n {/* Head */}\n <g className=\"kzl-head-group\" style={{ transformOrigin: \"25px 32px\" }}>\n <circle cx=\"25\" cy=\"24\" r=\"16\" fill={`url(#${u}-duck-grad)`} stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.5\" />\n {/* Duck Beak */}\n <path\n d=\"M 12 24 C 12 20, 22 18, 25 18 C 28 18, 38 20, 38 24 C 38 28, 28 32, 25 32 C 22 32, 12 28, 12 24 Z\"\n fill=\"#fbbf24\"\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n />\n {/* Eyes */}\n <circle cx=\"19\" cy=\"16\" r=\"2\" fill=\"var(--kz-text-primary)\" className=\"kzl-duck-eye\" />\n <circle cx=\"31\" cy=\"16\" r=\"2\" fill=\"var(--kz-text-primary)\" className=\"kzl-duck-eye\" />\n {/* Glasses */}\n <circle cx=\"19\" cy=\"16\" r=\"4.5\" fill=\"none\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n <circle cx=\"31\" cy=\"16\" r=\"4.5\" fill=\"none\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n <line x1=\"23.5\" y1=\"16\" x2=\"26.5\" y2=\"16\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n </g>\n\n {/* Holographic Laptop */}\n <g transform=\"translate(10, 52)\">\n {/* Base */}\n <polygon points=\"-8,16 38,16 30,22 -14,22\" fill=\"var(--kz-surface-3)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n {/* Hologram screen */}\n <polygon\n points=\"-4,14 34,14 30,-2 -8,-2\"\n fill=\"var(--kz-accent-soft)\"\n stroke=\"var(--kz-accent)\"\n strokeWidth=\"1\"\n opacity=\"0.8\"\n className=\"kzl-laptop-screen\"\n />\n {/* Glowing prompt line */}\n <line x1=\"-2\" y1=\"4\" x2=\"24\" y2=\"4\" stroke=\"var(--kz-accent)\" strokeWidth=\"1.5\" opacity=\"0.9\" />\n <line x1=\"-2\" y1=\"8\" x2=\"16\" y2=\"8\" stroke=\"var(--kz-accent)\" strokeWidth=\"1.5\" opacity=\"0.6\" />\n \n {/* Holographic Projection */}\n <polygon points=\"12,-2 -40,-80 70,-80\" fill={`url(#${u}-holo-grad)`} opacity=\"0\" className=\"kzl-holo-projection\" style={{ pointerEvents: \"none\" }} />\n {/* Tiny code elements inside hologram */}\n <g className=\"kzl-holo-elements\" opacity=\"0\">\n <rect x=\"-10\" y=\"-45\" width=\"22\" height=\"6\" rx=\"2\" fill=\"var(--kz-surface-3)\" stroke=\"#10b981\" strokeWidth=\"0.5\" />\n <rect x=\"18\" y=\"-35\" width=\"18\" height=\"6\" rx=\"2\" fill=\"var(--kz-surface-3)\" stroke=\"#10b981\" strokeWidth=\"0.5\" />\n </g>\n </g>\n </g>\n </g>\n\n {/* ─── MASCOT BIRD 3: High-Neck Flamingo-Bot (Blue - Right) ─── */}\n <g transform=\"translate(1000, 270) scale(1.75)\" className=\"kzl-bird-hitbox kzl-mobile-hide\">\n <rect x=\"-15\" y=\"0\" width=\"65\" height=\"165\" fill=\"transparent\" style={{ cursor: \"pointer\", pointerEvents: \"all\" }} />\n <g className=\"kzl-bird-graphics kzl-flamingo-bot\">\n {/* Shadow */}\n <ellipse cx=\"20\" cy=\"160\" rx=\"22\" ry=\"5\" fill=\"rgba(0,0,0,0.15)\" />\n\n {/* Long legs */}\n <line x1=\"12\" y1=\"105\" x2=\"12\" y2=\"160\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"2.5\" />\n <line x1=\"26\" y1=\"105\" x2=\"28\" y2=\"160\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"2.5\" />\n {/* Joints */}\n <circle cx=\"12\" cy=\"130\" r=\"2.5\" fill=\"#3b82f6\" />\n <circle cx=\"27\" cy=\"130\" r=\"2.5\" fill=\"#3b82f6\" />\n\n {/* Body */}\n <path\n d=\"M 2 80 C 2 68, 38 68, 38 80 C 38 108, 28 112, 20 112 C 12 112, 2 108, 2 80 Z\"\n fill={`url(#${u}-flamingo-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.5\"\n />\n\n {/* Wing (Vibrant contrast) */}\n <path\n d=\"M 8 82 L 20 74 L 32 82 L 32 94 L 20 102 L 8 94 Z\"\n fill=\"#ec4899\"\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1\"\n opacity=\"0.95\"\n className=\"kzl-flamingo-wing\"\n />\n\n {/* Curved neck */}\n <path\n d=\"M 20 74 C 20 60, -2 40, 8 18\"\n fill=\"none\"\n stroke={`url(#${u}-flamingo-grad)`}\n strokeWidth=\"6\"\n strokeLinecap=\"round\"\n className=\"kzl-flamingo-neck\"\n />\n\n {/* Head */}\n <g className=\"kzl-head-group\" transform=\"translate(8, 12)\" style={{ transformOrigin: \"0px 0px\" }}>\n <circle cx=\"0\" cy=\"0\" r=\"10\" fill={`url(#${u}-flamingo-grad)`} stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n \n {/* Eye */}\n <circle cx=\"-3\" cy=\"-2\" r=\"1.5\" fill=\"var(--kz-surface-0)\" />\n <circle cx=\"-3\" cy=\"-2\" r=\"0.6\" fill=\"#f43f5e\" className=\"kzl-flamingo-eye\" />\n\n {/* Beak */}\n <path d=\"M -8 -2 C -18 2, -16 14, -22 18 C -14 10, -8 4, -8 -2 Z\" fill=\"#fbbf24\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n\n {/* Hat */}\n <path d=\"M -8 -8 L 8 -8 L 6 -14 L -6 -14 Z\" fill=\"var(--kz-surface-3)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n <ellipse cx=\"0\" cy=\"-8\" rx=\"10\" ry=\"1.5\" fill=\"var(--kz-surface-3)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n </g>\n </g>\n </g>\n\n </>\n )}\n {/* ─── Floating Glowing Tech Particles ─── */}\n <circle cx=\"340\" cy=\"300\" r=\"6\" fill=\"#00f2fe\" opacity=\"0.75\" className=\"kzl-float-particle-1\" />\n <circle cx=\"520\" cy=\"220\" r=\"5\" fill=\"#a855f7\" opacity=\"0.65\" className=\"kzl-float-particle-2\" />\n <circle cx=\"710\" cy=\"310\" r=\"6.5\" fill=\"#3b82f6\" opacity=\"0.7\" className=\"kzl-float-particle-3\" />\n <circle cx=\"920\" cy=\"250\" r=\"5\" fill=\"#00f2fe\" opacity=\"0.8\" className=\"kzl-float-particle-4\" />\n </g>\n </svg>\n {fade && <div className=\"kzl-fade\" />}\n </div>\n );\n}\n"
|
|
134
|
+
"content": "// The Krizaka landscape — a valley at dusk under a constellation: three ranges of peaks, a phoenix over a river of\n// two flames, trees of light, a treehouse, and the flock at work (the falcon on watch, the owl, the duck at its\n// laptop, the flamingo). The brand layer's illustration, like the marks: drawn in code, ids unique per instance, its\n// own colours by default (`tone=\"own\"`) or the host brand's sky and peaks (`tone=\"brand\"`). Decorative.\nimport type * as React from \"react\";\nimport { useId } from \"react\";\n\nimport { cn } from \"../cn\";\n\n/** The sky and the peaks: the Krizaka dusk (`own`), or the host brand's accents (`brand`). Birds keep their colours. */\nconst TONES = {\n own: {\n \"--kzl-sun\": \"#f59e0b\",\n \"--kzl-sun-2\": \"#ec4899\",\n \"--kzl-sun-3\": \"#6366f1\",\n \"--kzl-far\": \"#6366f1\",\n \"--kzl-far-2\": \"#4f46e5\",\n \"--kzl-far-line\": \"#818cf8\",\n \"--kzl-mid\": \"#06b6d4\",\n \"--kzl-mid-2\": \"#0891b2\",\n \"--kzl-mid-line\": \"#22d3ee\",\n \"--kzl-near\": \"#d946ef\",\n \"--kzl-near-2\": \"#a855f7\",\n \"--kzl-near-line\": \"#e879f9\",\n \"--kzl-aurora-l\": \"#00f2fe\",\n \"--kzl-aurora-r\": \"#ec4899\",\n },\n brand: {\n \"--kzl-sun\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-sun-2\": \"var(--kz-accent)\",\n \"--kzl-sun-3\": \"var(--kz-accent)\",\n \"--kzl-far\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-far-2\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-far-line\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-mid\": \"color-mix(in srgb, var(--kz-accent) 55%, var(--kz-accent-2, var(--kz-accent)))\",\n \"--kzl-mid-2\": \"color-mix(in srgb, var(--kz-accent) 55%, var(--kz-accent-2, var(--kz-accent)))\",\n \"--kzl-mid-line\": \"color-mix(in srgb, var(--kz-accent) 55%, var(--kz-accent-2, var(--kz-accent)))\",\n \"--kzl-near\": \"var(--kz-accent)\",\n \"--kzl-near-2\": \"var(--kz-accent)\",\n \"--kzl-near-line\": \"var(--kz-accent)\",\n \"--kzl-aurora-l\": \"var(--kz-accent-2, var(--kz-accent))\",\n \"--kzl-aurora-r\": \"var(--kz-accent)\",\n },\n} as const;\n\nconst CSS = `\n.kzl { pointer-events: none; overflow: hidden; }\n.kzl-fade { position: absolute; bottom: 0; left: 0; right: 0; height: 120px; pointer-events: none; z-index: 3;\n background: linear-gradient(to top, var(--kz-surface-0) 0%, transparent 100%); }\n /* --- Cyber Phoenix & Flame Flow animations --- */\n @keyframes kzl-phoenix-flow-purple {\n from { stroke-dashoffset: 350; }\n to { stroke-dashoffset: 0; }\n }\n @keyframes kzl-phoenix-flow-gold {\n from { stroke-dashoffset: 0; }\n to { stroke-dashoffset: 350; }\n }\n @keyframes kzl-phoenix-bob {\n 0%, 100% { transform: translateY(0) scale(1); }\n 50% { transform: translateY(-8px) scale(1.02); }\n }\n @keyframes kzl-wing-flap-l-phoenix {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(-10deg) translateY(-2px); }\n }\n @keyframes kzl-wing-flap-r-phoenix {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(10deg) translateY(-2px); }\n }\n @keyframes kzl-core-glow {\n 0%, 100% { fill: #ffef5c; filter: drop-shadow(0 0 1px #ffef5c); }\n 50% { fill: #ffffff; filter: drop-shadow(0 0 5px #ff3c00); }\n }\n\n .kzl-cyber-phoenix {\n animation: kzl-phoenix-bob 4s ease-in-out infinite;\n transform-origin: 600px 325px;\n transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n }\n .kzl-cyber-phoenix:hover {\n transform: translateY(-4px) scale(1.08);\n }\n .kzl-phoenix-wing-l {\n animation: kzl-wing-flap-l-phoenix 2.5s ease-in-out infinite;\n }\n .kzl-phoenix-wing-r {\n animation: kzl-wing-flap-r-phoenix 2.5s ease-in-out infinite;\n }\n .kzl-cyber-phoenix:hover .kzl-phoenix-wing-l {\n animation: kzl-wing-flap-l-phoenix 0.6s linear infinite;\n }\n .kzl-cyber-phoenix:hover .kzl-phoenix-wing-r {\n animation: kzl-wing-flap-r-phoenix 0.6s linear infinite;\n }\n .kzl-phoenix-core {\n animation: kzl-core-glow 1.5s ease-in-out infinite;\n }\n\n /* --- Pulse Animations --- */\n @keyframes kzl-opacity-pulse {\n 0%, 100% { opacity: 0.35; }\n 50% { opacity: 0.95; }\n }\n .kzl-pulse-slow {\n animation: kzl-opacity-pulse 4s ease-in-out infinite;\n }\n @keyframes kzl-sun-pulse {\n 0%, 100% { opacity: 0.16; transform: scale(0.96); }\n 50% { opacity: 0.32; transform: scale(1.04); }\n }\n .kzl-sun-pulsing {\n animation: kzl-sun-pulse 6s ease-in-out infinite;\n transform-origin: 600px 200px;\n }\n\n /* --- Rising local data pulses --- */\n @keyframes kzl-rise-fade-1 {\n 0% { transform: translateY(80px) scale(0.5); opacity: 0; }\n 40% { opacity: 0.8; }\n 100% { transform: translateY(-30px) scale(1.3); opacity: 0; }\n }\n @keyframes kzl-rise-fade-2 {\n 0% { transform: translateY(60px) scale(0.4); opacity: 0; }\n 50% { opacity: 0.9; }\n 100% { transform: translateY(-50px) scale(1.2); opacity: 0; }\n }\n .kzl-rising-pulse-1 {\n animation: kzl-rise-fade-1 4s cubic-bezier(0.1, 0.8, 0.3, 1) infinite;\n transform-origin: center;\n }\n .kzl-rising-pulse-2 {\n animation: kzl-rise-fade-2 5s cubic-bezier(0.1, 0.8, 0.3, 1) infinite 1.5s;\n transform-origin: center;\n }\n\n /* --- Mascot Hover Animations (Stable Hitboxes) --- */\n .kzl-bird-graphics {\n transform-box: fill-box;\n transform-origin: center;\n transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n }\n .kzl-bird-hitbox:hover .kzl-bird-graphics {\n transform: scale(1.08) translateY(-4px);\n }\n\n /* --- Bird Eye Blinking/Glowing Animations --- */\n .kzl-falcon-eye {\n animation: kzl-falcon-eye-pulse 2.5s ease-in-out infinite;\n }\n .kzl-duck-eye {\n transform-box: fill-box;\n transform-origin: center;\n animation: kzl-eye-blink 5s ease-in-out infinite 1s;\n }\n .kzl-flamingo-eye {\n transform-box: fill-box;\n transform-origin: center;\n animation: kzl-eye-blink 6s ease-in-out infinite 2.5s;\n }\n .kzl-owl-eye {\n transform-box: fill-box;\n transform-origin: center;\n animation: kzl-eye-blink 4s ease-in-out infinite 0.5s;\n }\n\n @keyframes kzl-eye-blink {\n 0%, 90%, 100% {\n transform: scaleY(1);\n }\n 95% {\n transform: scaleY(0.15);\n }\n }\n\n @keyframes kzl-falcon-eye-pulse {\n 0%, 100% { fill: #00f2fe; filter: drop-shadow(0 0 2px #00f2fe); }\n 50% { fill: #00ff66; filter: drop-shadow(0 0 5px #00ff66); }\n }\n\n /* FalconBot constant loop animations */\n .kzl-falcon-bot .kzl-head-group {\n animation: kzl-head-bob 4s ease-in-out infinite;\n }\n .kzl-falcon-bot .kzl-wing-left {\n animation: kzl-wing-flap-left 3s ease-in-out infinite;\n }\n .kzl-falcon-bot .kzl-wing-right {\n animation: kzl-wing-flap-right 3s ease-in-out infinite;\n }\n .kzl-falcon-bot .kzl-sentry-laser {\n animation: kzl-scan-flicker 5s ease-in-out infinite;\n }\n\n @keyframes kzl-scan-flicker {\n 0%, 100% { opacity: 0; }\n 10%, 90% { opacity: 0.15; }\n 50% { opacity: 0.5; }\n }\n @keyframes kzl-head-bob {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 50% { transform: translateY(-2px) rotate(2deg); }\n }\n @keyframes kzl-wing-flap-left {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(-8deg) scaleX(1.05); }\n }\n @keyframes kzl-wing-flap-right {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(8deg) scaleX(1.05); }\n }\n\n /* Developer Duck constant loop animations */\n .kzl-developer-duck .kzl-head-group {\n animation: kzl-duck-look 6s ease-in-out infinite;\n }\n .kzl-developer-duck .kzl-wing-left-type {\n animation: kzl-wing-type-l 0.5s ease-in-out infinite;\n }\n .kzl-developer-duck .kzl-wing-right-type {\n animation: kzl-wing-type-r 0.5s ease-in-out infinite 0.25s;\n }\n .kzl-developer-duck .kzl-laptop-screen {\n animation: kzl-screen-flicker-idle 3s ease-in-out infinite;\n }\n .kzl-developer-duck .kzl-holo-projection {\n animation: kzl-holo-flicker 6s ease-in-out infinite;\n }\n .kzl-developer-duck .kzl-holo-elements {\n animation: kzl-holo-elements-rise 6s ease-in-out infinite;\n }\n\n @keyframes kzl-screen-flicker-idle {\n 0%, 100% { opacity: 0.7; }\n 50% { opacity: 0.95; filter: drop-shadow(0 0 3px var(--kz-accent)); }\n }\n @keyframes kzl-holo-flicker {\n 0%, 100% { opacity: 0; }\n 20%, 80% { opacity: 0.35; }\n 50% { opacity: 0.65; }\n }\n @keyframes kzl-holo-elements-rise {\n 0% { transform: translateY(10px); opacity: 0; }\n 50% { opacity: 0.8; }\n 100% { transform: translateY(-15px); opacity: 0; }\n }\n @keyframes kzl-duck-look {\n 0%, 100% { transform: rotate(0deg); }\n 30% { transform: rotate(-5deg); }\n 70% { transform: rotate(5deg); }\n }\n @keyframes kzl-wing-type-l {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 50% { transform: translateY(-3px) rotate(-4deg); }\n }\n @keyframes kzl-wing-type-r {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 50% { transform: translateY(-3px) rotate(4deg); }\n }\n\n /* Flamingo Bot constant loop animations */\n .kzl-flamingo-bot .kzl-head-group {\n animation: kzl-flamingo-head-bob 5s ease-in-out infinite;\n }\n .kzl-flamingo-bot .kzl-flamingo-neck {\n animation: kzl-flamingo-neck-sway 7s ease-in-out infinite;\n transform-origin: 20px 74px;\n }\n .kzl-flamingo-bot .kzl-flamingo-wing {\n animation: kzl-flamingo-wing-flap 4s ease-in-out infinite;\n }\n\n @keyframes kzl-flamingo-neck-sway {\n 0%, 100% { transform: rotate(0deg); }\n 50% { transform: rotate(-3deg) scaleY(1.02); }\n }\n @keyframes kzl-flamingo-head-bob {\n 0%, 100% { transform: translate(8px, 12px) translateY(0) rotate(0deg); }\n 50% { transform: translate(8px, 12px) translateY(-5px) rotate(-3deg); }\n }\n @keyframes kzl-flamingo-wing-flap {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 50% { transform: translateY(-2px) rotate(-6deg); }\n }\n\n /* Owl Bot constant loop animations */\n .kzl-owl-bot {\n animation: kzl-owl-sway 5s ease-in-out infinite;\n transform-origin: center;\n }\n @keyframes kzl-owl-sway {\n 0%, 100% { transform: rotate(0deg) translateY(0); }\n 50% { transform: rotate(-3deg) translateY(-2px); }\n }\n\n /* Treehouse hover glow */\n .kzl-cyber-treehouse:hover .kzl-window-glow {\n fill: #f59e0b;\n filter: drop-shadow(0 0 10px #f59e0b);\n }\n\n /* Floating tech particles */\n @keyframes kzl-float-up-down {\n 0%, 100% { transform: translateY(0); opacity: 0.4; }\n 50% { transform: translateY(-24px); opacity: 0.95; }\n }\n .kzl-float-particle-1 { animation: kzl-float-up-down 4.2s ease-in-out infinite; }\n .kzl-float-particle-2 { animation: kzl-float-up-down 5.2s ease-in-out infinite 1.2s; }\n .kzl-float-particle-3 { animation: kzl-float-up-down 4.7s ease-in-out infinite 0.6s; }\n .kzl-float-particle-4 { animation: kzl-float-up-down 6.2s ease-in-out infinite 2.2s; }\n\n @media (max-width: 1024px) {\n .kzl-mobile-hide {\n display: none !important;\n }\n }\n/* Still: with animated={false}, off screen, and under reduced motion — every loop holds its first frame. */\n.kzl[data-still] *, .kzl[data-offscreen] * { animation-play-state: paused !important; }\n@media (prefers-reduced-motion: reduce) {\n .kzl * { animation-play-state: paused !important; transition: none !important; }\n}\n`;\n\nexport type LandscapeProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> & {\n /**\n * `own`: the Krizaka dusk (indigo, cyan and magenta peaks). `brand`: the sky and the peaks in the host brand's\n * accents (`.brand-<id>`). The birds and the phoenix keep their own colours.\n * @default \"own\"\n */\n tone?: \"own\" | \"brand\";\n /**\n * The flock at work in the valley (hidden under 1024 px wide either way).\n * @default true\n */\n flock?: boolean;\n /**\n * The phoenix and its river of two flames.\n * @default true\n */\n phoenix?: boolean;\n /**\n * The slow loops (the sun, the stars, the flames, the birds). `false` holds the first frame; always held under\n * `prefers-reduced-motion` and while off screen (with `MotionObserver`).\n * @default true\n */\n animated?: boolean;\n /**\n * `absolute`: fills its positioned parent, anchored at the bottom (a backdrop). `relative`: a block in the flow — give\n * it a height.\n * @default \"absolute\"\n */\n position?: \"absolute\" | \"relative\";\n /**\n * Fades the bottom into the page's surface.\n * @default true\n */\n fade?: boolean;\n};\n\n/** The Krizaka landscape: a decorative backdrop for a hero or a page's end (`aria-hidden`). */\nexport function Landscape({ tone = \"own\", flock = true, phoenix = true, animated = true, position = \"absolute\", fade = true, className, style, ...props }: LandscapeProps) {\n const u = \"kzl\" + useId().replace(/[^a-zA-Z0-9_-]/g, \"\");\n const box: React.CSSProperties =\n position === \"absolute\" ? { position: \"absolute\", inset: \"auto 0 0 0\", height: \"100%\", width: \"100%\" } : { position: \"relative\", width: \"100%\", height: 440 };\n return (\n <div\n aria-hidden\n data-motion-scope=\"\"\n data-still={animated ? undefined : \"\"}\n className={cn(\"kzl\", className)}\n style={{ ...box, ...(TONES[tone] as React.CSSProperties), ...style }}\n {...props}\n >\n <style>{CSS}</style>\n <svg width=\"100%\" height=\"100%\" viewBox=\"0 50 1200 520\" preserveAspectRatio=\"xMidYMax slice\" fill=\"none\" style={{ display: \"block\", pointerEvents: \"none\" }}>\n <defs>\n {/* Vibrant Cyber Sun Glow */}\n <radialGradient id={`${u}-sun-glow`} cx=\"50%\" cy=\"50%\" r=\"50%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-sun)\" stopOpacity=\"0.45\" />\n <stop offset=\"30%\" stopColor=\"var(--kzl-sun-2)\" stopOpacity=\"0.28\" />\n <stop offset=\"70%\" stopColor=\"var(--kzl-sun-3)\" stopOpacity=\"0.16\" />\n <stop offset=\"100%\" stopColor=\"transparent\" stopOpacity=\"0\" />\n </radialGradient>\n\n {/* Mountains Vibrant Gradients */}\n <linearGradient id={`${u}-mtn-back`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-far)\" stopOpacity=\"0.75\" /> {/* indigo */}\n <stop offset=\"50%\" stopColor=\"var(--kzl-far-2)\" stopOpacity=\"0.45\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n <linearGradient id={`${u}-mtn-mid`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-mid)\" stopOpacity=\"0.7\" /> {/* cyan */}\n <stop offset=\"50%\" stopColor=\"var(--kzl-mid-2)\" stopOpacity=\"0.4\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n <linearGradient id={`${u}-mtn-front`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-near)\" stopOpacity=\"0.8\" /> {/* pink */}\n <stop offset=\"50%\" stopColor=\"var(--kzl-near-2)\" stopOpacity=\"0.5\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n\n {/* Vibrant Mascot Gradients */}\n <linearGradient id={`${u}-falcon-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#ff9f00\" />\n <stop offset=\"100%\" stopColor=\"#ff2a00\" />\n </linearGradient>\n <linearGradient id={`${u}-duck-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#f43f5e\" />\n <stop offset=\"100%\" stopColor=\"#be123c\" />\n </linearGradient>\n <linearGradient id={`${u}-flamingo-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#3e76a8\" />\n <stop offset=\"100%\" stopColor=\"#1d4ed8\" />\n </linearGradient>\n <linearGradient id={`${u}-owl-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#a78bfa\" />\n <stop offset=\"100%\" stopColor=\"#6d28d9\" />\n </linearGradient>\n\n {/* Hologram Projections */}\n <linearGradient id={`${u}-holo-grad`} x1=\"0%\" y1=\"100%\" x2=\"0%\" y2=\"0%\">\n <stop offset=\"0%\" stopColor=\"#10b981\" stopOpacity=\"0.5\" />\n <stop offset=\"100%\" stopColor=\"#10b981\" stopOpacity=\"0\" />\n </linearGradient>\n\n {/* Rival flame gradients for the Cyber-Phoenix */}\n <linearGradient id={`${u}-phoenix-gold-grad`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#ffb000\" />\n <stop offset=\"100%\" stopColor=\"#ff3c00\" />\n </linearGradient>\n <linearGradient id={`${u}-phoenix-purple-grad`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#c084fc\" />\n <stop offset=\"100%\" stopColor=\"#db2777\" />\n </linearGradient>\n <linearGradient id={`${u}-phoenix-body-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kz-surface-3)\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-2)\" />\n </linearGradient>\n\n {/* Glowing stream gradients */}\n <linearGradient id={`${u}-gold-glow`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#ff3c00\" stopOpacity=\"0.95\" />\n <stop offset=\"50%\" stopColor=\"#ffb000\" stopOpacity=\"0.75\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n <linearGradient id={`${u}-purple-glow`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#db2777\" stopOpacity=\"0.95\" />\n <stop offset=\"50%\" stopColor=\"#a78bfa\" stopOpacity=\"0.75\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-0)\" />\n </linearGradient>\n\n {/* River mask to fade out at the bottom */}\n <linearGradient id={`${u}-river-mask-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"85%\" stopColor=\"white\" />\n <stop offset=\"100%\" stopColor=\"black\" />\n </linearGradient>\n <mask id={`${u}-river-fade-mask`}>\n <rect x=\"0\" y=\"0\" width=\"1200\" height=\"1000\" fill={`url(#${u}-river-mask-grad)`} />\n </mask>\n\n {/* Cyber trees gradient */}\n <linearGradient id={`${u}-tree-grad`} x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"var(--kz-accent)\" stopOpacity=\"0.35\" />\n <stop offset=\"100%\" stopColor=\"transparent\" />\n </linearGradient>\n\n {/* Cyber Bench Gradient */}\n <linearGradient id={`${u}-bench-grad`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n <stop offset=\"0%\" stopColor=\"var(--kz-surface-3)\" />\n <stop offset=\"100%\" stopColor=\"var(--kz-surface-2)\" />\n </linearGradient>\n\n {/* Cyber Aurora Glows */}\n <radialGradient id={`${u}-aurora-left`} cx=\"20%\" cy=\"30%\" r=\"50%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-aurora-l)\" stopOpacity=\"0.22\" />\n <stop offset=\"100%\" stopColor=\"transparent\" stopOpacity=\"0\" />\n </radialGradient>\n <radialGradient id={`${u}-aurora-right`} cx=\"80%\" cy=\"25%\" r=\"50%\">\n <stop offset=\"0%\" stopColor=\"var(--kzl-aurora-r)\" stopOpacity=\"0.22\" />\n <stop offset=\"100%\" stopColor=\"transparent\" stopOpacity=\"0\" />\n </radialGradient>\n </defs>\n\n <g transform=\"translate(0, 60)\">\n {/* ─── Cyber Aurora Backdrop ─── */}\n <circle cx=\"200\" cy=\"180\" r=\"600\" fill={`url(#${u}-aurora-left)`} />\n <circle cx=\"1000\" cy=\"150\" r=\"600\" fill={`url(#${u}-aurora-right)`} />\n\n {/* ─── Ethereal Sun and Sky Network Nodes (Constellations) ─── */}\n <circle cx=\"600\" cy=\"200\" r=\"380\" fill={`url(#${u}-sun-glow)`} />\n <circle cx=\"600\" cy=\"200\" r=\"64\" fill=\"var(--kzl-sun)\" opacity=\"0.16\" className=\"kzl-sun-pulsing\" />\n\n {/* Constellation grid lines in the sky */}\n <g opacity=\"0.3\" stroke=\"var(--kz-accent)\" strokeWidth=\"1\">\n <line x1=\"300\" y1=\"120\" x2=\"380\" y2=\"80\" />\n <line x1=\"380\" y1=\"80\" x2=\"450\" y2=\"110\" />\n <line x1=\"450\" y1=\"110\" x2=\"300\" y2=\"120\" />\n <line x1=\"450\" y1=\"110\" x2=\"520\" y2=\"60\" />\n <line x1=\"750\" y1=\"80\" x2=\"840\" y2=\"130\" />\n <line x1=\"840\" y1=\"130\" x2=\"900\" y2=\"70\" />\n <line x1=\"900\" y1=\"70\" x2=\"750\" y2=\"80\" />\n </g>\n {/* Constellation node points */}\n <g fill=\"var(--kz-accent)\" opacity=\"0.65\">\n <circle cx=\"300\" cy=\"120\" r=\"3.5\" />\n <circle cx=\"380\" cy=\"80\" r=\"5\" className=\"kzl-pulse-slow\" />\n <circle cx=\"450\" cy=\"110\" r=\"3\" />\n <circle cx=\"520\" cy=\"60\" r=\"4.5\" />\n <circle cx=\"750\" cy=\"80\" r=\"4.5\" />\n <circle cx=\"840\" cy=\"130\" r=\"3.5\" />\n <circle cx=\"900\" cy=\"70\" r=\"6\" className=\"kzl-pulse-slow\" />\n </g>\n\n {/* ─── Layered Mountains (with Digital Contours) ─── */}\n {/* Far Peaks */}\n <path d=\"M 150 480 L 420 280 L 680 480 Z\" fill={`url(#${u}-mtn-back)`} stroke=\"var(--kzl-far-line)\" strokeWidth=\"1.5\" />\n <path d=\"M 520 480 L 780 230 L 1050 480 Z\" fill={`url(#${u}-mtn-back)`} stroke=\"var(--kzl-far-line)\" strokeWidth=\"1.5\" />\n\n {/* Mid Peaks */}\n <path d=\"M -50 500 L 220 320 L 500 500 Z\" fill={`url(#${u}-mtn-mid)`} stroke=\"var(--kzl-mid-line)\" strokeWidth=\"1.5\" />\n <path d=\"M 700 500 L 980 300 L 1250 500 Z\" fill={`url(#${u}-mtn-mid)`} stroke=\"var(--kzl-mid-line)\" strokeWidth=\"1.5\" />\n\n {/* Wireframe grids on mountains (Contour lines) */}\n <g stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.18\">\n {/* Mid peak left contours */}\n <line x1=\"30\" y1=\"440\" x2=\"410\" y2=\"440\" />\n <line x1=\"85\" y1=\"400\" x2=\"355\" y2=\"400\" />\n <line x1=\"140\" y1=\"360\" x2=\"300\" y2=\"360\" />\n {/* Mid peak right contours */}\n <line x1=\"770\" y1=\"450\" x2=\"1180\" y2=\"450\" />\n <line x1=\"825\" y1=\"410\" x2=\"1125\" y2=\"410\" />\n <line x1=\"880\" y1=\"370\" x2=\"1070\" y2=\"370\" />\n </g>\n\n {/* Front Peaks */}\n <path d=\"M 100 520 L 360 380 L 620 520 Z\" fill={`url(#${u}-mtn-front)`} stroke=\"var(--kzl-near-line)\" strokeWidth=\"1.8\" />\n <path d=\"M 580 520 L 850 350 L 1100 520 Z\" fill={`url(#${u}-mtn-front)`} stroke=\"var(--kzl-near-line)\" strokeWidth=\"1.8\" />\n\n {phoenix && (\n <>\n {/* ─── Cyber-Phoenix & Dual Glowing Flame Trails ─── */}\n {/* Dual Cascading Flame Trails */}\n {/* Left Purple Flame Trail */}\n <path\n d=\"M 590 340 C 570 370, 610 390, 590 410 C 570 430, 490 440, 510 480 C 530 520, 670 530, 700 560 C 720 580, 750 600, 730 630 C 710 660, 630 670, 650 710 C 660 730, 690 740, 700 760 C 710 780, 670 800, 650 830 C 630 860, 680 890, 690 920 C 695 935, 705 945, 710 1000\"\n fill=\"none\"\n stroke={`url(#${u}-purple-glow)`}\n strokeWidth=\"6\"\n strokeLinecap=\"round\"\n opacity=\"0.6\"\n mask={`url(#${u}-river-fade-mask)`}\n style={{\n filter: \"drop-shadow(0 0 6px rgba(219, 39, 119, 0.4))\",\n }}\n />\n <path\n d=\"M 590 340 C 570 370, 610 390, 590 410 C 570 430, 490 440, 510 480 C 530 520, 670 530, 700 560 C 720 580, 750 600, 730 630 C 710 660, 630 670, 650 710 C 660 730, 690 740, 700 760 C 710 780, 670 800, 650 830 C 630 860, 680 890, 690 920 C 695 935, 705 945, 710 1000\"\n fill=\"none\"\n stroke=\"#db2777\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n opacity=\"0.9\"\n mask={`url(#${u}-river-fade-mask)`}\n style={{\n strokeDasharray: \"25, 20\",\n animation: \"kzl-phoenix-flow-purple 8s linear infinite\",\n pointerEvents: \"none\",\n filter: \"drop-shadow(0 0 3px #db2777)\",\n }}\n />\n\n {/* Right Gold Flame Trail */}\n <path\n d=\"M 610 340 C 590 370, 630 390, 610 410 C 590 430, 510 440, 530 480 C 550 520, 690 530, 720 560 C 740 580, 770 600, 750 630 C 730 660, 650 670, 670 710 C 680 730, 710 740, 720 760 C 730 780, 690 800, 670 830 C 650 860, 700 890, 710 920 C 715 935, 725 945, 730 1000\"\n fill=\"none\"\n stroke={`url(#${u}-gold-glow)`}\n strokeWidth=\"6\"\n strokeLinecap=\"round\"\n opacity=\"0.6\"\n mask={`url(#${u}-river-fade-mask)`}\n style={{\n filter: \"drop-shadow(0 0 6px rgba(251, 191, 36, 0.4))\",\n }}\n />\n <path\n d=\"M 610 340 C 590 370, 630 390, 610 410 C 590 430, 510 440, 530 480 C 550 520, 690 530, 720 560 C 740 580, 770 600, 750 630 C 730 660, 650 670, 670 710 C 680 730, 710 740, 720 760 C 730 780, 690 800, 670 830 C 650 860, 700 890, 710 920 C 715 935, 725 945, 730 1000\"\n fill=\"none\"\n stroke=\"#fbbf24\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n opacity=\"0.9\"\n mask={`url(#${u}-river-fade-mask)`}\n style={{\n strokeDasharray: \"35, 15\",\n animation: \"kzl-phoenix-flow-gold 6s linear infinite\",\n pointerEvents: \"none\",\n filter: \"drop-shadow(0 0 3px #fbbf24)\",\n }}\n />\n\n {/* Hoverable Cyber-Phoenix Soaring in the Valley Center */}\n <g className=\"kzl-cyber-phoenix\" style={{ cursor: \"pointer\", pointerEvents: \"auto\" }}>\n {/* Main Body diamond capsule */}\n <polygon\n points=\"600,310 608,325 600,345 592,325\"\n fill={`url(#${u}-phoenix-body-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n />\n {/* Glowing Phoenix Core */}\n <circle cx=\"600\" cy=\"325\" r=\"3\" fill=\"#ffef5c\" className=\"kzl-phoenix-core\" />\n\n {/* Head */}\n <circle cx=\"600\" cy=\"302\" r=\"6\" fill={`url(#${u}-phoenix-body-grad)`} stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n {/* Visor */}\n <rect x=\"598\" y=\"300\" width=\"4\" height=\"2\" rx=\"0.5\" fill=\"#00f2fe\" />\n {/* Head Crest */}\n <polygon points=\"600,296 603,290 600,293 597,290\" fill=\"#ff3c00\" />\n\n {/* Left Wing (Purple mechanical fire) */}\n <path\n d=\"M 592 322 C 555 310, 520 325, 498 348 C 525 348, 545 338, 568 340 C 582 341, 588 333, 592 322 Z\"\n fill={`url(#${u}-phoenix-purple-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1\"\n className=\"kzl-phoenix-wing-l\"\n style={{ transformOrigin: \"592px 322px\" }}\n />\n\n {/* Right Wing (Gold mechanical fire) */}\n <path\n d=\"M 608 322 C 645 310, 680 325, 702 348 C 675 348, 655 338, 632 340 C 618 341, 612 333, 608 322 Z\"\n fill={`url(#${u}-phoenix-gold-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1\"\n className=\"kzl-phoenix-wing-r\"\n style={{ transformOrigin: \"608px 322px\" }}\n />\n </g>\n\n </>\n )}\n {/* ─── Cyber Trees & Hexagonal Foliage (Nature + Tech) ─── */}\n {/* Left Tree */}\n <g transform=\"translate(180, 360)\">\n {/* Server trunk */}\n <line x1=\"0\" y1=\"120\" x2=\"0\" y2=\"40\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"4\" />\n <rect x=\"-8\" y=\"50\" width=\"16\" height=\"28\" rx=\"2\" fill=\"var(--kz-surface-2)\" stroke=\"var(--kz-border-subtle)\" />\n {/* LED dots on trunk */}\n <circle cx=\"0\" cy=\"58\" r=\"1.5\" fill=\"var(--kz-accent)\" />\n <circle cx=\"0\" cy=\"66\" r=\"1.5\" fill=\"var(--kz-accent)\" opacity=\"0.6\" />\n {/* Hexagonal foliage */}\n <polygon points=\"0,-10 35,10 35,50 0,70 -35,50 -35,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.4\" />\n <polygon points=\"0,-5 25,10 25,40 0,55 -25,40 -25,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.6\" />\n </g>\n\n {/* Treehouse Tree (Center-Left) */}\n <g transform=\"translate(420, 320)\">\n {/* Trunk */}\n <line x1=\"0\" y1=\"180\" x2=\"0\" y2=\"60\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"5\" />\n <line x1=\"0\" y1=\"110\" x2=\"35\" y2=\"90\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"3.5\" />\n {/* Foliage */}\n <polygon points=\"0,-20 52,10 52,70 0,100 -52,70 -52,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.35\" />\n <polygon points=\"0,-10 38,10 38,55 0,75 -38,55 -38,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.5\" />\n\n {/* Hexagonal Treehouse */}\n <g transform=\"translate(0, 50)\" style={{ pointerEvents: \"auto\", cursor: \"pointer\" }} className=\"kzl-cyber-treehouse\">\n <polygon points=\"0,-30 26,-15 26,15 0,30 -26,15 -26,-15\" fill=\"var(--kz-surface-3)\" stroke=\"var(--kz-accent)\" strokeWidth=\"1.5\" />\n {/* Window */}\n <circle cx=\"0\" cy=\"0\" r=\"8\" fill=\"var(--kz-surface-1)\" stroke=\"var(--kz-border-strong)\" />\n <circle cx=\"0\" cy=\"0\" r=\"4\" fill=\"var(--kz-accent)\" className=\"kzl-window-glow\" />\n {/* Ladder */}\n <path d=\"M -6 30 L -6 95 M 6 30 L 6 95 M -6 42 L 6 42 M -6 54 L 6 54 M -6 66 L 6 66 M -6 78 L 6 78 M -6 90 L 6 90\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.5\" />\n {/* Animated green local data pulses rising from treehouse */}\n <circle cx=\"0\" cy=\"-45\" r=\"3\" fill=\"#10b981\" className=\"kzl-rising-pulse-1\" />\n <circle cx=\"15\" cy=\"-35\" r=\"2\" fill=\"#10b981\" className=\"kzl-rising-pulse-2\" />\n </g>\n </g>\n\n {/* Right Tree */}\n <g transform=\"translate(1000, 340)\">\n <line x1=\"0\" y1=\"160\" x2=\"0\" y2=\"60\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"4\" />\n <polygon points=\"0,-15 42,10 42,60 0,85 -42,60 -42,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.4\" />\n <polygon points=\"0,-5 28,10 28,42 0,60 -28,42 -28,10\" fill={`url(#${u}-tree-grad)`} stroke=\"var(--kz-accent)\" strokeWidth=\"1.2\" opacity=\"0.6\" />\n </g>\n\n {/* ─── Cyber Tech Bench (Center-Right) ─── */}\n <g transform=\"translate(740, 480)\">\n {/* Bench support legs */}\n <line x1=\"20\" y1=\"35\" x2=\"20\" y2=\"60\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"4\" />\n <line x1=\"140\" y1=\"35\" x2=\"140\" y2=\"60\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"4\" />\n {/* Bench seat */}\n <rect x=\"0\" y=\"22\" width=\"160\" height=\"12\" rx=\"4\" fill={`url(#${u}-bench-grad)`} stroke=\"var(--kz-border-default)\" strokeWidth=\"1.2\" />\n {/* Bench backrest */}\n <rect x=\"0\" y=\"0\" width=\"160\" height=\"10\" rx=\"3\" fill={`url(#${u}-bench-grad)`} stroke=\"var(--kz-border-default)\" strokeWidth=\"1.2\" transform=\"rotate(-5, 80, 5)\" />\n {/* Backrest brackets */}\n <line x1=\"15\" y1=\"10\" x2=\"15\" y2=\"24\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"3\" />\n <line x1=\"145\" y1=\"10\" x2=\"145\" y2=\"24\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"3\" />\n </g>\n\n {flock && (\n <>\n {/* ─── MASCOT BIRD 4: Cyber Owl (Teal/Indigo - Left Tree) ─── */}\n <g transform=\"translate(180, 275) scale(1.4)\" className=\"kzl-bird-hitbox kzl-mobile-hide\">\n <rect x=\"-20\" y=\"-15\" width=\"40\" height=\"70\" fill=\"transparent\" style={{ cursor: \"pointer\", pointerEvents: \"all\" }} />\n <g className=\"kzl-bird-graphics kzl-owl-bot\">\n {/* Shadow */}\n <ellipse cx=\"0\" cy=\"50\" rx=\"16\" ry=\"4\" fill=\"rgba(0,0,0,0.15)\" />\n {/* Body */}\n <path\n d=\"M -15,10 C -15,-10, 15,-10, 15,10 C 15,30, 10,45, 0,45 C -10,45, -15,30, -15,10 Z\"\n fill={`url(#${u}-owl-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n />\n {/* Belly plate */}\n <path\n d=\"M -8,15 C -8,5, 8,5, 8,15 C 8,28, 5,35, 0,35 C -5,35, -8,28, -8,15 Z\"\n fill=\"#00f2fe\"\n opacity=\"0.35\"\n />\n {/* Eyes */}\n <circle cx=\"-6\" cy=\"2\" r=\"5\" fill=\"var(--kz-surface-0)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n <circle cx=\"6\" cy=\"2\" r=\"5\" fill=\"var(--kz-surface-0)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n <circle cx=\"-6\" cy=\"2\" r=\"2\" fill=\"#00ff66\" className=\"kzl-owl-eye\" />\n <circle cx=\"6\" cy=\"2\" r=\"2\" fill=\"#00ff66\" className=\"kzl-owl-eye\" />\n {/* Beak */}\n <polygon points=\"-2,4 2,4 0,10\" fill=\"#fbbf24\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n {/* Horns / Ears */}\n <polygon points=\"-12,-8 -6,-4 -14,2\" fill=\"#7c3aed\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n <polygon points=\"12,-8 6,-4 14,2\" fill=\"#7c3aed\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n </g>\n </g>\n\n {/* ─── MASCOT BIRD 1: Cyber-Sentry Falcon (Orange - Left) ─── */}\n <g transform=\"translate(120, 360) scale(1.65)\" className=\"kzl-bird-hitbox kzl-mobile-hide\">\n <rect x=\"-10\" y=\"0\" width=\"70\" height=\"90\" fill=\"transparent\" style={{ cursor: \"pointer\", pointerEvents: \"all\" }} />\n <g className=\"kzl-bird-graphics kzl-falcon-bot\">\n {/* Shadow */}\n <ellipse cx=\"25\" cy=\"85\" rx=\"30\" ry=\"6\" fill=\"rgba(0,0,0,0.15)\" />\n \n {/* Legs */}\n <line x1=\"16\" y1=\"65\" x2=\"12\" y2=\"85\" stroke=\"#f97316\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n <line x1=\"34\" y1=\"65\" x2=\"38\" y2=\"85\" stroke=\"#f97316\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n {/* Feet claws */}\n <path d=\"M 6 85 L 14 85 M 34 85 L 44 85\" stroke=\"#f97316\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n\n {/* Body */}\n <path\n d=\"M 5 35 C 5 20, 45 20, 45 35 C 45 58, 38 68, 25 68 C 12 68, 5 58, 5 35 Z\"\n fill={`url(#${u}-falcon-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.5\"\n />\n {/* Belly plate */}\n <path\n d=\"M 12 38 C 12 28, 38 28, 38 38 C 38 52, 32 58, 25 58 C 18 58, 12 52, 12 38 Z\"\n fill=\"#ff9800\"\n opacity=\"0.85\"\n />\n\n {/* Wings */}\n <path\n d=\"M 2 30 C -8 40, -4 60, 10 58 C 5 50, 4 38, 2 30 Z\"\n fill=\"#d84315\"\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n className=\"kzl-wing-left\"\n style={{ transformOrigin: \"2px 30px\" }}\n />\n <path\n d=\"M 48 30 C 58 40, 54 60, 40 58 C 45 50, 46 38, 48 30 Z\"\n fill=\"#d84315\"\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n className=\"kzl-wing-right\"\n style={{ transformOrigin: \"48px 30px\" }}\n />\n\n {/* Tail feathers */}\n <path d=\"M 20 66 L 15 80 L 25 76 L 35 80 L 30 66\" fill=\"#bf360c\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n\n {/* Head */}\n <g className=\"kzl-head-group\" style={{ transformOrigin: \"25px 28px\" }}>\n <circle cx=\"25\" cy=\"22\" r=\"18\" fill={`url(#${u}-falcon-grad)`} stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.5\" />\n \n {/* Beak */}\n <polygon points=\"21,24 29,24 25,36\" fill=\"#ffb300\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n\n {/* Visor */}\n <rect x=\"9\" y=\"10\" width=\"32\" height=\"10\" rx=\"3\" fill=\"var(--kz-surface-0)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n {/* Lenses */}\n <circle cx=\"17\" cy=\"15\" r=\"2.5\" fill=\"#00f2fe\" className=\"kzl-falcon-eye\" />\n <circle cx=\"33\" cy=\"15\" r=\"2.5\" fill=\"#00f2fe\" className=\"kzl-falcon-eye\" />\n {/* Wire */}\n <path d=\"M 41 15 C 44 15, 43 25, 41 28\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" fill=\"none\" />\n </g>\n\n {/* Sentry Scan Laser Overlay */}\n <polygon points=\"25,28 -60,180 110,180\" fill={`url(#${u}-holo-grad)`} className=\"kzl-sentry-laser\" opacity=\"0\" style={{ transformOrigin: \"25px 28px\", pointerEvents: \"none\" }} />\n </g>\n </g>\n\n {/* ─── MASCOT BIRD 2: Developer Duck (Pink - Center Bench) ─── */}\n <g transform=\"translate(750, 355) scale(1.75)\" className=\"kzl-bird-hitbox kzl-mobile-hide\">\n <rect x=\"-10\" y=\"5\" width=\"70\" height=\"75\" fill=\"transparent\" style={{ cursor: \"pointer\", pointerEvents: \"all\" }} />\n <g className=\"kzl-bird-graphics kzl-developer-duck\">\n {/* Sitting body */}\n <path\n d=\"M 5 45 C 5 30, 45 30, 45 45 C 45 62, 38 72, 25 72 C 12 72, 5 62, 5 45 Z\"\n fill={`url(#${u}-duck-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.5\"\n />\n {/* Belly light */}\n <path\n d=\"M 12 48 C 12 40, 38 40, 38 48 C 38 60, 32 64, 25 64 C 18 64, 12 60, 12 48 Z\"\n fill=\"#f472b6\"\n opacity=\"0.85\"\n />\n\n {/* Wings typing */}\n <path\n d=\"M -2 40 C -8 46, -4 55, 10 52\"\n fill=\"none\"\n stroke=\"#db2777\"\n strokeWidth=\"8\"\n strokeLinecap=\"round\"\n className=\"kzl-wing-left-type\"\n />\n <path\n d=\"M 52 40 C 58 46, 54 55, 40 52\"\n fill=\"none\"\n stroke=\"#db2777\"\n strokeWidth=\"8\"\n strokeLinecap=\"round\"\n className=\"kzl-wing-right-type\"\n />\n\n {/* Head */}\n <g className=\"kzl-head-group\" style={{ transformOrigin: \"25px 32px\" }}>\n <circle cx=\"25\" cy=\"24\" r=\"16\" fill={`url(#${u}-duck-grad)`} stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.5\" />\n {/* Duck Beak */}\n <path\n d=\"M 12 24 C 12 20, 22 18, 25 18 C 28 18, 38 20, 38 24 C 38 28, 28 32, 25 32 C 22 32, 12 28, 12 24 Z\"\n fill=\"#fbbf24\"\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.2\"\n />\n {/* Eyes */}\n <circle cx=\"19\" cy=\"16\" r=\"2\" fill=\"var(--kz-text-primary)\" className=\"kzl-duck-eye\" />\n <circle cx=\"31\" cy=\"16\" r=\"2\" fill=\"var(--kz-text-primary)\" className=\"kzl-duck-eye\" />\n {/* Glasses */}\n <circle cx=\"19\" cy=\"16\" r=\"4.5\" fill=\"none\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n <circle cx=\"31\" cy=\"16\" r=\"4.5\" fill=\"none\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n <line x1=\"23.5\" y1=\"16\" x2=\"26.5\" y2=\"16\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n </g>\n\n {/* Holographic Laptop */}\n <g transform=\"translate(10, 52)\">\n {/* Base */}\n <polygon points=\"-8,16 38,16 30,22 -14,22\" fill=\"var(--kz-surface-3)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n {/* Hologram screen */}\n <polygon\n points=\"-4,14 34,14 30,-2 -8,-2\"\n fill=\"var(--kz-accent-soft)\"\n stroke=\"var(--kz-accent)\"\n strokeWidth=\"1\"\n opacity=\"0.8\"\n className=\"kzl-laptop-screen\"\n />\n {/* Glowing prompt line */}\n <line x1=\"-2\" y1=\"4\" x2=\"24\" y2=\"4\" stroke=\"var(--kz-accent)\" strokeWidth=\"1.5\" opacity=\"0.9\" />\n <line x1=\"-2\" y1=\"8\" x2=\"16\" y2=\"8\" stroke=\"var(--kz-accent)\" strokeWidth=\"1.5\" opacity=\"0.6\" />\n \n {/* Holographic Projection */}\n <polygon points=\"12,-2 -40,-80 70,-80\" fill={`url(#${u}-holo-grad)`} opacity=\"0\" className=\"kzl-holo-projection\" style={{ pointerEvents: \"none\" }} />\n {/* Tiny code elements inside hologram */}\n <g className=\"kzl-holo-elements\" opacity=\"0\">\n <rect x=\"-10\" y=\"-45\" width=\"22\" height=\"6\" rx=\"2\" fill=\"var(--kz-surface-3)\" stroke=\"#10b981\" strokeWidth=\"0.5\" />\n <rect x=\"18\" y=\"-35\" width=\"18\" height=\"6\" rx=\"2\" fill=\"var(--kz-surface-3)\" stroke=\"#10b981\" strokeWidth=\"0.5\" />\n </g>\n </g>\n </g>\n </g>\n\n {/* ─── MASCOT BIRD 3: High-Neck Flamingo-Bot (Blue - Right) ─── */}\n <g transform=\"translate(1000, 270) scale(1.75)\" className=\"kzl-bird-hitbox kzl-mobile-hide\">\n <rect x=\"-15\" y=\"0\" width=\"65\" height=\"165\" fill=\"transparent\" style={{ cursor: \"pointer\", pointerEvents: \"all\" }} />\n <g className=\"kzl-bird-graphics kzl-flamingo-bot\">\n {/* Shadow */}\n <ellipse cx=\"20\" cy=\"160\" rx=\"22\" ry=\"5\" fill=\"rgba(0,0,0,0.15)\" />\n\n {/* Long legs */}\n <line x1=\"12\" y1=\"105\" x2=\"12\" y2=\"160\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"2.5\" />\n <line x1=\"26\" y1=\"105\" x2=\"28\" y2=\"160\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"2.5\" />\n {/* Joints */}\n <circle cx=\"12\" cy=\"130\" r=\"2.5\" fill=\"#3e76a8\" />\n <circle cx=\"27\" cy=\"130\" r=\"2.5\" fill=\"#3e76a8\" />\n\n {/* Body */}\n <path\n d=\"M 2 80 C 2 68, 38 68, 38 80 C 38 108, 28 112, 20 112 C 12 112, 2 108, 2 80 Z\"\n fill={`url(#${u}-flamingo-grad)`}\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1.5\"\n />\n\n {/* Wing (Vibrant contrast) */}\n <path\n d=\"M 8 82 L 20 74 L 32 82 L 32 94 L 20 102 L 8 94 Z\"\n fill=\"#ec4899\"\n stroke=\"var(--kz-border-strong)\"\n strokeWidth=\"1\"\n opacity=\"0.95\"\n className=\"kzl-flamingo-wing\"\n />\n\n {/* Curved neck */}\n <path\n d=\"M 20 74 C 20 60, -2 40, 8 18\"\n fill=\"none\"\n stroke={`url(#${u}-flamingo-grad)`}\n strokeWidth=\"6\"\n strokeLinecap=\"round\"\n className=\"kzl-flamingo-neck\"\n />\n\n {/* Head */}\n <g className=\"kzl-head-group\" transform=\"translate(8, 12)\" style={{ transformOrigin: \"0px 0px\" }}>\n <circle cx=\"0\" cy=\"0\" r=\"10\" fill={`url(#${u}-flamingo-grad)`} stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n \n {/* Eye */}\n <circle cx=\"-3\" cy=\"-2\" r=\"1.5\" fill=\"var(--kz-surface-0)\" />\n <circle cx=\"-3\" cy=\"-2\" r=\"0.6\" fill=\"#f43f5e\" className=\"kzl-flamingo-eye\" />\n\n {/* Beak */}\n <path d=\"M -8 -2 C -18 2, -16 14, -22 18 C -14 10, -8 4, -8 -2 Z\" fill=\"#fbbf24\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n\n {/* Hat */}\n <path d=\"M -8 -8 L 8 -8 L 6 -14 L -6 -14 Z\" fill=\"var(--kz-surface-3)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1.2\" />\n <ellipse cx=\"0\" cy=\"-8\" rx=\"10\" ry=\"1.5\" fill=\"var(--kz-surface-3)\" stroke=\"var(--kz-border-strong)\" strokeWidth=\"1\" />\n </g>\n </g>\n </g>\n\n </>\n )}\n {/* ─── Floating Glowing Tech Particles ─── */}\n <circle cx=\"340\" cy=\"300\" r=\"6\" fill=\"#00f2fe\" opacity=\"0.75\" className=\"kzl-float-particle-1\" />\n <circle cx=\"520\" cy=\"220\" r=\"5\" fill=\"#a855f7\" opacity=\"0.65\" className=\"kzl-float-particle-2\" />\n <circle cx=\"710\" cy=\"310\" r=\"6.5\" fill=\"#3e76a8\" opacity=\"0.7\" className=\"kzl-float-particle-3\" />\n <circle cx=\"920\" cy=\"250\" r=\"5\" fill=\"#00f2fe\" opacity=\"0.8\" className=\"kzl-float-particle-4\" />\n </g>\n </svg>\n {fade && <div className=\"kzl-fade\" />}\n </div>\n );\n}\n"
|
|
135
135
|
},
|
|
136
136
|
{
|
|
137
137
|
"path": "landscape/meta.ts",
|